Merge branch 'main' into image_packages

This commit is contained in:
stnolting 2024-11-01 10:30:58 +01:00
commit e7549285ef
18 changed files with 126 additions and 1114 deletions

View file

@ -32,10 +32,9 @@ jobs:
make -C sw/example clean_all exe make -C sw/example clean_all exe
make -C sw/bootloader clean_all info bootloader make -C sw/bootloader clean_all info bootloader
Default_TB:
Simple:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: 'Simple testbench' name: 'Default testbench'
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -61,37 +60,3 @@ jobs:
info info
all all
sim-check sim-check
VUnit:
runs-on: ubuntu-latest
steps:
- name: '🧰 Repository Checkout'
uses: actions/checkout@v4
- name: '⚙️ Build and install Processor Check software'
uses: docker://ghcr.io/stnolting/neorv32/sim
with:
args: >-
make -C sw/example/processor_check
clean_all
USER_FLAGS+=-DUART0_SIM_MODE
USER_FLAGS+=-DSUPPRESS_OPTIONAL_UART_PRINT
USER_FLAGS+=-flto
MARCH=rv32imac_zicsr_zifencei
info
all
- name: '📤 Archive Processor Check application image'
uses: actions/upload-artifact@v4
with:
name: application
path: rtl/core/neorv32_application_image.vhd
- name: '🚧 Run Processor Hardware Tests with VUnit'
uses: VUnit/vunit_action@master
with:
image: ghcr.io/stnolting/neorv32/sim
cmd: ./sim/run.py --ci-mode -v

View file

@ -73,6 +73,7 @@ not working as expected. See how to [contribute](https://github.com/stnolting/ne
| GitHub pages (docs) | [neorv32](https://github.com/stnolting/neorv32) | [![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) | | GitHub pages (docs) | [neorv32](https://github.com/stnolting/neorv32) | [![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) |
| Build documentation | [neorv32](https://github.com/stnolting/neorv32) | [![Documentation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Documentation.yml?branch=main&longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) | | Build documentation | [neorv32](https://github.com/stnolting/neorv32) | [![Documentation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Documentation.yml?branch=main&longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) |
| Processor verification | [neorv32](https://github.com/stnolting/neorv32) | [![Processor](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Processor.yml?branch=main&longCache=true&style=flat-square&label=Processor%20Check&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) | | Processor verification | [neorv32](https://github.com/stnolting/neorv32) | [![Processor](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Processor.yml?branch=main&longCache=true&style=flat-square&label=Processor%20Check&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) |
| VUnit testbench | [neorv32-vunit](https://github.com/stnolting/neorv32-vunit) | [![neorv32-vunit](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-vunit/vunit.yml?branch=main&longCache=true&style=flat-square&label=neorv32-vunit&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-vunit/actions/workflows/vunit.yml) |
| RISCOF core verification | [neorv32-riscof](https://github.com/stnolting/neorv32-riscof) | [![neorv32-riscof](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-riscof/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-riscof&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-riscof/actions/workflows/main.yml) | | RISCOF core verification | [neorv32-riscof](https://github.com/stnolting/neorv32-riscof) | [![neorv32-riscof](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-riscof/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-riscof&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-riscof/actions/workflows/main.yml) |
| FPGA implementations | [neorv32-setups](https://github.com/stnolting/neorv32-setups) | [![Implementation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-setups/Implementation.yml?branch=main&longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-setups/actions?query=workflow%3AImplementation) | | FPGA implementations | [neorv32-setups](https://github.com/stnolting/neorv32-setups) | [![Implementation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-setups/Implementation.yml?branch=main&longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-setups/actions?query=workflow%3AImplementation) |
| All-Verilog version | [neorv32-verilog](https://github.com/stnolting/neorv32-verilog) | [![neorv32-verilog](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-verilog/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-verilog&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-verilog/actions/workflows/main.yml) | | All-Verilog version | [neorv32-verilog](https://github.com/stnolting/neorv32-verilog) | [![neorv32-verilog](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-verilog/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-verilog&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-verilog/actions/workflows/main.yml) |

View file

@ -284,7 +284,7 @@ puts $file_list
.File-List Usage Examples .File-List Usage Examples
[TIP] [TIP]
The provided file-list files are used by the GHDL-based simple simulation setup (`sim/tb_simple/ghdl.setup.sh`) as The provided file-list files are used by the GHDL-based simple simulation setup (`sim/ghdl.setup.sh`) as
well as by the Vivado IP packager script (`rtl/system_integration/neorv32_vivado_ip.tcl`). well as by the Vivado IP packager script (`rtl/system_integration/neorv32_vivado_ip.tcl`).

View file

@ -2,9 +2,9 @@
:sectnums: :sectnums:
== Simulating the Processor == Simulating the Processor
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional
the templates and examples. peripherals in the templates and examples. Therefore, there is a wide range of possible testing and
Therefore, there is a wide range of possible testing and verification strategies. verification strategies.
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view. On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view.
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s). That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s).
@ -13,27 +13,22 @@ On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/ver
are used for verifying the functionality of the various peripherals from a hardware point of view. are used for verifying the functionality of the various peripherals from a hardware point of view.
.AMD Vivado / ISIM .AMD Vivado / ISIM
[IMPORTANT] [TIP]
When using AMD Vivado (ISIM for simulation) make sure to **turn of** "incremental compilation" (_Project Setting_ When using AMD Vivado (ISIM for simulation) make sure to **turn of** "incremental compilation" (_Project Setting_
-> _Simulation_ -> _Advanced_ -> _Enable incremental compilation). This will slow down simulation relaunch but will -> _Simulation_ -> _Advanced_ -> _Enable incremental compilation). This will slow down simulation relaunch but will
ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader
[TIP]
The processor can check if it is being _simulated_ by checking the SYSINFO _SYSINFO_SOC_IS_SIM_ flag
(see https://stnolting.github.io/neorv32/#_system_configuration_information_memory_sysinfo).
Note that this flag is not guaranteed to be set correctly (depending on the HDL toolchain's pragma support).
:sectnums: :sectnums:
=== Testbench === Testbench
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and .VUnit Testbench
testing the processor. [TIP]
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E`. A more sophisticated testbench using **VUnit** is available in a separate repository:
https://github.com/stnolting/neorv32-vunit
[IMPORTANT] A plain-VHDL (no third-party libraries) testbench (`sim/neorv32_tb.vhd`) can be used for simulating and
In the simple testbench several optional extensions are disabled, such as C or E. testing the processor. This testbench features a 100MHz clock and enables all optional peripheral and CPU
If software is compiled using instructions corresponding to disabled extensions, the whole processor will hang in an eternal exception loop and, therefore, the simulation will timeout. extensions.
The `MARCH` must be a subset of the extensions enabled in the testbench.
.True Random Number Generator .True Random Number Generator
[NOTE] [NOTE]
@ -43,40 +38,6 @@ by pseudo-random LFSRs). See the neoTRNG documentation for more information.
The simulation setup is configured via the "User Configuration" section located right at the beginning of The simulation setup is configured via the "User Configuration" section located right at the beginning of
the testbench's architecture. Each configuration constant provides comments to explain the functionality. the testbench's architecture. Each configuration constant provides comments to explain the functionality.
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
to the processor's external bus/memory interface. These components are:
* an external instruction memory (that also allows booting from it)
* an external data memory
* an external memory to simulate "external IO devices"
* a memory-mapped registers to trigger the processor's interrupt signals
The following table shows the base addresses of these four components and their default configuration and
properties:
[NOTE]
====
Attributes:
* `r` = read
* `w` = write
* `e` = execute
* `8` = byte-accessible
* `16` = half-word-accessible
* `32` = word-accessible
====
.Testbench: processor-external memories
[cols="^4,>3,^5,<11"]
[options="header",grid="rows"]
|=======================
| Base address | Size | Attributes | Description
| `0x00000000` | `imem_size_c` | `r/w/e 8/16/32` | external IMEM (initialized with application image)
| `0x80000000` | `dmem_size_c` | `r/w/e 8/16/32` | external DMEM
| `0xf0000000` | 64 bytes | `r/w/e 8/16/32` | external "IO" memory
| `0xff000000` | 4 bytes | `-/w/- -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|=======================
[IMPORTANT] [IMPORTANT]
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
the `rtl/core/neorv32_application_image.vhd` image file). the `rtl/core/neorv32_application_image.vhd` image file).
@ -100,7 +61,7 @@ for UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_unive
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator
execution directory: execution directory:
* `neorv32.uart?.sim_mode.text.out`: ASCII data. * `neorv32.uart*.sim_mode.text.out`: ASCII data.
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application. You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application.
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled. In this case, the "real" UART0/UART1 transmitter unit is permanently disabled.
@ -123,13 +84,13 @@ completed with a line feed (newline, ASCII `\n` = 10).
:sectnums: :sectnums:
=== Simulation using a shell script (with GHDL) === Simulation using a shell script (with GHDL)
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script. To simulate the processor using _GHDL_ navigate to the `sim` folder and run the provided shell script.
Any arguments that are provided while executing this script are passed to GHDL. Any arguments that are provided while executing this script are passed to GHDL.
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument. For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument.
[source, bash] [source, bash]
---- ----
neorv32/sim/simple$ sh ghdl.sh --stop-time=20ms neorv32/sim$ sh ghdl.sh --stop-time=20ms
---- ----
@ -156,10 +117,6 @@ To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl
https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed. https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed.
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim`: Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim`:
[TIP]
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
[source, bash] [source, bash]
---- ----
neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
@ -208,39 +165,3 @@ Hello world! :)
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms). <5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms).
<6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear. <6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear.
<7> Execution of the actual program starts. <7> Execution of the actual program starts.
:sectnums:
=== Advanced Simulation using VUnit
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog.
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies.
The motto of VUnit is _"testing early and often"_ through automation.
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional
http://vunit.github.io/vhdl_libraries.html[VHDL libraries].
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and
gathering of the results regardless of the simulator used.
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc.
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc.
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc.
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing
NEORV32 and peripherals.
The entry-point for executing the tests is `sim/run.py`.
[source, bash]
----
# ./sim/run.py -l
neorv32.neorv32_tb.all
Listed 1 tests
# ./sim/run.py -v
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed
...
----
See http://vunit.github.io/user_guide.html[VUnit: User Guide] and http://vunit.github.io/cli.html[VUnit: Command Line Interface] for further info about VUnit's features.

View file

@ -1,24 +0,0 @@
## Simulation Sources
### > [`simple`](simple) testbench
"Simple" testbench for the NEORV32 Processor and script for simulation using GHDL.
- [`ghdl.setup.sh`](simple/ghdl.setup.sh)
- [`ghdl.run.sh`](simple/ghdl.run.sh)
- [`ghdl.sh`](simple/ghdl.sh)
- [`neorv32_tb.simple.vhd`](simple/neorv32_tb.simple.vhd)
- [`uart_rx.simple.vhd`](simple/uart_rx.simple.vhd)
### > VUnit testbench (this folder)
VUnit testbench for the NEORV32 Processor.
> [!WARNING]
> This testbench requires VHDL-2008 (or newer) as standard!
- [`run.py`](run.py)
- [`neorv32_tb.vhd`](neorv32_tb.vhd)
- [`uart_rx_pkg.vhd`](uart_rx_pkg.vhd)
- [`uart_rx.vhd`](uart_rx.vhd)

4
sim/simple/ghdl.run.sh → sim/ghdl.run.sh Executable file → Normal file
View file

@ -20,7 +20,7 @@ done
GHDL="${GHDL:-ghdl}" GHDL="${GHDL:-ghdl}"
$GHDL -m --work=neorv32 --workdir=build neorv32_tb_simple $GHDL -m --work=neorv32 --workdir=build neorv32_tb
if [ -z "$1" ] if [ -z "$1" ]
then then
@ -32,7 +32,7 @@ fi
echo "Using simulation run arguments: $GHDL_RUN_ARGS"; echo "Using simulation run arguments: $GHDL_RUN_ARGS";
runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb_simple \ runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb \
--max-stack-alloc=0 \ --max-stack-alloc=0 \
--ieee-asserts=disable \ --ieee-asserts=disable \
--assert-level=error $GHDL_RUN_ARGS" --assert-level=error $GHDL_RUN_ARGS"

6
sim/simple/ghdl.setup.sh → sim/ghdl.setup.sh Executable file → Normal file
View file

@ -4,7 +4,7 @@ set -e
cd $(dirname "$0") cd $(dirname "$0")
NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../../rtl} NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../rtl}
FILE_LIST=`cat $NEORV32_LOCAL_RTL/file_list_soc.f` FILE_LIST=`cat $NEORV32_LOCAL_RTL/file_list_soc.f`
CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_LOCAL_RTL"}" CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_LOCAL_RTL"}"
@ -16,5 +16,5 @@ ghdl -i --work=neorv32 --workdir=build \
"$NEORV32_LOCAL_RTL"/processor_templates/*.vhd \ "$NEORV32_LOCAL_RTL"/processor_templates/*.vhd \
"$NEORV32_LOCAL_RTL"/system_integration/*.vhd \ "$NEORV32_LOCAL_RTL"/system_integration/*.vhd \
"$NEORV32_LOCAL_RTL"/test_setups/*.vhd \ "$NEORV32_LOCAL_RTL"/test_setups/*.vhd \
neorv32_tb.simple.vhd \ neorv32_tb.vhd \
uart_rx.simple.vhd uart_rx.vhd

12
sim/ghdl.sh Normal file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Abort if any command returns != 0
set -e
cd $(dirname "$0")
# Setup simulation
/bin/bash ghdl.setup.sh
# Run simulation (pass down more than 1 parameter to GHDL)
/bin/bash ghdl.run.sh $@

View file

@ -1,5 +1,5 @@
-- ================================================================================ -- -- ================================================================================ --
-- NEORV32 - VUnit Processor Testbench -- -- NEORV32 - Default Processor Testbench --
-- -------------------------------------------------------------------------------- -- -- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. -- -- Copyright (c) NEORV32 contributors. --
@ -8,11 +8,6 @@
-- SPDX-License-Identifier: BSD-3-Clause -- -- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ -- -- ================================================================================ --
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
@ -24,33 +19,55 @@ use neorv32.neorv32_application_image.all; -- this file is generated by the imag
use std.textio.all; use std.textio.all;
library osvvm;
use osvvm.RandomPkg.all;
use work.uart_rx_pkg.all;
entity neorv32_tb is entity neorv32_tb is
generic (runner_cfg : string := runner_cfg_default; generic (
ci_mode : boolean := false); PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements
);
end neorv32_tb; end neorv32_tb;
architecture neorv32_tb_rtl of neorv32_tb is architecture neorv32_tb_rtl of neorv32_tb is
-- advanced configuration --
constant num_configs_c : natural := 3; -- number of pre-defined configurations
-- helpers --
type bool_t is array (0 to num_configs_c-1) of boolean;
type natural_t is array (0 to num_configs_c-1) of natural;
type performance_options_type_t is record
fast_mul_en_c : bool_t;
fast_shift_en_c : bool_t;
imem_size_c : natural_t;
icache_en_c : bool_t;
icache_block_size_c : natural_t;
dcache_en_c : bool_t;
dcache_block_size_c : natural_t;
end record;
-- User Configuration --------------------------------------------------------------------- -- User Configuration ---------------------------------------------------------------------
-- ------------------------------------------------------------------------------------------- -- -------------------------------------------------------------------------------------------
-- core performance options --
constant performance_options_c : performance_options_type_t := (
-- default fast core area core
fast_mul_en_c => ( true, true, false), -- Fast multiplication, more area
fast_shift_en_c => ( true, true, false), -- Fast shifting, more area
imem_size_c => ( 32*1024, 128*1024, 128*1024), -- Instruction memory size min. 128kB for performance tests
icache_en_c => ( true, false, false), -- I$ disabled for performance tests
icache_block_size_c => ( 32, 32, 32), -- I$ block size
dcache_en_c => ( true, false, false), -- D$ disabled for performance tests
dcache_block_size_c => ( 32, 32, 32) -- D$ block size
);
-- general -- -- general --
constant int_imem_c : boolean := false; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A) constant int_imem_c : boolean := true; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A)
constant int_dmem_c : boolean := false; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B) constant int_dmem_c : boolean := true; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B)
constant imem_size_c : natural := 32*1024; -- size in bytes of processor-internal IMEM / external mem A
constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B
constant f_clock_c : natural := 100000000; -- main clock in Hz constant f_clock_c : natural := 100000000; -- main clock in Hz
constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate
constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate
constant icache_en_c : boolean := false; -- implement i-cache
constant icache_block_size_c : natural := 64; -- i-cache block size in bytes
-- simulated external Wishbone memory A (can be used as external IMEM) -- -- simulated external Wishbone memory A (can be used as external IMEM) --
constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base) constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base)
constant ext_mem_a_size_c : natural := imem_size_c; -- wishbone memory size in bytes constant ext_mem_a_size_c : natural := performance_options_c.imem_size_c(PERFORMANCE_OPTION); -- wishbone memory size in bytes
constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory B (can be used as external DMEM) -- -- simulated external Wishbone memory B (can be used as external DMEM) --
constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base) constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base)
@ -58,7 +75,7 @@ architecture neorv32_tb_rtl of neorv32_tb is
constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory C (can be used to simulate external IO access) -- -- simulated external Wishbone memory C (can be used to simulate external IO access) --
constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area) constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area)
constant ext_mem_c_size_c : natural := icache_block_size_c/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block constant ext_mem_c_size_c : natural := performance_options_c.icache_block_size_c(PERFORMANCE_OPTION)/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block
constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulation interrupt trigger -- -- simulation interrupt trigger --
constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000"; constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000";
@ -72,6 +89,9 @@ architecture neorv32_tb_rtl of neorv32_tb is
-- generators -- -- generators --
signal clk_gen, rst_gen : std_ulogic := '0'; signal clk_gen, rst_gen : std_ulogic := '0';
-- text.io --
file file_uart0_tx_out : text open write_mode is "neorv32.testbench_uart0.out";
-- uart -- -- uart --
signal uart0_txd, uart1_txd : std_ulogic; signal uart0_txd, uart1_txd : std_ulogic;
signal uart0_cts, uart1_cts : std_ulogic; signal uart0_cts, uart1_cts : std_ulogic;
@ -131,55 +151,7 @@ architecture neorv32_tb_rtl of neorv32_tb is
end record; end record;
signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t; signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t;
constant uart0_rx_logger : logger_t := get_logger("UART0.RX");
constant uart1_rx_logger : logger_t := get_logger("UART1.RX");
constant uart0_rx_handle : uart_rx_t := new_uart_rx(uart0_baud_val_c, uart0_rx_logger);
constant uart1_rx_handle : uart_rx_t := new_uart_rx(uart1_baud_val_c, uart1_rx_logger);
begin begin
test_runner : process
variable msg : msg_t;
variable rnd : RandomPType;
begin
test_runner_setup(runner, runner_cfg);
rnd.InitSeed(test_runner'path_name);
-- Show passing checks for UART0 on the display (stdout)
show(uart0_rx_logger, display_handler, pass);
show(uart1_rx_logger, display_handler, pass);
if ci_mode then
check_uart(net, uart0_rx_handle, nul & nul);
else
check_uart(net, uart0_rx_handle, "Blinking LED demo program" & cr & lf);
end if;
if ci_mode then
-- No need to send the full expectation in one big chunk
check_uart(net, uart1_rx_handle, nul & nul);
check_uart(net, uart1_rx_handle, "0/55" & cr & lf);
end if;
-- Wait until all expected data has been received
--
-- wait_until_idle can take the VC actor as argument but
-- the more abstract view is that wait_until_idle is part
-- of the sync VCI and to use it a VC must be cast
-- to a sync VC
wait_until_idle(net, as_sync(uart0_rx_handle));
wait_until_idle(net, as_sync(uart1_rx_handle));
-- Wait a bit more if some extra unexpected data is produced. If so,
-- uart_rx will fail
wait for (20 * (1e9 / baud0_rate_c)) * ns;
test_runner_cleanup(runner);
end process;
-- In case we get stuck waiting there is a watchdog timeout to terminate and fail the
-- testbench
test_runner_watchdog(runner, 50 ms);
-- Clock/Reset Generator ------------------------------------------------------------------ -- Clock/Reset Generator ------------------------------------------------------------------
-- ------------------------------------------------------------------------------------------- -- -------------------------------------------------------------------------------------------
@ -201,7 +173,7 @@ begin
OCD_EN => true, -- implement on-chip debugger OCD_EN => true, -- implement on-chip debugger
OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication
-- RISC-V CPU Extensions -- -- RISC-V CPU Extensions --
RISCV_ISA_C => true, -- implement compressed extension? RISCV_ISA_C => false, -- implement compressed extension?
RISCV_ISA_E => false, -- implement embedded RF extension? RISCV_ISA_E => false, -- implement embedded RF extension?
RISCV_ISA_M => true, -- implement mul/div extension? RISCV_ISA_M => true, -- implement mul/div extension?
RISCV_ISA_U => true, -- implement user mode extension? RISCV_ISA_U => true, -- implement user mode extension?
@ -224,9 +196,9 @@ begin
RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension? RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension?
RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit? RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit?
-- Extension Options -- -- Extension Options --
FAST_MUL_EN => false, -- use DSPs for M extension's multiplier FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION), -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => false, -- use barrel shifter for shift operations FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION), -- use barrel shifter for shift operations
REGFILE_HW_RST => true, -- full hardware reset REGFILE_HW_RST => false, -- no hardware reset
-- Physical Memory Protection (PMP) -- -- Physical Memory Protection (PMP) --
PMP_NUM_REGIONS => 5, -- number of regions (0..16) PMP_NUM_REGIONS => 5, -- number of regions (0..16)
PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes
@ -237,20 +209,24 @@ begin
HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64) HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64)
-- Internal Instruction memory -- -- Internal Instruction memory --
MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => imem_size_c, -- size of processor-internal instruction memory in bytes MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION), -- size of processor-internal instruction memory in bytes
-- Internal Data memory -- -- Internal Data memory --
MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes
-- Internal Cache memory -- -- Internal Cache memory --
ICACHE_EN => false, -- implement instruction cache ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION), -- implement instruction cache
ICACHE_NUM_BLOCKS => 64, -- i-cache: number of blocks (min 2), has to be a power of 2
ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION), -- i-cache: block size in bytes (min 4), has to be a power of 2
-- Internal Data Cache (dCACHE) -- -- Internal Data Cache (dCACHE) --
DCACHE_EN => false, -- implement data cache DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION), -- implement data cache
DCACHE_NUM_BLOCKS => 32, -- d-cache: number of blocks (min 1), has to be a power of 2
DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION), -- d-cache: block size in bytes (min 4), has to be a power of 2
-- External bus interface -- -- External bus interface --
XBUS_EN => true, -- implement external memory bus interface? XBUS_EN => true, -- implement external memory bus interface?
XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled) XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled)
XBUS_REGSTAGE_EN => false, -- add register stage XBUS_REGSTAGE_EN => true, -- add register stage
XBUS_CACHE_EN => true, -- enable external bus cache (x-cache) XBUS_CACHE_EN => true, -- enable external bus cache (x-cache)
XBUS_CACHE_NUM_BLOCKS => 64, -- x-cache: number of blocks (min 1), has to be a power of 2 XBUS_CACHE_NUM_BLOCKS => 4, -- x-cache: number of blocks (min 1), has to be a power of 2
XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2 XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2
-- Execute in-place module (XIP) -- -- Execute in-place module (XIP) --
XIP_EN => true, -- implement execute in place module (XIP)? XIP_EN => true, -- implement execute in place module (XIP)?
@ -326,9 +302,9 @@ begin
-- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- -- XIP (execute in place via SPI) signals (available if XIP_EN = true) --
xip_csn_o => open, -- chip-select, low-active xip_csn_o => open, -- chip-select, low-active
xip_clk_o => open, -- serial clock xip_clk_o => open, -- serial clock
xip_dat_i => '1', -- device data input xip_dat_i => '0', -- device data input
xip_dat_o => open, -- controller data output xip_dat_o => open, -- controller data output
-- GPIO (available if IO_GPIO_NUM > 0) -- -- GPIO (available if IO_GPIO_NUM > true) --
gpio_o => gpio, -- parallel output gpio_o => gpio, -- parallel output
gpio_i => gpio, -- parallel input gpio_i => gpio, -- parallel input
-- primary UART0 (available if IO_UART0_EN = true) -- -- primary UART0 (available if IO_UART0_EN = true) --
@ -399,17 +375,28 @@ begin
sdi_di <= spi_do after 40 ns; sdi_di <= spi_do after 40 ns;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns; spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns;
-- UART Simulation Receiver ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
uart0_checker: entity work.uart_rx uart0_checker: entity work.uart_rx
generic map (uart0_rx_handle) generic map (
port map ( name => "uart0",
clk => clk_gen, uart_baud_val_c => uart0_baud_val_c
uart_txd => uart0_txd); )
port map (
clk => clk_gen,
uart_txd => uart0_txd
);
uart1_checker: entity work.uart_rx uart1_checker: entity work.uart_rx
generic map (uart1_rx_handle) generic map (
port map ( name => "uart1",
clk => clk_gen, uart_baud_val_c => uart1_baud_val_c
uart_txd => uart1_txd); )
port map (
clk => clk_gen,
uart_txd => uart1_txd
);
-- Wishbone Fabric ------------------------------------------------------------------------ -- Wishbone Fabric ------------------------------------------------------------------------

View file

@ -1,56 +0,0 @@
#!/usr/bin/env python3
import json
from pathlib import Path
from vunit import VUnit, VUnitCLI
cli = VUnitCLI()
cli.parser.add_argument(
"--ci-mode",
action="store_true",
default=False,
help="Enable special settings used by the CI",
)
args = cli.parse_args()
PRJ = VUnit.from_args(args=args)
PRJ.add_vhdl_builtins()
PRJ.add_com()
PRJ.add_verification_components()
PRJ.add_osvvm()
ROOT = Path(__file__).parent
NEORV32 = PRJ.add_library("neorv32")
NEORV32.add_source_files([
ROOT / "*.vhd",
ROOT / ".." / "rtl" / "**" / "*.vhd",
])
NEORV32.test_bench("neorv32_tb").set_generic("ci_mode", args.ci_mode)
PRJ.set_sim_option("disable_ieee_warnings", True)
PRJ.set_sim_option("ghdl.sim_flags", ["--max-stack-alloc=256"])
def _gen_vhdl_ls(vu):
"""
Generate the vhdl_ls.toml file required by VHDL-LS language server.
"""
# Repo root
parent = Path(__file__).parent.parent
proj = vu._project
libs = proj.get_libraries()
with open(parent / 'vhdl_ls.toml', "w") as f:
for lib in libs:
f.write(f"[libraries.{lib.name}]\n")
files = [str(file).replace('\\', '/') for file in lib._source_files
# Conflicts with *.default.vhd
if not any(exclude in file for exclude in ('neorv32_imem.simple.vhd', 'neorv32_imem.legacy.vhd', 'neorv32_dmem.legacy.vhd'))
]
f.write(f"files = {json.dumps(files, indent=4)}\n")
_gen_vhdl_ls(PRJ)
PRJ.main()

View file

@ -1,10 +0,0 @@
#!/usr/bin/env bash
# Abort if any command returns != 0
set -e
cd $(dirname "$0")
./ghdl.setup.sh
# We want to be able to pass down more than 1 parameter to GHDL
./ghdl.run.sh $@

View file

@ -1,605 +0,0 @@
-- ================================================================================ --
-- NEORV32 - Default Processor Testbench --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library neorv32;
use neorv32.neorv32_package.all;
use neorv32.neorv32_application_image.all; -- this file is generated by the image generator
use std.textio.all;
entity neorv32_tb_simple is
generic (
PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements
);
end neorv32_tb_simple;
architecture neorv32_tb_simple_rtl of neorv32_tb_simple is
-- advanced configuration --
constant num_configs_c : natural := 3; -- number of pre-defined configurations
-- helpers --
type bool_t is array (0 to num_configs_c-1) of boolean;
type natural_t is array (0 to num_configs_c-1) of natural;
type performance_options_type_t is record
fast_mul_en_c : bool_t;
fast_shift_en_c : bool_t;
imem_size_c : natural_t;
icache_en_c : bool_t;
icache_block_size_c : natural_t;
dcache_en_c : bool_t;
dcache_block_size_c : natural_t;
end record;
-- User Configuration ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- core performance options --
constant performance_options_c : performance_options_type_t := (
-- default fast core area core
fast_mul_en_c => ( true, true, false), -- Fast multiplication, more area
fast_shift_en_c => ( true, true, false), -- Fast shifting, more area
imem_size_c => ( 32*1024, 128*1024, 128*1024), -- Instruction memory size min. 128kB for performance tests
icache_en_c => ( true, false, false), -- I$ disabled for performance tests
icache_block_size_c => ( 32, 32, 32), -- I$ block size
dcache_en_c => ( true, false, false), -- D$ disabled for performance tests
dcache_block_size_c => ( 32, 32, 32) -- D$ block size
);
-- general --
constant int_imem_c : boolean := true; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A)
constant int_dmem_c : boolean := true; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B)
constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B
constant f_clock_c : natural := 100000000; -- main clock in Hz
constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate
constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate
-- simulated external Wishbone memory A (can be used as external IMEM) --
constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base)
constant ext_mem_a_size_c : natural := performance_options_c.imem_size_c(PERFORMANCE_OPTION); -- wishbone memory size in bytes
constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory B (can be used as external DMEM) --
constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base)
constant ext_mem_b_size_c : natural := dmem_size_c; -- wishbone memory size in bytes
constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory C (can be used to simulate external IO access) --
constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area)
constant ext_mem_c_size_c : natural := performance_options_c.icache_block_size_c(PERFORMANCE_OPTION)/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block
constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulation interrupt trigger --
constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000";
-- -------------------------------------------------------------------------------------------
-- internals - hands off! --
constant uart0_baud_val_c : real := real(f_clock_c) / real(baud0_rate_c);
constant uart1_baud_val_c : real := real(f_clock_c) / real(baud1_rate_c);
constant t_clock_c : time := (1 sec) / f_clock_c;
-- generators --
signal clk_gen, rst_gen : std_ulogic := '0';
-- text.io --
file file_uart0_tx_out : text open write_mode is "neorv32.testbench_uart0.out";
-- uart --
signal uart0_txd, uart1_txd : std_ulogic;
signal uart0_cts, uart1_cts : std_ulogic;
-- gpio --
signal gpio : std_ulogic_vector(63 downto 0);
-- twi --
signal twi_scl, twi_sda : std_logic;
signal twi_scl_i, twi_scl_o, twi_sda_i, twi_sda_o : std_ulogic;
-- 1-wire --
signal onewire : std_logic;
signal onewire_i, onewire_o : std_ulogic;
-- spi & sdi --
signal spi_csn: std_ulogic_vector(7 downto 0);
signal spi_di, spi_do, spi_clk : std_ulogic;
signal sdi_di, sdi_do, sdi_clk, sdi_csn : std_ulogic;
-- irq --
signal msi_ring, mei_ring : std_ulogic;
-- SLINK echo --
signal slink_dat : std_ulogic_vector(31 downto 0);
signal slink_val : std_ulogic;
signal slink_lst : std_ulogic;
signal slink_rdy : std_ulogic;
signal slink_id : std_ulogic_vector(3 downto 0);
-- Wishbone bus --
type wishbone_t is record
addr : std_ulogic_vector(31 downto 0); -- address
wdata : std_ulogic_vector(31 downto 0); -- master write data
rdata : std_ulogic_vector(31 downto 0); -- master read data
tag : std_ulogic_vector(2 downto 0); -- access tag
we : std_ulogic; -- write enable
sel : std_ulogic_vector(3 downto 0); -- byte enable
stb : std_ulogic; -- strobe
cyc : std_ulogic; -- valid cycle
ack : std_ulogic; -- transfer acknowledge
err : std_ulogic; -- transfer error
end record;
signal wb_cpu, wb_mem_a, wb_mem_b, wb_mem_c, wb_irq : wishbone_t;
-- Wishbone access latency type --
type ext_mem_read_latency_t is array (0 to 255) of std_ulogic_vector(31 downto 0);
-- simulated external memory c (IO) --
signal ext_ram_c : mem32_t(0 to ext_mem_c_size_c/4-1); -- uninitialized, used to simulate external IO
-- simulated external memory bus feedback type --
type ext_mem_t is record
rdata : ext_mem_read_latency_t;
acc_en : std_ulogic;
ack : std_ulogic_vector(255 downto 0);
end record;
signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t;
begin
-- Clock/Reset Generator ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
clk_gen <= not clk_gen after (t_clock_c/2);
rst_gen <= '0', '1' after 60*(t_clock_c/2);
-- The Core of the Problem ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode
HART_ID => x"00000000", -- hardware thread ID
JEDEC_ID => "00000000000", -- vendor's JEDEC ID
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- On-Chip Debugger (OCD) --
OCD_EN => true, -- implement on-chip debugger
OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication
-- RISC-V CPU Extensions --
RISCV_ISA_C => false, -- implement compressed extension?
RISCV_ISA_E => false, -- implement embedded RF extension?
RISCV_ISA_M => true, -- implement mul/div extension?
RISCV_ISA_U => true, -- implement user mode extension?
RISCV_ISA_Zalrsc => true, -- implement atomic reservation-set extension
RISCV_ISA_Zba => true, -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb => true, -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb => true, -- implement bit-manipulation instructions for cryptography
RISCV_ISA_Zbkc => true, -- implement carry-less multiplication instructions?
RISCV_ISA_Zbkx => true, -- implement cryptography crossbar permutation extension?
RISCV_ISA_Zbs => true, -- implement single-bit bit-manipulation extension
RISCV_ISA_Zfinx => true, -- implement 32-bit floating-point extension (using INT reg!)
RISCV_ISA_Zicntr => true, -- implement base counters?
RISCV_ISA_Zicond => true, -- implement integer conditional operations?
RISCV_ISA_Zihpm => true, -- implement hardware performance monitors?
RISCV_ISA_Zknd => true, -- implement cryptography NIST AES decryption extension?
RISCV_ISA_Zkne => true, -- implement cryptography NIST AES encryption extension?
RISCV_ISA_Zknh => true, -- implement cryptography NIST hash extension?
RISCV_ISA_Zksed => true, -- implement ShangMi block cypher extension?
RISCV_ISA_Zksh => true, -- implement ShangMi hash extension?
RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension?
RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit?
-- Extension Options --
FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION), -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION), -- use barrel shifter for shift operations
REGFILE_HW_RST => false, -- no hardware reset
-- Physical Memory Protection (PMP) --
PMP_NUM_REGIONS => 5, -- number of regions (0..16)
PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes
PMP_TOR_MODE_EN => true, -- implement TOR mode
PMP_NAP_MODE_EN => true, -- implement NAPOT/NA4 mode
-- Hardware Performance Monitors (HPM) --
HPM_NUM_CNTS => 12, -- number of implemented HPM counters (0..29)
HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64)
-- Internal Instruction memory --
MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION), -- size of processor-internal instruction memory in bytes
-- Internal Data memory --
MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes
-- Internal Cache memory --
ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION), -- implement instruction cache
ICACHE_NUM_BLOCKS => 64, -- i-cache: number of blocks (min 2), has to be a power of 2
ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION), -- i-cache: block size in bytes (min 4), has to be a power of 2
-- Internal Data Cache (dCACHE) --
DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION), -- implement data cache
DCACHE_NUM_BLOCKS => 32, -- d-cache: number of blocks (min 1), has to be a power of 2
DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION), -- d-cache: block size in bytes (min 4), has to be a power of 2
-- External bus interface --
XBUS_EN => true, -- implement external memory bus interface?
XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled)
XBUS_REGSTAGE_EN => true, -- add register stage
XBUS_CACHE_EN => true, -- enable external bus cache (x-cache)
XBUS_CACHE_NUM_BLOCKS => 4, -- x-cache: number of blocks (min 1), has to be a power of 2
XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2
-- Execute in-place module (XIP) --
XIP_EN => true, -- implement execute in place module (XIP)?
XIP_CACHE_EN => true, -- implement XIP cache?
XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2
XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32)
-- Processor peripherals --
IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64)
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
IO_UART0_EN => true, -- implement primary universal asynchronous receiver/transmitter (UART0)?
IO_UART0_RX_FIFO => 32, -- RX fifo depth, has to be a power of two, min 1
IO_UART0_TX_FIFO => 32, -- TX fifo depth, has to be a power of two, min 1
IO_UART1_EN => true, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
IO_UART1_RX_FIFO => 1, -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO => 1, -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN => true, -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO => 4, -- SPI RTX fifo depth, has to be zero or a power of two
IO_SDI_EN => true, -- implement serial data interface (SDI)?
IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN => true, -- implement two-wire interface (TWI)?
IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16)
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => true, -- implement true random number generator (TRNG)?
IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1
IO_CFS_EN => true, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => (others => '0'), -- custom CFS configuration generic
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)?
IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)?
IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)?
IO_DMA_EN => true, -- implement direct memory access controller (DMA)?
IO_SLINK_EN => true, -- implement stream link interface (SLINK)?
IO_SLINK_RX_FIFO => 4, -- RX fifo depth, has to be a power of two, min 1
IO_SLINK_TX_FIFO => 4, -- TX fifo depth, has to be a power of two, min 1
IO_CRC_EN => true -- implement cyclic redundancy check unit (CRC)?
)
port map (
-- Global control --
clk_i => clk_gen, -- global clock, rising edge
rstn_i => rst_gen, -- global reset, low-active, async
-- JTAG on-chip debugger interface (available if OCD_EN = true) --
jtag_tck_i => '0', -- serial clock
jtag_tdi_i => '0', -- serial data input
jtag_tdo_o => open, -- serial data output
jtag_tms_i => '0', -- mode select
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_cpu.addr, -- address
xbus_dat_o => wb_cpu.wdata, -- write data
xbus_tag_o => wb_cpu.tag, -- access tag
xbus_we_o => wb_cpu.we, -- read/write
xbus_sel_o => wb_cpu.sel, -- byte enable
xbus_stb_o => wb_cpu.stb, -- strobe
xbus_cyc_o => wb_cpu.cyc, -- valid cycle
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_ack_i => wb_cpu.ack, -- transfer acknowledge
xbus_err_i => wb_cpu.err, -- transfer error
-- Stream Link Interface (available if IO_SLINK_EN = true) --
slink_rx_dat_i => slink_dat, -- RX input data
slink_rx_src_i => slink_id, -- RX source routing information
slink_rx_val_i => slink_val, -- RX valid input
slink_rx_lst_i => slink_lst, -- RX last element of stream
slink_rx_rdy_o => slink_rdy, -- RX ready to receive
slink_tx_dat_o => slink_dat, -- TX output data
slink_tx_dst_o => slink_id, -- TX destination routing information
slink_tx_val_o => slink_val, -- TX valid output
slink_tx_lst_o => slink_lst, -- TX last element of stream
slink_tx_rdy_i => slink_rdy, -- TX ready to send
-- XIP (execute in place via SPI) signals (available if XIP_EN = true) --
xip_csn_o => open, -- chip-select, low-active
xip_clk_o => open, -- serial clock
xip_dat_i => '0', -- device data input
xip_dat_o => open, -- controller data output
-- GPIO (available if IO_GPIO_NUM > true) --
gpio_o => gpio, -- parallel output
gpio_i => gpio, -- parallel input
-- primary UART0 (available if IO_UART0_EN = true) --
uart0_txd_o => uart0_txd, -- UART0 send data
uart0_rxd_i => uart0_txd, -- UART0 receive data
uart0_rts_o => uart1_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart0_cts_i => uart0_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
-- secondary UART1 (available if IO_UART1_EN = true) --
uart1_txd_o => uart1_txd, -- UART1 send data
uart1_rxd_i => uart1_txd, -- UART1 receive data
uart1_rts_o => uart0_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart1_cts_i => uart1_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
-- SPI (available if IO_SPI_EN = true) --
spi_clk_o => spi_clk, -- SPI serial clock
spi_dat_o => spi_do, -- controller data out, peripheral data in
spi_dat_i => spi_di, -- controller data in, peripheral data out
spi_csn_o => spi_csn, -- SPI CS
-- SDI (available if IO_SDI_EN = true) --
sdi_clk_i => sdi_clk, -- SDI serial clock
sdi_dat_o => sdi_do, -- controller data out, peripheral data in
sdi_dat_i => sdi_di, -- controller data in, peripheral data out
sdi_csn_i => sdi_csn, -- chip-select
-- TWI (available if IO_TWI_EN = true) --
twi_sda_i => twi_sda_i, -- serial data line sense input
twi_sda_o => twi_sda_o, -- serial data line output (pull low only)
twi_scl_i => twi_scl_i, -- serial clock line sense input
twi_scl_o => twi_scl_o, -- serial clock line output (pull low only)
-- 1-Wire Interface (available if IO_ONEWIRE_EN = true) --
onewire_i => onewire_i, -- 1-wire bus sense input
onewire_o => onewire_o, -- 1-wire bus output (pull low only)
-- PWM (available if IO_PWM_NUM_CH > 0) --
pwm_o => open, -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i => (others => '0'), -- custom CFS inputs
cfs_out_o => open, -- custom CFS outputs
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
neoled_o => open, -- async serial data line
-- Machine timer system time (available if IO_MTIME_EN = true) --
mtime_time_o => open,
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
xirq_i => gpio(31 downto 0), -- IRQ channels
-- CPU Interrupts --
mtime_irq_i => '0', -- machine software interrupt, available if IO_MTIME_EN = false
msw_irq_i => msi_ring, -- machine software interrupt
mext_irq_i => mei_ring -- machine external interrupt
);
-- TWI tri-state driver --
twi_sda <= '0' when (twi_sda_o = '0') else 'Z'; -- module can only pull the line low actively
twi_scl <= '0' when (twi_scl_o = '0') else 'Z';
twi_sda_i <= std_ulogic(twi_sda);
twi_scl_i <= std_ulogic(twi_scl);
-- 1-Wire tri-state driver --
onewire <= '0' when (onewire_o = '0') else 'Z'; -- module can only pull the line low actively
onewire_i <= std_ulogic(onewire);
-- TWI termination (pull-ups) --
twi_scl <= 'H';
twi_sda <= 'H';
-- 1-Wire termination (pull-up) --
onewire <= 'H';
-- SPI/SDI echo with propagation delay --
sdi_clk <= spi_clk after 40 ns;
sdi_csn <= spi_csn(7) after 40 ns;
sdi_di <= spi_do after 40 ns;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns;
-- UART Simulation Receiver ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
uart0_checker: entity work.uart_rx_simple
generic map (
name => "uart0",
uart_baud_val_c => uart0_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart0_txd
);
uart1_checker: entity work.uart_rx_simple
generic map (
name => "uart1",
uart_baud_val_c => uart1_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart1_txd
);
-- Wishbone Fabric ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- CPU broadcast signals --
wb_mem_a.addr <= wb_cpu.addr;
wb_mem_a.wdata <= wb_cpu.wdata;
wb_mem_a.we <= wb_cpu.we;
wb_mem_a.sel <= wb_cpu.sel;
wb_mem_a.cyc <= wb_cpu.cyc;
wb_mem_b.addr <= wb_cpu.addr;
wb_mem_b.wdata <= wb_cpu.wdata;
wb_mem_b.we <= wb_cpu.we;
wb_mem_b.sel <= wb_cpu.sel;
wb_mem_b.cyc <= wb_cpu.cyc;
wb_mem_c.addr <= wb_cpu.addr;
wb_mem_c.wdata <= wb_cpu.wdata;
wb_mem_c.we <= wb_cpu.we;
wb_mem_c.sel <= wb_cpu.sel;
wb_mem_c.cyc <= wb_cpu.cyc;
wb_irq.addr <= wb_cpu.addr;
wb_irq.wdata <= wb_cpu.wdata;
wb_irq.we <= wb_cpu.we;
wb_irq.sel <= wb_cpu.sel;
wb_irq.cyc <= wb_cpu.cyc;
-- CPU read-back signals (no mux here since peripherals have "output gates") --
wb_cpu.rdata <= wb_mem_a.rdata or wb_mem_b.rdata or wb_mem_c.rdata or wb_irq.rdata;
wb_cpu.ack <= wb_mem_a.ack or wb_mem_b.ack or wb_mem_c.ack or wb_irq.ack;
wb_cpu.err <= wb_mem_a.err or wb_mem_b.err or wb_mem_c.err or wb_irq.err;
-- peripheral select via STROBE signal --
wb_mem_a.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_a_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_a_base_addr_c) + ext_mem_a_size_c)) else '0';
wb_mem_b.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_b_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_b_base_addr_c) + ext_mem_b_size_c)) else '0';
wb_mem_c.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_c_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_c_base_addr_c) + ext_mem_c_size_c)) else '0';
wb_irq.stb <= wb_cpu.stb when (wb_cpu.addr = irq_trigger_base_addr_c) else '0';
-- Wishbone Memory A (simulated external IMEM) --------------------------------------------
-- -------------------------------------------------------------------------------------------
generate_ext_imem:
if (int_imem_c = false) generate
ext_mem_a_access: process(clk_gen)
variable ext_ram_a : mem32_t(0 to ext_mem_a_size_c/4-1) := mem32_init_f(application_init_image, ext_mem_a_size_c/4); -- initialized, used to simulate external IMEM
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_a.ack(0) <= wb_mem_a.cyc and wb_mem_a.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_a.cyc and wb_mem_a.stb and wb_mem_a.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_a.sel(i) = '1') then
ext_ram_a(to_integer(unsigned(wb_mem_a.addr(index_size_f(ext_mem_a_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) := wb_mem_a.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_a.rdata(0) <= ext_ram_a(to_integer(unsigned(wb_mem_a.addr(index_size_f(ext_mem_a_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_a_latency_c > 1) then
for i in 1 to ext_mem_a_latency_c-1 loop
ext_mem_a.rdata(i) <= ext_mem_a.rdata(i-1);
ext_mem_a.ack(i) <= ext_mem_a.ack(i-1) and wb_mem_a.cyc;
end loop;
end if;
-- bus output register --
wb_mem_a.err <= '0';
if (ext_mem_a.ack(ext_mem_a_latency_c-1) = '1') and (wb_mem_a.cyc = '1') then
wb_mem_a.rdata <= ext_mem_a.rdata(ext_mem_a_latency_c-1);
wb_mem_a.ack <= '1';
else
wb_mem_a.rdata <= (others => '0');
wb_mem_a.ack <= '0';
end if;
end if;
end process ext_mem_a_access;
end generate;
generate_ext_imem_false:
if (int_imem_c = true) generate
wb_mem_a.rdata <= (others => '0');
wb_mem_a.ack <= '0';
wb_mem_a.err <= '0';
end generate;
-- Wishbone Memory B (simulated external DMEM) --------------------------------------------
-- -------------------------------------------------------------------------------------------
generate_ext_dmem:
if (int_dmem_c = false) generate
ext_mem_b_access: process(clk_gen)
variable ext_ram_b : mem32_t(0 to ext_mem_b_size_c/4-1) := (others => (others => '0')); -- zero, used to simulate external DMEM
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_b.ack(0) <= wb_mem_b.cyc and wb_mem_b.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_b.cyc and wb_mem_b.stb and wb_mem_b.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_b.sel(i) = '1') then
ext_ram_b(to_integer(unsigned(wb_mem_b.addr(index_size_f(ext_mem_b_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) := wb_mem_b.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_b.rdata(0) <= ext_ram_b(to_integer(unsigned(wb_mem_b.addr(index_size_f(ext_mem_b_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_b_latency_c > 1) then
for i in 1 to ext_mem_b_latency_c-1 loop
ext_mem_b.rdata(i) <= ext_mem_b.rdata(i-1);
ext_mem_b.ack(i) <= ext_mem_b.ack(i-1) and wb_mem_b.cyc;
end loop;
end if;
-- bus output register --
wb_mem_b.err <= '0';
if (ext_mem_b.ack(ext_mem_b_latency_c-1) = '1') and (wb_mem_b.cyc = '1') then
wb_mem_b.rdata <= ext_mem_b.rdata(ext_mem_b_latency_c-1);
wb_mem_b.ack <= '1';
else
wb_mem_b.rdata <= (others => '0');
wb_mem_b.ack <= '0';
end if;
end if;
end process ext_mem_b_access;
end generate;
generate_ext_dmem_false:
if (int_dmem_c = true) generate
wb_mem_b.rdata <= (others => '0');
wb_mem_b.ack <= '0';
wb_mem_b.err <= '0';
end generate;
-- Wishbone Memory C (simulated external IO) ----------------------------------------------
-- -------------------------------------------------------------------------------------------
ext_mem_c_access: process(clk_gen)
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_c.ack(0) <= wb_mem_c.cyc and wb_mem_c.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_c.cyc and wb_mem_c.stb and wb_mem_c.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_c.sel(i) = '1') then
ext_ram_c(to_integer(unsigned(wb_mem_c.addr(index_size_f(ext_mem_c_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) <= wb_mem_c.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_c.rdata(0) <= ext_ram_c(to_integer(unsigned(wb_mem_c.addr(index_size_f(ext_mem_c_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_c_latency_c > 1) then
for i in 1 to ext_mem_c_latency_c-1 loop
ext_mem_c.rdata(i) <= ext_mem_c.rdata(i-1);
ext_mem_c.ack(i) <= ext_mem_c.ack(i-1) and wb_mem_c.cyc;
end loop;
end if;
-- bus output register --
if (ext_mem_c.ack(ext_mem_c_latency_c-1) = '1') and (wb_mem_c.cyc = '1') then
wb_mem_c.rdata <= ext_mem_c.rdata(ext_mem_c_latency_c-1);
wb_mem_c.ack <= '1';
wb_mem_c.err <= '0';
else
wb_mem_c.rdata <= (others => '0');
wb_mem_c.ack <= '0';
wb_mem_c.err <= '0';
end if;
end if;
end process ext_mem_c_access;
-- Wishbone IRQ Triggers ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_trigger: process(rst_gen, clk_gen)
begin
if (rst_gen = '0') then
msi_ring <= '0';
mei_ring <= '0';
elsif rising_edge(clk_gen) then
-- bus interface --
wb_irq.rdata <= (others => '0');
wb_irq.ack <= wb_irq.cyc and wb_irq.stb and wb_irq.we and and_reduce_f(wb_irq.sel);
wb_irq.err <= '0';
-- trigger RISC-V platform IRQs --
if ((wb_irq.cyc and wb_irq.stb and wb_irq.we and and_reduce_f(wb_irq.sel)) = '1') then
msi_ring <= wb_irq.wdata(03); -- machine software interrupt
mei_ring <= wb_irq.wdata(11); -- machine software interrupt
end if;
end if;
end process irq_trigger;
end neorv32_tb_simple_rtl;

View file

@ -1,77 +0,0 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
entity uart_rx_simple is
generic (
name : string;
uart_baud_val_c : real);
port (
clk : in std_ulogic;
uart_txd : in std_ulogic
);
end entity;
architecture a of uart_rx_simple is
signal uart_rx_sync : std_ulogic_vector(04 downto 0) := (others => '1');
signal uart_rx_busy : std_ulogic := '0';
signal uart_rx_sreg : std_ulogic_vector(08 downto 0) := (others => '0');
signal uart_rx_baud_cnt : real;
signal uart_rx_bitcnt : natural;
file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & name & ".out";
begin
uart_rx_console : process(clk)
variable i : integer;
variable l : line;
begin
-- "UART" --
if rising_edge(clk) then
-- synchronizer --
uart_rx_sync <= uart_rx_sync(3 downto 0) & uart_txd;
-- arbiter --
if (uart_rx_busy = '0') then -- idle
uart_rx_busy <= '0';
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
uart_rx_bitcnt <= 9;
if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge)
uart_rx_busy <= '1';
end if;
else
if (uart_rx_baud_cnt <= 0.0) then
if (uart_rx_bitcnt = 1) then
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
else
uart_rx_baud_cnt <= round(uart_baud_val_c);
end if;
if (uart_rx_bitcnt = 0) then
uart_rx_busy <= '0'; -- done
i := to_integer(unsigned(uart_rx_sreg(8 downto 1)));
if (i < 32) or (i > 32+95) then -- printable char?
report name & ".tx: (" & integer'image(i) & ")"; -- print code
else
report name & ".tx: " & character'val(i); -- print ASCII
end if;
if (i = 10) then -- Linux line break
writeline(file_uart_tx_out, l);
elsif (i /= 13) then -- Remove additional carriage return
write(l, character'val(i));
end if;
else
uart_rx_sreg <= uart_rx_sync(4) & uart_rx_sreg(8 downto 1);
uart_rx_bitcnt <= uart_rx_bitcnt - 1;
end if;
else
uart_rx_baud_cnt <= uart_rx_baud_cnt - 1.0;
end if;
end if;
end if;
end process uart_rx_console;
end architecture;

View file

@ -5,15 +5,11 @@ use ieee.math_real.all;
use std.textio.all; use std.textio.all;
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;
use work.uart_rx_pkg.all;
entity uart_rx is entity uart_rx is
generic (handle : uart_rx_t); generic (
name : string;
uart_baud_val_c : real);
port ( port (
clk : in std_ulogic; clk : in std_ulogic;
uart_txd : in std_ulogic uart_txd : in std_ulogic
@ -27,49 +23,12 @@ architecture a of uart_rx is
signal uart_rx_baud_cnt : real; signal uart_rx_baud_cnt : real;
signal uart_rx_bitcnt : natural; signal uart_rx_bitcnt : natural;
file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & get_name(handle.p_logger) & ".out"; file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & name & ".out";
constant checker : checker_t := new_checker(handle.p_logger);
constant character_queue : queue_t := new_queue;
begin begin
control : process
variable request_msg, reply_msg : msg_t;
variable msg_type : msg_type_t;
procedure put_characters_in_queue(s : string) is
begin
for idx in s'range loop
push(character_queue, s(idx));
end loop;
end procedure put_characters_in_queue;
begin
receive(net, handle.p_actor, request_msg);
msg_type := message_type(request_msg);
-- Standard handling of standard wait_for_time messages = wait for the given time
-- before proceeeding
handle_wait_for_time(net, msg_type, request_msg);
if msg_type = check_uart_msg then
put_characters_in_queue(pop(request_msg));
-- Custom handling of standard wait_until_idle message
elsif msg_type = wait_until_idle_msg then
while not is_empty(character_queue) loop
wait until rising_edge(clk);
end loop;
reply_msg := new_msg(wait_until_idle_reply_msg);
reply(net, request_msg, reply_msg);
else
unexpected_msg_type(msg_type);
end if;
end process;
uart_rx_console : process(clk) uart_rx_console : process(clk)
variable i : integer; variable i : integer;
variable l : line; variable l : line;
variable expected_character : character;
begin begin
-- "UART" -- -- "UART" --
if rising_edge(clk) then if rising_edge(clk) then
@ -78,7 +37,7 @@ begin
-- arbiter -- -- arbiter --
if (uart_rx_busy = '0') then -- idle if (uart_rx_busy = '0') then -- idle
uart_rx_busy <= '0'; uart_rx_busy <= '0';
uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val); uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
uart_rx_bitcnt <= 9; uart_rx_bitcnt <= 9;
if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge) if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge)
uart_rx_busy <= '1'; uart_rx_busy <= '1';
@ -86,19 +45,18 @@ begin
else else
if (uart_rx_baud_cnt <= 0.0) then if (uart_rx_baud_cnt <= 0.0) then
if (uart_rx_bitcnt = 1) then if (uart_rx_bitcnt = 1) then
uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val); uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
else else
uart_rx_baud_cnt <= round(handle.p_baud_val); uart_rx_baud_cnt <= round(uart_baud_val_c);
end if; end if;
if (uart_rx_bitcnt = 0) then if (uart_rx_bitcnt = 0) then
uart_rx_busy <= '0'; -- done uart_rx_busy <= '0'; -- done
i := to_integer(unsigned(uart_rx_sreg(8 downto 1))); i := to_integer(unsigned(uart_rx_sreg(8 downto 1)));
if is_empty(character_queue) then if (i < 32) or (i > 32+95) then -- printable char?
check_failed(checker, "Extra characters received"); report name & ".tx: (" & integer'image(i) & ")"; -- print code
else else
expected_character := pop(character_queue); report name & ".tx: " & character'val(i); -- print ASCII
check_equal(checker, character'val(i), expected_character);
end if; end if;
if (i = 10) then -- Linux line break if (i = 10) then -- Linux line break

View file

@ -1,60 +0,0 @@
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
use vunit_lib.sync_pkg.all;
package uart_rx_pkg is
constant check_uart_msg : msg_type_t := new_msg_type("check_uart");
type uart_rx_t is record
p_baud_val : real;
p_logger : logger_t;
p_actor : actor_t;
end record;
impure function new_uart_rx(
baud_val : real;
logger : logger_t := null_logger;
actor : actor_t := null_actor) return uart_rx_t;
function as_sync(handle : uart_rx_t) return sync_handle_t;
procedure check_uart(
signal net : inout network_t;
constant handle : in uart_rx_t;
constant data : in string);
end package uart_rx_pkg;
package body uart_rx_pkg is
constant uart_rx_logger : logger_t := get_logger("neorv32_lib:uart_rx_pkg");
impure function new_uart_rx(
baud_val : real;
logger : logger_t := null_logger;
actor : actor_t := null_actor) return uart_rx_t is
variable result : uart_rx_t;
begin
result.p_baud_val := baud_val;
result.p_logger := logger when logger /= null_logger else uart_rx_logger;
result.p_actor := actor when actor /= null_actor else new_actor;
return result;
end;
function as_sync(handle : uart_rx_t) return sync_handle_t is
begin
return handle.p_actor;
end;
procedure check_uart(
signal net : inout network_t;
constant handle : in uart_rx_t;
constant data : in string) is
variable msg : msg_t;
begin
msg := new_msg(check_uart_msg);
push(msg, data);
send(net, handle.p_actor, msg);
end;
end package body uart_rx_pkg;

View file

@ -59,7 +59,7 @@ NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen
# Path to NEORV32 rtl folder # Path to NEORV32 rtl folder
NEORV32_RTL_PATH = $(NEORV32_LOCAL_RTL) NEORV32_RTL_PATH = $(NEORV32_LOCAL_RTL)
# Path to NEORV32 sim folder # Path to NEORV32 sim folder
NEORV32_SIM_PATH = $(NEORV32_HOME)/sim/simple NEORV32_SIM_PATH = $(NEORV32_HOME)/sim
# Marker file to check for NEORV32 home folder # Marker file to check for NEORV32 home folder
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h
@ -279,10 +279,10 @@ endif
@echo "Toolchain check OK" @echo "Toolchain check OK"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# In-console simulation using default/simple testbench and GHDL # In-console simulation using default testbench and GHDL
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
sim: $(APP_VHD) install sim: $(APP_VHD) install
@echo "Simulating processor using simple testbench..." @echo "Simulating processor using default testbench..."
@sh $(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS) @sh $(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -375,7 +375,7 @@ help:
@echo " mif - compile and generate <$(APP_MIF)> executable memory image" @echo " mif - compile and generate <$(APP_MIF)> executable memory image"
@echo " image - compile and generate VHDL IMEM application boot image <$(APP_VHD)> in local folder" @echo " image - compile and generate VHDL IMEM application boot image <$(APP_VHD)> in local folder"
@echo " install - compile, generate and install VHDL IMEM application boot image <$(APP_VHD)>" @echo " install - compile, generate and install VHDL IMEM application boot image <$(APP_VHD)>"
@echo " sim - in-console simulation using default/simple testbench and GHDL" @echo " sim - in-console simulation using default testbench (sim folder) and GHDL"
@echo " hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl" @echo " hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl"
@echo " all - exe + install + hex + bin + asm" @echo " all - exe + install + hex + bin + asm"
@echo " elf_info - show ELF layout info" @echo " elf_info - show ELF layout info"

View file

@ -33,4 +33,4 @@ NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk include $(NEORV32_HOME)/sw/common/common.mk
sim-check: sim sim-check: sim
cat $(NEORV32_HOME)/sim/simple/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)" cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)"

View file

@ -40,4 +40,4 @@ include $(NEORV32_HOME)/sw/common/common.mk
# Add test-specific makefile target # Add test-specific makefile target
sim-check: sim sim-check: sim
cat $(NEORV32_HOME)/sim/simple/neorv32.uart0.sim_mode.text.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!" cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!"