OpenCores
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_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;
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.