URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/example
- from Rev 60 to Rev 61
- ↔ Reverse comparison
Rev 60 → Rev 61
/demo_gpio_irq/main.c
File deleted
/demo_gpio_irq/makefile
File deleted
/demo_nco/main.c
File deleted
/demo_nco/makefile
File deleted
/blink_led/main.c
79,7 → 79,7
// check if GPIO unit is implemented at all |
if (neorv32_gpio_available() == 0) { |
neorv32_uart_print("Error! No GPIO unit synthesized!\n"); |
return 0; // nope, no GPIO unit synthesized |
return 1; // nope, no GPIO unit synthesized |
} |
|
// capture all exceptions and give debug info via UART |
86,9 → 86,6
// this is not required, but keeps us safe |
neorv32_rte_setup(); |
|
// check available hardware extensions and compare with compiler flags |
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch |
|
// say hello |
neorv32_uart_print("Blinking LED demo program\n"); |
|
/demo_xirq/main.c
0,0 → 1,196
// ################################################################################################# |
// # << NEORV32 - External Interrupt Controller (XIRQ) Demo Program >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file demo_xirq/main.c |
* @author Stephan Nolting |
* @brief External interrupt controller (XIRQ) demo program. |
**************************************************************************/ |
|
#include <neorv32.h> |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
/**@}*/ |
|
// prototypes |
void xirq_handler_ch0(void); |
void xirq_handler_ch1(void); |
void xirq_handler_ch2(void); |
void xirq_handler_ch3(void); |
|
|
/**********************************************************************//** |
* Main function |
* |
* @note This program requires the WDT and the UART to be synthesized. |
* |
* @return 0 if execution was successful |
**************************************************************************/ |
int main() { |
|
// initialize the neorv32 runtime environment |
// this will take care of handling all CPU traps (interrupts and exceptions) |
neorv32_rte_setup(); |
|
// setup UART0 at default baud rate, no parity bits, ho hw flow control |
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
// check if XIRQ unit is implemented at all |
if (neorv32_xirq_available() == 0) { |
neorv32_uart0_printf("XIRQ not synthesized!\n"); |
return 1; |
} |
|
|
// intro |
neorv32_uart0_printf("External interrupt controller (XIRQ) demo program\n\n"); |
|
int err_cnt = 0; |
|
|
// initialize XIRQ controller |
// this will disable all XIRQ channels and will also clear any pending external interrupts |
// (details: this will register the XIRQ's second-level interrupt handler in the NEORV32 RTE) |
err_cnt = neorv32_xirq_setup(); |
|
// check if setup went fine |
if (err_cnt) { |
neorv32_uart0_printf("Error during XIRQ setup!\n"); |
return 1; |
} |
|
|
// install handler functions for XIRQ channel 0,1,2,3. note that these functions are "normal" functions! |
// (details: these are "third-level" interrupt handler) |
err_cnt = 0; |
err_cnt += neorv32_xirq_install(0, xirq_handler_ch0); // handler function for channel 0 |
err_cnt += neorv32_xirq_install(1, xirq_handler_ch1); // handler function for channel 1 |
err_cnt += neorv32_xirq_install(2, xirq_handler_ch2); // handler function for channel 2 |
err_cnt += neorv32_xirq_install(3, xirq_handler_ch3); // handler function for channel 3 |
|
// check if installation went fine |
if (err_cnt) { |
neorv32_uart0_printf("Error during XIRQ install!\n"); |
return 1; |
} |
|
|
// allow XIRQ to trigger CPU interrupt |
neorv32_xirq_global_enable(); |
|
|
// enable global interrupts |
neorv32_cpu_eint(); |
|
|
// now we are ready to got! |
// the code below assumes the XIRQ inputs are connected to the processor's GPIO output port |
// so we can trigger the IRQs from software; if you have connected the XIRQs to buttons you |
// can remove the code below (note the trigger configuration using the XIRQ generics!) |
{ |
// trigger XIRQs 3:0 at once |
// assumes xirq_i <= gpio.output(31:0) |
|
// due to the prioritization this will execute |
// -> xirq_handler_ch0 |
// -> xirq_handler_ch1 |
// -> xirq_handler_ch2 |
// -> xirq_handler_ch3 |
neorv32_gpio_port_set(0xF); // set output pins 3:0 -> trigger XIRQ 3:0 |
neorv32_gpio_port_set(0x0); |
} |
|
|
// wait for interrupts |
while(1); |
|
|
// just as an example: to disable certain XIRQ interrupt channels, we can |
// uninstall the according handler. this will also clear a pending interrupt for that channel |
neorv32_xirq_uninstall(0); // disable XIRQ channel 0 and remove associated handler |
neorv32_xirq_uninstall(1); // disable XIRQ channel 1 and remove associated handler |
neorv32_xirq_uninstall(2); // disable XIRQ channel 2 and remove associated handler |
neorv32_xirq_uninstall(3); // disable XIRQ channel 3 and remove associated handler |
|
|
return 0; |
} |
|
|
/**********************************************************************//** |
* XIRQ handler channel 0. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch0(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 0); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 1. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch1(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 1); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 2. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch2(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 2); |
} |
|
/**********************************************************************//** |
* XIRQ handler channel 3. |
* |
* @warning This function has to be of type "void xyz(void)" and must not use any interrupt attributes! |
**************************************************************************/ |
void xirq_handler_ch3(void) { |
|
neorv32_uart0_printf("XIRQ interrupt from channel %i\n", 3); |
} |
/demo_xirq/makefile
0,0 → 1,338
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
# # |
# 1. Redistributions of source code must retain the above copyright notice, this list of # |
# conditions and the following disclaimer. # |
# # |
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
# conditions and the following disclaimer in the documentation and/or other materials # |
# provided with the distribution. # |
# # |
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
# endorse or promote products derived from this software without specific prior written # |
# permission. # |
# # |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
# OF THE POSSIBILITY OF SUCH DAMAGE. # |
# ********************************************************************************************* # |
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
################################################################################################# |
|
|
# ***************************************************************************** |
# USER CONFIGURATION |
# ***************************************************************************** |
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here |
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) |
|
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC ?= -I . |
# User's application include folders - for assembly files only (don't forget the '-I' before each entry) |
ASM_INC ?= -I . |
|
# Optimization |
EFFORT ?= -Os |
|
# Compiler toolchain |
RISCV_TOOLCHAIN ?= riscv32-unknown-elf |
|
# CPU architecture and ABI |
MARCH ?= -march=rv32i |
MABI ?= -mabi=ilp32 |
|
# User flags for additional configuration (will be added to compiler flags) |
USER_FLAGS ?= |
|
# Serial port for executable upload via bootloer |
COM_PORT ?= /dev/ttyUSB0 |
|
# Relative or absolute path to the NEORV32 home folder |
NEORV32_HOME ?= ../../.. |
# ***************************************************************************** |
|
|
|
# ----------------------------------------------------------------------------- |
# NEORV32 framework |
# ----------------------------------------------------------------------------- |
# Path to NEORV32 linker script and startup file |
NEORV32_COM_PATH = $(NEORV32_HOME)/sw/common |
# Path to main NEORV32 library include files |
NEORV32_INC_PATH = $(NEORV32_HOME)/sw/lib/include |
# Path to main NEORV32 library source files |
NEORV32_SRC_PATH = $(NEORV32_HOME)/sw/lib/source |
# Path to NEORV32 executable generator |
NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen |
# Path to NEORV32 core rtl folder |
NEORV32_RTL_PATH = $(NEORV32_HOME)/rtl/core |
# Marker file to check for NEORV32 home folder |
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h |
|
# Core libraries (peripheral and CPU drivers) |
CORE_SRC = $(wildcard $(NEORV32_SRC_PATH)/*.c) |
# Application start-up code |
CORE_SRC += $(NEORV32_COM_PATH)/crt0.S |
|
# Linker script |
LD_SCRIPT = $(NEORV32_COM_PATH)/neorv32.ld |
|
# Main output files |
APP_EXE = neorv32_exe.bin |
APP_ASM = main.asm |
APP_IMG = neorv32_application_image.vhd |
BOOT_IMG = neorv32_bootloader_image.vhd |
|
|
# ----------------------------------------------------------------------------- |
# Sources and objects |
# ----------------------------------------------------------------------------- |
# Define all sources |
SRC = $(APP_SRC) |
SRC += $(CORE_SRC) |
|
# Define all object files |
OBJ = $(SRC:%=%.o) |
|
|
# ----------------------------------------------------------------------------- |
# Tools and flags |
# ----------------------------------------------------------------------------- |
# Compiler tools |
CC = $(RISCV_TOOLCHAIN)-gcc |
OBJDUMP = $(RISCV_TOOLCHAIN)-objdump |
OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy |
SIZE = $(RISCV_TOOLCHAIN)-size |
|
# Host native compiler |
CC_X86 = g++ -Wall -O -g |
|
# NEORV32 executable image generator |
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
CC_OPTS += $(USER_FLAGS) |
|
|
# ----------------------------------------------------------------------------- |
# Application output definitions |
# ----------------------------------------------------------------------------- |
.PHONY: check info help elf_info clean clean_all bootloader |
.DEFAULT_GOAL := help |
|
# 'compile' is still here for compatibility |
exe: $(APP_ASM) $(APP_EXE) |
compile: $(APP_ASM) $(APP_EXE) |
install: $(APP_ASM) $(APP_IMG) |
all: $(APP_ASM) $(APP_EXE) $(APP_IMG) |
|
# Check if making bootloader |
# Use different base address and legth for instruction memory/"rom" (BOOTMEM instead of IMEM) |
# Also define "make_bootloader" for crt0.S |
target bootloader: CC_OPTS += -Wl,--defsym=make_bootloader=1 -Dmake_bootloader |
|
|
# ----------------------------------------------------------------------------- |
# Image generator targets |
# ----------------------------------------------------------------------------- |
# install/compile tools |
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.cpp |
@echo Compiling $(IMAGE_GEN) |
@$(CC_X86) $< -o $(IMAGE_GEN) |
|
|
# ----------------------------------------------------------------------------- |
# General targets: Assemble, compile, link, dump |
# ----------------------------------------------------------------------------- |
# Compile app *.s sources (assembly) |
%.s.o: %.s |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.S sources (assembly + C pre-processor) |
%.S.o: %.S |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.c sources |
%.c.o: %.c |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Compile app *.cpp sources |
%.cpp.o: %.cpp |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Link object files and show memory utilization |
main.elf: $(OBJ) |
@$(CC) $(CC_OPTS) -T $(LD_SCRIPT) $(OBJ) -o $@ -lm |
@echo "Memory utilization:" |
@$(SIZE) main.elf |
|
# Assembly listing file (for debugging) |
$(APP_ASM): main.elf |
@$(OBJDUMP) -d -S -z $< > $@ |
|
# Generate final executable from .text + .rodata + .data (in THIS order!) |
main.bin: main.elf $(APP_ASM) |
@$(OBJCOPY) -I elf32-little $< -j .text -O binary text.bin |
@$(OBJCOPY) -I elf32-little $< -j .rodata -O binary rodata.bin |
@$(OBJCOPY) -I elf32-little $< -j .data -O binary data.bin |
@cat text.bin rodata.bin data.bin > $@ |
@rm -f text.bin rodata.bin data.bin |
|
|
# ----------------------------------------------------------------------------- |
# Application targets: Generate binary executable, install (as VHDL file) |
# ----------------------------------------------------------------------------- |
# Generate NEORV32 executable image for upload via bootloader |
$(APP_EXE): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR)) |
@echo "Executable ($(APP_EXE)) size in bytes:" |
@wc -c < $(APP_EXE) |
|
# Generate NEORV32 executable VHDL boot image |
$(APP_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR)) |
@echo "Installing application image to $(NEORV32_RTL_PATH)/$(APP_IMG)" |
@cp $(APP_IMG) $(NEORV32_RTL_PATH)/. |
|
|
# ----------------------------------------------------------------------------- |
# Bootloader targets |
# ----------------------------------------------------------------------------- |
# Create and install bootloader VHDL init image |
$(BOOT_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -bld_img $< $(BOOT_IMG) $(shell basename $(CURDIR)) |
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/$(BOOT_IMG)" |
@cp $(BOOT_IMG) $(NEORV32_RTL_PATH)/. |
|
# Just an alias that |
bootloader: $(BOOT_IMG) |
|
|
# ----------------------------------------------------------------------------- |
# Check toolchain |
# ----------------------------------------------------------------------------- |
check: $(IMAGE_GEN) |
@echo "---------------- Check: NEORV32_HOME folder ----------------" |
ifneq ($(shell [ -e $(NEORV32_HOME_MARKER) ] && echo 1 || echo 0 ), 1) |
$(error NEORV32_HOME folder not found!) |
endif |
@echo "NEORV32_HOME: $(NEORV32_HOME)" |
@echo "---------------- Check: $(CC) ----------------" |
@$(CC) -v |
@echo "---------------- Check: $(OBJDUMP) ----------------" |
@$(OBJDUMP) -V |
@echo "---------------- Check: $(OBJCOPY) ----------------" |
@$(OBJCOPY) -V |
@echo "---------------- Check: $(SIZE) ----------------" |
@$(SIZE) -V |
@echo "---------------- Check: NEORV32 image_gen ----------------" |
@$(IMAGE_GEN) -help |
@echo "---------------- Check: Native GCC ----------------" |
@$(CC_X86) -v |
@echo |
@echo "Toolchain check OK" |
|
|
# ----------------------------------------------------------------------------- |
# Upload executable via serial port to bootloader |
# ----------------------------------------------------------------------------- |
upload: $(APP_EXE) |
@sh $(NEORV32_EXG_PATH)/uart_upload.sh $(COM_PORT) $(APP_EXE) |
|
|
# ----------------------------------------------------------------------------- |
# Show configuration |
# ----------------------------------------------------------------------------- |
info: |
@echo "---------------- Info: Project ----------------" |
@echo "Project folder: $(shell basename $(CURDIR))" |
@echo "Source files: $(APP_SRC)" |
@echo "Include folder(s): $(APP_INC)" |
@echo "ASM include folder(s): $(ASM_INC)" |
@echo "---------------- Info: NEORV32 ----------------" |
@echo "NEORV32 home folder (NEORV32_HOME): $(NEORV32_HOME)" |
@echo "IMAGE_GEN: $(IMAGE_GEN)" |
@echo "Core source files:" |
@echo "$(CORE_SRC)" |
@echo "Core include folder:" |
@echo "$(NEORV32_INC_PATH)" |
@echo "---------------- Info: Objects ----------------" |
@echo "Project object files:" |
@echo "$(OBJ)" |
@echo "---------------- Info: RISC-V CPU ----------------" |
@echo "MARCH: $(MARCH)" |
@echo "MABI: $(MABI)" |
@echo "---------------- Info: Toolchain ----------------" |
@echo "Toolchain: $(RISCV_TOLLCHAIN)" |
@echo "CC: $(CC)" |
@echo "OBJDUMP: $(OBJDUMP)" |
@echo "OBJCOPY: $(OBJCOPY)" |
@echo "SIZE: $(SIZE)" |
@echo "---------------- Info: Compiler Libraries ----------------" |
@echo "LIBGCC:" |
@$(CC) -print-libgcc-file-name |
@echo "SEARCH-DIRS:" |
@$(CC) -print-search-dirs |
@echo "---------------- Info: Flags ----------------" |
@echo "USER_FLAGS: $(USER_FLAGS)" |
@echo "CC_OPTS: $(CC_OPTS)" |
@echo "---------------- Info: Host Native GCC Flags ----------------" |
@echo "CC_X86: $(CC_X86)" |
|
|
# ----------------------------------------------------------------------------- |
# Show final ELF details (just for debugging) |
# ----------------------------------------------------------------------------- |
elf_info: main.elf |
@$(OBJDUMP) -x main.elf |
|
|
# ----------------------------------------------------------------------------- |
# Help |
# ----------------------------------------------------------------------------- |
help: |
@echo "<<< NEORV32 Application Makefile >>>" |
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable." |
@echo "Targets:" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " all - compile and generate <neorv32_exe.bin> executable for upload via bootloader and generate and install VHDL IMEM boot image (for application)" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo " upload - upload <neorv32_exe.bin> executable via serial port <COM_PORT> to bootloader" |
|
|
# ----------------------------------------------------------------------------- |
# Clean up |
# ----------------------------------------------------------------------------- |
clean: |
@rm -f *.elf *.o *.bin *.out *.asm *.vhd |
|
clean_all: clean |
@rm -f $(OBJ) $(IMAGE_GEN) |
/hex_viewer/main.c
210,7 → 210,7
char terminal_buffer[16]; |
uint32_t mem_address, rdata, wdata, status; |
|
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) { |
|
// enter memory address |
neorv32_uart_printf("Enter memory address (8 hex chars): 0x"); |
/processor_check/check.sh
33,6 → 33,7
clean_all \ |
USER_FLAGS+=-DRUN_CHECK \ |
USER_FLAGS+=-DUART0_SIM_MODE \ |
USER_FLAGS+=-DUART1_SIM_MODE \ |
MARCH=-march=rv32imac \ |
info \ |
all |
/processor_check/main.c
58,9 → 58,30
/**@}*/ |
|
|
/**********************************************************************//** |
* @name UART print macros |
**************************************************************************/ |
/**@{*/ |
//** for simulation only! */ |
#ifdef SUPPRESS_OPTIONAL_UART_PRINT |
//** print standard output to UART0 */ |
#define PRINT_STANDARD(...) |
//** print critical output to UART1 */ |
#define PRINT_CRITICAL(...) neorv32_uart1_printf(__VA_ARGS__) |
#else |
//** print standard output to UART0 */ |
#define PRINT_STANDARD(...) neorv32_uart0_printf(__VA_ARGS__) |
//** print critical output to UART0 */ |
#define PRINT_CRITICAL(...) neorv32_uart0_printf(__VA_ARGS__) |
#endif |
/**@}*/ |
|
|
// Prototypes |
void sim_irq_trigger(uint32_t sel); |
void global_trap_handler(void); |
void xirq_trap_handler0(void); |
void xirq_trap_handler1(void); |
void test_ok(void); |
void test_fail(void); |
|
71,10 → 92,12
int cnt_ok = 0; |
/// Global counter for total number of tests |
int cnt_test = 0; |
/// Global numbe rof available HPMs |
/// Global number of available HPMs |
uint32_t num_hpm_cnts_global = 0; |
/// XIRQ trap handler acknowledge |
uint32_t xirq_trap_handler_ack = 0; |
|
/// Variable to test atomic accessess |
/// Variable to test atomic accesses |
uint32_t atomic_access_addr; |
|
|
82,6 → 105,8
* High-level CPU/processor test program. |
* |
* @note Applications has to be compiler with <USER_FLAGS+=-DRUN_CPUTEST> |
* @warning This test is intended for simulation only. |
* @warning This test requires all optional extensions/modules to be enabled. |
* |
* @return 0 if execution was successful |
**************************************************************************/ |
88,31 → 113,27
int main() { |
|
register uint32_t tmp_a, tmp_b; |
volatile uint32_t dummy_dst __attribute__((unused)); |
uint8_t id; |
uint32_t is_simulation = 0; |
|
|
// init UART at default baud rate, no parity bits, no hw flow control |
neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
// init UARTs at default baud rate, no parity bits, no hw flow control |
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
UART1_CT = UART0_CT; // copy configuration to initialize UART1 |
|
#ifdef SUPPRESS_OPTIONAL_UART_PRINT |
neorv32_uart0_disable(); // do not generate any UART0 output |
#endif |
|
// Disable processor_check compilation by default |
#ifndef RUN_CHECK |
#warning processor_check HAS NOT BEEN COMPILED! Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it. |
|
// inform the user if you are actually executing this |
neorv32_uart_printf("ERROR! processor_check has not been compiled. Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.\n"); |
PRINT_CRITICAL("ERROR! processor_check has not been compiled. Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.\n"); |
|
return 1; |
#endif |
|
// check if this is a simulation (using primary UART0) |
if (UART0_CT & (1 << UART_CT_SIM_MODE)) { |
is_simulation = 1; |
} |
else { |
is_simulation = 0; |
} |
|
// ---------------------------------------------- |
// setup RTE |
124,8 → 145,8
|
|
// intro |
neorv32_uart_printf("\n<< PROCESSOR CHECK >>\n"); |
neorv32_uart_printf("build: "__DATE__" "__TIME__"\n"); |
PRINT_STANDARD("\n<< PROCESSOR CHECK >>\n"); |
PRINT_STANDARD("build: "__DATE__" "__TIME__"\n"); |
|
|
// reset performance counter |
156,7 → 177,7
|
// configure RTE |
// ----------------------------------------------- |
neorv32_uart_printf("\n\nConfiguring NEORV32 RTE... "); |
PRINT_STANDARD("\n\nConfiguring NEORV32 RTE... "); |
|
int install_err = 0; |
// initialize ALL provided trap handler (overriding the default debug handlers) |
165,18 → 186,18
} |
|
if (install_err) { |
neorv32_uart_printf("RTE install error (%i)!\n", install_err); |
PRINT_CRITICAL("RTE install error (%i)!\n", install_err); |
return 1; |
} |
|
// enable interrupt sources |
neorv32_cpu_irq_enable(CSR_MIE_MSIE); // machine software interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MTIE); // machine timer interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MEIE); // machine external interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MSIE); // machine software interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MTIE); // machine timer interrupt |
neorv32_cpu_irq_enable(CSR_MIE_MEIE); // machine external interrupt |
// enable FAST IRQ sources only where actually needed |
|
// test intro |
neorv32_uart_printf("\nStarting tests...\n\n"); |
PRINT_STANDARD("\nStarting tests...\n\n"); |
|
// enable global interrupts |
neorv32_cpu_eint(); |
186,7 → 207,7
// Test standard RISC-V performance counter [m]cycle[h] |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] [m]instret[h] counter: ", cnt_test); |
PRINT_STANDARD("[%i] [m]cycle[h] counter: ", cnt_test); |
|
cnt_test++; |
|
193,12 → 214,14
// make sure counter is enabled |
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY)); |
|
// get current cycle counter LOW |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE); |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLE) - tmp_a; |
// prepare overflow |
neorv32_cpu_set_mcycle(0x00000000FFFFFFFFULL); |
|
// make sure cycle counter has incremented and there was no exception during access |
if ((tmp_a > 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
// get current cycle counter HIGH |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLEH); |
|
// make sure cycle counter high has incremented and there was no exception during access |
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
210,7 → 233,7
// Test standard RISC-V performance counter [m]instret[h] |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] [m]cycle[h] counter: ", cnt_test); |
PRINT_STANDARD("[%i] [m]instret[h] counter: ", cnt_test); |
|
cnt_test++; |
|
217,19 → 240,15
// make sure counter is enabled |
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_IR)); |
|
// get instruction counter LOW |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET); |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRET) - tmp_a; |
// prepare overflow |
neorv32_cpu_set_minstret(0x00000000FFFFFFFFULL); |
|
// make sure instruction counter has incremented and there was no exception during access |
if ((tmp_a > 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
if (tmp_a > 1) { |
neorv32_uart_printf("INSTRET_diff > 1 (%u)!", tmp_a); |
test_fail(); |
} |
else { |
test_ok(); |
} |
// get instruction counter HIGH |
tmp_a = neorv32_cpu_csr_read(CSR_INSTRETH); |
|
// make sure instruction counter high has incremented and there was no exception during access |
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
240,7 → 259,7
// Test mcountinhibt: inhibit auto-inc of [m]cycle |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] mcountinhibt.cy CSR: ", cnt_test); |
PRINT_STANDARD("[%i] mcountinhibt.cy CSR: ", cnt_test); |
|
cnt_test++; |
|
276,10 → 295,10
// Test mcounteren: do not allow cycle[h] access from user-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] mcounteren.cy CSR: ", cnt_test); |
PRINT_STANDARD("[%i] mcounteren.cy CSR: ", cnt_test); |
|
// skip if U-mode is not implemented |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) { |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) { |
cnt_test++; |
|
// do not allow user-level code to access cycle[h] CSRs |
308,7 → 327,7
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
322,7 → 341,7
// Test performance counter: setup as many events and counter as feasible |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Initializing HPMs: ", cnt_test); |
PRINT_STANDARD("[%i] Configuring HPM events: ", cnt_test); |
|
num_hpm_cnts_global = neorv32_cpu_hpm_get_counters(); |
|
353,114 → 372,87
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
//// ---------------------------------------------------------- |
//// Bus timeout latency estimation |
//// out of order :P |
//// ---------------------------------------------------------- |
//neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
//neorv32_uart_printf("[%i] Estimating bus time-out latency: ", cnt_test); |
//cnt_test++; |
// |
//// start timing |
//neorv32_cpu_csr_write(CSR_MCYCLE, 0); |
// |
//// make sure there was a timeout |
//if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) { |
// neorv32_uart_printf("~%u cycles ", trap_timestamp32-175); // remove trap handler overhead - empiric value ;) |
// test_ok(); |
//} |
//else { |
// test_fail(); |
//} |
|
|
// ---------------------------------------------------------- |
// External memory interface test |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE); |
PRINT_STANDARD("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE); |
|
if (is_simulation) { // check if this is a simulation |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) { |
cnt_test++; |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) { |
cnt_test++; |
|
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
|
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
|
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
//// ---------------------------------------------------------- |
//// Test FENCE.I instruction (instruction buffer / i-cache clear & reload) |
//// ---------------------------------------------------------- |
//neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
//neorv32_uart_printf("[%i] FENCE.I: ", cnt_test); |
// |
//// check if implemented |
//if (neorv32_cpu_csr_read(CSR_MZEXT) & (1 << CSR_MZEXT_ZIFENCEI)) { |
// cnt_test++; |
// |
// asm volatile ("fence.i"); |
// |
// // make sure there was no exception (and that the cpu did not crash...) |
// if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// test_ok(); |
// } |
// else { |
// test_fail(); |
// } |
//} |
//else { |
// neorv32_uart_printf("skipped (not implemented)\n"); |
//} |
// ---------------------------------------------------------- |
// Test FENCE.I instruction (instruction buffer / i-cache clear & reload) |
// if Zifencei is not implemented FENCE.I should execute as NOP |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FENCE.I: ", cnt_test); |
|
cnt_test++; |
|
asm volatile ("fence.i"); |
|
// make sure there was no exception (and that the cpu did not crash...) |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Illegal CSR access (CSR not implemented) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Illegal CSR (0xfff) access: ", cnt_test); |
PRINT_STANDARD("[%i] Non-existent CSR access: ", cnt_test); |
|
cnt_test++; |
|
neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented |
tmp_a = neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented |
|
if (tmp_a != 0) { |
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27); |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
473,7 → 465,7
// Write-access to read-only CSR |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) write access: ", cnt_test); |
PRINT_STANDARD("[%i] Read-only CSR write access: ", cnt_test); |
|
cnt_test++; |
|
491,7 → 483,7
// No "real" CSR write access (because rs1 = r0) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) no-write (rs1=0) access: ", cnt_test); |
PRINT_STANDARD("[%i] Read-only CSR 'no-write' (rs1=0) access: ", cnt_test); |
|
cnt_test++; |
|
511,37 → 503,33
// Test pending interrupt |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Pending IRQ test (from MTIME): ", cnt_test); |
PRINT_STANDARD("[%i] Pending IRQ test (MTIME): ", cnt_test); |
|
if (neorv32_mtime_available()) { |
cnt_test++; |
cnt_test++; |
|
// disable global interrupts |
neorv32_cpu_dint(); |
// disable global interrupts |
neorv32_cpu_dint(); |
|
// force MTIME IRQ |
neorv32_mtime_set_timecmp(0); |
// prepare MTIME IRQ |
neorv32_mtime_set_time(0x00000000FFFFFFF8ULL); // prepare overflow |
neorv32_mtime_set_timecmp(0x0000000100000000ULL); // IRQ on overflow |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
// re-enable global interrupts |
neorv32_cpu_eint(); |
// re-enable global interrupts |
neorv32_cpu_eint(); |
|
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
|
549,10 → 537,10
// Unaligned instruction address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test); |
|
// skip if C-mode is implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) == 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) == 0) { |
|
cnt_test++; |
|
560,16 → 548,16
((void (*)(void))ADDR_UNALIGNED)(); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_MISALIGNED) { |
neorv32_uart_printf("ok\n"); |
PRINT_STANDARD("ok\n"); |
cnt_ok++; |
} |
else { |
neorv32_uart_printf("fail\n"); |
PRINT_STANDARD("fail\n"); |
cnt_fail++; |
} |
} |
else { |
neorv32_uart_printf("skipped (n.a. with C-ext)\n"); |
PRINT_STANDARD("skipped (n.a. with C-ext)\n"); |
} |
|
|
577,7 → 565,7
// Instruction access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ACC (instr. bus access) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] I_ACC (instr. bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// call unreachable aligned address |
595,7 → 583,7
// Illegal instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ILLEG (illegal instr.) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] I_ILLEG (illegal instr.) EXC: ", cnt_test); |
|
cnt_test++; |
|
621,10 → 609,10
// Illegal compressed instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] CI_ILLEG (illegal compr. instr.) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] CI_ILLEG (illegal compr. instr.) EXC: ", cnt_test); |
|
// skip if C-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) != 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C)) != 0) { |
|
cnt_test++; |
|
645,7 → 633,7
} |
} |
else { |
neorv32_uart_printf("skipped (n.a. with C-ext)\n"); |
PRINT_STANDARD("skipped (n.a. with C-ext)\n"); |
} |
|
|
653,7 → 641,7
// Breakpoint instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] BREAK (break instr.) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] BREAK (break instr.) EXC: ", cnt_test); |
cnt_test++; |
|
asm volatile("EBREAK"); |
670,11 → 658,11
// Unaligned load address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test); |
cnt_test++; |
|
// load from unaligned address |
asm volatile ("lw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED)); |
neorv32_cpu_load_unsigned_word(ADDR_UNALIGNED); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) { |
test_ok(); |
688,11 → 676,11
// Load access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ACC (load bus access) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] L_ACC (load bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// load from unreachable aligned address |
dummy_dst = neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE); |
neorv32_cpu_load_unsigned_word(ADDR_UNREACHABLE); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) { |
test_ok(); |
706,7 → 694,7
// Unaligned store address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test); |
cnt_test++; |
|
// store to unaligned address |
724,7 → 712,7
// Store access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ACC (store bus access) EXC: ", cnt_test); |
PRINT_STANDARD("[%i] S_ACC (store bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// store to unreachable aligned address |
742,7 → 730,7
// Environment call from M-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test); |
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test); |
cnt_test++; |
|
asm volatile("ECALL"); |
759,10 → 747,10
// Environment call from U-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test); |
PRINT_STANDARD("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test); |
|
// skip if U-mode is not implemented |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) { |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) { |
|
cnt_test++; |
|
781,7 → 769,7
|
} |
else { |
neorv32_uart_printf("skipped (n.a. without U-ext)\n"); |
PRINT_STANDARD("skipped (n.a. without U-ext)\n"); |
} |
|
|
789,66 → 777,56
// Machine timer interrupt (MTIME) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MTI (via MTIME): ", cnt_test); |
PRINT_STANDARD("[%i] MTI (via MTIME): ", cnt_test); |
|
if (neorv32_mtime_available()) { |
cnt_test++; |
cnt_test++; |
|
// configure MTIME IRQ (and check overflow form low owrd to high word) |
neorv32_mtime_set_timecmp(-1); |
neorv32_mtime_set_time(0); |
// configure MTIME IRQ (and check overflow form low owrd to high word) |
neorv32_mtime_set_timecmp(-1); |
neorv32_mtime_set_time(0); |
|
neorv32_cpu_csr_write(CSR_MIP, 0); // clear all pending IRQs |
neorv32_cpu_csr_write(CSR_MIP, 0); // clear all pending IRQs |
|
neorv32_mtime_set_timecmp(0x0000000100000000ULL); |
neorv32_mtime_set_time( 0x00000000FFFFFFFEULL); |
neorv32_mtime_set_timecmp(0x0000000100000000ULL); |
neorv32_mtime_set_time( 0x00000000FFFFFFFEULL); |
|
// wait some time for the IRQ to trigger and arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to trigger and arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
|
// ---------------------------------------------------------- |
// Machine software interrupt (MSI) via testbench |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MSI (via testbench): ", cnt_test); |
PRINT_STANDARD("[%i] MSI (via testbench): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
cnt_test++; |
|
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MSIE); |
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MSIE); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MSI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
856,27 → 834,22
// Machine external interrupt (MEI) via testbench |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MEI (via testbench): ", cnt_test); |
PRINT_STANDARD("[%i] MEI (via testbench): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
cnt_test++; |
|
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MEIE); |
// trigger IRQ |
sim_irq_trigger(1 << CSR_MIE_MEIE); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MEI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MEI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
884,27 → 857,22
// Non-maskable interrupt (NMI) via testbench |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] NMI (via testbench): ", cnt_test); |
PRINT_STANDARD("[%i] NMI (via testbench): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
cnt_test++; |
|
// trigger IRQ |
sim_irq_trigger(1 << 0); |
// trigger IRQ |
sim_irq_trigger(1 << 0); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_NMI) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_NMI) { |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
test_fail(); |
} |
|
|
911,10 → 879,10
// ---------------------------------------------------------- |
// Fast interrupt channel 0 (WDT) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ0 test (via WDT): ", cnt_test); |
if (neorv32_wdt_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ0 test (via WDT): ", cnt_test); |
|
if (neorv32_wdt_available()) { |
cnt_test++; |
|
// enable fast interrupt |
942,25 → 910,22
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ0E); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 1 (CFS) |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] FIRQ1 test (via CFS): ", cnt_test); |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("[%i] FIRQ1 test (via CFS): ", cnt_test); |
PRINT_STANDARD("skipped (n.a.)\n"); |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 2 (UART0.RX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ2 test (via UART0.RX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ2 test (via UART0.RX): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
|
// enable fast interrupt |
967,26 → 932,27
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E); |
|
// wait for UART0 to finish transmitting |
while(neorv32_uart_tx_busy()); |
while(neorv32_uart0_tx_busy()); |
|
// backup current UART0 configuration |
tmp_a = UART0_CT; |
|
// disable UART0 sim_mode if it is enabled |
// make sure UART is enabled |
UART0_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART0 RX IRQ |
// the default test bench connects UART0.TXD_O to UART0_RXD_I |
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active |
neorv32_uart0_putc(0); |
|
// wait for UART0 to finish transmitting |
while(neorv32_uart_tx_busy()); |
while(neorv32_uart0_tx_busy()); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// re-enable UART0 sim_mode if it was enabled |
// restore original configuration |
UART0_CT = tmp_a; |
|
// disable fast interrupt |
999,74 → 965,77
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 3 (UART0.TX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ3 test (via UART0.TX): ", cnt_test); |
if (neorv32_uart0_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ3 test (via UART0.TX): ", cnt_test); |
|
cnt_test++; |
cnt_test++; |
|
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
|
// wait for UART0 to finish transmitting |
while(neorv32_uart_tx_busy()); |
// wait for UART0 to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
// backup current UART0 configuration |
tmp_a = UART0_CT; |
// backup current UART0 configuration |
tmp_a = UART0_CT; |
|
// disable UART0 sim_mode if it is enabled |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
// make sure UART is enabled |
UART0_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART0 TX IRQ |
UART0_DATA = 0; // we need to access the raw HW here, since >UART0_SIM_MODE< might be active |
// trigger UART0 TX IRQ |
neorv32_uart0_putc(0); |
|
// wait for UART to finish transmitting |
while(neorv32_uart_tx_busy()); |
// wait for UART to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// re-enable UART sim_mode if it was enabled |
UART0_CT = tmp_a; |
// restore original configuration |
UART0_CT = tmp_a; |
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ3E); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ3E); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) { |
test_ok(); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 4 (UART1.RX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ4 test (via UART1.RX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ4 test (via UART1.RX): ", cnt_test); |
|
if ((neorv32_uart1_available()) && (is_simulation)) { // UART1 available and we are in a simulation |
cnt_test++; |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E); |
|
// initialize UART1 |
UART1_CT = 0; |
tmp_a = UART0_CT; // copy configuration from UART0 |
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled |
UART1_CT = tmp_a; |
// backup current UART1 configuration |
tmp_a = UART1_CT; |
|
// make sure UART is enabled |
UART1_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART1_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART1 RX IRQ |
UART1_DATA = 0; |
neorv32_uart1_putc(0); |
|
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
1075,8 → 1044,8
asm volatile("nop"); |
asm volatile("nop"); |
|
// disable UART1 |
UART1_CT = 0; |
// restore original configuration |
UART1_CT = tmp_a; |
|
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ4E); |
1088,31 → 1057,30
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 5 (UART1.TX) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ5 test (via UART1.TX): ", cnt_test); |
if (neorv32_uart1_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ5 test (via UART1.TX): ", cnt_test); |
|
if (neorv32_uart1_available()) { |
cnt_test++; |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E); |
|
// initialize UART1 |
UART1_CT = 0; |
tmp_a = UART0_CT; // copy configuration from UART0 |
tmp_a &= ~(1 << UART_CT_SIM_MODE); // make sure sim_mode is disabled |
UART1_CT = tmp_a; |
// backup current UART1 configuration |
tmp_a = UART1_CT; |
|
// make sure UART is enabled |
UART1_CT |= (1 << UART_CT_EN); |
// make sure sim mode is disabled |
UART1_CT &= ~(1 << UART_CT_SIM_MODE); |
|
// trigger UART1 TX IRQ |
UART1_DATA = 0; |
neorv32_uart1_putc(0); |
|
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
1121,8 → 1089,8
asm volatile("nop"); |
asm volatile("nop"); |
|
// disable UART1 |
UART1_CT = 0; |
// restore original configuration |
UART1_CT = tmp_a; |
|
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ5E); |
1134,18 → 1102,15
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 6 (SPI) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ6 test (via SPI): ", cnt_test); |
if (neorv32_spi_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ6 test (via SPI): ", cnt_test); |
|
if (neorv32_spi_available()) { |
cnt_test++; |
|
// enable fast interrupt |
1175,18 → 1140,15
// disable fast interrupt |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ6E); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 7 (TWI) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ7 test (via TWI): ", cnt_test); |
if (neorv32_twi_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ7 test (via TWI): ", cnt_test); |
|
if (neorv32_twi_available()) { |
cnt_test++; |
|
// configure TWI, fastest clock, no peripheral clock stretching |
1214,157 → 1176,143
neorv32_twi_disable(); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ7E); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 8 (GPIO) |
// Fast interrupt channel 8 (XIRQ) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ8 test (via GPIO): ", cnt_test); |
PRINT_STANDARD("[%i] FIRQ8 test (via XIRQ): ", cnt_test); |
if (neorv32_xirq_available()) { |
|
if (is_simulation) { // check if this is a simulation |
if (neorv32_gpio_available()) { |
cnt_test++; |
cnt_test++; |
|
// clear output port |
neorv32_gpio_port_set(0); |
int xirq_err_cnt = 0; |
xirq_trap_handler_ack = 0; |
|
neorv32_cpu_irq_enable(CSR_MIE_FIRQ8E); |
xirq_err_cnt += neorv32_xirq_setup(); // initialize XIRQ |
xirq_err_cnt += neorv32_xirq_install(0, xirq_trap_handler0); // install XIRQ IRQ handler channel 0 |
xirq_err_cnt += neorv32_xirq_install(1, xirq_trap_handler1); // install XIRQ IRQ handler channel 1 |
|
// configure GPIO.in(31) for pin-change IRQ |
neorv32_gpio_pin_change_config(0x80000000); |
neorv32_xirq_global_enable(); // enable XIRQ FIRQ |
|
// trigger pin-change IRQ by setting GPIO.out(31) |
// the testbench connects GPIO.out => GPIO.in |
neorv32_gpio_pin_set(31); |
// trigger XIRQ channel 1 and 0 |
neorv32_gpio_port_set(3); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
// wait for IRQs to arrive CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_8) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// disable GPIO pin-change IRQ |
neorv32_gpio_pin_change_config(0); |
|
// clear output port |
neorv32_gpio_port_set(0); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ8E); |
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_8) && // FIRQ8 IRQ |
(xirq_err_cnt == 0) && // no errors during XIRQ configuration |
(xirq_trap_handler_ack == 4)) { // XIRQ channel handler 0 executed before handler 1 |
test_ok(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_fail(); |
} |
|
neorv32_xirq_global_disable(); |
XIRQ_IER = 0; |
XIRQ_IPR = -1; |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 9 (reserved) |
// Fast interrupt channel 9 (NEOLED) |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] FIRQ9: ", cnt_test); |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("[%i] FIRQ9 (NEOLED): skipped\n", cnt_test); |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 10..15 (SoC fast IRQ 0..5) |
// Fast interrupt channel 10 & 11 (SLINK) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ10..15 (SoC fast IRQ 0..5; via testbench): ", cnt_test); |
if (neorv32_slink_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ10 & 11 (SLINK): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
|
cnt_test++; |
|
// enable SOC FIRQs |
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) { |
neorv32_cpu_irq_enable(id); |
// enable SLINK |
neorv32_slink_enable(); |
|
// enable SLINK FIRQs |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ10E); |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ11E); |
|
tmp_a = 0; // error counter |
|
// send single data word via link 0 |
if (neorv32_slink_tx0_nonblocking(0xA1B2C3D4)) { |
tmp_a++; // sending failed |
} |
|
// trigger all SoC Fast interrupts at once |
neorv32_cpu_dint(); // do not fire yet! |
sim_irq_trigger((1 << CSR_MIE_FIRQ10E) | (1 << CSR_MIE_FIRQ11E) | (1 << CSR_MIE_FIRQ12E) | (1 << CSR_MIE_FIRQ13E) | (1 << CSR_MIE_FIRQ14E) | (1 << CSR_MIE_FIRQ15E)); |
// get single data word from link 0 |
uint32_t slink_rx_data; |
if (neorv32_slink_rx0_nonblocking(&slink_rx_data)) { |
tmp_a++; // receiving failed |
} |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
|
// make sure all SoC FIRQs have been triggered |
tmp_a = (1 << CSR_MIP_FIRQ10P) | (1 << CSR_MIP_FIRQ11P) | (1 << CSR_MIP_FIRQ12P) | (1 << CSR_MIP_FIRQ13P) | (1 << CSR_MIP_FIRQ14P) | (1 << CSR_MIP_FIRQ15P); |
|
if (neorv32_cpu_csr_read(CSR_MIP) == tmp_a) { |
neorv32_cpu_eint(); // allow IRQs to fire again |
asm volatile ("nop"); |
asm volatile ("nop"); // irq should kick in HERE |
|
tmp_a = neorv32_cpu_csr_read(CSR_MCAUSE); |
if ((tmp_a >= TRAP_CODE_FIRQ_8) && (tmp_a <= TRAP_CODE_FIRQ_15)) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
tmp_b = neorv32_cpu_csr_read(CSR_MCAUSE); |
if (((tmp_b == TRAP_CODE_FIRQ_10) || (tmp_b == TRAP_CODE_FIRQ_11)) && // right trap code |
(tmp_a == 0) && // local error counter = 0 |
(slink_rx_data == 0xA1B2C3D4)) { // correct data read-back |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// disable SOC FIRQs |
for (id=CSR_MIE_FIRQ10E; id<=CSR_MIE_FIRQ15E; id++) { |
neorv32_cpu_irq_disable(id); |
} |
// shutdown SLINK |
neorv32_slink_disable(); |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
} |
|
neorv32_cpu_eint(); // re-enable IRQs globally |
|
//// ---------------------------------------------------------- |
//// Fast interrupt channel 12..15 (reserved) |
//// ---------------------------------------------------------- |
//PRINT_STANDARD("[%i] FIRQ12..15: ", cnt_test); |
//PRINT_STANDARD("skipped (n.a.)\n"); |
|
|
// ---------------------------------------------------------- |
// Test WFI ("sleep") instructions, wakeup via MTIME |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] WFI (sleep instruction) test (wake-up via MTIME): ", cnt_test); |
PRINT_STANDARD("[%i] WFI (sleep instruction) test (wake-up via MTIME): ", cnt_test); |
|
if (neorv32_mtime_available()) { |
cnt_test++; |
cnt_test++; |
|
// program wake-up timer |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000); |
// program wake-up timer |
neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + 1000); |
|
// put CPU into sleep mode |
asm volatile ("wfi"); |
// put CPU into sleep mode |
asm volatile ("wfi"); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_MTI) { |
test_fail(); |
} |
else { |
test_ok(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_MTI) { |
test_fail(); |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
test_ok(); |
} |
|
// no more mtime interrupts |
neorv32_mtime_set_timecmp(-1); |
|
|
// ---------------------------------------------------------- |
// Test invalid CSR access in user mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test); |
PRINT_STANDARD("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test); |
|
// skip if U-mode is not implemented |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) { |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U)) { |
|
cnt_test++; |
|
1375,13 → 1323,12
tmp_a = neorv32_cpu_csr_read(CSR_MISA); |
} |
|
if (tmp_a != 0) { |
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27); |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
if (tmp_a == 0) { // make sure user-level code CANNOT read machine-level CSR content! |
test_ok(); |
} |
else { |
test_fail(); |
} |
test_ok(); |
} |
else { |
test_fail(); |
1389,7 → 1336,7
|
} |
else { |
neorv32_uart_printf("skipped (n.a. without U-ext)\n"); |
PRINT_STANDARD("skipped (n.a. without U-ext)\n"); |
} |
|
|
1397,7 → 1344,7
// Test RTE debug trap handler |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] RTE (runtime env.) debug trap handler: ", cnt_test); |
PRINT_STANDARD("[%i] RTE debug trap handler: ", cnt_test); |
|
cnt_test++; |
|
1407,13 → 1354,13
// trigger illegal instruction exception |
neorv32_cpu_csr_read(0xfff); // CSR not available |
|
neorv32_uart_printf(" "); |
PRINT_STANDARD(" "); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) { |
test_ok(); |
} |
else { |
test_fail(); |
neorv32_uart_printf("answer: 0x%x", neorv32_cpu_csr_read(CSR_MCAUSE)); |
PRINT_STANDARD("answer: 0x%x", neorv32_cpu_csr_read(CSR_MCAUSE)); |
} |
|
// restore original handler |
1423,7 → 1370,7
// ---------------------------------------------------------- |
// Test physical memory protection |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] PMP - Physical memory protection: ", cnt_test); |
PRINT_STANDARD("[%i] PMP - Physical memory protection: ", cnt_test); |
|
// check if PMP is implemented |
if (neorv32_cpu_pmp_get_num_regions() != 0) { |
1433,14 → 1380,14
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
cnt_test++; |
|
// find out mininmal region size (granulartiy) |
// find out minimal region size (granularity) |
tmp_b = neorv32_cpu_pmp_get_granularity(); |
|
tmp_a = SYSINFO_DSPACE_BASE; // base address of protected region |
neorv32_uart_printf("Creating protected page (NAPOT, [!X,!W,R], %u bytes) @ 0x%x: ", tmp_b, tmp_a); |
PRINT_STANDARD("Creating protected page (NAPOT, [!X,!W,!R], %u bytes) @ 0x%x: ", tmp_b, tmp_a); |
|
// configure |
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, 0b00011001); // NAPOT, read permission, NO write and NO execute permissions |
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, 0b00011000); // NAPOT, NO read permission, NO write permission, and NO execute permissions |
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
1451,7 → 1398,7
|
|
// ------ EXECUTE: should fail ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] execute: ", cnt_test); |
PRINT_STANDARD("[%i] PMP: U-mode execute: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1462,13 → 1409,13
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
1475,8 → 1422,8
} |
|
|
// ------ LOAD: should work ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] read: ", cnt_test); |
// ------ LOAD: should fail ------ |
PRINT_STANDARD("[%i] PMP: U-mode read: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1483,17 → 1430,21
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
asm volatile ("lw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // load access -> should work |
tmp_b = neorv32_cpu_load_unsigned_word(tmp_a); // load access -> should fail |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// switch back to machine mode (if not allready) |
if (tmp_b != 0) { |
PRINT_CRITICAL("%c[1m<SECURITY FAILURE> %c[0m\n", 27, 27); |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) { |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
1501,7 → 1452,7
|
|
// ------ STORE: should fail ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] write: ", cnt_test); |
PRINT_STANDARD("[%i] PMP: U-mode write: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1508,17 → 1459,17
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
asm volatile ("sw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // store access -> should fail |
neorv32_cpu_store_unsigned_word(tmp_a, 0); // store access -> should fail |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_ok(); |
} |
else { |
// switch back to machine mode (if not allready) |
// switch back to machine mode (if not already) |
asm volatile ("ecall"); |
|
test_fail(); |
1526,7 → 1477,7
|
|
// ------ Lock test - pmpcfg0.0 / pmpaddr0 ------ |
neorv32_uart_printf("[%i] PMP: Entry [mode=off] lock: ", cnt_test); |
PRINT_STANDARD("[%i] PMP: Entry [mode=off] lock: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1548,7 → 1499,7
|
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
|
|
1556,11 → 1507,11
// Test atomic LR/SC operation - should succeed |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic access (LR+SC succeeding access): ", cnt_test); |
PRINT_STANDARD("[%i] Atomic access (LR+SC succeeding access): ", cnt_test); |
|
#ifdef __riscv_atomic |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) { |
|
cnt_test++; |
|
1582,10 → 1533,10
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1593,11 → 1544,11
// Test atomic LR/SC operation - should fail |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic access (LR+SC failing access 1): ", cnt_test); |
PRINT_STANDARD("[%i] Atomic access (LR+SC failing access 1): ", cnt_test); |
|
#ifdef __riscv_atomic |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) { |
|
cnt_test++; |
|
1618,10 → 1569,10
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1629,11 → 1580,11
// Test atomic LR/SC operation - should fail |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Atomic access (LR+SC failing access 2): ", cnt_test); |
PRINT_STANDARD("[%i] Atomic access (LR+SC failing access 2): ", cnt_test); |
|
#ifdef __riscv_atomic |
// skip if A-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A_EXT)) != 0) { |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) { |
|
cnt_test++; |
|
1654,10 → 1605,10
} |
} |
else { |
neorv32_uart_printf("skipped (on real HW)\n"); |
PRINT_STANDARD("skipped (on real HW)\n"); |
} |
#else |
neorv32_uart_printf("skipped (not implemented)\n"); |
PRINT_STANDARD("skipped (n.a.)\n"); |
#endif |
|
|
1665,39 → 1616,38
// HPM reports |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, -1); // stop all counters |
neorv32_uart_printf("\n\n-- HPM reports LOW (%u HPMs available) --\n", num_hpm_cnts_global); |
neorv32_uart_printf("#IR - Total number of instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); // = "HPM_0" |
//neorv32_uart_printf("#TM - Current system time: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_TIME)); // = "HPM_1" |
neorv32_uart_printf("#CY - Total number of clk cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); // = "HPM_2" |
neorv32_uart_printf("#03 - Retired compr. instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); |
neorv32_uart_printf("#04 - I-fetch wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); |
neorv32_uart_printf("#05 - I-issue wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); |
neorv32_uart_printf("#06 - Multi-cyc. ALU wait cyc.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); |
neorv32_uart_printf("#07 - Load operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); |
neorv32_uart_printf("#08 - Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); |
neorv32_uart_printf("#09 - Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); |
neorv32_uart_printf("#10 - Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); |
neorv32_uart_printf("#11 - Cond. branches (total): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); |
neorv32_uart_printf("#12 - Cond. branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); |
neorv32_uart_printf("#13 - Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); |
neorv32_uart_printf("#14 - Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); |
PRINT_STANDARD("\n\n-- HPM reports LOW (%u HPMs available) --\n", num_hpm_cnts_global); |
PRINT_STANDARD("#IR - Instr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); // = "HPM_0" |
//PRINT_STANDARD("#TM - Time: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_TIME)); // = "HPM_1" |
PRINT_STANDARD("#CY - CLKs: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); // = "HPM_2" |
PRINT_STANDARD("#03 - Compr.: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); |
PRINT_STANDARD("#04 - IF wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); |
PRINT_STANDARD("#05 - II wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); |
PRINT_STANDARD("#06 - ALU wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); |
PRINT_STANDARD("#07 - Loads: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); |
PRINT_STANDARD("#08 - Stores: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); |
PRINT_STANDARD("#09 - MEM wait: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); |
PRINT_STANDARD("#10 - Jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); |
PRINT_STANDARD("#11 - Branches: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); |
PRINT_STANDARD("#12 - Taken: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); |
PRINT_STANDARD("#13 - Traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); |
PRINT_STANDARD("#14 - Illegals: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); |
|
|
// ---------------------------------------------------------- |
// Final test reports |
// ---------------------------------------------------------- |
neorv32_uart_printf("\n\nTest results:\nOK: %i/%i\nFAILED: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test); |
PRINT_CRITICAL("\n\nTest results:\nPASS: %i/%i\nFAIL: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test); |
|
// final result |
if (cnt_fail == 0) { |
neorv32_uart_printf("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27); |
return 0; |
PRINT_STANDARD("%c[1m[CPU TEST COMPLETED SUCCESSFULLY!]%c[0m\n", 27, 27); |
} |
else { |
neorv32_uart_printf("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27); |
return 1; |
PRINT_STANDARD("%c[1m[CPU TEST FAILED!]%c[0m\n", 27, 27); |
} |
|
return (int)cnt_fail; // return error counter for after-main handler |
} |
|
|
1724,20 → 1674,57
|
|
/**********************************************************************//** |
* XIRQ handler channel 0. |
**************************************************************************/ |
void xirq_trap_handler0(void) { |
|
xirq_trap_handler_ack += 2; |
} |
|
|
/**********************************************************************//** |
* XIRQ handler channel 1. |
**************************************************************************/ |
void xirq_trap_handler1(void) { |
|
xirq_trap_handler_ack *= 2; |
} |
|
|
/**********************************************************************//** |
* Test results helper function: Shows "[ok]" and increments global cnt_ok |
**************************************************************************/ |
void test_ok(void) { |
|
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
PRINT_STANDARD("%c[1m[ok]%c[0m\n", 27, 27); |
cnt_ok++; |
} |
|
|
/**********************************************************************//** |
* Test results helper function: Shows "[FAILED]" and increments global cnt_fail |
* Test results helper function: Shows "[FAIL]" and increments global cnt_fail |
**************************************************************************/ |
void test_fail(void) { |
|
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
PRINT_CRITICAL("%c[1m[FAIL]%c[0m\n", 27, 27); |
cnt_fail++; |
} |
|
|
/**********************************************************************//** |
* "after-main" handler that is executed after the application's |
* main function returns (called by crt0.S start-up code): Output minimal |
* test report to physical UART |
**************************************************************************/ |
int __neorv32_crt0_after_main(int32_t return_code) { |
|
// make sure sim mode is disabled and UARTs are actually enabled |
UART0_CT |= (1 << UART_CT_EN); |
UART0_CT &= ~(1 << UART_CT_SIM_MODE); |
UART1_CT = UART0_CT; |
|
// minimal result report |
PRINT_CRITICAL("%u/%u\n", (uint32_t)return_code, (uint32_t)cnt_test); |
|
return 0; |
} |