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/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 --

powered by: WebSVN 2.1.0

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