OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /neorv32/trunk
    from Rev 14 to Rev 15
    Reverse comparison

Rev 14 → Rev 15

/docs/figures/neorv32_cpu.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/docs/figures/neorv32_processor.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/docs/NEORV32.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/rtl/core/neorv32_cpu.vhd
58,8 → 58,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Bus Interface --
BUS_TIMEOUT : natural := 15 -- cycles after which a valid bus access will timeout
);
130,8 → 135,46
signal cp0_data, cp1_data : std_ulogic_vector(data_width_c-1 downto 0);
signal cp0_valid, cp1_valid : std_ulogic;
 
-- pmp interface --
signal pmp_addr : pmp_addr_if_t;
signal pmp_maddr : pmp_addr_if_t;
signal pmp_ctrl : pmp_ctrl_if_t;
signal priv_mode : std_ulogic_vector(1 downto 0); -- current CPU privilege level
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
sanity_check: process(clk_i)
begin
if rising_edge(clk_i) then
-- CSR system --
if (CPU_EXTENSION_RISCV_Zicsr = false) then
assert false report "NEORV32 CONFIG WARNING! No exception/interrupt/machine features available when CPU_EXTENSION_RISCV_Zicsr = false." severity warning;
end if;
-- U-extension requires Zicsr extension --
if (CPU_EXTENSION_RISCV_Zicsr = false) and (CPU_EXTENSION_RISCV_U = true) then
assert false report "NEORV32 CONFIG ERROR! User mode requires CPU_EXTENSION_RISCV_Zicsr = true." severity error;
end if;
-- PMP requires Zicsr extension --
if (CPU_EXTENSION_RISCV_Zicsr = false) and (PMP_USE = true) then
assert false report "NEORV32 CONFIG ERROR! Physical memory protection (PMP) requires CPU_EXTENSION_RISCV_Zicsr = true." severity error;
end if;
-- performance counters requires Zicsr extension --
if (CPU_EXTENSION_RISCV_Zicsr = false) and (CSR_COUNTERS_USE = true) then
assert false report "NEORV32 CONFIG ERROR! Performance counter CSRs require CPU_EXTENSION_RISCV_Zicsr = true." severity error;
end if;
-- PMP regions --
if (PMP_NUM_REGIONS > pmp_max_r_c) and (PMP_USE = true) then
assert false report "NEORV32 CONFIG ERROR! Number of PMP regions out of valid range." severity error;
end if;
-- PMP granulartiy --
if ((PMP_GRANULARITY <= 1) or (PMP_GRANULARITY > 31)) and (PMP_USE = true) then
assert false report "NEORV32 CONFIG ERROR! Invalid PMP grnaulartiy (1 < G < 32)." severity error;
end if;
end if;
end process sanity_check;
 
-- Control Unit ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_cpu_control_inst: neorv32_cpu_control
141,11 → 184,16
HW_THREAD_ID => HW_THREAD_ID, -- hardware thread id
CPU_BOOT_ADDR => CPU_BOOT_ADDR, -- cpu boot address
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei -- implement instruction stream sync.?
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
-- Physical memory protection (PMP) --
PMP_USE => PMP_USE, -- implement physical memory protection?
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (1..4)
PMP_GRANULARITY => PMP_GRANULARITY -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
)
port map (
-- global control --
176,6 → 224,11
firq_i => firq_i,
-- system time input from MTIME --
time_i => time_i, -- current system time
-- physical memory protection --
pmp_addr_o => pmp_addr, -- addresses
pmp_maddr_i => pmp_maddr, -- masked addresses
pmp_ctrl_o => pmp_ctrl, -- configs
priv_mode_o => priv_mode, -- current CPU privilege level
-- bus access exceptions --
mar_i => mar, -- memory address register
ma_instr_i => ma_instr, -- misaligned instruction address
276,7 → 329,11
neorv32_cpu_bus_inst: neorv32_cpu_bus
generic map (
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
BUS_TIMEOUT => BUS_TIMEOUT -- cycles after which a valid bus access will timeout
BUS_TIMEOUT => BUS_TIMEOUT, -- cycles after which a valid bus access will timeout
-- Physical memory protection (PMP) --
PMP_USE => PMP_USE, -- implement physical memory protection?
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (1..4)
PMP_GRANULARITY => PMP_GRANULARITY -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
)
port map (
-- global control --
301,6 → 358,11
ma_store_o => ma_store, -- misaligned store data address
be_load_o => be_load, -- bus error on load data access
be_store_o => be_store, -- bus error on store data access
-- physical memory protection --
pmp_addr_i => pmp_addr, -- addresses
pmp_maddr_o => pmp_maddr, -- masked addresses
pmp_ctrl_i => pmp_ctrl, -- configs
priv_mode_i => priv_mode, -- current CPU privilege level
-- instruction bus --
i_bus_addr_o => i_bus_addr_o, -- bus access address
i_bus_rdata_i => i_bus_rdata_i, -- bus read data
/rtl/core/neorv32_cpu_bus.vhd
44,7 → 44,11
entity neorv32_cpu_bus is
generic (
CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
BUS_TIMEOUT : natural := 15 -- cycles after which a valid bus access will timeout
BUS_TIMEOUT : natural := 15; -- cycles after which a valid bus access will timeout
-- Physical memory protection (PMP) --
PMP_USE : boolean := false; -- implement physical memory protection?
PMP_NUM_REGIONS : natural := 4; -- number of regions (1..4)
PMP_GRANULARITY : natural := 16 -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
);
port (
-- global control --
69,6 → 73,11
ma_store_o : out std_ulogic; -- misaligned store data address
be_load_o : out std_ulogic; -- bus error on load data access
be_store_o : out std_ulogic; -- bus error on store data access
-- physical memory protection --
pmp_addr_i : in pmp_addr_if_t; -- addresses
pmp_maddr_o : out pmp_addr_if_t; -- masked addresses
pmp_ctrl_i : in pmp_ctrl_if_t; -- configs
priv_mode_i : in std_ulogic_vector(1 downto 0); -- current CPU privilege level
-- instruction bus --
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
96,6 → 105,20
 
architecture neorv32_cpu_bus_rtl of neorv32_cpu_bus is
 
-- PMP modes --
constant pmp_off_mode_c : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled)
constant pmp_tor_mode_c : std_ulogic_vector(1 downto 0) := "01"; -- top of range
constant pmp_na4_mode_c : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region
constant pmp_napot_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes)
 
-- PMP configuration register bits --
constant pmp_cfg_r_c : natural := 0; -- read permit
constant pmp_cfg_w_c : natural := 1; -- write permit
constant pmp_cfg_x_c : natural := 2; -- execute permit
constant pmp_cfg_al_c : natural := 3; -- mode bit low
constant pmp_cfg_ah_c : natural := 4; -- mode bit high
constant pmp_cfg_l_c : natural := 7; -- locked entry
 
-- data interface registers --
signal mar, mdo, mdi : std_ulogic_vector(data_width_c-1 downto 0);
 
117,6 → 140,24
end record;
signal i_arbiter, d_arbiter : bus_arbiter_t;
 
-- physical memory protection --
type pmp_addr34_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c+1 downto 0);
type pmp_addr_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c-1 downto 0);
type pmp_t is record
addr_mask : pmp_addr34_t; -- 34-bit
i_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for instruction interface
d_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region match for data interface
if_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for fetch operation
ld_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for load operation
st_fault : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); -- region access fault for store operation
end record;
signal pmp : pmp_t;
 
-- pmp faults anybody? --
signal if_pmp_fault : std_ulogic; -- pmp instruction access fault
signal ld_pmp_fault : std_ulogic; -- pmp load access fault
signal st_pmp_fault : std_ulogic; -- pmp store access fault
 
begin
 
-- Data Interface: Access Address ---------------------------------------------------------
303,7 → 344,7
i_bus_wdata_o <= (others => '0');
i_bus_ben_o <= (others => '0');
i_bus_we_o <= '0';
i_bus_re_o <= ctrl_i(ctrl_bus_if_c) and (not i_misaligned); -- no actual read when misaligned
i_bus_re_o <= ctrl_i(ctrl_bus_if_c) and (not i_misaligned) and (not if_pmp_fault); -- no actual read when misaligned or PMP fault
i_bus_fence_o <= ctrl_i(ctrl_bus_fencei_c);
instr_o <= i_bus_rdata_i;
 
357,14 → 398,101
ma_store_o <= d_arbiter.wr_req and d_arbiter.err_align;
be_store_o <= d_arbiter.wr_req and d_arbiter.err_bus;
 
-- data bus --
-- data bus (read/write)--
d_bus_addr_o <= mar;
d_bus_wdata_o <= d_bus_wdata;
d_bus_ben_o <= d_bus_ben;
d_bus_we_o <= ctrl_i(ctrl_bus_wr_c) and (not d_misaligned); -- no actual write when misaligned
d_bus_re_o <= ctrl_i(ctrl_bus_rd_c) and (not d_misaligned); -- no actual read when misaligned
d_bus_we_o <= ctrl_i(ctrl_bus_wr_c) and (not d_misaligned) and (not st_pmp_fault); -- no actual write when misaligned or PMP fault
d_bus_re_o <= ctrl_i(ctrl_bus_rd_c) and (not d_misaligned) and (not ld_pmp_fault); -- no actual read when misaligned or PMP fault
d_bus_fence_o <= ctrl_i(ctrl_bus_fence_c);
d_bus_rdata <= d_bus_rdata_i;
 
 
-- Physical Memory Protection (PMP) -------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- compute address masks --
pmp_masks: process(pmp_addr_i, pmp, pmp_ctrl_i)
begin
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
pmp.addr_mask(r) <= (others => '0'); -- default
for i in PMP_GRANULARITY+2 to 33 loop
if (i = PMP_GRANULARITY+2) then
if (pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) = pmp_napot_mode_c) then
pmp.addr_mask(r)(i) <= '0';
else -- OFF or unsupported mode
pmp.addr_mask(r)(i) <= '1'; -- required for SW to check min granularity when entry is disabled
end if;
else
if (pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) = pmp_napot_mode_c) then
-- current bit = not AND(all previous bits)
pmp.addr_mask(r)(i) <= not and_all_f(pmp_addr_i(r)(i-1 downto PMP_GRANULARITY+2));
else -- OFF or unsupported mode
pmp.addr_mask(r)(i) <= '1'; -- required for SW to check min granularity when entry is disabled
end if;
end if;
end loop; -- i
end loop; -- r
end process pmp_masks;
 
 
-- masked pmpaddr output for CSR read-back --
pmp_masked_output: process(pmp_addr_i, pmp)
begin
pmp_maddr_o <= (others => (others => '0'));
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
pmp_maddr_o(r) <= pmp_addr_i(r) and pmp.addr_mask(r);
end loop; -- r
end process pmp_masked_output;
 
 
-- check for access address match --
pmp_addr_check: process (pmp, fetch_pc_i, mar, pmp_addr_i)
variable i_cmp_v : std_ulogic_vector(31 downto 0);
variable d_cmp_v : std_ulogic_vector(31 downto 0);
variable b_cmp_v : std_ulogic_vector(31 downto 0);
begin
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
b_cmp_v := pmp_addr_i(r)(33 downto 2) and pmp.addr_mask(r)(33 downto 2);
-- instruction interface --
i_cmp_v := fetch_pc_i and pmp.addr_mask(r)(33 downto 2);
if (i_cmp_v(31 downto PMP_GRANULARITY+2) = b_cmp_v(31 downto PMP_GRANULARITY+2)) then
pmp.i_match(r) <= '1';
else
pmp.i_match(r) <= '0';
end if;
-- data interface --
d_cmp_v := mar and pmp.addr_mask(r)(33 downto 2);
if (d_cmp_v(31 downto PMP_GRANULARITY+2) = b_cmp_v(31 downto PMP_GRANULARITY+2)) then
pmp.d_match(r) <= '1';
else
pmp.d_match(r) <= '0';
end if;
end loop; -- r
end process pmp_addr_check;
 
 
-- check access type and regions's permissions --
pmp_check_permission: process(pmp, pmp_ctrl_i, priv_mode_i)
begin
for r in 0 to PMP_NUM_REGIONS-1 loop -- iterate over all regions
if ((priv_mode_i = u_priv_mode_c) or (pmp_ctrl_i(r)(pmp_cfg_l_c) = '1')) and -- user privilege level or locked pmp entry - enforce permissions also for machine mode
(pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) /= pmp_off_mode_c) then -- active entry
pmp.if_fault(r) <= pmp.i_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_x_c)); -- fetch access match no execute permission
pmp.ld_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_r_c)); -- load access match no read permission
pmp.st_fault(r) <= pmp.d_match(r) and (not pmp_ctrl_i(r)(pmp_cfg_w_c)); -- store access match no write permission
else
pmp.if_fault(r) <= '0';
pmp.ld_fault(r) <= '0';
pmp.st_fault(r) <= '0';
end if;
end loop; -- r
end process pmp_check_permission;
 
 
-- final PMP access fault signals --
if_pmp_fault <= or_all_f(pmp.if_fault) when (PMP_USE = true) else '0';
ld_pmp_fault <= or_all_f(pmp.ld_fault) when (PMP_USE = true) else '0';
st_pmp_fault <= or_all_f(pmp.st_fault) when (PMP_USE = true) else '0';
 
 
end neorv32_cpu_bus_rtl;
/rtl/core/neorv32_cpu_control.vhd
53,8 → 53,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true -- implement instruction stream sync.?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical memory protection (PMP) --
PMP_USE : boolean := false; -- implement physical memory protection?
PMP_NUM_REGIONS : natural := 4; -- number of regions (1..4)
PMP_GRANULARITY : natural := 0 -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
);
port (
-- global control --
85,6 → 90,11
firq_i : in std_ulogic_vector(3 downto 0);
-- system time input from MTIME --
time_i : in std_ulogic_vector(63 downto 0); -- current system time
-- physical memory protection --
pmp_addr_o : out pmp_addr_if_t; -- addresses
pmp_maddr_i : in pmp_addr_if_t; -- masked addresses
pmp_ctrl_o : out pmp_ctrl_if_t; -- configs
priv_mode_o : out std_ulogic_vector(1 downto 0); -- current CPU privilege level
-- bus access exceptions --
mar_i : in std_ulogic_vector(data_width_c-1 downto 0); -- memory address register
ma_instr_i : in std_ulogic; -- misaligned instruction address
192,6 → 202,8
signal bus_fast_ir : std_ulogic;
 
-- RISC-V control and status registers (CSRs) --
type pmp_ctrl_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(7 downto 0);
type pmp_addr_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(data_width_c-1 downto 0);
type csr_t is record
we : std_ulogic; -- write enable
we_nxt : std_ulogic;
203,6 → 215,8
mie_meie : std_ulogic; -- mie.MEIE: machine external interrupt enable (R/W)
mie_mtie : std_ulogic; -- mie.MEIE: machine timer interrupt enable (R/W
mie_firqe : std_ulogic_vector(3 downto 0); -- mie.firq*e: fast interrupt enabled (R/W)
mpp : std_ulogic_vector(1 downto 0); -- machine previous privilege mode
privilege : std_ulogic_vector(1 downto 0); -- hart's current previous privilege mode
mepc : std_ulogic_vector(data_width_c-1 downto 0); -- mepc: machine exception pc (R/W)
mcause : std_ulogic_vector(data_width_c-1 downto 0); -- mcause: machine trap cause (R/-)
mtvec : std_ulogic_vector(data_width_c-1 downto 0); -- mtvec: machine trap-handler base address (R/W), bit 1:0 == 00
212,6 → 226,8
minstret : std_ulogic_vector(32 downto 0); -- minstret (R/W), plus carry bit
mcycleh : std_ulogic_vector(19 downto 0); -- mcycleh (R/W) - REDUCED BIT-WIDTH!
minstreth : std_ulogic_vector(19 downto 0); -- minstreth (R/W) - REDUCED BIT-WIDTH!
pmpcfg : pmp_ctrl_t; -- physical memory protection - configuration registers
pmpaddr : pmp_addr_t; -- physical memory protection - address registers
end record;
signal csr : csr_t;
 
224,6 → 240,9
signal illegal_register : std_ulogic; -- only for E-extension
signal illegal_compressed : std_ulogic; -- only fir C-extension
 
-- access (privilege) check --
signal csr_acc_valid : std_ulogic; -- valid CSR access (implemented and valid access rights)
 
begin
 
-- ****************************************************************************************************************************
544,7 → 563,7
 
-- Execute Engine FSM Comb ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl,
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
alu_add_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
variable alu_immediate_v : std_ulogic;
variable alu_operation_v : std_ulogic_vector(2 downto 0);
744,7 → 763,7
 
when opcode_syscsr_c => -- system/csr access
-- ------------------------------------------------------------
csr.re_nxt <= '1'; -- always read CSR - regardless of actual operation
csr.re_nxt <= csr_acc_valid; -- read CSR if valid access
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when funct12_ecall_c => -- ECALL
785,17 → 804,17
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '0'; -- OPB = rs2
ctrl_nxt(ctrl_rf_clear_rs2_c) <= '1'; -- rs2 = 0
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= '1'; -- always write CSR
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
when funct3_csrrs_c => -- CSRRS
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= not rs1_is_r0_v; -- write CSR if rs1 is not zero_reg
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
when funct3_csrrc_c => -- CSRRC
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bitc_c; -- actual ALU operation = bit clear
csr.we_nxt <= not rs1_is_r0_v; -- write CSR if rs1 is not zero_reg
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
-- immediate operations --
when funct3_csrrwi_c => -- CSRRWI
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1
802,17 → 821,17
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- rs1 = 0
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= '1'; -- always write CSR
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
when funct3_csrrsi_c => -- CSRRSI
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR
csr.we_nxt <= not rs1_is_r0_v; -- write CSR if UIMM5 is not zero (bits from rs1 filed)
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
when funct3_csrrci_c => -- CSRRCI
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- OPA = csr
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = immediate
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bitc_c; -- actual ALU operation = bit clear
csr.we_nxt <= not rs1_is_r0_v; -- write CSR if UIMM5 is not zero (bits from rs1 filed)
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if UIMM5 is not zero (bits from rs1 filed) and if valid access
when others => -- undefined
NULL;
end case;
875,9 → 894,72
end process execute_engine_fsm_comb;
 
 
-- ****************************************************************************************************************************
-- Invalid Instruction / CSR access check
-- ****************************************************************************************************************************
 
 
-- Illegal CSR Access Check ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
invalid_csr_access_check: process(execute_engine, csr)
variable is_m_mode_v : std_ulogic;
begin
-- are we in machine mode? --
is_m_mode_v := '0';
if (csr.privilege = m_priv_mode_c) then
is_m_mode_v := '1';
end if;
 
-- check CSR access --
csr_acc_valid <= '0'; -- default
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when x"300" => csr_acc_valid <= is_m_mode_v; -- mstatus
when x"301" => csr_acc_valid <= is_m_mode_v; -- misa
when x"304" => csr_acc_valid <= is_m_mode_v; -- mie
when x"305" => csr_acc_valid <= is_m_mode_v; -- mtvev
when x"340" => csr_acc_valid <= is_m_mode_v; -- mscratch
when x"341" => csr_acc_valid <= is_m_mode_v; -- mepc
when x"342" => csr_acc_valid <= is_m_mode_v; -- mcause
when x"343" => csr_acc_valid <= is_m_mode_v; -- mtval
when x"344" => csr_acc_valid <= is_m_mode_v; -- mip
--
when x"3a0" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v; -- pmpacfg0
when x"3a1" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v; -- pmpacfg1
--
when x"3b0" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 1)) and is_m_mode_v; -- pmpaddr0
when x"3b1" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 2)) and is_m_mode_v; -- pmpaddr1
when x"3b2" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 3)) and is_m_mode_v; -- pmpaddr2
when x"3b3" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 4)) and is_m_mode_v; -- pmpaddr3
when x"3b4" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 5)) and is_m_mode_v; -- pmpaddr4
when x"3b5" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 6)) and is_m_mode_v; -- pmpaddr5
when x"3b6" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 7)) and is_m_mode_v; -- pmpaddr6
when x"3b7" => csr_acc_valid <= bool_to_ulogic_f(PMP_USE) and bool_to_ulogic_f(boolean(PMP_NUM_REGIONS >= 8)) and is_m_mode_v; -- pmpaddr7
--
when x"c00" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- cycle
when x"c01" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- time
when x"c02" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- instret
when x"c80" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- cycleh
when x"c81" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- timeh
when x"c82" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE); -- instreth
--
when x"b00" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE) and is_m_mode_v; -- mcycle
when x"b02" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE) and is_m_mode_v; -- minstret
when x"b80" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE) and is_m_mode_v; -- mcycleh
when x"b82" => csr_acc_valid <= bool_to_ulogic_f(CSR_COUNTERS_USE) and is_m_mode_v; -- minstreth
--
when x"f11" => csr_acc_valid <= is_m_mode_v; -- mvendorid
when x"f12" => csr_acc_valid <= is_m_mode_v; -- marchid
when x"f13" => csr_acc_valid <= is_m_mode_v; -- mimpid
when x"f14" => csr_acc_valid <= is_m_mode_v; -- mhartid
--
when others => csr_acc_valid <= '0'; -- undefined
end case;
end process invalid_csr_access_check;
 
 
-- Illegal Instruction Check --------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
illegal_instruction_check: process(execute_engine, csr, ctrl_nxt)
illegal_instruction_check: process(execute_engine, csr, ctrl_nxt, csr_acc_valid)
begin
-- illegal instructions are checked in the EXECUTE stage
-- the execute engine will only commit valid instructions
981,33 → 1063,8
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrsi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrci_c) then
-- valid CSR? --
if (execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"300") or -- mstatus
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"301") or -- misa
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"304") or -- mie
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"305") or -- mtvev
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"340") or -- mscratch
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"341") or -- mepc
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"342") or -- mcause
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"343") or -- mtval
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"344") or -- mip
--
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c00") and (CSR_COUNTERS_USE = true)) or -- cycle
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c01") and (CSR_COUNTERS_USE = true)) or -- time
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c02") and (CSR_COUNTERS_USE = true)) or -- instret
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c80") and (CSR_COUNTERS_USE = true)) or -- cycleh
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c81") and (CSR_COUNTERS_USE = true)) or -- timeh
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"c82") and (CSR_COUNTERS_USE = true)) or -- instreth
--
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"b00") and (CSR_COUNTERS_USE = true)) or -- mcycle
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"b02") and (CSR_COUNTERS_USE = true)) or -- minstret
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"b80") and (CSR_COUNTERS_USE = true)) or -- mcycleh
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"b82") and (CSR_COUNTERS_USE = true)) or -- minstreth
--
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"f11") or -- mvendorid
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"f12") or -- marchid
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"f13") or -- mimpid
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = x"f14") then -- mhartid
-- valid CSR access? --
if (csr_acc_valid = '1') then
illegal_instruction <= '0';
else
illegal_instruction <= '1';
1230,6 → 1287,10
csr.mepc <= (others => '0');
csr.mcause <= (others => '0');
csr.mtval <= (others => '0');
csr.mpp <= m_priv_mode_c; -- start in MACHINE mode
csr.privilege <= m_priv_mode_c; -- start in MACHINE mode
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => '0'));
elsif rising_edge(clk_i) then
if (CPU_EXTENSION_RISCV_Zicsr = true) then
-- access --
1239,7 → 1300,7
-- registers that can be modified by user --
if (csr.we = '1') then -- manual update
 
-- Machine CSRs: Standard read/write
-- Machine CSRs --
if (execute_engine.i_reg(31 downto 28) = x"3") then
-- machine trap setup --
if (execute_engine.i_reg(27 downto 24) = x"0") then
1247,6 → 1308,11
when x"0" => -- R/W: mstatus - machine status register
csr.mstatus_mie <= csr_wdata_i(03);
csr.mstatus_mpie <= csr_wdata_i(07);
--
if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented
csr.mpp(0) <= csr_wdata_i(11) and csr_wdata_i(12);
csr.mpp(1) <= csr_wdata_i(11) and csr_wdata_i(12);
end if;
when x"4" => -- R/W: mie - machine interrupt-enable register
csr.mie_msie <= csr_wdata_i(03); -- machine SW IRQ enable
csr.mie_mtie <= csr_wdata_i(07); -- machine TIMER IRQ enable
1275,6 → 1341,56
NULL;
end case;
end if;
-- machine physical memory protection (pmp) --
if (PMP_USE = true) then
-- pmpcfg --
if (execute_engine.i_reg(27 downto 24) = x"a") then
if (PMP_NUM_REGIONS >= 1) then
if (execute_engine.i_reg(23 downto 20) = x"0") then -- pmpcfg0
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(0+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(0+j)(0) <= csr_wdata_i(j*8+0); -- R
csr.pmpcfg(0+j)(1) <= csr_wdata_i(j*8+1); -- W
csr.pmpcfg(0+j)(2) <= csr_wdata_i(j*8+2); -- X
csr.pmpcfg(0+j)(3) <= csr_wdata_i(j*8+3) and csr_wdata_i(j*8+4); -- A_L
csr.pmpcfg(0+j)(4) <= csr_wdata_i(j*8+3) and csr_wdata_i(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(0+j)(5) <= '0'; -- reserved
csr.pmpcfg(0+j)(6) <= '0'; -- reserved
csr.pmpcfg(0+j)(7) <= csr_wdata_i(j*8+7); -- L
end if;
end if;
end loop; -- j (bytes in CSR)
end if;
end if;
if (PMP_NUM_REGIONS >= 5) then
if (execute_engine.i_reg(23 downto 20) = x"1") then -- pmpcfg1
for j in 0 to 3 loop -- bytes in pmpcfg CSR
if ((j+1+4) <= PMP_NUM_REGIONS) then
if (csr.pmpcfg(4+j)(7) = '0') then -- unlocked pmpcfg access
csr.pmpcfg(4+j)(0) <= csr_wdata_i(j*8+0); -- R
csr.pmpcfg(4+j)(1) <= csr_wdata_i(j*8+1); -- W
csr.pmpcfg(4+j)(2) <= csr_wdata_i(j*8+2); -- X
csr.pmpcfg(4+j)(3) <= csr_wdata_i(j*8+3) and csr_wdata_i(j*8+4); -- A_L
csr.pmpcfg(4+j)(4) <= csr_wdata_i(j*8+3) and csr_wdata_i(j*8+4); -- A_H - NAPOT/OFF only
csr.pmpcfg(4+j)(5) <= '0'; -- reserved
csr.pmpcfg(4+j)(6) <= '0'; -- reserved
csr.pmpcfg(4+j)(7) <= csr_wdata_i(j*8+7); -- L
end if;
end if;
end loop; -- j (bytes in CSR)
end if;
end if;
end if;
-- pmpaddr --
if (execute_engine.i_reg(27 downto 24) = x"b") then
for i in 0 to PMP_NUM_REGIONS-1 loop
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
csr.pmpaddr(i) <= csr_wdata_i;
end if;
end loop; -- i (CSRs)
end if;
end if; -- implement PMP at all?
end if;
 
-- automatic update by hardware --
1302,15 → 1418,27
end if;
 
-- context switch in mstatus --
if (trap_ctrl.env_start_ack = '1') then -- trap handler starting?
csr.mstatus_mie <= '0';
if (csr.mstatus_mpie = '0') then -- prevent loosing the prev MIE state in nested traps
csr.mstatus_mpie <= csr.mstatus_mie;
if (trap_ctrl.env_start_ack = '1') then -- ENTER: trap handler starting?
csr.mstatus_mie <= '0'; -- disable interrupts
csr.mstatus_mpie <= csr.mstatus_mie; -- buffer previous mie state
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= m_priv_mode_c; -- execute trap in machine mode
csr.mpp <= csr.privilege; -- buffer previous privilege mode
end if;
elsif (trap_ctrl.env_end = '1') then -- return from exception
csr.mstatus_mie <= csr.mstatus_mpie;
elsif (trap_ctrl.env_end = '1') then -- EXIT: return from exception
csr.mstatus_mie <= csr.mstatus_mpie; -- restore global IRQ enable flag
csr.mstatus_mpie <= '1';
if (CPU_EXTENSION_RISCV_U = true) then -- implement user mode
csr.privilege <= csr.mpp; -- go back to previous privilege mode
csr.mpp <= u_priv_mode_c;
end if;
end if;
 
-- user mode NOT implemented --
if (CPU_EXTENSION_RISCV_U = false) then -- implement user mode
csr.privilege <= m_priv_mode_c;
csr.mpp <= m_priv_mode_c;
end if;
end if;
end if;
end if;
1328,15 → 1456,16
 
-- machine trap setup --
when x"300" => -- R/W: mstatus - machine status register
csr_rdata_o(03) <= csr.mstatus_mie; -- MIE
csr_rdata_o(03) <= csr.mstatus_mie; -- MIE
csr_rdata_o(07) <= csr.mstatus_mpie; -- MPIE
csr_rdata_o(11) <= '1'; -- MPP low - M-mode
csr_rdata_o(12) <= '1'; -- MPP high - M-mode
csr_rdata_o(11) <= csr.mpp(0); -- MPP: machine previous privilege mode low
csr_rdata_o(12) <= csr.mpp(1); -- MPP: machine previous privilege mode high
when x"301" => -- R/-: misa - ISA and extensions
csr_rdata_o(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension
csr_rdata_o(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension
csr_rdata_o(08) <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E)
csr_rdata_o(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension
csr_rdata_o(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension
csr_rdata_o(23) <= '1'; -- X CPU extension (non-std extensions)
csr_rdata_o(25) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicsr) and bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Z CPU extension
csr_rdata_o(30) <= '1'; -- 32-bit architecture (MXL lo)
1372,6 → 1501,111
csr_rdata_o(18) <= trap_ctrl.irq_buf(interrupt_firq_2_c);
csr_rdata_o(19) <= trap_ctrl.irq_buf(interrupt_firq_3_c);
 
-- physical memory protection --
when x"3a0" => -- R/W: pmpcfg0 - physical memory protection configuration register 0
if (PMP_USE = true) then
if (PMP_NUM_REGIONS >= 1) then
csr_rdata_o(07 downto 00) <= csr.pmpcfg(0);
end if;
if (PMP_NUM_REGIONS >= 2) then
csr_rdata_o(15 downto 08) <= csr.pmpcfg(1);
end if;
if (PMP_NUM_REGIONS >= 3) then
csr_rdata_o(23 downto 16) <= csr.pmpcfg(2);
end if;
if (PMP_NUM_REGIONS >= 4) then
csr_rdata_o(31 downto 24) <= csr.pmpcfg(3);
end if;
end if;
when x"3a1" => -- R/W: pmpcfg1 - physical memory protection configuration register 1
if (PMP_USE = true) then
if (PMP_NUM_REGIONS >= 5) then
csr_rdata_o(07 downto 00) <= csr.pmpcfg(4);
end if;
if (PMP_NUM_REGIONS >= 6) then
csr_rdata_o(15 downto 08) <= csr.pmpcfg(5);
end if;
if (PMP_NUM_REGIONS >= 7) then
csr_rdata_o(23 downto 16) <= csr.pmpcfg(6);
end if;
if (PMP_NUM_REGIONS >= 8) then
csr_rdata_o(31 downto 24) <= csr.pmpcfg(7);
end if;
end if;
 
when x"3b0" => -- R/W: pmpaddr0 - physical memory protection address register 0
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 1) then
csr_rdata_o <= pmp_maddr_i(0)(33 downto 2);
if (csr.pmpcfg(0)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b1" => -- R/W: pmpaddr1 - physical memory protection address register 1
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 2) then
csr_rdata_o <= pmp_maddr_i(1)(33 downto 2);
if (csr.pmpcfg(1)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b2" => -- R/W: pmpaddr2 - physical memory protection address register 2
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 3) then
csr_rdata_o <= pmp_maddr_i(2)(33 downto 2);
if (csr.pmpcfg(2)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b3" => -- R/W: pmpaddr3 - physical memory protection address register 3
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 4) then
csr_rdata_o <= pmp_maddr_i(3)(33 downto 2);
if (csr.pmpcfg(3)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b4" => -- R/W: pmpaddr4 - physical memory protection address register 4
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 5) then
csr_rdata_o <= pmp_maddr_i(4)(33 downto 2);
if (csr.pmpcfg(4)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b5" => -- R/W: pmpaddr5 - physical memory protection address register 5
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 6) then
csr_rdata_o <= pmp_maddr_i(5)(33 downto 2);
if (csr.pmpcfg(5)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b6" => -- R/W: pmpaddr6 - physical memory protection address register 6
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 7) then
csr_rdata_o <= pmp_maddr_i(6)(33 downto 2);
if (csr.pmpcfg(6)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
when x"3b7" => -- R/W: pmpaddr7 - physical memory protection address register 7
if (PMP_USE = true) and (PMP_NUM_REGIONS >= 8) then
csr_rdata_o <= pmp_maddr_i(7)(33 downto 2);
if (csr.pmpcfg(7)(4 downto 3) = "00") then -- mode = off
csr_rdata_o(PMP_GRANULARITY-1 downto 0) <= (others => '0'); -- required for granularity check by SW
else -- mode = NAPOT
csr_rdata_o(PMP_GRANULARITY-2 downto 0) <= (others => '1');
end if;
end if;
 
-- counter and timers --
when x"c00" | x"b00" => -- R/(W): cycle/mcycle: Cycle counter LOW
csr_rdata_o <= csr.mcycle(31 downto 0);
1410,7 → 1644,23
-- time[h] CSR --
systime <= time_i when (CSR_COUNTERS_USE = true) else (others => '0');
 
-- CPU's current privilege level --
priv_mode_o <= csr.privilege;
 
-- PMP output --
pmp_output: process(csr)
begin
pmp_addr_o <= (others => (others => '0'));
pmp_ctrl_o <= (others => (others => '0'));
if (PMP_USE = true) then
for i in 0 to PMP_NUM_REGIONS-1 loop
pmp_addr_o(i) <= csr.pmpaddr(i) & "00";
pmp_ctrl_o(i) <= csr.pmpcfg(i);
end loop; -- i
end if;
end process pmp_output;
 
 
-- RISC-V Counter CSRs --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
csr_counters: process(rstn_i, clk_i)
/rtl/core/neorv32_package.vhd
41,7 → 41,8
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- data width - FIXED!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01030000"; -- no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01030500"; -- no touchy!
constant pmp_max_r_c : natural := 8; -- max PMP regions
 
-- Helper Functions -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
49,12 → 50,17
function cond_sel_natural_f(cond : boolean; val_t : natural; val_f : natural) return natural;
function cond_sel_stdulogicvector_f(cond : boolean; val_t : std_ulogic_vector; val_f : std_ulogic_vector) return std_ulogic_vector;
function bool_to_ulogic_f(cond : boolean) return std_ulogic;
function or_all_f( a : std_ulogic_vector) return std_ulogic;
function and_all_f( a : std_ulogic_vector) return std_ulogic;
function xor_all_f( a : std_ulogic_vector) return std_ulogic;
function or_all_f(a : std_ulogic_vector) return std_ulogic;
function and_all_f(a : std_ulogic_vector) return std_ulogic;
function xor_all_f(a : std_ulogic_vector) return std_ulogic;
function xnor_all_f(a : std_ulogic_vector) return std_ulogic;
function to_hexchar_f(input : std_ulogic_vector(3 downto 0)) return character;
 
-- Internal Types -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
type pmp_ctrl_if_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(7 downto 0);
type pmp_addr_if_t is array (0 to pmp_max_r_c-1) of std_ulogic_vector(33 downto 0);
 
-- Processor-internal Address Space Layout ------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Instruction Memory & Data Memory --
361,6 → 367,11
--
constant interrupt_width_c : natural := 7; -- length of this list in bits
 
-- CPU Privilege Modes --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant m_priv_mode_c : std_ulogic_vector(1 downto 0) := "11"; -- machine mode
constant u_priv_mode_c : std_ulogic_vector(1 downto 0) := "00"; -- user mode
 
-- Clock Generator -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant clk_div2_c : natural := 0;
385,8 → 396,13
CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := true; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Memory configuration: Instruction memory --
MEM_ISPACE_BASE : std_ulogic_vector(31 downto 0) := x"00000000"; -- base address of instruction memory space
MEM_ISPACE_SIZE : natural := 16*1024; -- total size of instruction memory space in byte
464,8 → 480,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Bus Interface --
BUS_TIMEOUT : natural := 15 -- cycles after which a valid bus access will timeout
);
518,8 → 539,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true -- implement instruction stream sync.?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical memory protection (PMP) --
PMP_USE : boolean := false; -- implement physical memory protection?
PMP_NUM_REGIONS : natural := 4; -- number of regions (1..4)
PMP_GRANULARITY : natural := 0 -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
);
port (
-- global control --
550,6 → 576,11
firq_i : in std_ulogic_vector(3 downto 0);
-- system time input from MTIME --
time_i : in std_ulogic_vector(63 downto 0); -- current system time
-- physical memory protection --
pmp_addr_o : out pmp_addr_if_t; -- addresses
pmp_maddr_i : in pmp_addr_if_t; -- masked addresses
pmp_ctrl_o : out pmp_ctrl_if_t; -- configs
priv_mode_o : out std_ulogic_vector(1 downto 0); -- current CPU privilege level
-- bus access exceptions --
mar_i : in std_ulogic_vector(data_width_c-1 downto 0); -- memory address register
ma_instr_i : in std_ulogic; -- misaligned instruction address
635,7 → 666,11
component neorv32_cpu_bus
generic (
CPU_EXTENSION_RISCV_C : boolean := true; -- implement compressed extension?
BUS_TIMEOUT : natural := 15 -- cycles after which a valid bus access will timeout
BUS_TIMEOUT : natural := 15; -- cycles after which a valid bus access will timeout
-- Physical memory protection (PMP) --
PMP_USE : boolean := false; -- implement physical memory protection?
PMP_NUM_REGIONS : natural := 4; -- number of regions (1..4)
PMP_GRANULARITY : natural := 0 -- granularity (0=none, 1=8B, 2=16B, 3=32B, ...)
);
port (
-- global control --
660,6 → 695,11
ma_store_o : out std_ulogic; -- misaligned store data address
be_load_o : out std_ulogic; -- bus error on load data access
be_store_o : out std_ulogic; -- bus error on store data access
-- physical memory protection --
pmp_addr_i : in pmp_addr_if_t; -- addresses
pmp_maddr_o : out pmp_addr_if_t; -- masked addresses
pmp_ctrl_i : in pmp_ctrl_if_t; -- configs
priv_mode_i : in std_ulogic_vector(1 downto 0); -- current CPU privilege level
-- instruction bus --
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
1126,9 → 1166,11
variable tmp_v : std_ulogic;
begin
tmp_v := a(a'low);
for i in a'low+1 to a'high loop
tmp_v := tmp_v or a(i);
end loop; -- i
if (a'low < a'high) then -- not null range?
for i in a'low+1 to a'high loop
tmp_v := tmp_v or a(i);
end loop; -- i
end if;
return tmp_v;
end function or_all_f;
 
1138,9 → 1180,11
variable tmp_v : std_ulogic;
begin
tmp_v := a(a'low);
for i in a'low+1 to a'high loop
tmp_v := tmp_v and a(i);
end loop; -- i
if (a'low < a'high) then -- not null range?
for i in a'low+1 to a'high loop
tmp_v := tmp_v and a(i);
end loop; -- i
end if;
return tmp_v;
end function and_all_f;
 
1150,9 → 1194,11
variable tmp_v : std_ulogic;
begin
tmp_v := a(a'low);
for i in a'low+1 to a'high loop
tmp_v := tmp_v xor a(i);
end loop; -- i
if (a'low < a'high) then -- not null range?
for i in a'low+1 to a'high loop
tmp_v := tmp_v xor a(i);
end loop; -- i
end if;
return tmp_v;
end function xor_all_f;
 
1162,9 → 1208,11
variable tmp_v : std_ulogic;
begin
tmp_v := a(a'low);
for i in a'low+1 to a'high loop
tmp_v := tmp_v xnor a(i);
end loop; -- i
if (a'low < a'high) then -- not null range?
for i in a'low+1 to a'high loop
tmp_v := tmp_v xnor a(i);
end loop; -- i
end if;
return tmp_v;
end function xnor_all_f;
 
/rtl/core/neorv32_top.vhd
55,8 → 55,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Memory configuration: Instruction memory --
MEM_ISPACE_BASE : std_ulogic_vector(31 downto 0) := x"00000000"; -- base address of instruction memory space
MEM_ISPACE_SIZE : natural := 16*1024; -- total size of instruction memory space in byte
247,11 → 252,6
assert false report "NEORV32 CONFIG ERROR! Core clock frequency (CLOCK_FREQUENCY) not specified." severity error;
end if;
 
-- CSR system not implemented --
if (CPU_EXTENSION_RISCV_Zicsr = false) then
assert false report "NEORV32 CONFIG WARNING! No exception/interrupt/machine features available when CPU_EXTENSION_RISCV_Zicsr = false." severity warning;
end if;
 
-- memory layout notifier --
if (MEM_ISPACE_BASE /= x"00000000") then
assert false report "NEORV32 CONFIG WARNING! Non-default base address for instruction address space. Make sure this is sync with the software framwork." severity warning;
328,8 → 328,13
CPU_EXTENSION_RISCV_C => CPU_EXTENSION_RISCV_C, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => CPU_EXTENSION_RISCV_E, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => CPU_EXTENSION_RISCV_M, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => CPU_EXTENSION_RISCV_U, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE => PMP_USE, -- implement PMP?
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (max 16)
PMP_GRANULARITY => PMP_GRANULARITY, -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Bus Interface --
BUS_TIMEOUT => MEM_EXT_TIMEOUT -- cycles after which a valid bus access will timeout
)
/rtl/top_templates/neorv32_test_setup.vhd
77,8 → 77,13
CPU_EXTENSION_RISCV_C => false, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => false, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => false, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => false, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => true, -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE => false, -- implement PMP?
PMP_NUM_REGIONS => 4, -- number of regions (max 16)
PMP_GRANULARITY => 15, -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Memory configuration: Instruction memory --
MEM_ISPACE_BASE => x"00000000", -- base address of instruction memory space
MEM_ISPACE_SIZE => 16*1024, -- total size of instruction memory space in byte
/sim/vivado/neorv32_tb_behav.wcfg
12,15 → 12,15
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="1345742867fs"></ZoomStartTime>
<ZoomEndTime time="1345761168fs"></ZoomEndTime>
<Cursor1Time time="1345799367fs"></Cursor1Time>
<ZoomStartTime time="1400827333fs"></ZoomStartTime>
<ZoomEndTime time="1401034534fs"></ZoomEndTime>
<Cursor1Time time="1400917733fs"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="178"></NameColumnWidth>
<ValueColumnWidth column_width="116"></ValueColumnWidth>
<ValueColumnWidth column_width="108"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="142" />
<WVObjectSize size="132" />
<wvobject type="divider" fp_name="divider273">
<obj_property name="label">CPU: Control.FETCH</obj_property>
<obj_property name="DisplayName">label</obj_property>
69,7 → 69,6
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/ipb" type="array">
<obj_property name="ElementShortName">ipb</obj_property>
<obj_property name="ObjectShortName">ipb</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider273">
<obj_property name="label">CPU: Control.EXE</obj_property>
159,6 → 158,10
<obj_property name="ElementShortName">illegal_instruction</obj_property>
<obj_property name="ObjectShortName">illegal_instruction</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr_acc_valid" type="logic">
<obj_property name="ElementShortName">csr_acc_valid</obj_property>
<obj_property name="ObjectShortName">csr_acc_valid</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/illegal_register" type="logic">
<obj_property name="ElementShortName">illegal_register</obj_property>
<obj_property name="ObjectShortName">illegal_register</obj_property>
171,70 → 174,6
<obj_property name="ElementShortName">execute_engine</obj_property>
<obj_property name="ObjectShortName">execute_engine</obj_property>
<obj_property name="isExpanded"></obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.state" type="other">
<obj_property name="ElementShortName">.state</obj_property>
<obj_property name="ObjectShortName">.state</obj_property>
<obj_property name="CustomSignalColor">#FFA500</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.state_nxt" type="other">
<obj_property name="ElementShortName">.state_nxt</obj_property>
<obj_property name="ObjectShortName">.state_nxt</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.i_reg" type="array">
<obj_property name="ElementShortName">.i_reg[31:0]</obj_property>
<obj_property name="ObjectShortName">.i_reg[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.i_reg_nxt" type="array">
<obj_property name="ElementShortName">.i_reg_nxt[31:0]</obj_property>
<obj_property name="ObjectShortName">.i_reg_nxt[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.is_ci" type="logic">
<obj_property name="ElementShortName">.is_ci</obj_property>
<obj_property name="ObjectShortName">.is_ci</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.is_ci_nxt" type="logic">
<obj_property name="ElementShortName">.is_ci_nxt</obj_property>
<obj_property name="ObjectShortName">.is_ci_nxt</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.is_jump" type="logic">
<obj_property name="ElementShortName">.is_jump</obj_property>
<obj_property name="ObjectShortName">.is_jump</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.is_jump_nxt" type="logic">
<obj_property name="ElementShortName">.is_jump_nxt</obj_property>
<obj_property name="ObjectShortName">.is_jump_nxt</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.branch_taken" type="logic">
<obj_property name="ElementShortName">.branch_taken</obj_property>
<obj_property name="ObjectShortName">.branch_taken</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.pc" type="array">
<obj_property name="ElementShortName">.pc[31:0]</obj_property>
<obj_property name="ObjectShortName">.pc[31:0]</obj_property>
<obj_property name="CustomSignalColor">#FFFFFF</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.pc_nxt" type="array">
<obj_property name="ElementShortName">.pc_nxt[31:0]</obj_property>
<obj_property name="ObjectShortName">.pc_nxt[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.next_pc" type="array">
<obj_property name="ElementShortName">.next_pc[31:0]</obj_property>
<obj_property name="ObjectShortName">.next_pc[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.last_pc" type="array">
<obj_property name="ElementShortName">.last_pc[31:0]</obj_property>
<obj_property name="ObjectShortName">.last_pc[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.sleep" type="logic">
<obj_property name="ElementShortName">.sleep</obj_property>
<obj_property name="ObjectShortName">.sleep</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/execute_engine.sleep_nxt" type="logic">
<obj_property name="ElementShortName">.sleep_nxt</obj_property>
<obj_property name="ObjectShortName">.sleep_nxt</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/CPU_EXTENSION_RISCV_C" type="other">
<obj_property name="ElementShortName">CPU_EXTENSION_RISCV_C</obj_property>
273,6 → 212,99
<obj_property name="ElementShortName">csr</obj_property>
<obj_property name="ObjectShortName">csr</obj_property>
<obj_property name="isExpanded"></obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.we" type="logic">
<obj_property name="ElementShortName">.we</obj_property>
<obj_property name="ObjectShortName">.we</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.we_nxt" type="logic">
<obj_property name="ElementShortName">.we_nxt</obj_property>
<obj_property name="ObjectShortName">.we_nxt</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.re" type="logic">
<obj_property name="ElementShortName">.re</obj_property>
<obj_property name="ObjectShortName">.re</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.re_nxt" type="logic">
<obj_property name="ElementShortName">.re_nxt</obj_property>
<obj_property name="ObjectShortName">.re_nxt</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mstatus_mie" type="logic">
<obj_property name="ElementShortName">.mstatus_mie</obj_property>
<obj_property name="ObjectShortName">.mstatus_mie</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mstatus_mpie" type="logic">
<obj_property name="ElementShortName">.mstatus_mpie</obj_property>
<obj_property name="ObjectShortName">.mstatus_mpie</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mie_msie" type="logic">
<obj_property name="ElementShortName">.mie_msie</obj_property>
<obj_property name="ObjectShortName">.mie_msie</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mie_meie" type="logic">
<obj_property name="ElementShortName">.mie_meie</obj_property>
<obj_property name="ObjectShortName">.mie_meie</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mie_mtie" type="logic">
<obj_property name="ElementShortName">.mie_mtie</obj_property>
<obj_property name="ObjectShortName">.mie_mtie</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mie_firqe" type="array">
<obj_property name="ElementShortName">.mie_firqe[3:0]</obj_property>
<obj_property name="ObjectShortName">.mie_firqe[3:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mpp" type="array">
<obj_property name="ElementShortName">.mpp[1:0]</obj_property>
<obj_property name="ObjectShortName">.mpp[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.privilege" type="array">
<obj_property name="ElementShortName">.privilege[1:0]</obj_property>
<obj_property name="ObjectShortName">.privilege[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mepc" type="array">
<obj_property name="ElementShortName">.mepc[31:0]</obj_property>
<obj_property name="ObjectShortName">.mepc[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mcause" type="array">
<obj_property name="ElementShortName">.mcause[31:0]</obj_property>
<obj_property name="ObjectShortName">.mcause[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mtvec" type="array">
<obj_property name="ElementShortName">.mtvec[31:0]</obj_property>
<obj_property name="ObjectShortName">.mtvec[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mtval" type="array">
<obj_property name="ElementShortName">.mtval[31:0]</obj_property>
<obj_property name="ObjectShortName">.mtval[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mscratch" type="array">
<obj_property name="ElementShortName">.mscratch[31:0]</obj_property>
<obj_property name="ObjectShortName">.mscratch[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mcycle" type="array">
<obj_property name="ElementShortName">.mcycle[32:0]</obj_property>
<obj_property name="ObjectShortName">.mcycle[32:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.minstret" type="array">
<obj_property name="ElementShortName">.minstret[32:0]</obj_property>
<obj_property name="ObjectShortName">.minstret[32:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.mcycleh" type="array">
<obj_property name="ElementShortName">.mcycleh[19:0]</obj_property>
<obj_property name="ObjectShortName">.mcycleh[19:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.minstreth" type="array">
<obj_property name="ElementShortName">.minstreth[19:0]</obj_property>
<obj_property name="ObjectShortName">.minstreth[19:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.pmpcfg" type="array">
<obj_property name="ElementShortName">.pmpcfg[0:3][7:0]</obj_property>
<obj_property name="ObjectShortName">.pmpcfg[0:3][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_control_inst/csr.pmpaddr" type="array">
<obj_property name="ElementShortName">.pmpaddr[0:3][31:0]</obj_property>
<obj_property name="ObjectShortName">.pmpaddr[0:3][31:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
</wvobject>
<wvobject type="divider" fp_name="divider139">
<obj_property name="label">CPU: RegFile</obj_property>
286,18 → 318,6
<obj_property name="label">CPU: ALU</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/clk_i" type="logic">
<obj_property name="ElementShortName">clk_i</obj_property>
<obj_property name="ObjectShortName">clk_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/rstn_i" type="logic">
<obj_property name="ElementShortName">rstn_i</obj_property>
<obj_property name="ObjectShortName">rstn_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/ctrl_i" type="array">
<obj_property name="ElementShortName">ctrl_i[49:0]</obj_property>
<obj_property name="ObjectShortName">ctrl_i[49:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/rs1_i" type="array">
<obj_property name="ElementShortName">rs1_i[31:0]</obj_property>
<obj_property name="ObjectShortName">rs1_i[31:0]</obj_property>
330,22 → 350,6
<obj_property name="ElementShortName">res_o[31:0]</obj_property>
<obj_property name="ObjectShortName">res_o[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp0_data_i" type="array">
<obj_property name="ElementShortName">cp0_data_i[31:0]</obj_property>
<obj_property name="ObjectShortName">cp0_data_i[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp0_valid_i" type="logic">
<obj_property name="ElementShortName">cp0_valid_i</obj_property>
<obj_property name="ObjectShortName">cp0_valid_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp1_data_i" type="array">
<obj_property name="ElementShortName">cp1_data_i[31:0]</obj_property>
<obj_property name="ObjectShortName">cp1_data_i[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp1_valid_i" type="logic">
<obj_property name="ElementShortName">cp1_valid_i</obj_property>
<obj_property name="ObjectShortName">cp1_valid_i</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/wait_o" type="logic">
<obj_property name="ElementShortName">wait_o</obj_property>
<obj_property name="ObjectShortName">wait_o</obj_property>
362,66 → 366,6
<obj_property name="ElementShortName">opc[31:0]</obj_property>
<obj_property name="ObjectShortName">opc[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/add_res" type="array">
<obj_property name="ElementShortName">add_res[31:0]</obj_property>
<obj_property name="ObjectShortName">add_res[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/alu_res" type="array">
<obj_property name="ElementShortName">alu_res[31:0]</obj_property>
<obj_property name="ObjectShortName">alu_res[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_opx" type="array">
<obj_property name="ElementShortName">cmp_opx[32:0]</obj_property>
<obj_property name="ObjectShortName">cmp_opx[32:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_opy" type="array">
<obj_property name="ElementShortName">cmp_opy[32:0]</obj_property>
<obj_property name="ObjectShortName">cmp_opy[32:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_sub" type="array">
<obj_property name="ElementShortName">cmp_sub[32:0]</obj_property>
<obj_property name="ObjectShortName">cmp_sub[32:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/sub_res" type="array">
<obj_property name="ElementShortName">sub_res[31:0]</obj_property>
<obj_property name="ObjectShortName">sub_res[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_equal" type="logic">
<obj_property name="ElementShortName">cmp_equal</obj_property>
<obj_property name="ObjectShortName">cmp_equal</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cmp_less" type="logic">
<obj_property name="ElementShortName">cmp_less</obj_property>
<obj_property name="ObjectShortName">cmp_less</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_cmd_ff" type="logic">
<obj_property name="ElementShortName">cp_cmd_ff</obj_property>
<obj_property name="ObjectShortName">cp_cmd_ff</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_run" type="logic">
<obj_property name="ElementShortName">cp_run</obj_property>
<obj_property name="ObjectShortName">cp_run</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_start" type="logic">
<obj_property name="ElementShortName">cp_start</obj_property>
<obj_property name="ObjectShortName">cp_start</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_busy" type="logic">
<obj_property name="ElementShortName">cp_busy</obj_property>
<obj_property name="ObjectShortName">cp_busy</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_rb_ff0" type="logic">
<obj_property name="ElementShortName">cp_rb_ff0</obj_property>
<obj_property name="ObjectShortName">cp_rb_ff0</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/cp_rb_ff1" type="logic">
<obj_property name="ElementShortName">cp_rb_ff1</obj_property>
<obj_property name="ObjectShortName">cp_rb_ff1</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_alu_inst/shifter" type="array">
<obj_property name="ElementShortName">shifter</obj_property>
<obj_property name="ObjectShortName">shifter</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider367">
<obj_property name="label">CPU: BUS_UNIT</obj_property>
<obj_property name="DisplayName">label</obj_property>
481,23 → 425,302
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/i_arbiter" type="array">
<obj_property name="ElementShortName">i_arbiter</obj_property>
<obj_property name="ObjectShortName">i_arbiter</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/d_arbiter" type="array">
<obj_property name="ElementShortName">d_arbiter</obj_property>
<obj_property name="ObjectShortName">d_arbiter</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/cpu_i" type="array">
<obj_property name="ElementShortName">cpu_i</obj_property>
<obj_property name="ObjectShortName">cpu_i</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/cpu_d" type="array">
<obj_property name="ElementShortName">cpu_d</obj_property>
<obj_property name="ObjectShortName">cpu_d</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/PMP_USE" type="other">
<obj_property name="ElementShortName">PMP_USE</obj_property>
<obj_property name="ObjectShortName">PMP_USE</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/PMP_NUM_REGIONS" type="other">
<obj_property name="ElementShortName">PMP_NUM_REGIONS</obj_property>
<obj_property name="ObjectShortName">PMP_NUM_REGIONS</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/PMP_GRANULARITY" type="other">
<obj_property name="ElementShortName">PMP_GRANULARITY</obj_property>
<obj_property name="ObjectShortName">PMP_GRANULARITY</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp" type="array">
<obj_property name="ElementShortName">pmp</obj_property>
<obj_property name="ObjectShortName">pmp</obj_property>
<obj_property name="isExpanded"></obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.addr_mask" type="array">
<obj_property name="ElementShortName">.addr_mask[0:3][33:0]</obj_property>
<obj_property name="ObjectShortName">.addr_mask[0:3][33:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.addr_mask[0]" type="array">
<obj_property name="ElementShortName">[0][33:0]</obj_property>
<obj_property name="ObjectShortName">[0][33:0]</obj_property>
<obj_property name="Radix">BINARYRADIX</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.addr_mask[1]" type="array">
<obj_property name="ElementShortName">[1][33:0]</obj_property>
<obj_property name="ObjectShortName">[1][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.addr_mask[2]" type="array">
<obj_property name="ElementShortName">[2][33:0]</obj_property>
<obj_property name="ObjectShortName">[2][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.addr_mask[3]" type="array">
<obj_property name="ElementShortName">[3][33:0]</obj_property>
<obj_property name="ObjectShortName">[3][33:0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.i_match" type="array">
<obj_property name="ElementShortName">.i_match[3:0]</obj_property>
<obj_property name="ObjectShortName">.i_match[3:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.d_match" type="array">
<obj_property name="ElementShortName">.d_match[3:0]</obj_property>
<obj_property name="ObjectShortName">.d_match[3:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.if_fault" type="array">
<obj_property name="ElementShortName">.if_fault[3:0]</obj_property>
<obj_property name="ObjectShortName">.if_fault[3:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.ld_fault" type="array">
<obj_property name="ElementShortName">.ld_fault[3:0]</obj_property>
<obj_property name="ObjectShortName">.ld_fault[3:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp.st_fault" type="array">
<obj_property name="ElementShortName">.st_fault[3:0]</obj_property>
<obj_property name="ObjectShortName">.st_fault[3:0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i" type="array">
<obj_property name="ElementShortName">pmp_addr_i[0:15][33:0]</obj_property>
<obj_property name="ObjectShortName">pmp_addr_i[0:15][33:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[0]" type="array">
<obj_property name="ElementShortName">[0][33:0]</obj_property>
<obj_property name="ObjectShortName">[0][33:0]</obj_property>
<obj_property name="Radix">BINARYRADIX</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[1]" type="array">
<obj_property name="ElementShortName">[1][33:0]</obj_property>
<obj_property name="ObjectShortName">[1][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[2]" type="array">
<obj_property name="ElementShortName">[2][33:0]</obj_property>
<obj_property name="ObjectShortName">[2][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[3]" type="array">
<obj_property name="ElementShortName">[3][33:0]</obj_property>
<obj_property name="ObjectShortName">[3][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[4]" type="array">
<obj_property name="ElementShortName">[4][33:0]</obj_property>
<obj_property name="ObjectShortName">[4][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[5]" type="array">
<obj_property name="ElementShortName">[5][33:0]</obj_property>
<obj_property name="ObjectShortName">[5][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[6]" type="array">
<obj_property name="ElementShortName">[6][33:0]</obj_property>
<obj_property name="ObjectShortName">[6][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[7]" type="array">
<obj_property name="ElementShortName">[7][33:0]</obj_property>
<obj_property name="ObjectShortName">[7][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[8]" type="array">
<obj_property name="ElementShortName">[8][33:0]</obj_property>
<obj_property name="ObjectShortName">[8][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[9]" type="array">
<obj_property name="ElementShortName">[9][33:0]</obj_property>
<obj_property name="ObjectShortName">[9][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[10]" type="array">
<obj_property name="ElementShortName">[10][33:0]</obj_property>
<obj_property name="ObjectShortName">[10][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[11]" type="array">
<obj_property name="ElementShortName">[11][33:0]</obj_property>
<obj_property name="ObjectShortName">[11][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[12]" type="array">
<obj_property name="ElementShortName">[12][33:0]</obj_property>
<obj_property name="ObjectShortName">[12][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[13]" type="array">
<obj_property name="ElementShortName">[13][33:0]</obj_property>
<obj_property name="ObjectShortName">[13][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[14]" type="array">
<obj_property name="ElementShortName">[14][33:0]</obj_property>
<obj_property name="ObjectShortName">[14][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_addr_i[15]" type="array">
<obj_property name="ElementShortName">[15][33:0]</obj_property>
<obj_property name="ObjectShortName">[15][33:0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o" type="array">
<obj_property name="ElementShortName">pmp_maddr_o[0:15][33:0]</obj_property>
<obj_property name="ObjectShortName">pmp_maddr_o[0:15][33:0]</obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[0]" type="array">
<obj_property name="ElementShortName">[0][33:0]</obj_property>
<obj_property name="ObjectShortName">[0][33:0]</obj_property>
<obj_property name="Radix">BINARYRADIX</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[1]" type="array">
<obj_property name="ElementShortName">[1][33:0]</obj_property>
<obj_property name="ObjectShortName">[1][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[2]" type="array">
<obj_property name="ElementShortName">[2][33:0]</obj_property>
<obj_property name="ObjectShortName">[2][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[3]" type="array">
<obj_property name="ElementShortName">[3][33:0]</obj_property>
<obj_property name="ObjectShortName">[3][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[4]" type="array">
<obj_property name="ElementShortName">[4][33:0]</obj_property>
<obj_property name="ObjectShortName">[4][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[5]" type="array">
<obj_property name="ElementShortName">[5][33:0]</obj_property>
<obj_property name="ObjectShortName">[5][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[6]" type="array">
<obj_property name="ElementShortName">[6][33:0]</obj_property>
<obj_property name="ObjectShortName">[6][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[7]" type="array">
<obj_property name="ElementShortName">[7][33:0]</obj_property>
<obj_property name="ObjectShortName">[7][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[8]" type="array">
<obj_property name="ElementShortName">[8][33:0]</obj_property>
<obj_property name="ObjectShortName">[8][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[9]" type="array">
<obj_property name="ElementShortName">[9][33:0]</obj_property>
<obj_property name="ObjectShortName">[9][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[10]" type="array">
<obj_property name="ElementShortName">[10][33:0]</obj_property>
<obj_property name="ObjectShortName">[10][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[11]" type="array">
<obj_property name="ElementShortName">[11][33:0]</obj_property>
<obj_property name="ObjectShortName">[11][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[12]" type="array">
<obj_property name="ElementShortName">[12][33:0]</obj_property>
<obj_property name="ObjectShortName">[12][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[13]" type="array">
<obj_property name="ElementShortName">[13][33:0]</obj_property>
<obj_property name="ObjectShortName">[13][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[14]" type="array">
<obj_property name="ElementShortName">[14][33:0]</obj_property>
<obj_property name="ObjectShortName">[14][33:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_maddr_o[15]" type="array">
<obj_property name="ElementShortName">[15][33:0]</obj_property>
<obj_property name="ObjectShortName">[15][33:0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i" type="array">
<obj_property name="ElementShortName">pmp_ctrl_i[0:15][7:0]</obj_property>
<obj_property name="ObjectShortName">pmp_ctrl_i[0:15][7:0]</obj_property>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[0]" type="array">
<obj_property name="ElementShortName">[0][7:0]</obj_property>
<obj_property name="ObjectShortName">[0][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[1]" type="array">
<obj_property name="ElementShortName">[1][7:0]</obj_property>
<obj_property name="ObjectShortName">[1][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[2]" type="array">
<obj_property name="ElementShortName">[2][7:0]</obj_property>
<obj_property name="ObjectShortName">[2][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[3]" type="array">
<obj_property name="ElementShortName">[3][7:0]</obj_property>
<obj_property name="ObjectShortName">[3][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[4]" type="array">
<obj_property name="ElementShortName">[4][7:0]</obj_property>
<obj_property name="ObjectShortName">[4][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[5]" type="array">
<obj_property name="ElementShortName">[5][7:0]</obj_property>
<obj_property name="ObjectShortName">[5][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[6]" type="array">
<obj_property name="ElementShortName">[6][7:0]</obj_property>
<obj_property name="ObjectShortName">[6][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[7]" type="array">
<obj_property name="ElementShortName">[7][7:0]</obj_property>
<obj_property name="ObjectShortName">[7][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[8]" type="array">
<obj_property name="ElementShortName">[8][7:0]</obj_property>
<obj_property name="ObjectShortName">[8][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[9]" type="array">
<obj_property name="ElementShortName">[9][7:0]</obj_property>
<obj_property name="ObjectShortName">[9][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[10]" type="array">
<obj_property name="ElementShortName">[10][7:0]</obj_property>
<obj_property name="ObjectShortName">[10][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[11]" type="array">
<obj_property name="ElementShortName">[11][7:0]</obj_property>
<obj_property name="ObjectShortName">[11][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[12]" type="array">
<obj_property name="ElementShortName">[12][7:0]</obj_property>
<obj_property name="ObjectShortName">[12][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[13]" type="array">
<obj_property name="ElementShortName">[13][7:0]</obj_property>
<obj_property name="ObjectShortName">[13][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[14]" type="array">
<obj_property name="ElementShortName">[14][7:0]</obj_property>
<obj_property name="ObjectShortName">[14][7:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/pmp_ctrl_i[15]" type="array">
<obj_property name="ElementShortName">[15][7:0]</obj_property>
<obj_property name="ObjectShortName">[15][7:0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/priv_mode_i" type="array">
<obj_property name="ElementShortName">priv_mode_i[1:0]</obj_property>
<obj_property name="ObjectShortName">priv_mode_i[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/if_pmp_fault" type="logic">
<obj_property name="ElementShortName">if_pmp_fault</obj_property>
<obj_property name="ObjectShortName">if_pmp_fault</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/ld_pmp_fault" type="logic">
<obj_property name="ElementShortName">ld_pmp_fault</obj_property>
<obj_property name="ObjectShortName">ld_pmp_fault</obj_property>
</wvobject>
<wvobject fp_name="/neorv32_tb/neorv32_top_inst/neorv32_cpu_inst/neorv32_cpu_bus_inst/st_pmp_fault" type="logic">
<obj_property name="ElementShortName">st_pmp_fault</obj_property>
<obj_property name="ObjectShortName">st_pmp_fault</obj_property>
</wvobject>
<wvobject type="divider" fp_name="divider298">
<obj_property name="label">BUS_CROSSBAR</obj_property>
<obj_property name="DisplayName">label</obj_property>
/sim/neorv32_tb.vhd
134,8 → 134,13
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => false, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => true, -- implement muld/div extension?
CPU_EXTENSION_RISCV_U => true, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei => true, -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE => true, -- implement PMP?
PMP_NUM_REGIONS => 4, -- number of regions (max 16)
PMP_GRANULARITY => 15, -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Memory configuration: Instruction memory --
MEM_ISPACE_BASE => x"00000000", -- base address of instruction memory space
MEM_ISPACE_SIZE => 16*1024, -- total size of instruction memory space in byte
/sw/example/cpu_test/main.c
74,8 → 74,11
void test_fail(void);
 
// Global variables (also test initialization of global vars here)
/// Global counter for failing tests
int cnt_fail = 0;
/// Global counter for successful tests
int cnt_ok = 0;
/// Global counter for total number of tests
int cnt_test = 0;
 
 
96,6 → 99,7
int main() {
 
register uint32_t tmp_a;
uint32_t i;
volatile uint32_t dummy_dst __attribute__((unused));
 
union {
181,7 → 185,7
#if (PROBING_MEM_TEST == 1)
cnt_test++;
 
register uint32_t dmem_probe_addr = neorv32_cpu_csr_read(CSR_MISPACEBASE);
register uint32_t dmem_probe_addr = SYSINFO_ISPACE_BASE;
uint32_t dmem_probe_cnt = 0;
 
while(1) {
193,9 → 197,9
dmem_probe_cnt++;
}
neorv32_uart_printf("%u bytes (should be %u bytes) ", dmem_probe_cnt, neorv32_cpu_csr_read(CSR_MISPACESIZE));
neorv32_uart_printf("@ 0x%x ", neorv32_cpu_csr_read(CSR_MISPACEBASE));
if (dmem_probe_cnt == neorv32_cpu_csr_read(CSR_MISPACESIZE)) {
neorv32_uart_printf("%u bytes (should be %u bytes) ", dmem_probe_cnt, SYSINFO_ISPACE_SIZE);
neorv32_uart_printf("@ 0x%x ", SYSINFO_ISPACE_BASE);
if (dmem_probe_cnt == SYSINFO_ISPACE_SIZE) {
test_ok();
}
else {
213,7 → 217,7
#if (PROBING_MEM_TEST == 1)
cnt_test++;
 
register uint32_t imem_probe_addr = neorv32_cpu_csr_read(CSR_MDSPACEBASE);
register uint32_t imem_probe_addr =SYSINFO_DSPACE_BASE;
uint32_t imem_probe_cnt = 0;
 
while(1) {
225,9 → 229,9
imem_probe_cnt++;
}
neorv32_uart_printf("%u bytes (should be %u bytes) ", imem_probe_cnt, neorv32_cpu_csr_read(CSR_MDSPACESIZE));
neorv32_uart_printf("@ 0x%x ", neorv32_cpu_csr_read(CSR_MDSPACEBASE));
if (imem_probe_cnt == neorv32_cpu_csr_read(CSR_MDSPACESIZE)) {
neorv32_uart_printf("%u bytes (should be %u bytes) ", imem_probe_cnt, SYSINFO_DSPACE_SIZE);
neorv32_uart_printf("@ 0x%x ", SYSINFO_DSPACE_BASE);
if (imem_probe_cnt == SYSINFO_DSPACE_SIZE) {
test_ok();
}
else {
623,6 → 627,8
test_fail();
}
#endif
// no more mtime interrupts
neorv32_wdt_disable();
}
else {
neorv32_uart_printf("skipped (WDT not implemented)\n");
633,7 → 639,7
// Test WFI ("sleep") instructions, wakeup via MTIME
// ----------------------------------------------------------
exception_handler_answer = 0xFFFFFFFF;
neorv32_uart_printf("WFI: ");
neorv32_uart_printf("WFI (MTIME): ");
 
if (neorv32_mtime_available()) {
cnt_test++;
652,6 → 658,8
test_ok();
}
#endif
// no more mtime interrupts
neorv32_mtime_set_timecmp(-1);
}
else {
neorv32_uart_printf("skipped (MTIME not implemented)\n");
658,8 → 666,182
}
 
 
// ----------------------------------------------------------
// Test invalid CSR access in user mode
// ----------------------------------------------------------
exception_handler_answer = 0xFFFFFFFF;
neorv32_uart_printf("USR INV_CSR: ");
 
// skip if U-mode is not implemented
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CPU_MISA_U_EXT)) {
 
cnt_test++;
 
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
neorv32_cpu_goto_user_mode();
{
// access to mstatus not allowed for user mode programs
neorv32_cpu_csr_read(CSR_MSTATUS);
}
 
#if (DETAILED_EXCEPTION_DEBUG==0)
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) {
test_ok();
}
else {
test_fail();
}
#endif
}
else {
neorv32_uart_printf("skipped (not possible when U-EXT disabled)\n");
}
 
 
// ----------------------------------------------------------
// Test RTE debug handler
// ----------------------------------------------------------
exception_handler_answer = 0xFFFFFFFF;
neorv32_uart_printf("RTE DB TEST: ");
 
cnt_test++;
 
// uninstall custom handler and use default RTE debug handler
neorv32_rte_exception_uninstall(RTE_TRAP_I_ILLEGAL);
 
// trigger illegal instruction exception
neorv32_cpu_csr_read(0xfff); // CSR not available
 
neorv32_uart_printf(" ");
if (exception_handler_answer == 0xFFFFFFFF) {
test_ok();
}
else {
test_fail();
neorv32_uart_printf("answer: 0x%x", exception_handler_answer);
}
 
// restore original handler
neorv32_rte_exception_install(RTE_TRAP_I_ILLEGAL, global_trap_handler);
 
 
// ----------------------------------------------------------
// Test physical memory protection
// ----------------------------------------------------------
exception_handler_answer = 0xFFFFFFFF;
neorv32_uart_printf("\nPhysical memory protection: ");
 
// check if PMP is implemented
neorv32_cpu_csr_read(0x3a0);
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) {
neorv32_uart_printf("test skipped (PMP not implemented)\n");
}
else {
neorv32_uart_printf("implemented\n");
 
// find out number of regions
for (i=0; i<16; i++) {
exception_handler_answer = 0xFFFFFFFF;
switch (i) {
case 0: neorv32_cpu_csr_read(0x3b0); break;
case 1: neorv32_cpu_csr_read(0x3b1); break;
case 2: neorv32_cpu_csr_read(0x3b2); break;
case 3: neorv32_cpu_csr_read(0x3b3); break;
case 4: neorv32_cpu_csr_read(0x3b4); break;
case 5: neorv32_cpu_csr_read(0x3b5); break;
case 6: neorv32_cpu_csr_read(0x3b6); break;
case 7: neorv32_cpu_csr_read(0x3b7); break;
case 8: neorv32_cpu_csr_read(0x3b8); break;
case 9: neorv32_cpu_csr_read(0x3b9); break;
case 10: neorv32_cpu_csr_read(0x3ba); break;
case 11: neorv32_cpu_csr_read(0x3bb); break;
case 12: neorv32_cpu_csr_read(0x3bc); break;
case 13: neorv32_cpu_csr_read(0x3bd); break;
case 14: neorv32_cpu_csr_read(0x3be); break;
case 15: neorv32_cpu_csr_read(0x3bf); break;
default: break;
}
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) {
break;
}
}
neorv32_uart_printf("Regions: %u\n", i);
 
 
// check granulartiy
neorv32_cpu_csr_write(0x3a0, 0);
neorv32_cpu_csr_write(0x3b0, 0xffffffff);
uint32_t pmp_test_g = neorv32_cpu_csr_read(0x3b0);
 
// find least-significat set bit
for (i=31; i>=0; i--) {
if (((pmp_test_g >> i) & 1) == 0) {
break;
}
}
neorv32_uart_printf("Min granulartiy: %u bytes per region\n", 1<<(i+2));
 
 
// test available modes
neorv32_uart_printf("Mode TOR: ");
neorv32_cpu_csr_write(0x3a0, 0x08);
if ((neorv32_cpu_csr_read(0x3a0) & 0xFF) == 0x08) {
neorv32_uart_printf("available\n");
}
else {
neorv32_uart_printf("not implemented\n");
}
 
neorv32_uart_printf("Mode NA4: ");
neorv32_cpu_csr_write(0x3a0, 0x10);
if ((neorv32_cpu_csr_read(0x3a0) & 0xFF) == 0x10) {
neorv32_uart_printf("available\n");
}
else {
neorv32_uart_printf("not implemented\n");
}
 
neorv32_uart_printf("Mode NAPOT: ");
neorv32_cpu_csr_write(0x3a0, 0x18);
if ((neorv32_cpu_csr_read(0x3a0) & 0xFF) == 0x18) {
neorv32_uart_printf("available\n");
}
else {
neorv32_uart_printf("not implemented\n");
}
 
 
// test user mode access fault
neorv32_cpu_csr_write(0x3b0, 0x00007fff); // 64k area @ 0x00000000
neorv32_cpu_csr_write(0x3a0, 0b00011100); // NAPOT, execute permission, NO load permission
 
neorv32_uart_printf("U-mode protected load fault test: ");
cnt_test++;
 
exception_handler_answer = 0xFFFFFFFF;
 
// switch to user mode (hart will be back in MACHINE mode when trap handler returns)
neorv32_cpu_goto_user_mode();
{
// load from protected area
asm volatile ("lw zero, 0(zero)");
}
 
#if (DETAILED_EXCEPTION_DEBUG==0)
if (exception_handler_answer == TRAP_CODE_L_ACCESS) {
neorv32_uart_printf("ok\n");
cnt_ok++;
}
else {
neorv32_uart_printf("fail\n");
cnt_fail++;
}
#endif
}
 
 
 
// ----------------------------------------------------------
// Final test reports
// ----------------------------------------------------------
neorv32_uart_printf("\n\nTests: %i\nOK: %i\nFAIL: %i\n\n", cnt_test, cnt_ok, cnt_fail);
682,6 → 864,10
void global_trap_handler(void) {
 
exception_handler_answer = neorv32_cpu_csr_read(CSR_MCAUSE);
 
// hack: always come back in MACHINE MODE
register uint32_t mask = (1<<CPU_MSTATUS_MPP_H) | (1<<CPU_MSTATUS_MPP_L);
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
}
 
 
703,3 → 889,4
neorv32_uart_printf("fail\n");
cnt_fail++;
}
 
/sw/lib/include/neorv32.h
68,6 → 68,18
CSR_MTVAL = 0x343, /**< 0x343 - mtval (r/w): Machine bad address or instruction */
CSR_MIP = 0x344, /**< 0x344 - mip (r/w): Machine interrupt pending register */
 
CSR_PMPCFG0 = 0x3a0, /**< 0x3a0 - pmpcfg0 (r/w): Physical memory protection configuration register 0 */
CSR_PMPCFG1 = 0x3a1, /**< 0x3a1 - pmpcfg1 (r/w): Physical memory protection configuration register 1 */
 
CSR_PMPADDR0 = 0x3b0, /**< 0x3b0 - pmpaddr0 (r/w): Physical memory protection address register 0 */
CSR_PMPADDR1 = 0x3b1, /**< 0x3b1 - pmpaddr1 (r/w): Physical memory protection address register 1 */
CSR_PMPADDR2 = 0x3b2, /**< 0x3b2 - pmpaddr2 (r/w): Physical memory protection address register 2 */
CSR_PMPADDR3 = 0x3b3, /**< 0x3b3 - pmpaddr3 (r/w): Physical memory protection address register 3 */
CSR_PMPADDR4 = 0x3b4, /**< 0x3b4 - pmpaddr4 (r/w): Physical memory protection address register 4 */
CSR_PMPADDR5 = 0x3b5, /**< 0x3b5 - pmpaddr5 (r/w): Physical memory protection address register 5 */
CSR_PMPADDR6 = 0x3b6, /**< 0x3b6 - pmpaddr6 (r/w): Physical memory protection address register 6 */
CSR_PMPADDR7 = 0x3b7, /**< 0x3b7 - pmpaddr7 (r/w): Physical memory protection address register 7 */
 
CSR_MCYCLE = 0xb00, /**< 0xb00 - mcycle (r/w): Machine cycle counter low word */
CSR_MINSTRET = 0xb02, /**< 0xb02 - minstret (r/w): Machine instructions-retired counter low word */
CSR_MCYCLEH = 0xb80, /**< 0xb80 - mcycleh (r/w): Machine cycle counter high word - only 20-bit wide!*/
92,8 → 104,10
* CPU <b>mstatus</b> CSR (r/w): Machine status (RISC-V spec.)
**************************************************************************/
enum NEORV32_CPU_MSTATUS_enum {
CPU_MSTATUS_MIE = 3, /**< CPU mstatus CSR (3): Machine interrupt enable bit (r/w) */
CPU_MSTATUS_MPIE = 7 /**< CPU mstatus CSR (7): Machine previous interrupt enable bit (r/w) */
CPU_MSTATUS_MIE = 3, /**< CPU mstatus CSR (3): Machine interrupt enable bit (r/w) */
CPU_MSTATUS_MPIE = 7, /**< CPU mstatus CSR (7): Machine previous interrupt enable bit (r/w) */
CPU_MSTATUS_MPP_L = 11, /**< CPU mstatus CSR (11): Machine previous privilege mode bit low (r/w) */
CPU_MSTATUS_MPP_H = 12 /**< CPU mstatus CSR (12): Machine previous privilege mode bit high (r/w) */
};
 
 
104,7 → 118,6
CPU_MIE_MSIE = 3, /**< CPU mie CSR (3): Machine software interrupt enable (r/w) */
CPU_MIE_MTIE = 7, /**< CPU mie CSR (7): Machine timer interrupt enable bit (r/w) */
CPU_MIE_MEIE = 11, /**< CPU mie CSR (11): Machine external interrupt enable bit (r/w) */
 
CPU_MIE_FIRQ0E = 16, /**< CPU mie CSR (16): Fast interrupt channel 0 enable bit (r/w) */
CPU_MIE_FIRQ1E = 17, /**< CPU mie CSR (17): Fast interrupt channel 1 enable bit (r/w) */
CPU_MIE_FIRQ2E = 18, /**< CPU mie CSR (18): Fast interrupt channel 2 enable bit (r/w) */
131,10 → 144,11
* CPU <b>misa</b> CSR (r/w): Machine instruction set extensions (RISC-V spec.)
**************************************************************************/
enum NEORV32_CPU_MISA_enum {
CPU_MISA_C_EXT = 2, /**< CPU misa CSR (2): C: Compressed instructions CPU extension available (r/-), can be switched on/off */
CPU_MISA_C_EXT = 2, /**< CPU misa CSR (2): C: Compressed instructions CPU extension available (r/-)*/
CPU_MISA_E_EXT = 4, /**< CPU misa CSR (3): E: Embedded CPU extension available (r/-) */
CPU_MISA_I_EXT = 8, /**< CPU misa CSR (8): I: Base integer ISA CPU extension available (r/-) */
CPU_MISA_M_EXT = 12, /**< CPU misa CSR (12): M: Multiplier/divider CPU extension available (r/-), can be switched on/off */
CPU_MISA_M_EXT = 12, /**< CPU misa CSR (12): M: Multiplier/divider CPU extension available (r/-)*/
CPU_MISA_U_EXT = 20, /**< CPU misa CSR (20): U: User mode CPU extension available (r/-)*/
CPU_MISA_X_EXT = 23, /**< CPU misa CSR (23): X: Non-standard CPU extension available (r/-) */
CPU_MISA_Z_EXT = 25, /**< CPU misa CSR (25): Z: Privileged architecture CPU extension(s) available (r/-) */
CPU_MISA_MXL_LO_EXT = 30, /**< CPU misa CSR (30): MXL.lo: CPU data width (r/-) */
/sw/lib/include/neorv32_cpu.h
51,6 → 51,7
void neorv32_cpu_set_minstret(uint64_t value);
uint64_t neorv32_cpu_get_systime(void);
void neorv32_cpu_delay_ms(uint32_t time_ms);
void __attribute__((naked)) neorv32_cpu_goto_user_mode(void);
 
 
/**********************************************************************//**
/sw/lib/source/neorv32_cpu.c
237,3 → 237,20
}
}
 
 
/**********************************************************************//**
* Switch from privilege mode MACHINE to privilege mode USER.
*
* @note This function requires the U extension to be implemented.
**************************************************************************/
void __attribute__((naked)) neorv32_cpu_goto_user_mode(void) {
 
register uint32_t mask = (1<<CPU_MSTATUS_MPP_H) | (1<<CPU_MSTATUS_MPP_L);
mask = ~mask;
asm volatile ("csrrc zero, mstatus, %[input_j]" : : [input_j] "r" (mask));
 
// return and switch to user mode
asm volatile ("csrw mepc, ra");
asm volatile ("mret");
}
 
/sw/lib/source/neorv32_rte.c
211,32 → 211,11
**************************************************************************/
static void __neorv32_rte_debug_exc_handler(void) {
 
neorv32_uart_printf("\n\n<< NEORV32 Runtime Environment >>\n");
// intro
neorv32_uart_printf("<RTE> ");
 
neorv32_uart_printf("System time: 0x%x_%x\n", neorv32_cpu_csr_read(CSR_TIMEH), neorv32_cpu_csr_read(CSR_TIME));
 
// cause
register uint32_t trap_cause = neorv32_cpu_csr_read(CSR_MCAUSE);
register uint32_t trap_addr = neorv32_cpu_csr_read(CSR_MEPC);
register uint32_t trap_inst;
 
asm volatile ("lh %[result], 0(%[input_i])" : [result] "=r" (trap_inst) : [input_i] "r" (trap_addr));
 
 
if (trap_cause & 0x80000000) {
neorv32_uart_printf("INTERRUPT");
}
else {
neorv32_uart_printf("EXCEPTION");
if ((trap_inst & 3) == 3) {
trap_addr -= 4;
}
else {
trap_addr -= 2;
}
}
neorv32_uart_printf(" at instruction address: 0x%x\n", trap_addr);
 
neorv32_uart_printf("Cause: ");
switch (trap_cause) {
case TRAP_CODE_I_MISALIGNED: neorv32_uart_printf("Instruction address misaligned"); break;
case TRAP_CODE_I_ACCESS: neorv32_uart_printf("Instruction access fault"); break;
257,18 → 236,21
default: neorv32_uart_printf("Unknown (0x%x)", trap_cause); break;
}
 
// fault address
neorv32_uart_printf("\nFaulting instruction (low half word): 0x%x", trap_inst);
// address
register uint32_t trap_addr = neorv32_cpu_csr_read(CSR_MEPC);
register uint32_t trap_inst;
 
if ((trap_inst & 3) != 3) {
neorv32_uart_printf(" (decompressed)\n");
asm volatile ("lh %[result], 0(%[input_i])" : [result] "=r" (trap_inst) : [input_i] "r" (trap_addr));
 
if ((trap_cause & 0x80000000) == 0) {
if ((trap_inst & 3) == 3) {
trap_addr -= 4;
}
else {
trap_addr -= 2;
}
}
 
neorv32_uart_printf("\nMTVAL: 0x%x\n", neorv32_cpu_csr_read(CSR_MTVAL));
 
neorv32_uart_printf("Trying to resume application @ 0x%x...", neorv32_cpu_csr_read(CSR_MEPC));
 
neorv32_uart_printf("\n<</NEORV32 Runtime Environment >>\n\n");
neorv32_uart_printf(" @0x%x, MTVAL=0x%x </RTE>", trap_addr, neorv32_cpu_csr_read(CSR_MTVAL));
}
 
 
326,11 → 308,14
}
neorv32_uart_printf("(0x%x)\n", tmp);
 
// Clock speed
neorv32_uart_printf("Clock speed: %u Hz\n", SYSINFO_CLK);
 
// Misc
neorv32_uart_printf("\n-- System --\n");
neorv32_uart_printf("Clock: %u Hz\n", SYSINFO_CLK);
 
 
// Memory configuration
neorv32_uart_printf("\n-- Memory Configuration --\n");
neorv32_uart_printf("\n-- Processor Memory Configuration --\n");
 
uint32_t size = SYSINFO_ISPACE_SIZE;
uint32_t base = SYSINFO_ISPACE_BASE;
353,7 → 338,8
__neorv32_rte_print_true_false(SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT));
 
// peripherals
neorv32_uart_printf("\n-- Peripherals --\n");
neorv32_uart_printf("\n-- Processor Peripherals --\n");
 
tmp = SYSINFO_FEATURES;
 
neorv32_uart_printf("GPIO: ");
/README.md
21,8 → 21,8
## Introduction
 
The **NEORV32 processor** is a customizable full-scale mikrocontroller-like processor system based on the RISC-V-compliant
`rv32i` NEORV32 CPU with optional `M`, `E`, `C` and `Zicsr` and `Zifencei` extensions. The CPU was built from scratch and
is compliant to the *Unprivileged ISA Specification Version 2.2* and a subset of the *Privileged Architecture
`rv32i` NEORV32 CPU with optional `M`, `E`, `C` and `U`, `Zicsr` and `Zifencei` extensions and optional physical memory protection (PMP).
The CPU was built from scratch and is compliant to the *Unprivileged ISA Specification Version 2.2* and a subset of the *Privileged Architecture
Specification Version 1.12-draft*.
 
The **processor** is intended as auxiliary processor within a larger SoC designs or as stand-alone
45,7 → 45,18
 
For more information take a look a the [![NEORV32 datasheet](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/figures/PDF_32.png) NEORV32 datasheet](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/NEORV32.pdf).
 
### Key Features
 
- RISC-V-compliant `rv32i` CPU with optional `C`, `E`, `M`, `U`, `Zicsr`, `rv32Zifencei` and PMP (physical memory protection) extensions
- GCC-based toolchain ([pre-compiled rv32i and rv32 etoolchains available](https://github.com/stnolting/riscv_gcc_prebuilt))
- Application compilation based on [GNU makefiles](https://github.com/stnolting/neorv32/blob/master/sw/example/blink_led/makefile)
- [Doxygen-based](https://github.com/stnolting/neorv32/blob/master/docs/doxygen_makefile_sw) documentation of the software framework: available on [GitHub pages](https://stnolting.github.io/neorv32/files.html)
- Detailed [datasheet](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/NEORV32.pdf) (pdf)
- Completely described in behavioral, platform-independent VHDL – no primitives, macros, etc.
- Fully synchronous design, no latches, no gated clocks
- Small hardware footprint and high operating frequency
- Highly configurable CPU and processor setup
 
### Design Principles
 
* From zero to main(): Completely open source and documented.
75,20 → 86,21
* `misa` CSR is read-only - no dynamic enabling/disabling of implemented CPU extensions during runtime
* `mcause` CSR is read-only
* The `[m]cycleh` and `[m]instreth` CSR counters are only 20-bit wide (in contrast to original 32-bit)
* The physical memory protection (**PMP**) only supports `NAPOT` mode and only up to 8 regions
 
 
### Custom CPU Extensions
 
The custom extensions are always enabled and are indicated via the `X` bit in the `misa` CSR.
 
* Four *fast interrupt* request channels with according control/status bits in `mie` and `mip` and custom exception codes in `mcause`
 
 
### To-Do / Wish List
 
- Add instructions how to use the NEORV32 CPU without the processor surroundings
- Add AXI / AXI-Lite bridges
- Option to use DSP-based multiplier in `M` extension (would be so much faster)
- Synthesis results for more platforms
- Implement user mode (`U` extension)
- Port Dhrystone benchmark
- Implement atomic operations (`A` extension) and floating-point operations (`F` extension)
- Maybe port an RTOS (like [Zephyr](https://github.com/zephyrproject-rtos/zephyr), [freeRTOS](https://www.freertos.org) or [RIOT](https://www.riot-os.org))
102,28 → 114,20
 
![neorv32 Overview](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/figures/neorv32_processor.png)
 
- RISC-V-compliant `rv32i` CPU with optional `C`, `E`, `M`, `Zicsr` and `rv32Zifencei` extensions
- GCC-based toolchain ([pre-compiled rv32i and rv32 etoolchains available](https://github.com/stnolting/riscv_gcc_prebuilt))
- Application compilation based on [GNU makefiles](https://github.com/stnolting/neorv32/blob/master/sw/example/blink_led/makefile)
- [Doxygen-based](https://github.com/stnolting/neorv32/blob/master/docs/doxygen_makefile_sw) documentation of the software framework: available on [GitHub pages](https://stnolting.github.io/neorv32/files.html)
- Detailed [datasheet](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/NEORV32.pdf) (pdf)
- Completely described in behavioral, platform-independent VHDL – no primitives, macros, etc.
- Fully synchronous design, no latches, no gated clocks
- Small hardware footprint and high operating frequency
- Highly customizable processor configuration
- _Optional_ processor-internal data and instruction memories (DMEM/IMEM)
- _Optional_ internal bootloader with UART console and automatic SPI flash boot option
- _Optional_ machine system timer (MTIME), RISC-V-compliant
- _Optional_ universal asynchronous receiver and transmitter (UART)
- _Optional_ 8/16/24/32-bit serial peripheral interface controller (SPI) with 8 dedicated chip select lines
- _Optional_ two wire serial interface controller (TWI), compatible to the I²C standard
- _Optional_ general purpose parallel IO port (GPIO), 16xOut & 16xIn, with pin-change interrupt
- _Optional_ 32-bit external bus interface, Wishbone b4 compliant (WISHBONE)
- _Optional_ watchdog timer (WDT)
- _Optional_ PWM controller with 4 channels and 8-bit duty cycle resolution (PWM)
- _Optional_ GARO-based true random number generator (TRNG)
- _Optional_ dummy device (DEVNULL) (can be used for *fast* simulation console output)
- System configuration information memory to check hardware configuration by software (SYSINFO)
Highly customizable processor configuration:
- Optional processor-internal data and instruction memories (DMEM/IMEM)
- Optional internal bootloader with UART console and automatic SPI flash boot option
- Optional machine system timer (MTIME), RISC-V-compliant
- Optional universal asynchronous receiver and transmitter (UART)
- Optional 8/16/24/32-bit serial peripheral interface controller (SPI) with 8 dedicated chip select lines
- Optional two wire serial interface controller (TWI), compatible to the I²C standard
- Optional general purpose parallel IO port (GPIO), 16xOut & 16xIn, with pin-change interrupt
- Optional 32-bit external bus interface, Wishbone b4 compliant (WISHBONE)
- Optional watchdog timer (WDT)
- Optional PWM controller with 4 channels and 8-bit duty cycle resolution (PWM)
- Optional GARO-based true random number generator (TRNG)
- Optional dummy device (DEVNULL) (can be used for *fast* simulation console output)
- System configuration information memory to check hardware configuration by software (SYSINFO)
 
### CPU Features
 
140,7 → 144,8
**General**:
* Modified Harvard architecture (separate CPU interfaces for data and instructions; single processor-bus via bus switch)
* Two stages in-order pipeline (FETCH, EXECUTE); each stage uses a multi-cycle processing scheme
* No hardware support of unaligned accesses - they will trigger and exception
* No hardware support of unaligned accesses - they will trigger an exception
* Privilege levels: `machine` mode, `user` mode (if enabled via `U` extension)
 
 
**RV32I base instruction set** (`I` extension):
178,19 → 183,27
* Store address misaligned
* Store access fault
* Environment call from M-mode (via `ecall` instruction)
* Machine timer interrupt `mti` (via MTIME unit)
* Machine external interrupt `mei` (via CLIC unit)
* Machine timer interrupt `mti` (via processor's MTIME unit)
* Machine software interrupt `msi` (via external signal)
* Machine external interrupt `mei` (via external signal)
* Four fast interrupt requests (custom extension)
 
**Privileged architecture / User mode** (`U` extension, requires `Zicsr` extension):
* Privilege levels: `M-mode` (Machine mode) + `U-Mode` (User mode)
 
**Privileged architecture / FENCE.I** (`Zifencei` extension):
* System instructions: `FENCE.I`
* System instructions: `FENCEI`
 
**Physical memory protection** (`PMP`, requires `Zicsr` extension):
* Additional machine CSRs: `pmpcfgx` `pmpaddrx`
 
 
## FPGA Implementation Results
 
This chapter shows exemplary implementation results of the NEORV32 processor for an **Intel Cyclone IV EP4CE22F17C6N FPGA** on
a DE0-nano board. The design was synthesized using **Intel Quartus Prime Lite 19.1** ("balanced implementation"). The timing
information is derived from the Timing Analyzer / Slow 1200mV 0C Model. If not otherwise specified, the default configuration
of the processor's generics is assumed. No constraints were used at all.
of the CPU's generics is assumed (no PMP). No constraints were used at all.
 
### CPU
 
229,7 → 242,7
### Exemplary FPGA Setups
 
Exemplary implementation results for different FPGA platforms. The processor setup uses *all provided peripherals*,
no external memory interface and only internal instruction and data memories. IMEM uses 16kB and DMEM uses 8kB memory space. The setup's top entity connects most of the
no external memory interface, no PMP and only internal instruction and data memories. IMEM uses 16kB and DMEM uses 8kB memory space. The setup's top entity connects most of the
processor's [top entity](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_top.vhd) signals
to FPGA pins - except for the Wishbone bus and the interrupt signals.
 
325,8 → 338,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Memory configuration: Instruction memory --
MEM_ISPACE_BASE : std_ulogic_vector(31 downto 0) := x"00000000"; -- base address of instruction memory space
MEM_ISPACE_SIZE : natural := 16*1024; -- total size of instruction memory space in byte
406,8 → 424,13
CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension?
CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M : boolean := false; -- implement muld/div extension?
CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr : boolean := true; -- implement CSR system?
CPU_EXTENSION_RISCV_Zifencei : boolean := true; -- implement instruction stream sync.?
-- Physical Memory Protection (PMP) --
PMP_USE : boolean := false; -- implement PMP?
PMP_NUM_REGIONS : natural := 4; -- number of regions (max 16)
PMP_GRANULARITY : natural := 15; -- region granularity (1=8B, 2=16B, 3=32B, ...) default is 64k
-- Bus Interface --
BUS_TIMEOUT : natural := 15 -- cycles after which a valid bus access will timeout
);
469,8 → 492,8
To build the toolchain by yourself, follow the official [build instructions](https://github.com/riscv/riscv-gnu-toolchain.
Make sure to use the `ilp32` or `ilp32e` ABI.
 
Alternatively, you can download a prebuilt toolchain. I have uploaded the toolchain(s) I am using to GitHub. This toolchain
has been compiled on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually). Download the toolchain of choice:
**Alternatively**, you can download a prebuilt toolchain. I have uploaded the toolchains I am using to GitHub. These toolchains
were compiled on a 64-bit x86 Ubuntu 20.04 LTS (Ubuntu on Windows, actually). Download the toolchain of choice:
 
[https://github.com/stnolting/riscv_gcc_prebuilt](https://github.com/stnolting/riscv_gcc_prebuilt)
 

powered by: WebSVN 2.1.0

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