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 43 to Rev 44
    Reverse comparison

Rev 43 → Rev 44

/bit_manipulation/README.md
0,0 → 1,15
# NEORV32 Bit Manipulation `B` Extension
 
:warning: The RISC-V `B` extension is not ratified yet. Hence, it is not supported by the upstream RISC-V GCC port.
 
:warning: The NEORV32's bit manipulation instruction only supports the `Zbb` base instructions subset yet.
 
The provided test program `main.c` verifies all instructions of the `B.Zbb` extensions by checking the results against a pure-software emulation model.
The emulation functions as well as the available **intrinsics** for the `B` extension are located in `neorv32_b_extension_intrinsics.h`.
 
:information_source: More information regarding the RISC-V bit manipulation extension can be found in the officail GitHub repo:
[github.com/riscv/riscv-bitmanip](https://github.com/riscv/riscv-bitmanip). The current specification of the bitmanipulation spec supported by the NEORV32
can be found in `docs/bitmanip-draft.pdf`.
 
:information_source: Compiling the test program (`main.c`) and/or the intriniscs library using the `MARCH` `b` flag should be avoided (might add further instructions from the `B` extension
that are not part of the `Zbb` subset).
/bit_manipulation/main.c
0,0 → 1,360
// #################################################################################################
// # << NEORV32 - Bit manipulation 'B.Zbb' test 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 bit_manipulation/main.c
* @author Stephan Nolting
* @brief Test program for the NEORV32 'B' extension (Zbb subset) using pseudo-random data as input; compares results from hardware against pure-sw reference functions.
**************************************************************************/
 
#include <neorv32.h>
#include "neorv32_b_extension_intrinsics.h"
 
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE (19200)
//** Number of test cases for each instruction */
#define NUM_TEST_CASES (10000)
/**@}*/
 
 
// Prototypes
uint32_t xorshift32(void);
uint32_t check_result(uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res);
void print_report(int num_err, int num_tests);
 
 
/**********************************************************************//**
* Main function; test all available operations of the NEORV32 'B' extensions using bit manipulation intrinsics and software-only reference functions (emulation).
*
* @note This program requires the B CPU extension.
*
* @return Irrelevant.
**************************************************************************/
int main() {
 
uint32_t opa = 0, opb = 0, res_hw = 0, res_sw = 0;
int i = 0, err_cnt = 0;
const int num_tests = (int)NUM_TEST_CASES;
 
// capture all exceptions and give debug info via UART
neorv32_rte_setup();
 
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// intro
neorv32_uart_printf("NEORV32 Bit Manipulation (B.Zbb) Extension Test\n\n");
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
 
neorv32_uart_printf("Starting bit manipulation extensions tests (%i test cases per instruction)...\n", num_tests);
 
// CLZ
neorv32_uart_printf("\nCLZ:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_clz(opa);
res_hw = riscv_intrinsic_clz(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// CTZ
neorv32_uart_printf("\nCTZ:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_ctz(opa);
res_hw = riscv_intrinsic_ctz(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// CPOP
neorv32_uart_printf("\nCPOP:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_cpop(opa);
res_hw = riscv_intrinsic_cpop(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// SEXT.B
neorv32_uart_printf("\nSEXT.B:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_sextb(opa);
res_hw = riscv_intrinsic_sextb(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// SEXT.H
neorv32_uart_printf("\nSEXT.H:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_sexth(opa);
res_hw = riscv_intrinsic_sexth(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// MIN
neorv32_uart_printf("\nMIN:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_min(opa, opb);
res_hw = riscv_intrinsic_min(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// MINU
neorv32_uart_printf("\nMINU:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_minu(opa, opb);
res_hw = riscv_intrinsic_minu(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// MAX
neorv32_uart_printf("\nMAX:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_max(opa, opb);
res_hw = riscv_intrinsic_max(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// MAXU
neorv32_uart_printf("\nMAXU:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_maxu(opa, opb);
res_hw = riscv_intrinsic_maxu(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// PACK
neorv32_uart_printf("\nPACK:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_pack(opa, opb);
res_hw = riscv_intrinsic_pack(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// ANDN
neorv32_uart_printf("\nANDN:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_andn(opa, opb);
res_hw = riscv_intrinsic_andn(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// ORN
neorv32_uart_printf("\nORN:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_orn(opa, opb);
res_hw = riscv_intrinsic_orn(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// XNOR
neorv32_uart_printf("\nXNOR:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_xnor(opa, opb);
res_hw = riscv_intrinsic_xnor(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// ROL
neorv32_uart_printf("\nROL:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_rol(opa, opb);
res_hw = riscv_intrinsic_rol(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// ROR
neorv32_uart_printf("\nROR:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
opb = xorshift32();
res_sw = riscv_emulate_ror(opa, opb);
res_hw = riscv_intrinsic_ror(opa, opb);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// RORI
neorv32_uart_printf("\nRORI (imm=20):\n"); // FIXME: static immediate
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_ror(opa, 20);
res_hw = riscv_intrinsic_rori20(opa);
err_cnt += check_result(opa, opb, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// ORC.B
neorv32_uart_printf("\nORC.B:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_orcb(opa);
res_hw = riscv_intrinsic_orcb(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
// REV8
neorv32_uart_printf("\nREV8:\n");
err_cnt = 0;
for (i=0;i<num_tests; i++) {
opa = xorshift32();
res_sw = riscv_emulate_rev8(opa);
res_hw = riscv_intrinsic_rev8(opa);
err_cnt += check_result(opa, 0, res_sw, res_hw);
}
print_report(err_cnt, num_tests);
 
 
neorv32_uart_printf("\nBit manipulation extension tests done.\n");
 
return 0;
}
 
 
/**********************************************************************//**
* Pseudo-Random Number Generator (to generate test vectors).
*
* @return Random data (32-bit).
**************************************************************************/
uint32_t xorshift32(void) {
 
static uint32_t x32 = 314159265;
 
x32 ^= x32 << 13;
x32 ^= x32 >> 17;
x32 ^= x32 << 5;
 
return x32;
}
 
 
/**********************************************************************//**
* Check results (reference (SW) vs actual hardware).
*
* @param[in] opa Operand 1
* @param[in] opb Operand 2
* @param[in] ref Software reference
* @param[in] res Actual results
* @return zero if results are equal.
**************************************************************************/
uint32_t check_result(uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res) {
 
if (ref != res) {
neorv32_uart_printf("opa = 0x%x, opb = 0x%x : ref = 0x%x vs res = 0x%x ", opa, opb, ref, res);
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
return 1;
}
else {
return 0;
}
}
 
 
/**********************************************************************//**
* Print test report.
*
* @param[in] num_err Number or errors in this test.
* @param[in] num_tests Total number of conducted tests.
**************************************************************************/
void print_report(int num_err, int num_tests) {
 
neorv32_uart_printf("Errors: %i/%i ", num_err, num_tests);
 
if (num_err == 0) {
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
}
else {
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
}
}
/bit_manipulation/makefile
0,0 → 1,338
#################################################################################################
# << NEORV32 - Application Makefile >> #
# ********************************************************************************************* #
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. #
# ********************************************************************************************* #
# BSD 3-Clause License #
# #
# Copyright (c) 2020, 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
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 $@
@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)
/bit_manipulation/neorv32_b_extension_intrinsics.h
0,0 → 1,842
// #################################################################################################
// # << NEORV32 - Intrinsics + Emulation Functions for the B.Zbb CPU extensions >> #
// # ********************************************************************************************* #
// # 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 bit_manipulation/neorv32_b_extension_intrinsics.h
* @author Stephan Nolting
* @brief "Intrinsic" library for the NEORV32 bit manipulation (B.Zbb) extension. Also provides emulation functions for all intrinsics (functionality re-built in pure software).
*
* @warning This library is just a temporary fall-back until the B/Zbb extensions are supported by the upstream RISC-V GCC port.
**************************************************************************/
#ifndef neorv32_b_extension_intrinsics_h
#define neorv32_b_extension_intrinsics_h
 
/**********************************************************************//**
* @name Custom instructions helper macros
**************************************************************************/
/**@{*/
 
//** Selection helper macro */
#define STR1(x) #x
//** Selection helper macro 2 */
#define STR(x) STR1(x)
 
//** Register address converter */
#define GET_REG_ADDR(x) REG_ADDR_##x
 
#define REG_ADDR_x0 0 /**< register 0 */
#define REG_ADDR_x1 1 /**< register 1 */
#define REG_ADDR_x2 2 /**< register 2 */
#define REG_ADDR_x3 3 /**< register 3 */
#define REG_ADDR_x4 4 /**< register 4 */
#define REG_ADDR_x5 5 /**< register 5 */
#define REG_ADDR_x6 6 /**< register 6 */
#define REG_ADDR_x7 7 /**< register 7 */
#define REG_ADDR_x8 8 /**< register 8 */
#define REG_ADDR_x9 9 /**< register 9 */
#define REG_ADDR_x10 10 /**< register 10 */
#define REG_ADDR_x11 11 /**< register 11 */
#define REG_ADDR_x12 12 /**< register 12 */
#define REG_ADDR_x13 13 /**< register 13 */
#define REG_ADDR_x14 14 /**< register 14 */
#define REG_ADDR_x15 15 /**< register 15 */
#define REG_ADDR_x16 16 /**< register 16 */
#define REG_ADDR_x17 17 /**< register 17 */
#define REG_ADDR_x18 18 /**< register 18 */
#define REG_ADDR_x19 19 /**< register 19 */
#define REG_ADDR_x20 20 /**< register 20 */
#define REG_ADDR_x21 21 /**< register 21 */
#define REG_ADDR_x22 22 /**< register 22 */
#define REG_ADDR_x23 23 /**< register 23 */
#define REG_ADDR_x24 24 /**< register 24 */
#define REG_ADDR_x25 25 /**< register 25 */
#define REG_ADDR_x26 26 /**< register 26 */
#define REG_ADDR_x27 27 /**< register 27 */
#define REG_ADDR_x28 28 /**< register 28 */
#define REG_ADDR_x29 29 /**< register 29 */
#define REG_ADDR_x30 30 /**< register 30 */
#define REG_ADDR_x31 31 /**< register 31 */
#define REG_ADDR_zero 0 /**< register 0 - according to calling convention */
#define REG_ADDR_ra 1 /**< register 1 - according to calling convention */
#define REG_ADDR_sp 2 /**< register 2 - according to calling convention */
#define REG_ADDR_gp 3 /**< register 3 - according to calling convention */
#define REG_ADDR_tp 4 /**< register 4 - according to calling convention */
#define REG_ADDR_t0 5 /**< register 5 - according to calling convention */
#define REG_ADDR_t1 6 /**< register 6 - according to calling convention */
#define REG_ADDR_t2 7 /**< register 7 - according to calling convention */
#define REG_ADDR_s0 8 /**< register 8 - according to calling convention */
#define REG_ADDR_s1 9 /**< register 9 - according to calling convention */
#define REG_ADDR_a0 10 /**< register 10 - according to calling convention */
#define REG_ADDR_a1 11 /**< register 11 - according to calling convention */
#define REG_ADDR_a2 12 /**< register 12 - according to calling convention */
#define REG_ADDR_a3 13 /**< register 13 - according to calling convention */
#define REG_ADDR_a4 14 /**< register 14 - according to calling convention */
#define REG_ADDR_a5 15 /**< register 15 - according to calling convention */
#define REG_ADDR_a6 16 /**< register 16 - according to calling convention */
#define REG_ADDR_a7 17 /**< register 17 - according to calling convention */
#define REG_ADDR_s2 18 /**< register 18 - according to calling convention */
#define REG_ADDR_s3 19 /**< register 19 - according to calling convention */
#define REG_ADDR_s4 20 /**< register 20 - according to calling convention */
#define REG_ADDR_s5 21 /**< register 21 - according to calling convention */
#define REG_ADDR_s6 22 /**< register 22 - according to calling convention */
#define REG_ADDR_s7 23 /**< register 23 - according to calling convention */
#define REG_ADDR_s8 24 /**< register 24 - according to calling convention */
#define REG_ADDR_s9 25 /**< register 25 - according to calling convention */
#define REG_ADDR_s10 26 /**< register 26 - according to calling convention */
#define REG_ADDR_s11 27 /**< register 27 - according to calling convention */
#define REG_ADDR_t3 28 /**< register 28 - according to calling convention */
#define REG_ADDR_t4 29 /**< register 29 - according to calling convention */
#define REG_ADDR_t5 30 /**< register 30 - according to calling convention */
#define REG_ADDR_t6 31 /**< register 31 - according to calling convention */
 
//** Construct instruction word (32-bit) for R-type instruction */
#define CMD_WORD_R_TYPE(funct7, rs2, rs1, funct3, rd, opcode) \
( (opcode & 0x7f) << 0 ) + \
( (rd & 0x1f) << 7 ) + \
( (rs1 & 0x1f) << 15 ) + \
( (rs2 & 0x1f) << 20 ) + \
( (funct7 & 0x7f) << 25 ) + \
( (funct3 & 0x1f) << 12 )
 
//** Construct instruction word (32-bit) for I-type instruction */
#define CMD_WORD_I_TYPE(imm12, rs1_f5, funct3, rd, opcode) \
( (opcode & 0x7f) << 0 ) + \
( (rd & 0x1f) << 7 ) + \
( (rs1_f5 & 0x1f) << 15 ) + \
( (imm12 & 0xfff) << 20 ) + \
( (funct3 & 0x1f) << 12 )
 
//** Construct custom instruction for R-type instruction */
#define CUSTOM_INSTR_R_TYPE(funct7, rs2, rs1, funct3, rd, opcode) \
asm volatile (".word "STR(CMD_WORD_R_TYPE(funct7, GET_REG_ADDR(rs2), GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n");
 
//** Construct custom instruction for R1-type instruction (register + 5-bit immediate/function_select) */
#define CUSTOM_INSTR_R1_TYPE(funct7, funct5, rs1, funct3, rd, opcode) \
asm volatile (".word "STR(CMD_WORD_R_TYPE(funct7, funct5, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n");
//** Construct custom instruction for I-type instruction */
#define CUSTOM_INSTR_I_TYPE(imm12, rs1, funct3, rd, opcode) \
asm volatile (".word "STR(CMD_WORD_I_TYPE(imm12, GET_REG_ADDR(rs1), funct3, GET_REG_ADDR(rd), opcode))"\n");
/**@}*/
 
 
// ################################################################################################
// "Intrinsics"
// ################################################################################################
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CLZ (count leading zeros) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of leading zeros in source operand.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_clz(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// clz a0, a0
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00000, a0, 0b001, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CTZ (count trailing zeros) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of trailing zeros in source operand.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_ctz(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// ctz a0, a0
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00001, a0, 0b001, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CPOP (count set bits) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of set bits in source operand.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_cpop(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// cpop a0, a0
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00010, a0, 0b001, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Sign extended byte (operand(7:0)).
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sextb(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// sext.b a0, a0
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00100, a0, 0b001, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Sign extended half-word (operand(15:0)).
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sexth(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// sext.h a0, a0
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00101, a0, 0b001, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MIN (select signed minimum) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Signed minimum.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_min(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// min a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b100, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MINU (select unsigned minimum) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Unsigned minimum.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_minu(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// minu a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b101, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MAX (select signed maximum) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Signed maximum.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_max(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// max a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b110, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MAXU (select unsigned maximum) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Unsigned maximum.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_maxu(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// maxu a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b111, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation PACK (pack lower words) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Packed lower words.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_pack(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// maxu a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0000100, a1, a0, 0b100, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ANDN (logical and-negate) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Operand 1 AND NOT operand 2.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_andn(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// andn a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b111, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ORN (logical or-negate) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Operand 1 OR NOT operand 2.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_orn(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// orn a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b110, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation XNOR (logical xor-negate) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Operand 1 XOR NOT operand 2.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_xnor(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// xnor a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b100, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ROL (rotate-left) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Operand 1 rotated left by operand_2(4:0) positions.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rol(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// rol a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0110000, a1, a0, 0b001, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ROR (rotate-right) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 2 (a0).
* @return Operand 1 rotated right by operand_2(4:0) positions.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_ror(uint32_t rs1, uint32_t rs2) {
 
register uint32_t result __asm__ ("a0");
 
// ror a0, a0, a1
CUSTOM_INSTR_R_TYPE(0b0110000, a1, a0, 0b101, a0, 0b0110011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation RORI (rotate-right) by 20 positions. [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
* @warning Fixed shift amount (20) for now.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Operand 1 rotated right by 20 positions.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rori20(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// rori a0, a0, 20
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b10100, a0, 0b101, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ORC.B (or-combine byte) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return OR-combined bytes of operand 1.
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_orcb(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// gorci a0, a0, 7 (pseudo-instruction: orc.b a0, a0)
CUSTOM_INSTR_R1_TYPE(0b0010100, 0b00111, a0, 0b101, a0, 0b0010011);
 
return result;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation REV8 (byte-swap) [B.Zbb]
*
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
*
* @param[in] rs1 Source operand 1 (a0).
* @return Byte swap of operand 1
**************************************************************************/
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rev8(uint32_t rs1) {
 
register uint32_t result __asm__ ("a0");
 
// grevi a0, a0, -8 (pseudo-instruction: rev8 a0, a0)
CUSTOM_INSTR_R1_TYPE(0b0110100, 0b11000, a0, 0b101, a0, 0b0010011);
 
return result;
}
 
 
// ################################################################################################
// Emulation functions
// ################################################################################################
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CLZ (count leading zeros) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of leading zeros in source operand.
**************************************************************************/
uint32_t riscv_emulate_clz(uint32_t rs1) {
 
uint32_t sreg = rs1;
uint32_t cnt = 0;
 
while(1) {
if (sreg & 0x80000000UL) {
break;
}
else {
sreg <<= 1;
cnt++;
}
}
 
return cnt;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CTZ (count trailing zeros) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of trailing zeros in source operand.
**************************************************************************/
uint32_t riscv_emulate_ctz(uint32_t rs1) {
 
uint32_t sreg = rs1;
uint32_t cnt = 0;
 
while(1) {
if (sreg & 1) {
break;
}
else {
sreg >>= 1;
cnt++;
}
}
 
return cnt;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation CPOP (population count) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Number of set bits in source operand.
**************************************************************************/
uint32_t riscv_emulate_cpop(uint32_t rs1) {
 
uint32_t sreg = rs1;
uint32_t cnt = 0;
int i;
 
for (i=0; i<32; i++) {
if (sreg & 1) {
cnt++;
}
sreg >>= 1;
}
 
return cnt;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Sign-extended byte (operand(7:0)).
**************************************************************************/
uint32_t riscv_emulate_sextb(uint32_t rs1) {
 
uint32_t tmp = rs1 & 0xff;
 
if (tmp & 0x80) {
tmp |= 0xFFFFFF00UL;
}
 
return tmp;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Sign-extended half-word (operand(15:0)).
**************************************************************************/
uint32_t riscv_emulate_sexth(uint32_t rs1) {
 
uint32_t tmp = rs1 & 0xffff;
 
if (tmp & 0x8000) {
tmp |= 0xFFFF0000UL;
}
 
return tmp;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MIN (select signed minimum) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Signed minimum.
**************************************************************************/
uint32_t riscv_emulate_min(uint32_t rs1, uint32_t rs2) {
 
int32_t s_opa = (int32_t)rs1;
int32_t s_opb = (int32_t)rs2;
 
if (s_opa < s_opb) {
return rs1;
}
else {
return rs2;
}
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MINU (select unsigned minimum) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Unsigned minimum.
**************************************************************************/
uint32_t riscv_emulate_minu(uint32_t rs1, uint32_t rs2) {
 
if (rs1 < rs2) {
return rs1;
}
else {
return rs2;
}
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MAX (select signed maximum) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Signed maximum.
**************************************************************************/
uint32_t riscv_emulate_max(uint32_t rs1, uint32_t rs2) {
 
int32_t s_opa = (int32_t)rs1;
int32_t s_opb = (int32_t)rs2;
 
if (s_opa < s_opb) {
return rs2;
}
else {
return rs1;
}
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation MAXU (select unsigned maximum) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Unsigned maximum.
**************************************************************************/
uint32_t riscv_emulate_maxu(uint32_t rs1, uint32_t rs2) {
 
if (rs1 < rs2) {
return rs2;
}
else {
return rs1;
}
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation PACK (pack lower words) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Unsigned maximum.
**************************************************************************/
uint32_t riscv_emulate_pack(uint32_t rs1, uint32_t rs2) {
 
uint32_t tmp_a = rs1 & 0xffff;
uint32_t tmp_b = rs2 & 0xffff;
 
return (tmp_b << 16) | tmp_a;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ANDN (logical and-negate) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Operand 1 AND NOT operand 2.
**************************************************************************/
uint32_t riscv_emulate_andn(uint32_t rs1, uint32_t rs2) {
 
return rs1 & (~rs2);
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ORN (logical or-negate) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Operand 1 OR NOT operand 2.
**************************************************************************/
uint32_t riscv_emulate_orn(uint32_t rs1, uint32_t rs2) {
 
return rs1 | (~rs2);
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation XNOR (logical xor-negate) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Operand 1 XOR NOT operand 2.
**************************************************************************/
uint32_t riscv_emulate_xnor(uint32_t rs1, uint32_t rs2) {
 
return rs1 ^ (~rs2);
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ROL (rotate-left) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Operand 1 rotated left by operand_2(4:0) positions.
**************************************************************************/
uint32_t riscv_emulate_rol(uint32_t rs1, uint32_t rs2) {
 
uint32_t shamt = rs2 & 0x1f;
 
uint32_t tmp_a = rs1 << shamt;
uint32_t tmp_b = rs1 >> (32-shamt);
 
return tmp_a | tmp_b;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ROR (rotate-right) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @param[in] rs2 Source operand 1 (a0).
* @return Operand 1 rotated right by operand_2(4:0) positions.
**************************************************************************/
uint32_t riscv_emulate_ror(uint32_t rs1, uint32_t rs2) {
 
uint32_t shamt = rs2 & 0x1f;
 
uint32_t tmp_a = rs1 >> shamt;
uint32_t tmp_b = rs1 << (32-shamt);
 
return tmp_a | tmp_b;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation REV8 (byte swap) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return Operand 1 byte swapped.
**************************************************************************/
uint32_t riscv_emulate_rev8(uint32_t rs1) {
 
uint32_t tmp_a = (rs1 & 0x000000ffUL) << 24;
uint32_t tmp_b = (rs1 & 0x0000ff00UL) << 8;
uint32_t tmp_c = (rs1 & 0x00ff0000UL) >> 8;
uint32_t tmp_d = (rs1 & 0xff000000UL) >> 24;
 
return tmp_a | tmp_b | tmp_c | tmp_d;
}
 
 
/**********************************************************************//**
* Intrinsic: Bit manipulation ORCB (or-combine bytes) [emulation]
*
* @param[in] rs1 Source operand 1 (a0).
* @return OR-combined bytes of operand 1.
**************************************************************************/
uint32_t riscv_emulate_orcb(uint32_t rs1) {
 
uint32_t tmp = 0;
 
if (rs1 & 0x000000ffUL) {
tmp |= 0x000000ffUL;
}
if (rs1 & 0x0000ff00UL) {
tmp |= 0x0000ff00UL;
}
if (rs1 & 0x00ff0000UL) {
tmp |= 0x00ff0000UL;
}
if (rs1 & 0xff000000UL) {
tmp |= 0xff000000UL;
}
 
return tmp;
}
 
 
#endif // neorv32_b_extension_intrinsics_h
/blink_led/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
86,6 → 86,9
// 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");
 
/coremark/core_portme.c
164,6 → 164,9
while(1);
#endif
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
num_hpm_cnts_global = neorv32_cpu_hpm_get_counters();
 
// try to setup as many HPMs as possible
/cpu_test/main.c
140,20 → 140,22
return 0;
#endif
 
neorv32_uart_printf("\n--- PROCESSOR/CPU TEST ---\n");
neorv32_uart_printf("\n<< PROCESSOR/CPU TEST >>\n");
neorv32_uart_printf("build: "__DATE__" "__TIME__"\n");
neorv32_uart_printf("This test suite is intended to verify the default NEORV32 processor setup using the default testbench.\n\n");
 
// check if we came from hardware reset
neorv32_uart_printf("Coming from hardware reset? ");
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_RESET) {
neorv32_uart_printf("true\n");
neorv32_uart_printf("yes\n");
}
else {
neorv32_uart_printf("unknown (mcause != TRAP_CODE_RESET)\n");
}
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
 
// reset performance counter
neorv32_cpu_set_minstret(0);
neorv32_cpu_set_mcycle(0);
183,7 → 185,7
 
// configure RTE
// -----------------------------------------------
neorv32_uart_printf("\n\nInitializing NEORV32 run-time environment (RTE)... ");
neorv32_uart_printf("\n\nInitializing NEORV32 RTE... ");
 
neorv32_rte_setup(); // this will install a full-detailed debug handler for all traps
 
208,7 → 210,7
install_err += neorv32_rte_exception_install(RTE_TRAP_FIRQ_3, global_trap_handler);
 
if (install_err) {
neorv32_uart_printf("RTE install error (%i)!\n", install_err);
neorv32_uart_printf("RTE error (%i)!\n", install_err);
return 0;
}
 
237,7 → 239,7
// Test standard RISC-V performance counter [m]cycle[h]
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
neorv32_uart_printf("[%i] Testing [m]instret[h] counters: ", cnt_test);
neorv32_uart_printf("[%i] [m]instret[h] counter test: ", cnt_test);
 
cnt_test++;
 
262,7 → 264,7
// Test standard RISC-V performance counter [m]instret[h]
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
neorv32_uart_printf("[%i] Testing [m]cycle[h] counters: ", cnt_test);
neorv32_uart_printf("[%i] [m]cycle[h] counter test: ", cnt_test);
 
cnt_test++;
 
287,7 → 289,7
// Test mcountinhibt: inhibit auto-inc of [m]cycle
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
neorv32_uart_printf("[%i] Testing mcountINHIBT.cy CSR: ", cnt_test);
neorv32_uart_printf("[%i] mcountinhibt.cy CSR test: ", cnt_test);
 
cnt_test++;
 
323,7 → 325,7
// Test mcounteren: do not allow cycle[h] access from user-mode
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
neorv32_uart_printf("[%i] Testing mcounterEN.cy CSR: ", cnt_test);
neorv32_uart_printf("[%i] mcounteren.cy CSR test: ", cnt_test);
 
cnt_test++;
 
1209,7 → 1211,7
// Test RTE debug trap handler
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
neorv32_uart_printf("[%i] RTE (runtime environment) debug trap handler test: ", cnt_test);
neorv32_uart_printf("[%i] RTE (runtime env.) debug trap handler test: ", cnt_test);
 
cnt_test++;
 
1489,7 → 1491,7
// HPM reports
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, -1); // stop all counters
neorv32_uart_printf("\n\nHPM results:\n");
neorv32_uart_printf("\n\n-- HPM results --\n");
if (num_hpm_cnts_global == 0) {neorv32_uart_printf("no HPMs available\n"); }
if (num_hpm_cnts_global > 0) {neorv32_uart_printf("# Retired compr. instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); }
if (num_hpm_cnts_global > 1) {neorv32_uart_printf("# I-fetch wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); }
1508,8 → 1510,8
// ----------------------------------------------------------
// Final test reports
// ----------------------------------------------------------
neorv32_uart_printf("\nExecuted instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET));
neorv32_uart_printf( "Required clock cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE));
neorv32_uart_printf("\n# Instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET));
neorv32_uart_printf( "# Clock cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE));
 
neorv32_uart_printf("\nTest results:\nOK: %i/%i\nFAILED: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test);
 
/demo_freeRTOS/main.c
129,6 → 129,9
 
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
}
 
/*-----------------------------------------------------------*/
/demo_gpio_irq/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
75,7 → 75,10
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
 
// check if GPIO unit is implemented at all
if (neorv32_gpio_available() == 0) {
neorv32_uart_print("ERROR! GPIO unit not synthesized!\n");
/demo_pwm/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
76,6 → 76,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// 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("PWM demo program\n");
 
/demo_trng/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
82,6 → 82,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// intro
neorv32_uart_printf("\n--- TRNG Demo ---\n\n");
 
/demo_twi/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
86,6 → 86,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// intro
neorv32_uart_printf("\n--- TWI Bus Explorer ---\n\n");
 
/demo_wdt/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
79,6 → 79,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// simple text output via UART (strings only)
neorv32_uart_print("\nWatchdog system reset demo program\n\n");
 
/game_of_life/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
100,7 → 100,10
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
 
while (1) {
 
int u = 0, cell = 0, n = 0;
/hello_world/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
68,6 → 68,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// print project logo via UART
neorv32_rte_print_logo();
 
/hex_viewer/main.c
3,7 → 3,7
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
// # 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: #
85,6 → 85,9
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// intro
neorv32_uart_printf("\n--- Hex Viewer ---\n\n");
 

powered by: WebSVN 2.1.0

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