diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d27c3615..852fb0bd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Ticket | |:----:|:-------:|:--------|:------:| +| 10.11.2024 | 1.10.6.4 | rework default processor testbench | [#1093](https://github.com/stnolting/neorv32/pull/1093) | | 06.11.2024 | 1.10.6.3 | minor rtl edits and cleanups | [#1090](https://github.com/stnolting/neorv32/pull/1090) | | 02.11.2024 | 1.10.6.2 | :warning: rework processor boot configuration; add new boot-configuration generics | [#1086](https://github.com/stnolting/neorv32/pull/1086) | | 01.11.2024 | 1.10.6.1 | :test_tube: convert VHDL memory images into full-scale VHDL packages | [#1084](https://github.com/stnolting/neorv32/pull/1084) | diff --git a/docs/datasheet/soc_uart.adoc b/docs/datasheet/soc_uart.adoc index 9cb7fb826..82ff068e4 100644 --- a/docs/datasheet/soc_uart.adoc +++ b/docs/datasheet/soc_uart.adoc @@ -116,7 +116,7 @@ unconnected. If the CTS handshake is not required it has to be tied to zero. The UART provides a _simulation-only_ mode to dump console data as well as raw data directly to a file. When the simulation mode is enabled (by setting the `UART_CTRL_SIM_MODE` bit) there will be **no** physical transaction on the `uart0_txd_o` signal. Instead, all data written to the `DATA` register is immediately dumped to a file. Data written to `DATA[7:0]` will be dumped as -ASCII chars to a file named `neorv32.uart0.sim_mode.text.out`. Additionally, the ASCII data is printed to the simulator console. +ASCII chars to a file named `neorv32.uart0_sim_mode.out`. Additionally, the ASCII data is printed to the simulator console. Both file are created in the simulation's home folder. @@ -192,7 +192,7 @@ as for the primary UART. The RX and TX interrupts of UART1 are mapped to differe **Simulation Mode** The secondary UART (UART1) provides the same simulation options as the primary UART (UART0). However, output data is -written to UART1-specific file `neorv32.uart1.sim_mode.text.out`. This data is also printed to the simulator console. +written to UART1-specific file `neorv32.uart1_sim_mode.out`. This data is also printed to the simulator console. **Register Map** diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 15da04daa..84c803578 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -29,7 +29,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100603"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100604"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -181,6 +181,43 @@ package neorv32_package is ack : std_ulogic; end record; + -- External Bus Interface (XBUS / Wishbone) ----------------------------------------------- + -- ------------------------------------------------------------------------------------------- + -- xbus request -- + type xbus_req_t is record + addr : std_ulogic_vector(31 downto 0); -- access address + data : std_ulogic_vector(31 downto 0); -- write data + tag : std_ulogic_vector(2 downto 0); -- access tag + we : std_ulogic; -- read/write + sel : std_ulogic_vector(3 downto 0); -- byte enable + stb : std_ulogic; -- strobe + cyc : std_ulogic; -- valid cycle + end record; + + -- xbus response -- + type xbus_rsp_t is record + data : std_ulogic_vector(31 downto 0); -- read data, valid if ack=1 + ack : std_ulogic; -- access acknowledge + err : std_ulogic; -- access error + end record; + + -- endpoint (response) termination -- + constant xbus_rsp_terminate_c : xbus_rsp_t := ( + data => (others => '0'), + ack => '0', + err => '0' + ); + + -- External Stream-Link Interface (SLINK / AXI4-Stream) ----------------------------------- + -- ------------------------------------------------------------------------------------------- + type slink_t is record + data : std_ulogic_vector(31 downto 0); -- data + addr : std_ulogic_vector(3 downto 0); -- source/destination ID + valid : std_ulogic; -- source valid + last : std_ulogic; -- last element of packet + ready : std_ulogic; -- sink ready + end record; + -- ********************************************************************************************************** -- RISC-V ISA Definitions -- ********************************************************************************************************** diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 2517d0984..d0ba7fe8a 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -1218,7 +1218,7 @@ begin neorv32_uart0_inst: entity neorv32.neorv32_uart generic map ( SIM_MODE_EN => true, - SIM_LOG_FILE => "neorv32.uart0.sim_mode.text.out", + SIM_LOG_FILE => "neorv32.uart0_sim_mode.out", UART_RX_FIFO => IO_UART0_RX_FIFO, UART_TX_FIFO => IO_UART0_TX_FIFO ) @@ -1256,7 +1256,7 @@ begin neorv32_uart1_inst: entity neorv32.neorv32_uart generic map ( SIM_MODE_EN => true, - SIM_LOG_FILE => "neorv32.uart1.sim_mode.text.out", + SIM_LOG_FILE => "neorv32.uart1_sim_mode.out", UART_RX_FIFO => IO_UART1_RX_FIFO, UART_TX_FIFO => IO_UART1_TX_FIFO ) diff --git a/sim/ghdl.run.sh b/sim/ghdl.run.sh index 09da93f43..678e338cd 100644 --- a/sim/ghdl.run.sh +++ b/sim/ghdl.run.sh @@ -4,34 +4,47 @@ set -e cd $(dirname "$0") -echo "[TIP] Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to enable UART[0/1]'s simulation mode (redirect UART output to simulator console)." - -# Prepare simulation output files for UART0 and UART 1 -# - Testbench receiver log file (neorv32.testbench_uart?.out) -# - Direct simulation output (neorv32.uart?.sim_mode.text.out) -for uart in 0 1; do - for item in \ - testbench_uart"$uart" \ - uart"$uart".sim_mode.text; do - touch neorv32."$item".out - chmod 777 neorv32."$item".out - done -done - +NEORV32_RTL=${NEORV32_RTL:-../rtl} +FILE_LIST=`cat $NEORV32_RTL/file_list_soc.f` +CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_RTL"}" GHDL="${GHDL:-ghdl}" +# Prepare UART SIM_MODE output files +touch neorv32.uart0_sim_mode.out neorv32.uart1_sim_mode.out +chmod 777 neorv32.uart0_sim_mode.out neorv32.uart1_sim_mode.out + +# Prepare testbench UART log files +touch neorv32_tb.uart0_rx.out neorv32_tb.uart1_rx.out +chmod 777 neorv32_tb.uart0_rx.out neorv32_tb.uart1_rx.out + +# GHDL build directory +mkdir -p build + +# GHDL import +$GHDL -i --work=neorv32 --workdir=build \ + $CORE_SRCS \ + "$NEORV32_RTL"/processor_templates/*.vhd \ + "$NEORV32_RTL"/system_integration/*.vhd \ + "$NEORV32_RTL"/test_setups/*.vhd \ + neorv32_tb.vhd \ + sim_uart_rx.vhd \ + xbus_gateway.vhd \ + xbus_memory.vhd + +# GHDL analyze $GHDL -m --work=neorv32 --workdir=build neorv32_tb +# GHDL run parameters if [ -z "$1" ] then GHDL_RUN_ARGS="${@:---stop-time=10ms}" else - # Lets pass down all the parameters to GHDL instead of just 1 + # Let's pass down all the parameters to GHDL GHDL_RUN_ARGS=$@ fi +echo "GHDL simulation run parameters: $GHDL_RUN_ARGS"; -echo "Using simulation run arguments: $GHDL_RUN_ARGS"; - +# GHDL run runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb \ --max-stack-alloc=0 \ --ieee-asserts=disable \ diff --git a/sim/ghdl.setup.sh b/sim/ghdl.setup.sh deleted file mode 100644 index af162a09a..000000000 --- a/sim/ghdl.setup.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd $(dirname "$0") - -NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../rtl} - -FILE_LIST=`cat $NEORV32_LOCAL_RTL/file_list_soc.f` -CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_LOCAL_RTL"}" - -mkdir -p build - -ghdl -i --work=neorv32 --workdir=build \ - $CORE_SRCS \ - "$NEORV32_LOCAL_RTL"/processor_templates/*.vhd \ - "$NEORV32_LOCAL_RTL"/system_integration/*.vhd \ - "$NEORV32_LOCAL_RTL"/test_setups/*.vhd \ - neorv32_tb.vhd \ - uart_rx.vhd diff --git a/sim/ghdl.sh b/sim/ghdl.sh index 33223f9a7..58d754f8f 100644 --- a/sim/ghdl.sh +++ b/sim/ghdl.sh @@ -5,8 +5,7 @@ set -e cd $(dirname "$0") -# Setup simulation -/bin/bash ghdl.setup.sh +echo "[TIP] Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to enable UART[0/1]'s simulation mode (redirect UART output to simulator console)." # Run simulation (pass down more than 1 parameter to GHDL) /bin/bash ghdl.run.sh $@ diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd index bc15070e8..932376893 100644 --- a/sim/neorv32_tb.vhd +++ b/sim/neorv32_tb.vhd @@ -15,148 +15,79 @@ 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 is generic ( - PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements + CLOCK_FREQUENCY : natural := 100_000_000; -- clock frequency of clk_i in Hz + BOOT_MODE_SELECT : natural range 0 to 2 := 2; -- boot from pre-initialized IMEM + RISCV_ISA_C : boolean := false; -- implement compressed extension + RISCV_ISA_E : boolean := false; -- implement embedded RF extension + RISCV_ISA_M : boolean := true; -- implement mul/div extension + RISCV_ISA_U : boolean := true; -- implement user mode extension + RISCV_ISA_Zalrsc : boolean := true; -- implement atomic reservation-set extension + RISCV_ISA_Zba : boolean := true; -- implement shifted-add bit-manipulation extension + RISCV_ISA_Zbb : boolean := true; -- implement basic bit-manipulation extension + RISCV_ISA_Zbkb : boolean := true; -- implement bit-manipulation instructions for cryptography + RISCV_ISA_Zbkc : boolean := true; -- implement carry-less multiplication instructions + RISCV_ISA_Zbkx : boolean := true; -- implement cryptography crossbar permutation extension + RISCV_ISA_Zbs : boolean := true; -- implement single-bit bit-manipulation extension + RISCV_ISA_Zfinx : boolean := true; -- implement 32-bit floating-point extension + RISCV_ISA_Zicntr : boolean := true; -- implement base counters + RISCV_ISA_Zicond : boolean := true; -- implement integer conditional operations + RISCV_ISA_Zihpm : boolean := true; -- implement hardware performance monitors + RISCV_ISA_Zknd : boolean := true; -- implement cryptography NIST AES decryption extension + RISCV_ISA_Zkne : boolean := true; -- implement cryptography NIST AES encryption extension + RISCV_ISA_Zknh : boolean := true; -- implement cryptography NIST hash extension + RISCV_ISA_Zksed : boolean := true; -- implement ShangMi block cypher extension + RISCV_ISA_Zksh : boolean := true; -- implement ShangMi hash extension + RISCV_ISA_Zmmul : boolean := true; -- implement multiply-only M sub-extension + RISCV_ISA_Zxcfu : boolean := true; -- implement custom (instr.) functions unit + FAST_MUL_EN : boolean := true; -- use DSPs for M extension's multiplier + FAST_SHIFT_EN : boolean := true; -- use barrel shifter for shift operations + REGFILE_HW_RST : boolean := true; -- implement full hardware reset for register file + MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory + MEM_INT_IMEM_SIZE : natural := 32*1024; -- size of processor-internal instruction memory in bytes (use a power of 2) + MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory + MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes (use a power of 2) + ICACHE_EN : boolean := true; -- implement instruction cache + ICACHE_NUM_BLOCKS : natural range 1 to 256 := 64; -- i-cache: number of blocks (min 1), has to be a power of 2 + ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 32; -- i-cache: block size in bytes (min 4), has to be a power of 2 + DCACHE_EN : boolean := true; -- implement data cache + DCACHE_NUM_BLOCKS : natural range 1 to 256 := 32; -- d-cache: number of blocks (min 1), has to be a power of 2 + DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 32 -- d-cache: block size in bytes (min 4), has to be a power of 2 ); end neorv32_tb; 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 --------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - -- 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 -- + -- IO connection -- + signal uart0_txd, uart0_cts, uart1_txd, uart1_cts : std_ulogic; 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_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; + signal msi, mei, mti : 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; + -- slink -- + signal slink_tx, slink_rx : slink_t; + + -- XBUS (Wishbone b4) bus -- + signal xbus_core_req, xbus_imem_req, xbus_dmem_req, xbus_mmio_req, xbus_trig_req : xbus_req_t; + signal xbus_core_rsp, xbus_imem_rsp, xbus_dmem_rsp, xbus_mmio_rsp, xbus_trig_rsp : xbus_rsp_t; begin - -- Clock/Reset Generator ------------------------------------------------------------------ + -- Clock & Reset Generators --------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - clk_gen <= not clk_gen after (t_clock_c/2); - rst_gen <= '0', '1' after 60*(t_clock_c/2); + clk_gen <= not clk_gen after (((1 sec) / CLOCK_FREQUENCY) / 2); + rst_gen <= '0', '1' after 60*(((1 sec) / CLOCK_FREQUENCY) / 2); -- The Core of the Problem ---------------------------------------------------------------- @@ -164,44 +95,44 @@ begin neorv32_top_inst: neorv32_top generic map ( -- Clocking -- - CLOCK_FREQUENCY => f_clock_c, + CLOCK_FREQUENCY => CLOCK_FREQUENCY, CLOCK_GATING_EN => true, -- Identification -- HART_ID => x"00000000", JEDEC_ID => "00000000000", -- Boot Configuration -- - BOOT_MODE_SELECT => 2, -- boot from pre-initialized internal IMEM + BOOT_MODE_SELECT => BOOT_MODE_SELECT, BOOT_ADDR_CUSTOM => x"00000000", -- On-Chip Debugger (OCD) -- OCD_EN => true, OCD_AUTHENTICATION => true, -- RISC-V CPU Extensions -- - RISCV_ISA_C => false, - RISCV_ISA_E => false, - RISCV_ISA_M => true, - RISCV_ISA_U => true, - RISCV_ISA_Zalrsc => true, - RISCV_ISA_Zba => true, - RISCV_ISA_Zbb => true, - RISCV_ISA_Zbkb => true, - RISCV_ISA_Zbkc => true, - RISCV_ISA_Zbkx => true, - RISCV_ISA_Zbs => true, - RISCV_ISA_Zfinx => true, - RISCV_ISA_Zicntr => true, - RISCV_ISA_Zicond => true, - RISCV_ISA_Zihpm => true, - RISCV_ISA_Zknd => true, - RISCV_ISA_Zkne => true, - RISCV_ISA_Zknh => true, - RISCV_ISA_Zksed => true, - RISCV_ISA_Zksh => true, - RISCV_ISA_Zmmul => false, - RISCV_ISA_Zxcfu => true, + RISCV_ISA_C => RISCV_ISA_C, + RISCV_ISA_E => RISCV_ISA_E, + RISCV_ISA_M => RISCV_ISA_M, + RISCV_ISA_U => RISCV_ISA_U, + RISCV_ISA_Zalrsc => RISCV_ISA_Zalrsc, + RISCV_ISA_Zba => RISCV_ISA_Zba, + RISCV_ISA_Zbb => RISCV_ISA_Zbb, + RISCV_ISA_Zbkb => RISCV_ISA_Zbkb, + RISCV_ISA_Zbkc => RISCV_ISA_Zbkc, + RISCV_ISA_Zbkx => RISCV_ISA_Zbkx, + RISCV_ISA_Zbs => RISCV_ISA_Zbs, + RISCV_ISA_Zfinx => RISCV_ISA_Zfinx, + RISCV_ISA_Zicntr => RISCV_ISA_Zicntr, + RISCV_ISA_Zicond => RISCV_ISA_Zicond, + RISCV_ISA_Zihpm => RISCV_ISA_Zihpm, + RISCV_ISA_Zknd => RISCV_ISA_Zknd, + RISCV_ISA_Zkne => RISCV_ISA_Zkne, + RISCV_ISA_Zknh => RISCV_ISA_Zknh, + RISCV_ISA_Zksed => RISCV_ISA_Zksed, + RISCV_ISA_Zksh => RISCV_ISA_Zksh, + RISCV_ISA_Zmmul => RISCV_ISA_Zmmul, + RISCV_ISA_Zxcfu => RISCV_ISA_Zxcfu, -- Extension Options -- - FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION), - FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION), - REGFILE_HW_RST => false, + FAST_MUL_EN => FAST_MUL_EN, + FAST_SHIFT_EN => FAST_SHIFT_EN, + REGFILE_HW_RST => REGFILE_HW_RST, -- Physical Memory Protection (PMP) -- PMP_NUM_REGIONS => 5, PMP_MIN_GRANULARITY => 4, @@ -211,19 +142,19 @@ begin HPM_NUM_CNTS => 12, HPM_CNT_WIDTH => 40, -- Internal Instruction memory -- - MEM_INT_IMEM_EN => int_imem_c , - MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION), + MEM_INT_IMEM_EN => MEM_INT_IMEM_EN , + MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- Internal Data memory -- - MEM_INT_DMEM_EN => int_dmem_c, - MEM_INT_DMEM_SIZE => dmem_size_c, + MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, + MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE, -- Internal Cache memory -- - ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION), - ICACHE_NUM_BLOCKS => 64, - ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION), + ICACHE_EN => ICACHE_EN, + ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, + ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE, -- Internal Data Cache (dCACHE) -- - DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION), - DCACHE_NUM_BLOCKS => 32, - DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION), + DCACHE_EN => DCACHE_EN, + DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, + DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, -- External bus interface -- XBUS_EN => true, XBUS_TIMEOUT => 256, @@ -275,334 +206,261 @@ begin -- Global control -- clk_i => clk_gen, rstn_i => rst_gen, - -- JTAG on-chip debugger interface (available if OCD_EN = true) -- + -- JTAG on-chip debugger interface -- jtag_tck_i => '0', jtag_tdi_i => '0', jtag_tdo_o => open, jtag_tms_i => '0', - -- External bus interface (available if XBUS_EN = true) -- - xbus_adr_o => wb_cpu.addr, - xbus_dat_o => wb_cpu.wdata, - xbus_tag_o => wb_cpu.tag, - xbus_we_o => wb_cpu.we, - xbus_sel_o => wb_cpu.sel, - xbus_stb_o => wb_cpu.stb, - xbus_cyc_o => wb_cpu.cyc, - xbus_dat_i => wb_cpu.rdata, - xbus_ack_i => wb_cpu.ack, - xbus_err_i => wb_cpu.err, - -- Stream Link Interface (available if IO_SLINK_EN = true) -- - slink_rx_dat_i => slink_dat, - slink_rx_src_i => slink_id, - slink_rx_val_i => slink_val, - slink_rx_lst_i => slink_lst, - slink_rx_rdy_o => slink_rdy, - slink_tx_dat_o => slink_dat, - slink_tx_dst_o => slink_id, - slink_tx_val_o => slink_val, - slink_tx_lst_o => slink_lst, - slink_tx_rdy_i => slink_rdy, - -- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- + -- External bus interface -- + xbus_adr_o => xbus_core_req.addr, + xbus_dat_o => xbus_core_req.data, + xbus_tag_o => xbus_core_req.tag, + xbus_we_o => xbus_core_req.we, + xbus_sel_o => xbus_core_req.sel, + xbus_stb_o => xbus_core_req.stb, + xbus_cyc_o => xbus_core_req.cyc, + xbus_dat_i => xbus_core_rsp.data, + xbus_ack_i => xbus_core_rsp.ack, + xbus_err_i => xbus_core_rsp.err, + -- Stream Link Interface -- + slink_rx_dat_i => slink_rx.data, + slink_rx_src_i => slink_rx.addr, + slink_rx_val_i => slink_rx.valid, + slink_rx_lst_i => slink_rx.last, + slink_rx_rdy_o => slink_rx.ready, + slink_tx_dat_o => slink_tx.data, + slink_tx_dst_o => slink_tx.addr, + slink_tx_val_o => slink_tx.valid, + slink_tx_lst_o => slink_tx.last, + slink_tx_rdy_i => slink_tx.ready, + -- XIP -- xip_csn_o => open, xip_clk_o => open, xip_dat_i => '0', xip_dat_o => open, - -- GPIO (available if IO_GPIO_NUM > true) -- + -- GPIO -- gpio_o => gpio, gpio_i => gpio, - -- primary UART0 (available if IO_UART0_EN = true) -- + -- primary UART0 -- uart0_txd_o => uart0_txd, uart0_rxd_i => uart0_txd, - uart0_rts_o => uart1_cts, + uart0_rts_o => uart0_cts, uart0_cts_i => uart0_cts, - -- secondary UART1 (available if IO_UART1_EN = true) -- + -- secondary UART1 -- uart1_txd_o => uart1_txd, uart1_rxd_i => uart1_txd, - uart1_rts_o => uart0_cts, + uart1_rts_o => uart1_cts, uart1_cts_i => uart1_cts, - -- SPI (available if IO_SPI_EN = true) -- + -- SPI -- spi_clk_o => spi_clk, spi_dat_o => spi_do, spi_dat_i => spi_di, spi_csn_o => spi_csn, - -- SDI (available if IO_SDI_EN = true) -- + -- SDI -- sdi_clk_i => sdi_clk, sdi_dat_o => sdi_do, sdi_dat_i => sdi_di, sdi_csn_i => sdi_csn, - -- TWI (available if IO_TWI_EN = true) -- + -- TWI -- twi_sda_i => twi_sda_i, twi_sda_o => twi_sda_o, twi_scl_i => twi_scl_i, twi_scl_o => twi_scl_o, - -- 1-Wire Interface (available if IO_ONEWIRE_EN = true) -- + -- 1-Wire Interface -- onewire_i => onewire_i, onewire_o => onewire_o, - -- PWM (available if IO_PWM_NUM_CH > 0) -- + -- PWM -- pwm_o => open, -- Custom Functions Subsystem IO -- cfs_in_i => (others => '0'), cfs_out_o => open, - -- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) -- + -- NeoPixel-compatible smart LED interface -- neoled_o => open, - -- Machine timer system time (available if IO_MTIME_EN = true) -- + -- Machine timer system time -- mtime_time_o => open, - -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- + -- External platform interrupts -- xirq_i => gpio(31 downto 0), -- CPU Interrupts -- - mtime_irq_i => '0', - msw_irq_i => msi_ring, - mext_irq_i => mei_ring + mtime_irq_i => mti, + msw_irq_i => msi, + mext_irq_i => mei ); - -- 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); + -- Two-Wire Bus --------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + twi_sda <= '0' when (twi_sda_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively + twi_scl <= '0' when (twi_scl_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively + twi_sda_i <= std_ulogic(twi_sda); -- sense input + twi_scl_i <= std_ulogic(twi_scl); -- sense input + + -- TWI bus termination -- + twi_scl <= 'H'; -- weak pull-up "resistor" + twi_sda <= 'H'; -- weak pull-up "resistor" + + + -- One-Wire Bus --------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + onewire <= '0' when (onewire_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively + onewire_i <= std_ulogic(onewire); -- sense input - -- TWI termination (pull-ups) -- - twi_scl <= 'H'; - twi_sda <= 'H'; + -- 1-Wire bus termination -- + onewire <= 'H'; -- weak pull-up "resistor" - -- 1-Wire termination (pull-up) -- - onewire <= 'H'; - -- SPI/SDI echo with propagation delay -- - sdi_clk <= spi_clk after 40 ns; + -- SP/SDI --------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + sdi_clk <= spi_clk after 40 ns; -- echo with propagation delay 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 --------------------------------------------------------------- + -- Stream-Link FIFO Buffer ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - uart0_checker: entity work.uart_rx + slink_buffer: entity neorv32.neorv32_fifo + generic map ( + FIFO_DEPTH => 4, + FIFO_WIDTH => 32+4+1, + FIFO_RSYNC => false, + FIFO_SAFE => true, + FULL_RESET => true + ) + port map ( + -- control -- + clk_i => clk_gen, + rstn_i => rst_gen, + clear_i => '0', + half_o => open, + -- write port -- + wdata_i(31 downto 0) => slink_tx.data, + wdata_i(35 downto 32) => slink_tx.addr, + wdata_i(36) => slink_tx.last, + we_i => slink_tx.valid, + free_o => slink_tx.ready, + -- read port -- + re_i => slink_rx.ready, + rdata_o(31 downto 0) => slink_rx.data, + rdata_o(35 downto 32) => slink_rx.addr, + rdata_o(36) => slink_rx.last, + avail_o => slink_rx.valid + ); + + + -- UART Simulation Receivers -------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + sim_rx_uart0: entity work.sim_uart_rx generic map ( name => "uart0", - uart_baud_val_c => uart0_baud_val_c + fclk => real(CLOCK_FREQUENCY), + baud => real(19200) ) port map ( clk => clk_gen, - uart_txd => uart0_txd + rxd => uart0_txd ); - uart1_checker: entity work.uart_rx + sim_rx_uart1: entity work.sim_uart_rx generic map ( name => "uart1", - uart_baud_val_c => uart1_baud_val_c + fclk => real(CLOCK_FREQUENCY), + baud => real(19200) ) port map ( clk => clk_gen, - uart_txd => uart1_txd + rxd => 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) -------------------------------------------- + -- XBUS / Wishbone Interconnect ----------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - 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; + xbus_interconnect: entity work.xbus_gateway + generic map ( + -- device address size in bytes and base address -- + DEV_0_SIZE => MEM_INT_IMEM_SIZE, DEV_0_BASE => mem_imem_base_c, + DEV_1_SIZE => MEM_INT_DMEM_SIZE, DEV_1_BASE => mem_dmem_base_c, + DEV_2_SIZE => 64, DEV_2_BASE => x"F0000000", + DEV_3_SIZE => 4, DEV_3_BASE => x"FF000000" + ) + port map ( + -- host port -- + host_req_i => xbus_core_req, + host_rsp_o => xbus_core_rsp, + -- device ports -- + dev_0_req_o => xbus_imem_req, dev_0_rsp_i => xbus_imem_rsp, + dev_1_req_o => xbus_dmem_req, dev_1_rsp_i => xbus_dmem_rsp, + dev_2_req_o => xbus_mmio_req, dev_2_rsp_i => xbus_mmio_rsp, + dev_3_req_o => xbus_trig_req, dev_3_rsp_i => xbus_trig_rsp + ); - -- Wishbone Memory B (simulated external DMEM) -------------------------------------------- + -- XBUS: Instruction Memory --------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - 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; + xbus_imem: entity work.xbus_memory + generic map ( + MEM_SIZE => MEM_INT_IMEM_SIZE, + MEM_LATE => 1 + ) + port map ( + clk_i => clk_gen, + rstn_i => rst_gen, + xbus_req_i => xbus_imem_req, + xbus_rsp_o => xbus_imem_rsp + ); - -- Wishbone Memory C (simulated external IO) ---------------------------------------------- + -- XBUS: Data Memory ---------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - 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; + xbus_dmem: entity work.xbus_memory + generic map ( + MEM_SIZE => MEM_INT_DMEM_SIZE, + MEM_LATE => 1 + ) + port map ( + clk_i => clk_gen, + rstn_i => rst_gen, + xbus_req_i => xbus_dmem_req, + xbus_rsp_o => xbus_dmem_rsp + ); - -- 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; + -- XBUS: Memory-Mapped IO ----------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + xbus_mmio: entity work.xbus_memory + generic map ( + MEM_SIZE => 64, + MEM_LATE => 32 + ) + port map ( + clk_i => clk_gen, + rstn_i => rst_gen, + xbus_req_i => xbus_mmio_req, + xbus_rsp_o => xbus_mmio_rsp + ); - -- Wishbone IRQ Triggers ------------------------------------------------------------------ + -- XBUS: IRQ Triggers --------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - irq_trigger: process(rst_gen, clk_gen) + xbus_irq_trigger: process(rst_gen, clk_gen) begin if (rst_gen = '0') then - msi_ring <= '0'; - mei_ring <= '0'; + msi <= '0'; + mti <= '0'; + mei <= '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'; + -- bus response defaults -- + xbus_trig_rsp.data <= (others => '0'); + xbus_trig_rsp.ack <= '0'; + xbus_trig_rsp.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 + if ((xbus_trig_req.cyc and xbus_trig_req.stb and xbus_trig_req.we and and_reduce_f(xbus_trig_req.sel)) = '1') then + xbus_trig_rsp.ack <= '1'; + msi <= xbus_trig_req.data(03); -- machine software interrupt + mti <= xbus_trig_req.data(07); -- machine timer interrupt + mei <= xbus_trig_req.data(11); -- machine external interrupt end if; end if; - end process irq_trigger; + end process xbus_irq_trigger; end neorv32_tb_rtl; diff --git a/sim/sim_uart_rx.vhd b/sim/sim_uart_rx.vhd new file mode 100644 index 000000000..0bb03ff81 --- /dev/null +++ b/sim/sim_uart_rx.vhd @@ -0,0 +1,93 @@ +-- ================================================================================ -- +-- NEORV32 - Simulation UART Receiver (print to simulator console) -- +-- -------------------------------------------------------------------------------- -- +-- 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; +use std.textio.all; + +entity sim_uart_rx is + generic ( + name : string; -- receiver name (for log file) + fclk : real; -- clock speed of clk_i in Hz + baud : real -- baud rate + ); + port ( + clk : in std_ulogic; -- global clock + rxd : in std_ulogic -- serial UART RX data + ); +end entity sim_uart_rx; + +architecture sim_uart_rx_rtl of sim_uart_rx is + + signal sync : std_ulogic_vector(4 downto 0) := (others => '1'); + signal busy : std_ulogic := '0'; + signal sreg : std_ulogic_vector(8 downto 0) := (others => '0'); + signal baudcnt : real; + signal bitcnt : natural; + constant baud_val_c : real := fclk / baud; + file file_out : text open write_mode is "neorv32_tb." & name & "_rx.out"; + +begin + + sim_receiver: process(clk) + variable c : integer; + variable l : line; + begin + if rising_edge(clk) then + -- synchronizer -- + sync <= sync(3 downto 0) & rxd; + -- arbiter -- + if (busy = '0') then -- idle + busy <= '0'; + baudcnt <= round(0.5 * baud_val_c); + bitcnt <= 9; + if (sync(4 downto 1) = "1100") then -- start bit (falling edge) + busy <= '1'; + end if; + else -- receiving + + if (baudcnt <= 0.0) then + if (bitcnt = 1) then + baudcnt <= round(0.5 * baud_val_c); + else + baudcnt <= round(baud_val_c); + end if; + + if (bitcnt = 0) then + busy <= '0'; -- done + c := to_integer(unsigned(sreg(8 downto 1))); + + if (c < 32) or (c > 32+95) then -- non-printable character? + report name & ".rx: (" & integer'image(c) & ")"; + else + report name & ".rx: " & character'val(c); + end if; + + if (c = 10) then -- LF line break + writeline(file_out, l); + elsif (c /= 13) then -- no additional CR + write(l, character'val(c)); + end if; + + else + sreg <= sync(4) & sreg(8 downto 1); + bitcnt <= bitcnt - 1; + end if; + + else + baudcnt <= baudcnt - 1.0; + end if; + end if; + end if; + end process sim_receiver; + +end architecture sim_uart_rx_rtl; diff --git a/sim/uart_rx.vhd b/sim/uart_rx.vhd deleted file mode 100644 index 84f0fac9e..000000000 --- a/sim/uart_rx.vhd +++ /dev/null @@ -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 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 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; diff --git a/sim/xbus_gateway.vhd b/sim/xbus_gateway.vhd new file mode 100644 index 000000000..6d1da599d --- /dev/null +++ b/sim/xbus_gateway.vhd @@ -0,0 +1,102 @@ +-- ================================================================================ -- +-- NEORV32 - Simple Combinatorial XBUS / Wishbone Gateway -- +-- -------------------------------------------------------------------------------- -- +-- 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; + +library neorv32; +use neorv32.neorv32_package.all; + +entity xbus_gateway is + generic ( + -- device address size in bytes and base address -- + DEV_0_SIZE : natural := 0; DEV_0_BASE : std_ulogic_vector(31 downto 0) := (others => '0'); + DEV_1_SIZE : natural := 0; DEV_1_BASE : std_ulogic_vector(31 downto 0) := (others => '0'); + DEV_2_SIZE : natural := 0; DEV_2_BASE : std_ulogic_vector(31 downto 0) := (others => '0'); + DEV_3_SIZE : natural := 0; DEV_3_BASE : std_ulogic_vector(31 downto 0) := (others => '0') + ); + port ( + -- host port -- + host_req_i : in xbus_req_t; + host_rsp_o : out xbus_rsp_t; + -- device ports -- + dev_0_req_o : out xbus_req_t; dev_0_rsp_i : in xbus_rsp_t; + dev_1_req_o : out xbus_req_t; dev_1_rsp_i : in xbus_rsp_t; + dev_2_req_o : out xbus_req_t; dev_2_rsp_i : in xbus_rsp_t; + dev_3_req_o : out xbus_req_t; dev_3_rsp_i : in xbus_rsp_t + ); +end xbus_gateway; + +architecture xbus_gateway_rtl of xbus_gateway is + + -- module configuration -- + constant num_devs_c : natural := 4; -- number of device ports + + -- list of device base address and address size -- + type dev_base_list_t is array (0 to num_devs_c-1) of std_ulogic_vector(31 downto 0); + type dev_size_list_t is array (0 to num_devs_c-1) of natural; + constant dev_base_list_c : dev_base_list_t := (DEV_0_BASE, DEV_1_BASE, DEV_2_BASE, DEV_3_BASE); + constant dev_size_list_c : dev_size_list_t := (DEV_0_SIZE, DEV_1_SIZE, DEV_2_SIZE, DEV_3_SIZE); + + -- device ports combined as arrays -- + type dev_req_t is array (0 to num_devs_c-1) of xbus_req_t; + type dev_rsp_t is array (0 to num_devs_c-1) of xbus_rsp_t; + signal dev_req : dev_req_t; + signal dev_rsp : dev_rsp_t; + + -- access enable -- + signal acc_en : std_ulogic_vector(num_devs_c-1 downto 0); + +begin + + -- combine device ports -- + dev_0_req_o <= dev_req(0); dev_rsp(0) <= dev_0_rsp_i; + dev_1_req_o <= dev_req(1); dev_rsp(1) <= dev_1_rsp_i; + dev_2_req_o <= dev_req(2); dev_rsp(2) <= dev_2_rsp_i; + dev_3_req_o <= dev_req(3); dev_rsp(3) <= dev_3_rsp_i; + + -- device select -- + acc_en_gen: + for i in 0 to num_devs_c-1 generate + acc_en(i) <= '1' when (dev_size_list_c(i) > 0) and + (unsigned(host_req_i.addr) >= unsigned(dev_base_list_c(i))) and + (unsigned(host_req_i.addr) < (unsigned(dev_base_list_c(i)) + dev_size_list_c(i))) else '0'; + end generate; + + -- request -- + bus_request_gen: + for i in 0 to num_devs_c-1 generate + bus_request: process(host_req_i, acc_en) + begin + dev_req(i) <= host_req_i; + dev_req(i).cyc <= host_req_i.cyc and acc_en(i); + dev_req(i).stb <= host_req_i.stb and acc_en(i); + end process bus_request; + end generate; + + -- response -- + bus_response: process(dev_rsp, acc_en) + variable tmp_v : xbus_rsp_t; + begin + tmp_v.data := (others => '0'); + tmp_v.ack := '0'; + tmp_v.err := '0'; + for i in 0 to num_devs_c-1 loop -- OR all enabled response buses + if (acc_en(i) = '1') then + tmp_v.data := tmp_v.data or dev_rsp(i).data; + tmp_v.ack := tmp_v.ack or dev_rsp(i).ack; + tmp_v.err := tmp_v.err or dev_rsp(i).err; + end if; + end loop; + host_rsp_o <= tmp_v; + end process bus_response; + +end xbus_gateway_rtl; diff --git a/sim/xbus_memory.vhd b/sim/xbus_memory.vhd new file mode 100644 index 000000000..6eb22505d --- /dev/null +++ b/sim/xbus_memory.vhd @@ -0,0 +1,100 @@ +-- ================================================================================ -- +-- NEORV32 - Simple XBUS / Wishbone Memory (meant for simulation only) -- +-- -------------------------------------------------------------------------------- -- +-- 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; + +library neorv32; +use neorv32.neorv32_package.all; + +entity xbus_memory is + generic ( + MEM_SIZE : natural := 1024; -- memory size in bytes; should be a power of two + MEM_LATE : natural := 1 -- number of latency cycles (min 1) + ); + port ( + clk_i : in std_ulogic; + rstn_i : in std_ulogic; + xbus_req_i : in xbus_req_t; + xbus_rsp_o : out xbus_rsp_t + ); +end xbus_memory; + +architecture xbus_memory_rtl of xbus_memory is + + -- memory type -- + type mem8_bv_t is array (natural range <>) of bit_vector(7 downto 0); -- bit_vector type for optimized system storage + + -- memory access -- + signal addr : integer range 0 to (MEM_SIZE/4)-1; + signal rdata : std_ulogic_vector(31 downto 0); + signal ack : std_ulogic; + + -- latency generator -- + type late_data_t is array (MEM_LATE downto 0) of std_ulogic_vector(31 downto 0); + signal late_data : late_data_t; + signal late_ack : std_ulogic_vector(MEM_LATE downto 0); + +begin + + -- word-aligned read/write address -- + addr <= to_integer(unsigned(xbus_req_i.addr(index_size_f(MEM_SIZE/4)+1 downto 2))); + + + -- Non-Initialized Memory Core ------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + memory_core: process(clk_i) + variable mem8_bv_b0_v, mem8_bv_b1_v, mem8_bv_b2_v, mem8_bv_b3_v : mem8_bv_t(0 to (MEM_SIZE/4)-1); + begin + if rising_edge(clk_i) then + ack <= '0'; + if (xbus_req_i.cyc = '1') and (xbus_req_i.stb = '1') then + ack <= '1'; + if (xbus_req_i.we = '1') then + if (xbus_req_i.sel(0) = '1') then mem8_bv_b0_v(addr) := to_bitvector(xbus_req_i.data(07 downto 00)); end if; + if (xbus_req_i.sel(1) = '1') then mem8_bv_b1_v(addr) := to_bitvector(xbus_req_i.data(15 downto 08)); end if; + if (xbus_req_i.sel(2) = '1') then mem8_bv_b2_v(addr) := to_bitvector(xbus_req_i.data(23 downto 16)); end if; + if (xbus_req_i.sel(3) = '1') then mem8_bv_b3_v(addr) := to_bitvector(xbus_req_i.data(31 downto 24)); end if; + else + rdata(07 downto 00) <= to_stdulogicvector(mem8_bv_b0_v(addr)); + rdata(15 downto 08) <= to_stdulogicvector(mem8_bv_b1_v(addr)); + rdata(23 downto 16) <= to_stdulogicvector(mem8_bv_b2_v(addr)); + rdata(31 downto 24) <= to_stdulogicvector(mem8_bv_b3_v(addr)); + end if; + end if; + end if; + end process memory_core; + + + -- Latency Generator ---------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + latency_gen: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + late_data <= (others => (others => '0')); + late_ack <= (others => '0'); + elsif rising_edge(clk_i) then + late_data(0) <= rdata; + late_ack(0) <= ack; + for i in 0 to MEM_LATE-1 loop + late_data(i+1) <= late_data(i); + late_ack(i+1) <= late_ack(i); + end loop; + end if; + end process latency_gen; + + -- bus response -- + xbus_rsp_o.data <= rdata when (MEM_LATE = 1) else late_data(MEM_LATE-1); + xbus_rsp_o.ack <= ack when (MEM_LATE = 1) else late_ack(MEM_LATE-1); + xbus_rsp_o.err <= '0'; + + +end xbus_memory_rtl; diff --git a/sw/example/hello_world/makefile b/sw/example/hello_world/makefile index 99ad7967d..7b878d256 100644 --- a/sw/example/hello_world/makefile +++ b/sw/example/hello_world/makefile @@ -33,4 +33,4 @@ NEORV32_HOME ?= ../../.. include $(NEORV32_HOME)/sw/common/common.mk sim-check: sim - cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)" + cat $(NEORV32_HOME)/sim/neorv32.uart0_sim_mode.out | grep "Hello world! :)" diff --git a/sw/example/processor_check/main.c b/sw/example/processor_check/main.c index 530ec7185..16fd68c68 100644 --- a/sw/example/processor_check/main.c +++ b/sw/example/processor_check/main.c @@ -31,6 +31,8 @@ #define ADDR_UNREACHABLE (NEORV32_DM_BASE) //** External memory base address */ #define EXT_MEM_BASE (0xF0000000UL) +//** External IRQ trigger base address */ +#define SIM_TRIG_BASE (0xFF000000UL) /**@}*/ @@ -239,9 +241,9 @@ int main() { cnt_test++; - // set execute permission for u-mode + // set execute permission for u-mode for the entire address range // use entry 2 so we can use entries 0 & 1 later on for higher-prioritized configurations - tmp_a = neorv32_cpu_pmp_configure_region(2, -1, (PMP_NAPOT << PMPCFG_A_LSB) | (1 << PMPCFG_X)); + tmp_a = neorv32_cpu_pmp_configure_region(2, 0xffffffff, (PMP_NAPOT << PMPCFG_A_LSB) | (1 << PMPCFG_X)); if ((neorv32_cpu_csr_read(CSR_MCAUSE) == mcause_never_c) && (tmp_a == 0)) { test_ok(); @@ -2237,7 +2239,7 @@ int main() { **************************************************************************/ void sim_irq_trigger(uint32_t sel) { - *((volatile uint32_t*) (0xFF000000)) = sel; + *((volatile uint32_t*)SIM_TRIG_BASE) = sel; } diff --git a/sw/example/processor_check/makefile b/sw/example/processor_check/makefile index 27d2a844d..2aaaf063d 100644 --- a/sw/example/processor_check/makefile +++ b/sw/example/processor_check/makefile @@ -23,7 +23,7 @@ override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k # Adjust maximum heap size -#SER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096 +override USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096 # Simulation arguments override GHDL_RUN_FLAGS ?= --stop-time=15ms @@ -40,4 +40,4 @@ include $(NEORV32_HOME)/sw/common/common.mk # Add test-specific makefile target sim-check: sim - cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!" + cat $(NEORV32_HOME)/sim/neorv32.uart0_sim_mode.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!"