URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/rtl/core
- from Rev 37 to Rev 38
- ↔ Reverse comparison
Rev 37 → Rev 38
/neorv32_cpu.vhd
10,6 → 10,8
-- # * neorv32_cpu_decompressor.vhd - Compressed instructions decoder # |
-- # * neorv32_cpu_regfile.vhd - Data register file # |
-- # # |
-- # * neorv32_package.vhd - Main CPU/processor package file # |
-- # # |
-- # Check out the processor's data sheet for more information: docs/NEORV32.pdf # |
-- # ********************************************************************************************* # |
-- # BSD 3-Clause License # |
159,6 → 161,8
assert not ((PMP_NUM_REGIONS > pmp_max_r_c) and (PMP_USE = true)) report "NEORV32 CPU CONFIG ERROR! Number of PMP regions out of valid range." severity error; |
-- PMP granulartiy -- |
assert not (((PMP_GRANULARITY < 1) or (PMP_GRANULARITY > 32)) and (PMP_USE = true)) report "NEORV32 CPU CONFIG ERROR! Invalid PMP granulartiy (0 < PMP_GRANULARITY < 33)." severity error; |
-- Instruction prefetch buffer size -- |
assert not (is_power_of_two_f(ipb_entries_c) = false) report "NEORV32 CPU CONFIG ERROR! Number of entries in instruction prefetch buffer <ipb_entries_c> has to be a power of two." severity error; |
|
|
-- Control Unit --------------------------------------------------------------------------- |
289,7 → 293,7
if (CPU_EXTENSION_RISCV_M = true) generate |
neorv32_cpu_cp_muldiv_inst: neorv32_cpu_cp_muldiv |
generic map ( |
FAST_MUL_EN => FAST_MUL_EN -- use DSPs for faster multiplication |
FAST_MUL_EN => FAST_MUL_EN -- use DSPs for faster multiplication |
) |
port map ( |
-- global control -- |
313,7 → 317,7
end generate; |
|
|
-- Co-Processor 1: Not implemented yet ---------------------------------------------------- |
-- Co-Processor 1: Not implemented (yet) -------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
-- control: ctrl cp1_start |
-- inputs: rs1 rs2 alu_cmp alu_opb |
321,7 → 325,7
cp1_valid <= '0'; |
|
|
-- Co-Processor 2: Not implemented yet ---------------------------------------------------- |
-- Co-Processor 2: Not implemented (yet) -------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
-- control: ctrl cp2_start |
-- inputs: rs1 rs2 alu_cmp alu_opb |
329,7 → 333,7
cp2_valid <= '0'; |
|
|
-- Co-Processor 3: Not implemented yet ---------------------------------------------------- |
-- Co-Processor 3: Not implemented (yet) -------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
-- control: ctrl cp3_start |
-- inputs: rs1 rs2 alu_cmp alu_opb |
350,6 → 354,7
port map ( |
-- global control -- |
clk_i => clk_i, -- global clock, rising edge |
rstn_i => rstn_i, -- global reset, low-active, async |
ctrl_i => ctrl, -- main control bus |
-- cpu instruction fetch interface -- |
fetch_pc_i => fetch_pc, -- PC for instruction fetch |
/neorv32_cpu_bus.vhd
52,6 → 52,7
port ( |
-- global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic := '0'; -- global reset, low-active, async |
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus |
-- cpu instruction fetch interface -- |
fetch_pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- PC for instruction fetch |
289,9 → 290,14
|
-- Instruction Fetch Arbiter -------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
ifetch_arbiter: process(clk_i) |
ifetch_arbiter: process(rstn_i, clk_i) |
begin |
if rising_edge(clk_i) then |
if (rstn_i = '0') then |
i_arbiter.rd_req <= '0'; |
i_arbiter.err_align <= '0'; |
i_arbiter.err_bus <= '0'; |
i_arbiter.timeout <= (others => '0'); |
elsif rising_edge(clk_i) then |
-- instruction fetch request -- |
if (i_arbiter.rd_req = '0') then -- idle |
i_arbiter.rd_req <= ctrl_i(ctrl_bus_if_c); |
333,9 → 339,15
|
-- Data Access Arbiter -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
data_access_arbiter: process(clk_i) |
data_access_arbiter: process(rstn_i, clk_i) |
begin |
if rising_edge(clk_i) then |
if (rstn_i = '0') then |
d_arbiter.wr_req <= '0'; |
d_arbiter.rd_req <= '0'; |
d_arbiter.err_align <= '0'; |
d_arbiter.err_bus <= '0'; |
d_arbiter.timeout <= (others => '0'); |
elsif rising_edge(clk_i) then |
-- data access request -- |
if (d_arbiter.wr_req = '0') and (d_arbiter.rd_req = '0') then -- idle |
d_arbiter.wr_req <= ctrl_i(ctrl_bus_wr_c); |
/neorv32_cpu_control.vhd
521,11 → 521,11
|
-- Immediate Generator -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
imm_gen: process(clk_i) |
imm_gen: process(execute_engine.i_reg, clk_i) |
variable opcode_v : std_ulogic_vector(6 downto 0); |
begin |
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; |
if rising_edge(clk_i) then |
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; |
case opcode_v is -- save some bits here, LSBs are always 11 for rv32 |
when opcode_store_c => -- S-immediate |
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension |
1233,7 → 1233,7
|
|
-- **************************************************************************************************************************** |
-- Exception and Interrupt Control |
-- Exception and Interrupt (= Trap) Control |
-- **************************************************************************************************************************** |
|
|
1305,7 → 1305,7
trap_ctrl.cause_nxt <= (others => '0'); |
trap_ctrl.irq_ack_nxt <= (others => '0'); |
|
-- the following traps are caused by asynchronous exceptions (-> interrupts) |
-- the following traps are caused by *asynchronous* exceptions (= interrupts) |
-- here we do need a specific acknowledge mask since several sources can trigger at once |
|
-- interrupt: 1.11 machine external interrupt -- |
1345,45 → 1345,45
trap_ctrl.irq_ack_nxt(interrupt_firq_3_c) <= '1'; |
|
|
-- the following traps are caused by synchronous exceptions |
-- the following traps are caused by *synchronous* exceptions (= classic exceptions) |
-- here we do not need a specific acknowledge mask since only one exception (the one |
-- with highest priority) can trigger at once |
-- with highest priority) is evaluated at once |
|
-- trap/fault: 0.1 instruction access fault -- |
-- exception: 0.1 instruction access fault -- |
elsif (trap_ctrl.exc_buf(exception_iaccess_c) = '1') then |
trap_ctrl.cause_nxt <= trap_iba_c; |
|
-- trap/fault: 0.2 illegal instruction -- |
-- exception: 0.2 illegal instruction -- |
elsif (trap_ctrl.exc_buf(exception_iillegal_c) = '1') then |
trap_ctrl.cause_nxt <= trap_iil_c; |
|
-- trap/fault: 0.0 instruction address misaligned -- |
-- exception: 0.0 instruction address misaligned -- |
elsif (trap_ctrl.exc_buf(exception_ialign_c) = '1') then |
trap_ctrl.cause_nxt <= trap_ima_c; |
|
|
-- trap/fault: 0.11 environment call from M-mode -- |
-- exception: 0.11 environment call from M-mode -- |
elsif (trap_ctrl.exc_buf(exception_m_envcall_c) = '1') then |
trap_ctrl.cause_nxt <= trap_menv_c; |
|
-- trap/fault: 0.3 breakpoint -- |
-- exception: 0.3 breakpoint -- |
elsif (trap_ctrl.exc_buf(exception_break_c) = '1') then |
trap_ctrl.cause_nxt <= trap_brk_c; |
|
|
-- trap/fault: 0.6 store address misaligned - |
-- exception: 0.6 store address misaligned - |
elsif (trap_ctrl.exc_buf(exception_salign_c) = '1') then |
trap_ctrl.cause_nxt <= trap_sma_c; |
|
-- trap/fault: 0.4 load address misaligned -- |
-- exception: 0.4 load address misaligned -- |
elsif (trap_ctrl.exc_buf(exception_lalign_c) = '1') then |
trap_ctrl.cause_nxt <= trap_lma_c; |
|
-- trap/fault: 0.7 store access fault -- |
-- exception: 0.7 store access fault -- |
elsif (trap_ctrl.exc_buf(exception_saccess_c) = '1') then |
trap_ctrl.cause_nxt <= trap_sbe_c; |
|
-- trap/fault: 0.5 load access fault -- |
-- exception: 0.5 load access fault -- |
elsif (trap_ctrl.exc_buf(exception_laccess_c) = '1') then |
trap_ctrl.cause_nxt <= trap_lbe_c; |
|
1407,11 → 1407,11
-- CSR operand source -- |
if (execute_engine.i_reg(instr_funct3_msb_c) = '1') then -- immediate |
csr_operand_v := (others => '0'); |
csr_operand_v(4 downto 0) := execute_engine.i_reg(19 downto 15); |
csr_operand_v(4 downto 0) := execute_engine.i_reg(19 downto 15); -- uimm5 |
else -- register |
csr_operand_v := rs1_i; |
end if; |
-- "mini ALU" for CSR update operations -- |
-- tiny ALU for CSR access operations -- |
case execute_engine.i_reg(instr_funct3_lsb_c+1 downto instr_funct3_lsb_c) is |
when "10" => csr.wdata <= csr.rdata or csr_operand_v; -- CSRRS(I) |
when "11" => csr.wdata <= csr.rdata and (not csr_operand_v); -- CSRRC(I) |
1680,7 → 1680,9
csr.rdata(00) <= '0'; -- A CPU extension |
csr.rdata(01) <= '0'; -- B CPU extension |
csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension |
csr.rdata(03) <= '0'; -- D CPU extension |
csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension |
csr.rdata(05) <= '0'; -- F CPU extension |
csr.rdata(08) <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E) |
csr.rdata(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension |
csr.rdata(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension |
/neorv32_imem.vhd
57,7 → 57,6
rden_i : in std_ulogic; -- read enable |
wren_i : in std_ulogic; -- write enable |
ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable |
upen_i : in std_ulogic; -- update enable |
addr_i : in std_ulogic_vector(31 downto 0); -- address |
data_i : in std_ulogic_vector(31 downto 0); -- data in |
data_o : out std_ulogic_vector(31 downto 0); -- data out |
167,7 → 166,7
rdata(31 downto 24) <= imem_file_rom_hh(to_integer(unsigned(addr))); |
|
elsif (BOOTLOADER_USE = true) then -- implement IMEM as non-initialized RAM |
if (wren_i = '1') and (upen_i = '1') then |
if (wren_i = '1') then |
if (ben_i(0) = '1') then |
imem_file_ram_ll(to_integer(unsigned(addr))) <= data_i(07 downto 00); |
end if; |
187,7 → 186,7
rdata(31 downto 24) <= imem_file_ram_hh(to_integer(unsigned(addr))); |
|
else -- implement IMEM as PRE-INITIALIZED RAM |
if (wren_i = '1') and (upen_i = '1') then |
if (wren_i = '1') then |
if (ben_i(0) = '1') then |
imem_file_init_ram_ll(to_integer(unsigned(addr))) <= data_i(07 downto 00); |
end if; |
/neorv32_package.vhd
42,7 → 42,7
-- ------------------------------------------------------------------------------------------- |
constant ispace_base_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- default instruction memory address space base address |
constant dspace_base_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- default data memory address space base address |
constant bus_timeout_c : natural := 127; -- cycles after which a valid bus access will timeout and trigger an access exception |
constant bus_timeout_c : natural := 127; -- cycles after which an *unacknwoledged* bus access will timeout and trigger an access exception |
constant wb_pipe_mode_c : boolean := false; -- false: classic/standard wishbone mode, true: pipelined wishbone mode |
constant ipb_entries_c : natural := 2; -- entries in instruction prefetch buffer, must be a power of 2, default=2 |
constant rf_r0_is_reg_c : boolean := true; -- reg_file.r0 is a physical register that has to be initialized to zero by the CPU HW |
50,7 → 50,7
-- Architecture Constants ----------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant data_width_c : natural := 32; -- data width - do not change! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040700"; -- no touchy! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040702"; -- no touchy! |
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED! |
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off! |
|
762,6 → 762,7
port ( |
-- global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic := '0'; -- global reset, low-active, async |
ctrl_i : in std_ulogic_vector(ctrl_width_c-1 downto 0); -- main control bus |
-- cpu instruction fetch interface -- |
fetch_pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- PC for instruction fetch |
880,7 → 881,6
rden_i : in std_ulogic; -- read enable |
wren_i : in std_ulogic; -- write enable |
ben_i : in std_ulogic_vector(03 downto 0); -- byte write enable |
upen_i : in std_ulogic; -- update enable |
addr_i : in std_ulogic_vector(31 downto 0); -- address |
data_i : in std_ulogic_vector(31 downto 0); -- data in |
data_o : out std_ulogic_vector(31 downto 0); -- data out |
1361,8 → 1361,10
-- ------------------------------------------------------------------------------------------- |
function is_power_of_two_f(input : natural) return boolean is |
begin |
if ((input / 2) /= 0) and ((input mod 2) = 0) then |
if (input = 1) then -- 2^0 |
return true; |
elsif ((input / 2) /= 0) and ((input mod 2) = 0) then |
return true; |
else |
return false; |
end if; |
/neorv32_top.vhd
463,7 → 463,6
rden_i => p_bus.re, -- read enable |
wren_i => p_bus.we, -- write enable |
ben_i => p_bus.ben, -- byte write enable |
upen_i => '1', -- update enable |
addr_i => p_bus.addr, -- address |
data_i => p_bus.wdata, -- data in |
data_o => imem_rdata, -- data out |
/neorv32_wishbone.vhd
101,7 → 101,7
signal wb_access : std_ulogic; |
|
-- bus arbiter |
type ctrl_state_t is (IDLE, BUSY, CANCELED); |
type ctrl_state_t is (IDLE, BUSY, CANCELED, RESYNC); |
type ctrl_t is record |
state : ctrl_state_t; |
state_prev : ctrl_state_t; |
204,7 → 204,7
ctrl.state <= IDLE; |
end if; |
|
when CANCELED => -- |
when CANCELED => -- wait for cycle to be completed either by peripheral or by timeout (ignore result of transfer) |
-- ------------------------------------------------------------ |
ctrl.wr_req <= ctrl.wr_req or wren_i; -- buffer new request |
ctrl.rd_req <= ctrl.rd_req or rden_i; -- buffer new request |
212,6 → 212,12
-- or wait for a timeout and force termination |
ctrl.timeout <= std_ulogic_vector(unsigned(ctrl.timeout) - 1); -- timeout counter |
if (wb_ack_i = '1') or (or_all_f(ctrl.timeout) = '0') then |
ctrl.state <= RESYNC; |
end if; |
|
when RESYNC => -- make sure transfer is done! |
-- ------------------------------------------------------------ |
if (wb_ack_i = '0') then |
ctrl.state <= IDLE; |
end if; |
|
241,7 → 247,7
wb_cyc_o <= cyc_int; |
|
stb_int <= '1' when ((ctrl.state = BUSY) and (ctrl.state_prev = IDLE)) else '0'; |
cyc_int <= '0' when (ctrl.state = IDLE) else '1'; |
cyc_int <= '0' when ((ctrl.state = IDLE) or (ctrl.state = RESYNC)) else '1'; |
|
|
end neorv32_wishbone_rtl; |