Line 619... |
Line 619... |
ctrl_nxt(ctrl_alu_shift_dir_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- shift direction (left/right)
|
ctrl_nxt(ctrl_alu_shift_dir_c) <= execute_engine.i_reg(instr_funct3_msb_c); -- shift direction (left/right)
|
ctrl_nxt(ctrl_alu_shift_ar_c) <= execute_engine.i_reg(30); -- is arithmetic shift
|
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_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_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_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_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_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
|
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? --
|
-- is immediate ALU operation? --
|
alu_immediate_v := '0';
|
alu_immediate_v := not execute_engine.i_reg(instr_opcode_msb_c-1);
|
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') then
|
|
alu_immediate_v := '1';
|
-- is rs1 == r0? --
|
end if;
|
rs1_is_r0_v := not or_all_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c));
|
|
|
-- 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;
|
|
|
|
-- state machine --
|
-- state machine --
|
case execute_engine.state is
|
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))
|
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?
|
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_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_r0_we_c) <= '1'; -- allow write access to r0
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
end if;
|
end if;
|
--
|
--
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
Line 698... |
Line 694... |
|
|
when opcode_alu_c | opcode_alui_c => -- (immediate) 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_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_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
|
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) --
|
-- actual ALU operation (re-coding) --
|
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
|
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_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_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_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_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_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_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 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
|
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;
|
end case;
|
end case;
|
|
|
-- cp access? --
|
-- cp access? --
|
if (CPU_EXTENSION_RISCV_M = true) and (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
|
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?
|
(execute_engine.i_reg(instr_funct7_lsb_c) = '1') then -- MULDIV?
|
Line 730... |
Line 725... |
-- multi cycle alu operation? --
|
-- multi cycle alu operation? --
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation?
|
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_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.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;
|
execute_engine.state_nxt <= ALU_WAIT;
|
else
|
else -- single cycle ALU operation
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC
|
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- ALU.OPA = PC (for AUIPC only)
|
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
|
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;
|
end if;
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
|
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_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_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
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
Line 758... |
Line 753... |
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
|
ctrl_nxt(ctrl_bus_mdo_we_c) <= '1'; -- write to MDO (only relevant for stores)
|
execute_engine.state_nxt <= LOADSTORE_0;
|
execute_engine.state_nxt <= LOADSTORE_0;
|
|
|
when opcode_branch_c => -- branch instruction
|
when opcode_branch_c => -- branch instruction
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_opa_mux_lsb_c) <= '1'; -- use PC as ALU.OPA
|
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
|
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= '1'; -- use RS2 as ALU.OPC
|
ctrl_nxt(ctrl_alu_opc_mux_c) <= '0'; -- use RS2 as ALU.OPC (for branch condition check)
|
execute_engine.state_nxt <= BRANCH;
|
execute_engine.state_nxt <= BRANCH;
|
|
|
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register)
|
when opcode_jal_c | opcode_jalr_c => -- jump and link (with register)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
-- compute target address --
|
-- compute target address --
|
Line 781... |
Line 776... |
execute_engine.is_jump_nxt <= '1'; -- this is a jump operation
|
execute_engine.is_jump_nxt <= '1'; -- this is a jump operation
|
execute_engine.state_nxt <= BRANCH;
|
execute_engine.state_nxt <= BRANCH;
|
|
|
when opcode_fence_c => -- fence operations
|
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
|
-- foe simplicity: internally, fence and fence.i perform the same operations ;)
|
fetch_engine.reset <= '1';
|
-- 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
|
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)
|
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';
|
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
|
end if;
|
|
-- FENCE --
|
|
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
end if;
|
end if;
|
|
--
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
|
|
when opcode_syscsr_c => -- system/csr access
|
when opcode_syscsr_c => -- system/csr access
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
csr.re_nxt <= csr_acc_valid; -- always read CSR if valid 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)
|
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
|
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
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
when funct12_ecall_c => -- ECALL
|
when funct12_ecall_c => -- ECALL
|
Line 837... |
Line 838... |
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
|
csr.we_nxt <= csr_acc_valid; -- always write CSR if valid access
|
when funct3_csrrs_c | funct3_csrrsi_c => -- CSRRS(I)
|
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_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
|
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
|
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_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
|
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
|
csr.we_nxt <= (not rs1_is_r0_v) and csr_acc_valid; -- write CSR if rs1 is not zero_reg and if valid access
|
end case;
|
end case;
|
-- RF write back --
|
-- 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_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
|
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
|
when ALU_WAIT => -- wait for multi-cycle ALU operation (shifter or CP) to finish
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
|
ctrl_nxt(ctrl_alu_cmd2_c downto ctrl_alu_cmd0_c) <= alu_cmd_shift_c;
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "00"; -- RF input = ALU result
|
Line 892... |
Line 893... |
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_bus_mdi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for LOAD)
|
ctrl_nxt(ctrl_bus_mdi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for LOAD)
|
ctrl_nxt(ctrl_rf_in_mux_msb_c downto ctrl_rf_in_mux_lsb_c) <= "01"; -- RF input = memory input (only relevant for LOAD)
|
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
|
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;
|
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
|
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
|
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
|
end if;
|
end if;
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
Line 914... |
Line 915... |
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
-- Illegal CSR Access Check ---------------------------------------------------------------
|
-- 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;
|
variable is_m_mode_v : std_ulogic;
|
begin
|
begin
|
-- are we in machine mode? --
|
-- are we in machine mode? --
|
is_m_mode_v := '0';
|
is_m_mode_v := '0';
|
if (csr.privilege = m_priv_mode_c) then
|
if (csr.privilege = m_priv_mode_c) then
|
Line 928... |
Line 929... |
-- check CSR access --
|
-- check CSR access --
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
case execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
when x"300" => csr_acc_valid <= is_m_mode_v; -- mstatus
|
when x"300" => csr_acc_valid <= is_m_mode_v; -- mstatus
|
when x"301" => csr_acc_valid <= is_m_mode_v; -- misa
|
when x"301" => csr_acc_valid <= is_m_mode_v; -- misa
|
when x"304" => csr_acc_valid <= is_m_mode_v; -- mie
|
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"340" => csr_acc_valid <= is_m_mode_v; -- mscratch
|
when x"341" => csr_acc_valid <= is_m_mode_v; -- mepc
|
when x"341" => csr_acc_valid <= is_m_mode_v; -- mepc
|
when x"342" => csr_acc_valid <= is_m_mode_v; -- mcause
|
when x"342" => csr_acc_valid <= is_m_mode_v; -- mcause
|
when x"343" => csr_acc_valid <= is_m_mode_v; -- mtval
|
when x"343" => csr_acc_valid <= is_m_mode_v; -- mtval
|
when x"344" => csr_acc_valid <= is_m_mode_v; -- mip
|
when x"344" => csr_acc_valid <= is_m_mode_v; -- mip
|
Line 973... |
Line 974... |
end process invalid_csr_access_check;
|
end process invalid_csr_access_check;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- 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
|
begin
|
-- illegal instructions are checked in the EXECUTE stage
|
-- illegal instructions are checked in the EXECUTE stage
|
-- the execute engine will only commit valid instructions
|
-- the execute engine will only commit valid instructions
|
if (execute_engine.state = EXECUTE) then
|
if (execute_engine.state = EXECUTE) then
|
-- defaults --
|
-- defaults --
|
Line 1449... |
Line 1450... |
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS only (is mcause(31))
|
if (trap_ctrl.cause(trap_ctrl.cause'left) = '1') then -- for INTERRUPTS only (is mcause(31))
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
csr.mepc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- this is the CURRENT pc = interrupted instruction
|
csr.mtval <= (others => '0'); -- mtval is zero for interrupts
|
csr.mtval <= (others => '0'); -- mtval is zero for interrupts
|
else -- for EXCEPTIONS (according to their priority)
|
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
|
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
|
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 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_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
|
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
|
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
|
csr.mtval <= execute_engine.i_reg; -- faulting instruction itself
|
else -- load/store misalignments/access errors
|
else -- load/store misalignments/access errors
|
csr.mtval <= mar_i; -- faulting data access address
|
csr.mtval <= mar_i; -- faulting data access address
|
Line 1665... |
Line 1666... |
csr_rdata_o <= time_i(63 downto 32);
|
csr_rdata_o <= time_i(63 downto 32);
|
when x"c82" | x"b82" => -- R/(W): instreth/minstreth: Instructions-retired counter HIGH
|
when x"c82" | x"b82" => -- R/(W): instreth/minstreth: Instructions-retired counter HIGH
|
csr_rdata_o <= x"000" & csr.minstreth(19 downto 0); -- only the lowest 20 bit!
|
csr_rdata_o <= x"000" & csr.minstreth(19 downto 0); -- only the lowest 20 bit!
|
|
|
-- machine information registers --
|
-- machine information registers --
|
when x"f11" => -- R/-: mvendorid
|
when x"f11" => -- R/-: mvendorid - vendor ID
|
csr_rdata_o <= (others => '0'); -- not assigned
|
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
|
csr_rdata_o <= (others => '0'); -- not assigned
|
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32 version
|
when x"f13" => -- R/-: mimpid - implementation ID / NEORV32 version
|
csr_rdata_o <= hw_version_c;
|
csr_rdata_o <= hw_version_c;
|
when x"f14" => -- R/-: mhartid - hardware thread ID
|
when x"f14" => -- R/-: mhartid - hardware thread ID
|
csr_rdata_o <= HW_THREAD_ID;
|
csr_rdata_o <= HW_THREAD_ID;
|