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 24 to Rev 25
- ↔ Reverse comparison
Rev 24 → Rev 25
/neorv32_cpu_alu.vhd
127,11 → 127,11
when others => opa <= csr_i; |
end case; |
-- opb (second ALU input operand) -- |
case ctrl_i(ctrl_alu_opb_mux_msb_c downto ctrl_alu_opb_mux_lsb_c) is |
when "00" => opb <= rs2_i; |
when "01" => opb <= imm_i; |
when others => opb <= rs1_i; |
end case; |
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) -- |
if (ctrl_i(ctrl_alu_opc_mux_c) = '0') then |
opc <= imm_i; |
251,7 → 251,7
|
-- ALU Function Select -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
alu_function_mux: process(ctrl_i, opa, opb, add_res, sub_res, cmp_less, shifter) |
alu_function_mux: process(ctrl_i, opa, opb, add_res, sub_res, cmp_less, shifter.sreg) |
begin |
case ctrl_i(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) is |
when alu_cmd_xor_c => alu_res <= opa xor opb; |
/neorv32_cpu_control.vhd
562,13 → 562,9
|
-- CPU Control Bus Output ----------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
ctrl_output: process(ctrl, execute_engine, fetch_engine, trap_ctrl, csr, bus_fast_ir) |
ctrl_output: process(ctrl, fetch_engine, trap_ctrl, csr, bus_fast_ir) |
begin |
ctrl_o <= ctrl; |
-- direct output of register addresses -- |
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c); |
ctrl_o(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c); |
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c); |
-- fast bus access requests -- |
ctrl_o(ctrl_bus_if_c) <= ctrl(ctrl_bus_if_c) or bus_fast_ir; |
-- bus error control -- |
582,7 → 578,6
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); |
variable rs1_is_r0_v : std_ulogic; |
begin |
-- arbiter defaults -- |
625,8 → 620,11
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift |
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_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_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'; |
634,24 → 632,6
alu_immediate_v := '1'; |
end if; |
|
-- alu operation re-coding -- |
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is |
when funct3_subadd_c => -- SUB / ADD(I) |
if (alu_immediate_v = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1') then -- not immediate and funct7 = SUB |
alu_operation_v := alu_cmd_sub_c; |
else |
alu_operation_v := alu_cmd_add_c; |
end if; |
when funct3_sll_c => alu_operation_v := alu_cmd_shift_c; -- SLL(I) |
when funct3_slt_c => alu_operation_v := alu_cmd_slt_c; -- SLT(I) |
when funct3_sltu_c => alu_operation_v := alu_cmd_slt_c; -- SLTU(I) |
when funct3_xor_c => alu_operation_v := alu_cmd_xor_c; -- XOR(I) |
when funct3_sr_c => alu_operation_v := alu_cmd_shift_c; -- SRL(I) / SRA(I) |
when funct3_or_c => alu_operation_v := alu_cmd_or_c; -- OR(I) |
when funct3_and_c => alu_operation_v := alu_cmd_and_c; -- AND(I) |
when others => alu_operation_v := (others => '0'); -- undefined |
end case; |
|
-- is rs1 = r0? -- |
rs1_is_r0_v := '0'; |
if (execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then |
661,20 → 641,35
-- state machine -- |
case execute_engine.state is |
|
when SYS_WAIT => -- Delay cycle (used to wait for side effects to kick in) |
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)) |
-- ------------------------------------------------------------ |
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_r0_we_c) <= '1'; -- allow write access to r0 |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
end if; |
-- |
execute_engine.state_nxt <= DISPATCH; |
|
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB) |
-- ------------------------------------------------------------ |
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB) |
-- ------------------------------------------------------------ |
if (ipb.avail = '1') then -- instruction available? |
ipb.re <= '1'; |
-- |
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address |
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch |
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction |
-- |
ctrl_nxt(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= ipb.rdata(instr_rd_msb_c downto instr_rd_lsb_c); -- rd addr |
ctrl_nxt(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= ipb.rdata(instr_rs1_msb_c downto instr_rs1_lsb_c); -- rs1 addr |
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= ipb.rdata(instr_rs2_msb_c downto instr_rs2_lsb_c); -- rs2 addr |
-- |
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a compressed instruction beeing executed |
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0); |
execute_engine.if_rst_nxt <= '0'; |
-- |
if (execute_engine.if_rst = '0') then -- if there was no non-linear PC modification |
execute_engine.pc_nxt <= execute_engine.next_pc; |
end if; |
701,47 → 696,64
-- ------------------------------------------------------------ |
case execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) is |
|
when opcode_alu_c | opcode_alui_c => -- ALU operation |
when opcode_alu_c | opcode_alui_c => -- (immediate) ALU operation |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA |
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= alu_immediate_v; -- use IMM as ALU.OPB for immediate operations |
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_cmd2_c downto ctrl_alu_cmd0_c) <= alu_operation_v; -- actual ALU operation |
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 |
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? -- |
if (CPU_EXTENSION_RISCV_M = true) and (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? |
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP |
end if; |
|
-- multi cycle alu operation? -- |
if (alu_operation_v = alu_cmd_shift_c) or -- shift operation? |
((CPU_EXTENSION_RISCV_M = true) and (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? |
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation? |
(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 |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
execute_engine.state_nxt <= DISPATCH; |
end if; |
-- cp access? -- |
if (CPU_EXTENSION_RISCV_M = true) and (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? |
ctrl_nxt(ctrl_cp_use_c) <= '1'; -- use CP |
end if; |
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate (add to PC) |
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_rf_clear_rs1_c) <= '1'; -- force RS1 = r0 (only relevant for LUI) |
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_auipc_c(5)) then -- AUIPC |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA |
else -- LUI |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA ( = 0) |
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) |
end if; |
ctrl_nxt(ctrl_alu_opb_mux_lsb_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 |
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 |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
execute_engine.state_nxt <= DISPATCH; |
execute_engine.state_nxt <= DISPATCH; |
|
when opcode_load_c | opcode_store_c => -- load/store |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA |
ctrl_nxt(ctrl_alu_opb_mux_lsb_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 |
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 |
ctrl_nxt(ctrl_bus_mar_we_c) <= '1'; -- write to MAR |
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores) |
execute_engine.state_nxt <= LOADSTORE_0; |
749,7 → 761,7
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_lsb_c) <= '1'; -- use IMM as ALU.OPB |
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 |
execute_engine.state_nxt <= BRANCH; |
|
761,7 → 773,7
else -- JALR |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- use RS1 as ALU.OPA |
end if; |
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- use IMM as ALU.OPB |
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB |
-- save return address -- |
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "10"; -- RF input = next PC (save return address) |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
785,6 → 797,9
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_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 |
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is |
when funct12_ecall_c => -- ECALL |
792,12 → 807,12
when funct12_ebreak_c => -- EBREAK |
trap_ctrl.break_point <= '1'; |
when funct12_mret_c => -- MRET |
trap_ctrl.env_end <= '1'; |
execute_engine.pc_nxt <= csr.mepc; |
fetch_engine.reset <= '1'; |
trap_ctrl.env_end <= '1'; |
execute_engine.pc_nxt <= csr.mepc; |
fetch_engine.reset <= '1'; |
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification |
when funct12_wfi_c => -- WFI = "CPU sleep" |
execute_engine.sleep_nxt <= '1'; -- good night |
when funct12_wfi_c => -- WFI (CPU sleep) |
execute_engine.sleep_nxt <= '1'; -- sleep well |
when others => -- undefined |
NULL; |
end case; |
814,53 → 829,25
|
when CSR_ACCESS => -- write CSR data to RF, write ALU.res to CSR |
-- ------------------------------------------------------------ |
ctrl_nxt(ctrl_alu_opa_mux_msb_c) <= '0'; -- default |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- default |
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '0'; -- default |
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '0'; -- default |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- default ALU operation = OR |
ctrl_nxt(ctrl_alu_opb_mux_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- OPB = rs2 (which is rs1 here) / immediate |
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is |
-- register operations -- |
when funct3_csrrw_c => -- CSRRW |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1 |
ctrl_nxt(ctrl_alu_opb_mux_lsb_c) <= '1'; -- OPB = rs1 |
ctrl_nxt(ctrl_alu_opb_mux_msb_c) <= '1'; -- OPB = rs1 |
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I) |
ctrl_nxt(ctrl_alu_opa_mux_msb_c downto ctrl_alu_opa_mux_lsb_c) <= "00"; -- OPA = rs1 (which is zero here) |
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_or_c; -- actual ALU operation = OR |
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 |
when funct3_csrrs_c | funct3_csrrsi_c => -- CSRRS(I) |
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 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 |
when others => -- CSRRC(I) |
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 |
-- immediate operations -- |
when funct3_csrrwi_c => -- CSRRWI |
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '0'; -- OPA = rs1 |
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 <= 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) 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_bclr_c; -- actual ALU operation = bit clear |
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; |
-- 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 <= DISPATCH; -- FIXME? should be 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 |
-- ------------------------------------------------------------ |
929,7 → 916,7
|
-- Illegal CSR Access Check --------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
invalid_csr_access_check: process(execute_engine, csr) |
invalid_csr_access_check: process(execute_engine, csr.privilege) |
variable is_m_mode_v : std_ulogic; |
begin |
-- are we in machine mode? -- |
/neorv32_cpu_regfile.vhd
2,7 → 2,9
-- # << NEORV32 - CPU Register File >> # |
-- # ********************************************************************************************* # |
-- # General purpose data registers. 32 entries for normal mode, 16 entries for embedded mode when # |
-- # RISC-V M extension is enabled. x0 output is allways set to zero. # |
-- # RISC-V "E" extension is enabled. Register zero (r0/x0) is a normal physical registers, that # |
-- # has to be initialized to zero by the CPU control system. For normal operations, x0 cannot be # |
-- # written. # |
-- # ********************************************************************************************* # |
-- # BSD 3-Clause License # |
-- # # |
70,13 → 72,8
signal reg_file_emb : reg_file_emb_t; |
signal rf_write_data : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data |
signal valid_wr : std_ulogic; -- writing not to r0 |
signal rs1_read : std_ulogic_vector(data_width_c-1 downto 0); -- internal operand rs1 |
signal rs2_read : std_ulogic_vector(data_width_c-1 downto 0); -- internal operand rs2 |
|
-- reading from r0? -- |
signal rs1_clear, rs2_clear : std_ulogic; |
|
|
-- attributes - these are *NOT mandatory*; just for footprint / timing optimization -- |
-- -------------------------------------------------------------------------------- -- |
|
104,9 → 101,9
end case; |
end process input_mux; |
|
-- only write if destination is not x0 (pretty irrelevant, but might save some power) -- |
valid_wr <= or_all_f(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)) when (CPU_EXTENSION_RISCV_E = false) else |
or_all_f(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c)); |
-- only write if destination is not x0; except we are forcing a r0 write access -- |
valid_wr <= or_all_f(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)) or ctrl_i(ctrl_rf_r0_we_c) when (CPU_EXTENSION_RISCV_E = false) else |
or_all_f(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c)) or ctrl_i(ctrl_rf_r0_we_c); |
|
|
-- Register file read/write access -------------------------------------------------------- |
115,49 → 112,25
begin |
if rising_edge(clk_i) then -- sync read and write |
if (CPU_EXTENSION_RISCV_E = false) then -- normal register file with 32 entries |
-- check if reading from r0 -- |
rs1_clear <= '0'; |
rs2_clear <= '0'; |
if (ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) = "00000") then |
rs1_clear <= '1'; |
end if; |
if (ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) = "00000") then |
rs2_clear <= '1'; |
end if; |
-- write -- |
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and (valid_wr = '1') then -- valid write-back |
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and ((valid_wr = '1') or (rf_r0_is_reg_c = false)) then -- valid write-back |
reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)))) <= rf_write_data; |
end if; |
-- read -- |
rs1_read <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c)))); |
rs2_read <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c)))); |
rs1_o <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c)))); |
rs2_o <= reg_file(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c)))); |
|
else -- embedded register file with 16 entries |
-- check if reading from r0 -- |
rs1_clear <= '0'; |
rs2_clear <= '0'; |
if (ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c) = "0000") then |
rs1_clear <= '1'; |
end if; |
if (ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c) = "0000") then |
rs2_clear <= '1'; |
end if; |
-- write -- |
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and (valid_wr = '1') then -- valid write-back |
if (ctrl_i(ctrl_rf_wb_en_c) = '1') and ((valid_wr = '1') or (rf_r0_is_reg_c = false)) then -- valid write-back |
reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c)))) <= rf_write_data; |
end if; |
-- read -- |
rs1_read <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c)))); |
rs2_read <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c)))); |
rs1_o <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs1_adr3_c downto ctrl_rf_rs1_adr0_c)))); |
rs2_o <= reg_file_emb(to_integer(unsigned(ctrl_i(ctrl_rf_rs2_adr3_c downto ctrl_rf_rs2_adr0_c)))); |
end if; |
end if; |
end process rf_access; |
|
|
-- Check if reading from x0 --------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
rs1_o <= (others => '0') when ((rs1_clear or ctrl_i(ctrl_rf_clear_rs1_c)) = '1') else rs1_read; |
rs2_o <= (others => '0') when (rs2_clear = '1') else rs2_read; |
|
|
end neorv32_cpu_regfile_rtl; |
/neorv32_mtime.vhd
103,16 → 103,16
wr_access: process(clk_i) |
begin |
if rising_edge(clk_i) then |
-- mtimecmp -- |
if (wren = '1') then |
if (addr = mtime_cmp_lo_addr_c) then -- low |
mtimecmp_lo <= data_i; |
end if; |
if (addr = mtime_cmp_hi_addr_c) then -- high |
mtimecmp_hi <= data_i; |
end if; |
-- mtimecmp low -- |
if (wren = '1') and (addr = mtime_cmp_lo_addr_c) then |
mtimecmp_lo <= data_i; |
end if; |
|
-- mtimecmp high -- |
if (wren = '1') and (addr = mtime_cmp_hi_addr_c) then |
mtimecmp_hi <= data_i; |
end if; |
|
-- mtime low -- |
if (wren = '1') and (addr = mtime_time_lo_addr_c) then |
mtime_lo_msb_ff <= '0'; |
140,15 → 140,18
ack_o <= acc_en and (rden_i or wren_i); |
data_o <= (others => '0'); -- default |
if (rden_i = '1') and (acc_en = '1') then |
if (addr = mtime_time_lo_addr_c) then -- mtime LOW |
data_o <= mtime_lo(31 downto 00); |
elsif (addr = mtime_time_hi_addr_c) then -- mtime HIGH |
data_o <= mtime_hi; |
elsif (addr = mtime_cmp_lo_addr_c) then -- mtimecmp LOW |
data_o <= mtimecmp_lo; |
else -- (addr = mtime_cmp_hi_addr_c) then -- mtimecmp HIGH |
data_o <= mtimecmp_hi; |
end if; |
case addr is |
when mtime_time_lo_addr_c => -- mtime LOW |
data_o <= mtime_lo(31 downto 00); |
when mtime_time_hi_addr_c => -- mtime HIGH |
data_o <= mtime_hi; |
when mtime_cmp_lo_addr_c => -- mtimecmp LOW |
data_o <= mtimecmp_lo; |
when 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; |
/neorv32_package.vhd
40,10 → 40,11
|
-- Architecture Constants/Configuration --------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant data_width_c : natural := 32; -- data width - FIXED! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040300"; -- 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 data_width_c : natural := 32; -- data width - FIXED! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01040302"; -- 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 |
|
-- Helper Functions ----------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
177,7 → 178,7
constant ctrl_rf_rd_adr3_c : natural := 15; -- destiantion register address bit 3 |
constant ctrl_rf_rd_adr4_c : natural := 16; -- destiantion register address bit 4 |
constant ctrl_rf_wb_en_c : natural := 17; -- write back enable |
constant ctrl_rf_clear_rs1_c : natural := 18; -- force rs1=r0 |
constant ctrl_rf_r0_we_c : natural := 18; -- allow write access to r0 (zero), also forces dst=r0 |
-- alu -- |
constant ctrl_alu_cmd0_c : natural := 19; -- ALU command bit 0 |
constant ctrl_alu_cmd1_c : natural := 20; -- ALU command bit 1 |
184,35 → 185,34
constant ctrl_alu_cmd2_c : natural := 21; -- ALU command bit 2 |
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_lsb_c : natural := 24; -- operand B select lsb (00=rs2, 01=IMM) |
constant ctrl_alu_opb_mux_msb_c : natural := 25; -- operand B select msb (1-=rs1) |
constant ctrl_alu_opc_mux_c : natural := 26; -- operand C select (0=IMM, 1=rs2) |
constant ctrl_alu_unsigned_c : natural := 27; -- is unsigned ALU operation |
constant ctrl_alu_shift_dir_c : natural := 28; -- shift direction (0=left, 1=right) |
constant ctrl_alu_shift_ar_c : natural := 29; -- is arithmetic shift |
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_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 |
-- bus interface -- |
constant ctrl_bus_size_lsb_c : natural := 30; -- transfer size lsb (00=byte, 01=half-word) |
constant ctrl_bus_size_msb_c : natural := 31; -- transfer size msb (10=word, 11=?) |
constant ctrl_bus_rd_c : natural := 32; -- read data request |
constant ctrl_bus_wr_c : natural := 33; -- write data request |
constant ctrl_bus_if_c : natural := 34; -- instruction fetch request |
constant ctrl_bus_mar_we_c : natural := 35; -- memory address register write enable |
constant ctrl_bus_mdo_we_c : natural := 36; -- memory data out register write enable |
constant ctrl_bus_mdi_we_c : natural := 37; -- memory data in register write enable |
constant ctrl_bus_unsigned_c : natural := 38; -- is unsigned load |
constant ctrl_bus_ierr_ack_c : natural := 39; -- acknowledge instruction fetch bus exception |
constant ctrl_bus_derr_ack_c : natural := 40; -- acknowledge data access bus exception |
constant ctrl_bus_fence_c : natural := 41; -- executed fence operation |
constant ctrl_bus_fencei_c : natural := 42; -- executed fencei operation |
constant ctrl_bus_size_lsb_c : natural := 29; -- transfer size lsb (00=byte, 01=half-word) |
constant ctrl_bus_size_msb_c : natural := 30; -- transfer size msb (10=word, 11=?) |
constant ctrl_bus_rd_c : natural := 31; -- read data request |
constant ctrl_bus_wr_c : natural := 32; -- write data request |
constant ctrl_bus_if_c : natural := 33; -- instruction fetch request |
constant ctrl_bus_mar_we_c : natural := 34; -- memory address register write enable |
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_fence_c : natural := 40; -- executed fence operation |
constant ctrl_bus_fencei_c : natural := 41; -- executed fencei operation |
-- co-processor -- |
constant ctrl_cp_use_c : natural := 43; -- is cp operation |
constant ctrl_cp_id_lsb_c : natural := 44; -- cp select lsb |
constant ctrl_cp_id_msb_c : natural := 45; -- cp select msb |
constant ctrl_cp_cmd0_c : natural := 46; -- cp command bit 0 |
constant ctrl_cp_cmd1_c : natural := 47; -- cp command bit 1 |
constant ctrl_cp_cmd2_c : natural := 48; -- cp command bit 2 |
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 |
constant ctrl_cp_cmd0_c : natural := 45; -- cp command bit 0 |
constant ctrl_cp_cmd1_c : natural := 46; -- cp command bit 1 |
constant ctrl_cp_cmd2_c : natural := 47; -- cp command bit 2 |
-- control bus size -- |
constant ctrl_width_c : natural := 49; -- control bus size |
constant ctrl_width_c : natural := 48; -- control bus size |
|
-- ALU Comparator Bus --------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
331,7 → 331,7
constant alu_cmd_xor_c : std_ulogic_vector(2 downto 0) := "100"; -- r <= A xor B |
constant alu_cmd_or_c : std_ulogic_vector(2 downto 0) := "101"; -- r <= A or B |
constant alu_cmd_and_c : std_ulogic_vector(2 downto 0) := "110"; -- r <= A and B |
constant alu_cmd_bclr_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= A and (not B) |
constant alu_cmd_bclr_c : std_ulogic_vector(2 downto 0) := "111"; -- r <= A and (not B) |
|
-- Trap ID Codes -------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
/neorv32_top.vhd
302,7 → 302,7
generic map ( |
-- General -- |
HW_THREAD_ID => (others => '0'), -- hardware thread id |
CPU_BOOT_ADDR => cpu_boot_addr_c, -- cpu boot address |
CPU_BOOT_ADDR => cpu_boot_addr_c, -- 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? |
311,13 → 311,13
CPU_EXTENSION_RISCV_Zicsr => CPU_EXTENSION_RISCV_Zicsr, -- implement CSR system? |
CPU_EXTENSION_RISCV_Zifencei => CPU_EXTENSION_RISCV_Zifencei, -- implement instruction stream sync.? |
-- Extension Options -- |
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier |
FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier |
-- Physical Memory Protection (PMP) -- |
PMP_USE => PMP_USE, -- implement PMP? |
PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (max 8) |
PMP_GRANULARITY => PMP_GRANULARITY, -- minimal 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 |
BUS_TIMEOUT => MEM_EXT_TIMEOUT -- cycles after which a valid bus access will timeout |
) |
port map ( |
-- global control -- |