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 25 to Rev 26
- ↔ Reverse comparison
Rev 25 → Rev 26
/docs/NEORV32.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/rtl/core/neorv32_cfu.vhd
142,7 → 142,7
begin |
if rising_edge(clk_i) then |
-- transfer ack -- |
ack_o <= wr_en or rd_en; |
ack_o <= wr_en or rd_en; -- required for the CPU to check the CFU is answering a bus read OR write request |
|
-- write access -- |
if (wr_en = '1') then |
163,15 → 163,13
-- read access -- |
data_o <= (others => '0'); -- make sure the output is zero if there is no actual read access |
if (rd_en = '1') then |
if (addr = cfu_reg0_addr_c) then |
data_o <= cfu_reg_out(0); |
elsif (addr = cfu_reg1_addr_c) then |
data_o <= cfu_reg_out(1); |
elsif (addr = cfu_reg2_addr_c) then |
data_o <= cfu_reg_out(2); |
else -- addr = cfu_reg3_addr_c |
data_o <= cfu_reg_out(3); |
end if; |
case addr is |
when cfu_reg0_addr_c => data_o <= cfu_reg_out(0); |
when cfu_reg1_addr_c => data_o <= cfu_reg_out(1); |
when cfu_reg2_addr_c => data_o <= cfu_reg_out(2); |
when cfu_reg3_addr_c => data_o <= cfu_reg_out(3); |
when others => data_o <= (others => '0'); |
end case; |
end if; |
end if; |
end process rw_access; |
/rtl/core/neorv32_cpu_alu.vhd
120,23 → 120,23
-- ------------------------------------------------------------------------------------------- |
input_op_mux: process(ctrl_i, csr_i, pc2_i, rs1_i, rs2_i, imm_i) |
begin |
-- opa (first ALU input operand) -- |
-- operand a (first ALU input operand) -- |
case ctrl_i(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) is |
when "00" => opa <= rs1_i; |
when "01" => opa <= pc2_i; |
when others => opa <= csr_i; |
end case; |
-- opb (second ALU input operand) -- |
-- operand b (second ALU input operand) -- |
if (ctrl_i(ctrl_alu_opb_mux_c) = '0') then |
opb <= rs2_i; |
else |
opb <= imm_i; |
end if; |
-- opc (second operand for comparison and SUB) -- |
-- operand c (third ALU input operand for comparison and SUB) -- |
if (ctrl_i(ctrl_alu_opc_mux_c) = '0') then |
opc <= rs2_i; |
else |
opc <= imm_i; |
else |
opc <= rs2_i; |
end if; |
end process input_op_mux; |
|
150,10 → 150,10
cmp_less <= cmp_sub(cmp_sub'left); -- carry (borrow) indicates a "less" |
sub_res <= cmp_sub(data_width_c-1 downto 0); -- use the less-comparator also for SUB operations |
|
-- equal (x = y) -- |
cmp_equal <= '1' when (rs1_i = opc) else '0'; |
-- equal (for branch check only) -- |
cmp_equal <= '1' when (rs1_i = rs2_i) else '0'; |
|
-- output for branch condition evaluation - |
-- output for branch condition evaluation -- |
cmp_o(alu_cmp_equal_c) <= cmp_equal; |
cmp_o(alu_cmp_less_c) <= cmp_less; |
|
161,7 → 161,7
-- Binary Adder --------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
add_res <= std_ulogic_vector(unsigned(opa) + unsigned(opb)); |
add_o <= add_res; -- direct output |
add_o <= add_res; -- direct output (for PC modification) |
|
|
-- Iterative Shifter Unit ----------------------------------------------------------------- |
/rtl/core/neorv32_cpu_control.vhd
621,32 → 621,28
ctrl_nxt(ctrl_bus_size_lsb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- transfer size lsb (00=byte, 01=half-word) |
ctrl_nxt(ctrl_bus_size_msb_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- transfer size msb (10=word, 11=?) |
ctrl_nxt(ctrl_cp_cmd2_c downto ctrl_cp_cmd0_c) <= execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c); -- CP operation |
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (MULDIV) implemented yet |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- default ALU operation: ADD(I) |
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- only CP0 (=MULDIV) implemented yet |
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ctrl(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c); -- keep rd addr |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- keep rs1 addr |
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c); -- keep rs2 addr |
|
-- is immediate operation? -- |
alu_immediate_v := '0'; |
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') then |
alu_immediate_v := '1'; |
end if; |
-- is immediate ALU operation? -- |
alu_immediate_v := not execute_engine.i_reg(instr_opcode_msb_c-1); |
|
-- is rs1 = r0? -- |
rs1_is_r0_v := '0'; |
if (execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then |
rs1_is_r0_v := '1'; |
end if; |
-- is rs1 == r0? -- |
rs1_is_r0_v := not or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c)); |
|
|
-- state machine -- |
case execute_engine.state is |
|
when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) ((and to init r0 with zero if it is a physical register)) |
-- ------------------------------------------------------------ |
-- set reg_file's r0 to zero -- |
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero? |
-- set reg_file.r0 to zero |
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= (others => '0'); -- rd addr = r0 |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (results zero since there is no valid CSR_read request) |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output (hacky! results zero since there is no valid CSR_read request) |
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- allow write access to r0 |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
end if; |
700,25 → 696,24
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA |
ctrl_nxt(ctrl_alu_opb_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations |
ctrl_nxt(ctrl_alu_opc_mux_c) <= not alu_immediate_v; |
ctrl_nxt(ctrl_alu_opc_mux_c) <= alu_immediate_v; -- use IMM as ALU.OPC for immediate operations (SLT(I)(U)) |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result |
|
-- actual ALU operation (re-coding) -- |
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is |
when funct3_subadd_c => -- ADD(I) / SUB |
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 => SUB |
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I) |
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I) |
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I) |
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I) |
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I) |
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I) |
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I) |
when others => -- ADD(I) / SUB |
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not an immediate op and funct7.6 set => SUB |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_sub_c; -- SUB |
else |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- ADD(I) |
end if; |
when funct3_sll_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SLL(I) |
when funct3_slt_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLT(I) |
when funct3_sltu_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_slt_c; -- SLTU(I) |
when funct3_xor_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_xor_c; -- XOR(I) |
when funct3_sr_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c; -- SRL(I) / SRA(I) |
when funct3_or_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- OR(I) |
when funct3_and_c => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_and_c; -- AND(I) |
when others => ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= (others => '0'); -- undefined |
end case; |
|
-- cp access? -- |
732,7 → 727,7
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation? |
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (execute_engine.i_reg(instr_funct7_lsb_c) = '1')) then -- MULDIV? |
execute_engine.state_nxt <= ALU_WAIT; |
else |
else -- single cycle ALU operation |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
execute_engine.state_nxt <= DISPATCH; |
end if; |
741,7 → 736,7
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- ALU.OPA = PC (for AUIPC only) |
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI |
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- ALU.OPA = CSR = 0 (hacky: csr.result is 0 since there was no csr_read_request) |
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '1'; -- ALU.OPA = CSR = 0 (hacky: csr.result is 0 since there is no csr_read_request) |
end if; |
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_add_c; -- actual ALU operation = ADD |
760,9 → 755,9
|
when opcode_branch_c => -- branch instruction |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA |
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB |
ctrl_nxt(ctrl_alu_opc_mux_c) <= '1'; -- use RS2 as ALU.OPC |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA (branch target address base) |
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset) |
ctrl_nxt(ctrl_alu_opc_mux_c) <= '0'; -- use RS2 as ALU.OPC (for branch condition check) |
execute_engine.state_nxt <= BRANCH; |
|
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register) |
783,21 → 778,27
|
when opcode_fence_c => -- fence operations |
-- ------------------------------------------------------------ |
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCE.I |
fetch_engine.reset <= '1'; |
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification |
execute_engine.pc_nxt <= execute_engine.next_pc; -- "refetch" next instruction (only relevant for fence.i) |
ctrl_nxt(ctrl_bus_fencei_c) <= '1'; |
-- foe simplicity: internally, fence and fence.i perform the same operations ;) |
-- FENCE.I -- |
if (CPU_EXTENSION_RISCV_Zifencei = true) then |
execute_engine.pc_nxt <= execute_engine.next_pc; -- "refetch" next instruction |
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification |
fetch_engine.reset <= '1'; |
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fencei_c(0)) then |
ctrl_nxt(ctrl_bus_fencei_c) <= '1'; |
end if; |
end if; |
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then -- FENCE |
-- FENCE -- |
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then |
ctrl_nxt(ctrl_bus_fence_c) <= '1'; |
end if; |
-- |
execute_engine.state_nxt <= SYS_WAIT; |
|
when opcode_syscsr_c => -- system/csr access |
-- ------------------------------------------------------------ |
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid access |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= (others => '0'); -- set rs1_addr to r0 (zero) |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= (others => '0'); -- set rs1_addr to r0 (zero) (for CSR mod) |
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ctrl(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- copy rs1_addr to rs2_addr (for CSR mod) |
-- |
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system |
839,7 → 840,7
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR |
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) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access |
when others => -- CSRRC(I) |
when others => -- CSRRC(I) -- FIXME?! |
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "10"; -- OPA = CSR |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_bclr_c; -- actual ALU operation = bit clear |
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access |
847,7 → 848,7
-- RF write back -- |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "11"; -- RF input = CSR output |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
execute_engine.state_nxt <= DISPATCH; -- FIXME? should be SYS_WAIT? have another cycle to let side-effects kick in |
execute_engine.state_nxt <= SYS_WAIT; -- have another cycle to let side-effects kick in |
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish |
-- ------------------------------------------------------------ |
894,7 → 895,7
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "01"; -- RF input = memory input (only relevant for LOAD) |
if (ma_load_i = '1') or (be_load_i = '1') or (ma_store_i = '1') or (be_store_i = '1') then -- abort if exception |
execute_engine.state_nxt <= SYS_WAIT; |
elsif (bus_d_wait_i = '0') then -- wait here for bus to finish transaction |
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction |
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') then -- LOAD |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
end if; |
916,7 → 917,7
|
-- Illegal CSR Access Check --------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
invalid_csr_access_check: process(execute_engine, csr.privilege) |
invalid_csr_access_check: process(execute_engine.i_reg, csr.privilege) |
variable is_m_mode_v : std_ulogic; |
begin |
-- are we in machine mode? -- |
930,7 → 931,7
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"305" => csr_acc_valid <= is_m_mode_v; -- mtvec |
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 |
975,7 → 976,7
|
-- Illegal Instruction Check -------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
illegal_instruction_check: process(execute_engine, csr, ctrl_nxt, csr_acc_valid) |
illegal_instruction_check: process(execute_engine, csr_acc_valid) |
begin |
-- illegal instructions are checked in the EXECUTE stage |
-- the execute engine will only commit valid instructions |
1451,10 → 1452,10
csr.mtval <= (others => '0'); -- mtval is zero for interrupts |
else -- for EXCEPTIONS (according to their priority) |
csr.mepc <= execute_engine.last_pc(data_width_c-1 downto 1) & '0'; -- this is the LAST pc = last executed instruction |
if (trap_ctrl.cause(4 downto 0) = trap_iba_c(4 downto 0)) or -- instr access error OR |
(trap_ctrl.cause(4 downto 0) = trap_ima_c(4 downto 0)) or -- misaligned instruction OR |
if (trap_ctrl.cause(4 downto 0) = trap_iba_c(4 downto 0)) or -- instruction access error OR |
(trap_ctrl.cause(4 downto 0) = trap_ima_c(4 downto 0)) or -- misaligned instruction address OR |
(trap_ctrl.cause(4 downto 0) = trap_brk_c(4 downto 0)) or -- breakpoint OR |
(trap_ctrl.cause(4 downto 0) = trap_menv_c(4 downto 0)) then -- env call OR |
(trap_ctrl.cause(4 downto 0) = trap_menv_c(4 downto 0)) then -- environment call |
csr.mtval <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- address of faulting instruction |
elsif (trap_ctrl.cause(4 downto 0) = trap_iil_c(4 downto 0)) then -- illegal instruction |
csr.mtval <= execute_engine.i_reg; -- faulting instruction itself |
1667,9 → 1668,9
csr_rdata_o <= x"000" & csr.minstreth(19 downto 0); -- only the lowest 20 bit! |
|
-- machine information registers -- |
when x"f11" => -- R/-: mvendorid |
when x"f11" => -- R/-: mvendorid - vendor ID |
csr_rdata_o <= (others => '0'); -- not assigned |
when x"f12" => -- R/-: marchid |
when x"f12" => -- R/-: marchid - architecture ID |
csr_rdata_o <= (others => '0'); -- not assigned |
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32 version |
csr_rdata_o <= hw_version_c; |
/rtl/core/neorv32_mtime.vhd
147,16 → 147,14
data_o <= mtime_hi; |
when mtime_cmp_lo_addr_c => -- mtimecmp LOW |
data_o <= mtimecmp_lo; |
when mtime_cmp_hi_addr_c => -- mtimecmp HIGH |
when others => -- mtime_cmp_hi_addr_c - mtimecmp HIGH |
data_o <= mtimecmp_hi; |
when others => |
data_o <= (others => '0'); |
end case; |
end if; |
end if; |
end process rd_access; |
|
-- time output for cpu -- |
-- system time output for cpu -- |
time_o <= mtime_hi & mtime_lo(31 downto 00); |
|
|
/rtl/core/neorv32_package.vhd
41,7 → 41,7
-- Architecture Constants/Configuration --------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant data_width_c : natural := 32; -- data width - FIXED! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040302"; -- no touchy! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040303"; -- no touchy! |
constant pmp_max_r_c : natural := 8; -- max PMP regions - FIXED! |
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 |
65,8 → 65,8
|
-- General Address Space Layout ----------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant ispace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"00000000"; -- instruction memory space base address |
constant dspace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"80000000"; -- data memory space base address |
constant ispace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"00000000"; -- default instruction memory space base address |
constant dspace_base_c : std_ulogic_vector(data_width_c-1 downto 0) := x"80000000"; -- default data memory space base address |
|
-- Processor-Internal Address Space Layout ------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
186,7 → 186,7
constant ctrl_alu_opa_mux_lsb_c : natural := 22; -- operand A select lsb (00=rs1, 01=PC) |
constant ctrl_alu_opa_mux_msb_c : natural := 23; -- operand A select msb (1-=CSR) |
constant ctrl_alu_opb_mux_c : natural := 24; -- operand B select (0=rs2, 1=IMM) |
constant ctrl_alu_opc_mux_c : natural := 25; -- operand C select (0=IMM, 1=rs2) |
constant ctrl_alu_opc_mux_c : natural := 25; -- operand C select (0=rs2, 1=IMM) |
constant ctrl_alu_unsigned_c : natural := 26; -- is unsigned ALU operation |
constant ctrl_alu_shift_dir_c : natural := 27; -- shift direction (0=left, 1=right) |
constant ctrl_alu_shift_ar_c : natural := 28; -- is arithmetic shift |
200,11 → 200,11
constant ctrl_bus_mdo_we_c : natural := 35; -- memory data out register write enable |
constant ctrl_bus_mdi_we_c : natural := 36; -- memory data in register write enable |
constant ctrl_bus_unsigned_c : natural := 37; -- is unsigned load |
constant ctrl_bus_ierr_ack_c : natural := 38; -- acknowledge instruction fetch bus exception |
constant ctrl_bus_derr_ack_c : natural := 39; -- acknowledge data access bus exception |
constant ctrl_bus_ierr_ack_c : natural := 38; -- acknowledge instruction fetch bus exceptions |
constant ctrl_bus_derr_ack_c : natural := 39; -- acknowledge data access bus exceptions |
constant ctrl_bus_fence_c : natural := 40; -- executed fence operation |
constant ctrl_bus_fencei_c : natural := 41; -- executed fencei operation |
-- co-processor -- |
-- co-processors -- |
constant ctrl_cp_use_c : natural := 42; -- is cp operation |
constant ctrl_cp_id_lsb_c : natural := 43; -- cp select ID lsb |
constant ctrl_cp_id_msb_c : natural := 44; -- cp select ID msb |
/rtl/core/neorv32_trng.vhd
104,7 → 104,6
|
-- access control -- |
signal acc_en : std_ulogic; -- module access enable |
signal addr : std_ulogic_vector(31 downto 0); -- access address |
signal wren : std_ulogic; -- full word write enable |
signal rden : std_ulogic; -- read enable |
|
140,7 → 139,6
-- Access Control ------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0'; |
addr <= trng_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned |
wren <= acc_en and wren_i; |
rden <= acc_en and rden_i; |
|
/sw/lib/include/neorv32.h
443,7 → 443,7
**************************************************************************/ |
/**@{*/ |
/** TRNG control/data register (r/w) */ |
#define TRNG_CT (*(IO_REG32 0xFFFFFFC0UL)) |
#define TRNG_CT (*(IO_REG32 0xFFFFFFC0UL)) |
|
/** TRNG control/data register bits */ |
enum NEORV32_TRNG_CT_enum { |
529,6 → 529,7
#include "neorv32_rte.h" |
|
// io/peripheral devices |
#include "neorv32_cfu.h" |
#include "neorv32_gpio.h" |
#include "neorv32_mtime.h" |
#include "neorv32_pwm.h" |
/sw/lib/include/neorv32_cfu.h
0,0 → 1,53
// ################################################################################################# |
// # << NEORV32: neorv32_cfu.h - Custom Functions Unit (CFU) HW Driver >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_cfu.h |
* @author Stephan Nolting |
* @brief Custom Functions Unit (CFU) HW driver header file. |
* |
* @warning There are no "real" CFU driver functions available here, because these functions are defined by the actual hardware. |
* @warning Hence, the CFU designer has to provide the actual driver functions. |
* |
* @note These functions should only be used if the CFU was synthesized (IO_CFU_USE = true). |
**************************************************************************/ |
|
#ifndef neorv32_cfu_h |
#define neorv32_cfu_h |
|
// prototypes |
int neorv32_cfu_available(void); |
|
#endif // neorv32_cfu_h |
/sw/lib/source/neorv32_cfu.c
0,0 → 1,64
// ################################################################################################# |
// # << NEORV32: neorv32_cfu.c - Custom Functions Unit (CFU) HW Driver >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file neorv32_cfu.c |
* @author Stephan Nolting |
* @brief Custom functions unit (CFU) HW driver source file. |
* |
* @warning There are no "real" CFU driver functions available here, because these functions are defined by the actual hardware. |
* @warning Hence, the CFU designer has to provide the actual driver functions. |
* |
* @note These functions should only be used if the CFU was synthesized (IO_CFU_USE = true). |
**************************************************************************/ |
|
#include "neorv32.h" |
#include "neorv32_cfu.h" |
|
|
/**********************************************************************//** |
* Check if CFU unit was synthesized. |
* |
* @return 0 if CFU was not synthesized, 1 if CFU is available. |
**************************************************************************/ |
int neorv32_cfu_available(void) { |
|
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_IO_CFU)) { |
return 1; |
} |
else { |
return 0; |
} |
} |
/sw/lib/source/neorv32_gpio.c
137,7 → 137,7
* |
* @note The pin-change IRQ will trigger on any transition (rising and falling edge) for any enabled input pin. |
* |
* @param[in] pin_en Mask to select which input pins can cause a pin-change IRQ (32-bit), 1 = pin enabled. |
* @param[in] pin_sel Mask to select which input pins can cause a pin-change IRQ (32-bit), 1 = pin enabled. |
**************************************************************************/ |
void neorv32_gpio_pin_change_config(uint32_t pin_sel) { |
|
/README.md
124,7 → 124,7
![neorv32 Overview](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/figures/neorv32_processor.png) |
|
The NEORV32 Processor provides a full-scale microcontroller-like SoC based on the NEORV32 CPU. The setup |
is highly customizable via the processor top's generics. |
is highly customizable via the processor's top generics. |
|
- Optional processor-internal data and instruction memories (**DMEM** / **IMEM**) |
- Optional internal **Bootloader** with UART console and automatic SPI flash boot option |
154,7 → 154,7
|
|
**General**: |
* Modified Harvard architecture (separate CPU interfaces for data and instructions; NEORV32 processor: Single processor-internal bus via bus I/D mux) |
* Modified Harvard architecture (separate CPU interfaces for data and instructions; NEORV32 processor: Single processor-internal bus via I/D mux) |
* Two stages in-order pipeline (FETCH, EXECUTE); each stage uses a multi-cycle processing scheme |
* No hardware support of unaligned accesses - they will trigger an exception |
* Little-endian byte order |
238,40 → 238,40
This chapter shows exemplary implementation results of the NEORV32 CPU 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 CPU's generics is assumed (e.g., no PMP). No constraints were used at all. |
of the CPU's generics is assumed (for example no PMP). No constraints were used at all. |
|
Results generated for hardware version: `1.3.6.5` |
Results generated for hardware version: `1.4.3.3` |
|
| CPU Configuration | LEs | FFs | Memory bits | DSPs | f_max | |
|:---------------------------------|:----------:|:--------:|:-----------:|:----:|:-------:| |
| `rv32i` | 1113 | 479 | 2048 | 0 | 109 MHz | |
| `rv32i` + `Zicsr` + `Zifencei` | 1851 | 817 | 2048 | 0 | 100 MHz | |
| `rv32im` + `Zicsr` + `Zifencei` | 2462 | 1065 | 2048 | 0 | 100 MHz | |
| `rv32imc` + `Zicsr` + `Zifencei` | 2714 | 1064 | 2048 | 0 | 100 MHz | |
| `rv32emc` + `Zicsr` + `Zifencei` | 2717 | 1064 | 1024 | 0 | 100 MHz | |
| CPU Configuration | LEs | FFs | Memory bits | DSPs | f_max | |
|:---------------------------------------|:----------:|:--------:|:-----------:|:----:|:-------:| |
| `rv32i` | 1033 | 567 | 2048 | 0 | 120 MHz | |
| `rv32i` + `u` + `Zicsr` + `Zifencei` | 1778 | 806 | 2048 | 0 | 103 MHz | |
| `rv32im` + `u` + `Zicsr` + `Zifencei` | 2389 | 1052 | 2048 | 0 | 102 MHz | |
| `rv32imc` + `u` + `Zicsr` + `Zifencei` | 2644 | 1053 | 2048 | 0 | 106 MHz | |
| `rv32emc` + `u` + `Zicsr` + `Zifencei` | 2646 | 1050 | 1024 | 0 | 103 MHz | |
|
|
### NEORV32 Processor-Internal Peripherals and Memories |
|
Results generated for hardware version: `1.3.6.5` |
Results generated for hardware version: `1.4.3.3` |
|
| Module | Description | LEs | FFs | Memory bits | DSPs | |
|:----------|:-----------------------------------------------------|:---:|:---:|:-----------:|:----:| |
| BOOT ROM | Bootloader ROM (default 4kB) | 4 | 1 | 32 768 | 0 | |
| BUSSWITCH | Mux for CPU I & D interfaces | 62 | 8 | 0 | 0 | |
| BOOT ROM | Bootloader ROM (default 4kB) | 3 | 1 | 32 768 | 0 | |
| BUSSWITCH | Mux for CPU I & D interfaces | 59 | 8 | 0 | 0 | |
| CFU | Custom functions unit | - | - | - | - | |
| DEVNULL | Dummy device | 3 | 1 | 0 | 0 | |
| DMEM | Processor-internal data memory (default 8kB) | 12 | 2 | 65 536 | 0 | |
| GPIO | General purpose input/output ports | 40 | 33 | 0 | 0 | |
| IMEM | Processor-internal instruction memory (default 16kb) | 7 | 2 | 131 072 | 0 | |
| MTIME | Machine system timer | 266 | 166 | 0 | 0 | |
| DEVNULL | Dummy device | 1 | 1 | 0 | 0 | |
| DMEM | Processor-internal data memory (default 8kB) | 13 | 2 | 65 536 | 0 | |
| GPIO | General purpose input/output ports | 69 | 65 | 0 | 0 | |
| IMEM | Processor-internal instruction memory (default 16kb) | 9 | 2 | 131 072 | 0 | |
| MTIME | Machine system timer | 281 | 166 | 0 | 0 | |
| PWM | Pulse-width modulation controller | 72 | 69 | 0 | 0 | |
| SPI | Serial peripheral interface | 198 | 125 | 0 | 0 | |
| SPI | Serial peripheral interface | 189 | 125 | 0 | 0 | |
| SYSINFO | System configuration information memory | 10 | 9 | 0 | 0 | |
| TRNG | True random number generator | 105 | 93 | 0 | 0 | |
| TWI | Two-wire interface | 75 | 44 | 0 | 0 | |
| UART | Universal asynchronous receiver/transmitter | 153 | 108 | 0 | 0 | |
| WDT | Watchdog timer | 59 | 45 | 0 | 0 | |
| TRNG | True random number generator | 175 | 132 | 0 | 0 | |
| TWI | Two-wire interface | 72 | 44 | 0 | 0 | |
| UART | Universal asynchronous receiver/transmitter | 175 | 132 | 0 | 0 | |
| WDT | Watchdog timer | 60 | 45 | 0 | 0 | |
|
|
### NEORV32 Processor - Exemplary FPGA Setups |
281,13 → 281,13
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. |
|
Results generated for hardware version: `1.4.0.0` |
Results generated for hardware version: `1.4.3.3` |
|
| Vendor | FPGA | Board | Toolchain | Strategy | CPU Configuration | LUT / LE | FF / REG | DSP | Memory Bits | BRAM / EBR | SPRAM | Frequency | |
|:--------|:----------------------------------|:-----------------|:---------------------------|:-------- |:------------------------------------------|:-----------|:-----------|:-------|:-------------|:-----------|:---------|---------------:| |
| Intel | Cyclone IV `EP4CE22F17C6N` | Terasic DE0-Nano | Quartus Prime Lite 19.1 | balanced | `rv32imcu` + `Zicsr` + `Zifencei` + `PMP` | 4020 (18%) | 1766 (8%) | 0 (0%) | 231424 (38%) | - | - | 100 MHz | |
| Lattice | iCE40 UltraPlus `iCE40UP5K-SG48I` | Upduino v2.0 | Radiant 2.1 (Synplify Pro) | default | `rv32icu` + `Zicsr` + `Zifencei` | 4249 (80%) | 1617 (31%) | 0 (0%) | - | 12 (40%) | 4 (100%) | *c* 20.25 MHz | |
| Xilinx | Artix-7 `XC7A35TICSG324-1L` | Arty A7-35T | Vivado 2019.2 | default | `rv32imcu` + `Zicsr` + `Zifencei` + `PMP` | 2447 (12%) | 1803 (4%) | 0 (0%) | - | 8 (16%) | - | *c* 100 MHz | |
| Vendor | FPGA | Board | Toolchain | Strategy | CPU Configuration | LUT / LE | FF / REG | DSP | Memory Bits | BRAM / EBR | SPRAM | Frequency | |
|:--------|:----------------------------------|:-----------------|:---------------------------|:-------- |:-----------------------------------------------|:-----------|:-----------|:-------|:-------------|:-----------|:---------|--------------:| |
| Intel | Cyclone IV `EP4CE22F17C6N` | Terasic DE0-Nano | Quartus Prime Lite 19.1 | balanced | `rv32imc` + `u` + `Zicsr` + `Zifencei` + `PMP` | 4120 (18%) | 1944 (9%) | 0 (0%) | 231424 (38%) | - | - | 103 MHz | |
| Lattice | iCE40 UltraPlus `iCE40UP5K-SG48I` | Upduino v2.0 | Radiant 2.1 (Synplify Pro) | default | `rv32ic` + `u` + `Zicsr` + `Zifencei` | 4288 (81%) | 1693 (32%) | 0 (0%) | - | 12 (40%) | 4 (100%) | *c* 22.5 MHz | |
| Xilinx | Artix-7 `XC7A35TICSG324-1L` | Arty A7-35T | Vivado 2019.2 | default | `rv32imc` + `u` + `Zicsr` + `Zifencei` + `PMP` | 2385 (11%) | 2008 (5%) | 0 (0%) | - | 8 (16%) | - | *c* 100 MHz | |
|
**_Notes_** |
* The Lattice iCE40 UltraPlus setup uses the FPGA's SPRAM memory primitives for the internal IMEM and DMEM (each 64kb). |
372,7 → 372,7
in [`rtl/top_templates`](https://github.com/stnolting/neorv32/blob/master/rtl/top_templates) folder. |
|
|
### CPU |
### NEORV32 CPU |
|
```vhdl |
entity neorv32_cpu is |
435,7 → 435,7
``` |
|
|
### Processor |
### NEORV32 Processor |
|
```vhdl |
entity neorv32_top is |
674,9 → 674,9
|
#### Citation |
|
If you are using the NEORV32 Processor in some kind of publication, please cite it as follows: |
If you are using the NEORV32 Processor/CPU in some kind of publication, please cite it as follows: |
|
> S. Nolting, "The NEORV32 Processor", github.com/stnolting/neorv32 |
> S. Nolting, "The NEORV32 Processor/CPU", github.com/stnolting/neorv32 |
|
#### BSD 3-Clause License |
|