Line 147... |
Line 147... |
signal pc_backup2_reg : std_ulogic_vector(data_width_c-1 downto 0); -- delayed delayed PC (for exception handling)
|
signal pc_backup2_reg : std_ulogic_vector(data_width_c-1 downto 0); -- delayed delayed PC (for exception handling)
|
signal mepc : std_ulogic_vector(data_width_c-1 downto 0); -- exception PC
|
signal mepc : std_ulogic_vector(data_width_c-1 downto 0); -- exception PC
|
|
|
-- irq controller --
|
-- irq controller --
|
signal exc_buf : std_ulogic_vector(exception_width_c-1 downto 0);
|
signal exc_buf : std_ulogic_vector(exception_width_c-1 downto 0);
|
signal exc_ack : std_ulogic_vector(exception_width_c-1 downto 0);
|
signal exc_ack : std_ulogic;
|
signal exc_ack_nxt : std_ulogic_vector(exception_width_c-1 downto 0);
|
|
signal exc_src : std_ulogic_vector(exception_width_c-1 downto 0);
|
signal exc_src : std_ulogic_vector(exception_width_c-1 downto 0);
|
signal exc_fire : std_ulogic;
|
signal exc_fire : std_ulogic;
|
signal irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
signal irq_buf : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
signal irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
signal irq_ack : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
signal irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
signal irq_ack_nxt : std_ulogic_vector(interrupt_width_c-1 downto 0);
|
Line 322... |
Line 321... |
|
|
|
|
-- Arbiter State Machine Comb -----------------------------------------------
|
-- Arbiter State Machine Comb -----------------------------------------------
|
-- -----------------------------------------------------------------------------
|
-- -----------------------------------------------------------------------------
|
arbiter_comb: process(state, ctrl, i_reg, alu_wait_i, bus_wait_i, exc_cpu_start, ma_load_i, be_load_i, ma_store_i, be_store_i,
|
arbiter_comb: process(state, ctrl, i_reg, alu_wait_i, bus_wait_i, exc_cpu_start, ma_load_i, be_load_i, ma_store_i, be_store_i,
|
i_reg, ci_reg, i_buf, instr_i, is_ci, iavail, pc_backup_reg, ci_valid, ci_instr32)
|
ci_reg, i_buf, instr_i, is_ci, iavail, pc_backup_reg, ci_valid, ci_instr32)
|
variable alu_immediate_v : std_ulogic;
|
variable alu_immediate_v : std_ulogic;
|
variable alu_operation_v : std_ulogic_vector(2 downto 0);
|
variable alu_operation_v : std_ulogic_vector(2 downto 0);
|
variable rs1_is_r0_v : std_ulogic;
|
variable rs1_is_r0_v : std_ulogic;
|
variable rd_is_r0_v : std_ulogic;
|
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
state_nxt <= state;
|
state_nxt <= state;
|
is_branch_nxt <= '0';
|
is_branch_nxt <= '0';
|
exc_cpu_ack <= '0';
|
exc_cpu_ack <= '0';
|
Line 396... |
Line 394... |
rs1_is_r0_v := '0';
|
rs1_is_r0_v := '0';
|
if (i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
if (i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
|
rs1_is_r0_v := '1';
|
rs1_is_r0_v := '1';
|
end if;
|
end if;
|
|
|
-- is rd = r0? --
|
|
rd_is_r0_v := '0';
|
|
if (i_reg(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") then
|
|
rd_is_r0_v := '1';
|
|
end if;
|
|
|
|
|
|
-- state machine: instruction fetch and execution --
|
-- state machine: instruction fetch and execution --
|
case state is
|
case state is
|
|
|
when IFETCH_0 => -- output current PC to bus system
|
when IFETCH_0 => -- output current PC to bus system
|
Line 571... |
Line 563... |
ctrl_nxt(ctrl_csr_pc_we_c) <= '1'; -- update PC
|
ctrl_nxt(ctrl_csr_pc_we_c) <= '1'; -- update PC
|
state_nxt <= IFETCH_0;
|
state_nxt <= IFETCH_0;
|
|
|
when opcode_syscsr_c => -- system/csr access
|
when opcode_syscsr_c => -- system/csr access
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl_nxt(ctrl_csr_re_c) <= '1'; -- ALWAYS READ CSR!!! (OLD: not rd_is_r0_v; -- valid CSR read if rd is not r0)
|
ctrl_nxt(ctrl_csr_re_c) <= '1'; -- ALWAYS READ CSR!!! (OLD: valid CSR read if rd is not r0)
|
if (i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
|
if (i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system
|
case i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
case i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) is
|
when x"000" => env_call <= '1'; state_nxt <= IFETCH_0; -- ECALL
|
when x"000" => env_call <= '1'; state_nxt <= IFETCH_0; -- ECALL
|
when x"001" => break_point <= '1'; state_nxt <= IFETCH_0; -- EBREAK
|
when x"001" => break_point <= '1'; state_nxt <= IFETCH_0; -- EBREAK
|
when x"302" => exc_cpu_end <= '1'; state_nxt <= IFETCH_0; -- MRET
|
when x"302" => exc_cpu_end <= '1'; state_nxt <= IFETCH_0; -- MRET
|
Line 688... |
Line 680... |
end process arbiter_comb;
|
end process arbiter_comb;
|
|
|
|
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- Illegal Instruction Check --------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
illegal_instruction_check: process(i_reg, state, ctrl_nxt)
|
illegal_instruction_check: process(i_reg, state, ctrl_nxt, ci_valid, ci_illegal)
|
begin
|
begin
|
if (state = EXECUTE) then
|
if (state = EXECUTE) then
|
-- defaults --
|
-- defaults --
|
illegal_instruction <= '0';
|
illegal_instruction <= '0';
|
illegal_register <= '0';
|
illegal_register <= '0';
|
Line 900... |
Line 892... |
exception_controller: process(rstn_i, clk_i)
|
exception_controller: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
exc_buf <= (others => '0');
|
exc_buf <= (others => '0');
|
irq_buf <= (others => '0');
|
irq_buf <= (others => '0');
|
exc_ack <= (others => '0');
|
exc_ack <= '0';
|
irq_ack <= (others => '0');
|
irq_ack <= (others => '0');
|
exc_src <= (others => '0');
|
exc_src <= (others => '0');
|
exc_cpu_start <= '0';
|
exc_cpu_start <= '0';
|
exc_cause <= (others => '0');
|
exc_cause <= (others => '0');
|
mtinst <= (others => '0');
|
mtinst <= (others => '0');
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
-- exception buffer: misaligned load/store/instruction address
|
-- exception buffer: misaligned load/store/instruction address
|
exc_buf(exception_lalign_c) <= (exc_buf(exception_lalign_c) or ma_load_i) and (not exc_ack(exception_lalign_c));
|
exc_buf(exception_lalign_c) <= (exc_buf(exception_lalign_c) or ma_load_i) and (not exc_ack);
|
exc_buf(exception_salign_c) <= (exc_buf(exception_salign_c) or ma_store_i) and (not exc_ack(exception_salign_c));
|
exc_buf(exception_salign_c) <= (exc_buf(exception_salign_c) or ma_store_i) and (not exc_ack);
|
exc_buf(exception_ialign_c) <= (exc_buf(exception_ialign_c) or ma_instr_i) and (not exc_ack(exception_ialign_c));
|
exc_buf(exception_ialign_c) <= (exc_buf(exception_ialign_c) or ma_instr_i) and (not exc_ack);
|
-- exception buffer: load/store/instruction bus access error
|
-- exception buffer: load/store/instruction bus access error
|
exc_buf(exception_laccess_c) <= (exc_buf(exception_laccess_c) or be_load_i) and (not exc_ack(exception_laccess_c));
|
exc_buf(exception_laccess_c) <= (exc_buf(exception_laccess_c) or be_load_i) and (not exc_ack);
|
exc_buf(exception_saccess_c) <= (exc_buf(exception_saccess_c) or be_store_i) and (not exc_ack(exception_saccess_c));
|
exc_buf(exception_saccess_c) <= (exc_buf(exception_saccess_c) or be_store_i) and (not exc_ack);
|
exc_buf(exception_iaccess_c) <= (exc_buf(exception_iaccess_c) or be_instr_i) and (not exc_ack(exception_iaccess_c));
|
exc_buf(exception_iaccess_c) <= (exc_buf(exception_iaccess_c) or be_instr_i) and (not exc_ack);
|
-- exception buffer: illegal instruction / env call / break point
|
-- exception buffer: illegal instruction / env call / break point
|
exc_buf(exception_iillegal_c) <= (exc_buf(exception_iillegal_c) or illegal_instr_exc) and (not exc_ack(exception_iillegal_c));
|
exc_buf(exception_iillegal_c) <= (exc_buf(exception_iillegal_c) or illegal_instr_exc) and (not exc_ack);
|
exc_buf(exception_m_envcall_c) <= (exc_buf(exception_m_envcall_c) or env_call) and (not exc_ack(exception_m_envcall_c));
|
exc_buf(exception_m_envcall_c) <= (exc_buf(exception_m_envcall_c) or env_call) and (not exc_ack);
|
exc_buf(exception_break_c) <= (exc_buf(exception_break_c) or break_point) and (not exc_ack(exception_break_c));
|
exc_buf(exception_break_c) <= (exc_buf(exception_break_c) or break_point) and (not exc_ack);
|
-- interrupt buffer: machine software/external/timer interrupt
|
-- interrupt buffer: machine software/external/timer interrupt
|
irq_buf(interrupt_msw_irq_c) <= mie_msie and (irq_buf(interrupt_msw_irq_c) or mip_msip) and (not irq_ack(interrupt_msw_irq_c));
|
irq_buf(interrupt_msw_irq_c) <= mie_msie and (irq_buf(interrupt_msw_irq_c) or mip_msip) and (not irq_ack(interrupt_msw_irq_c));
|
if (IO_CLIC_USE = true) then
|
|
irq_buf(interrupt_mext_irq_c) <= mie_meie and (irq_buf(interrupt_mext_irq_c) or clic_irq_i) and (not irq_ack(interrupt_mext_irq_c));
|
irq_buf(interrupt_mext_irq_c) <= mie_meie and (irq_buf(interrupt_mext_irq_c) or clic_irq_i) and (not irq_ack(interrupt_mext_irq_c));
|
else
|
|
irq_buf(interrupt_mext_irq_c) <= '0';
|
|
end if;
|
|
if (IO_MTIME_USE = true) then
|
|
irq_buf(interrupt_mtime_irq_c) <= mie_mtie and (irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not irq_ack(interrupt_mtime_irq_c));
|
irq_buf(interrupt_mtime_irq_c) <= mie_mtie and (irq_buf(interrupt_mtime_irq_c) or mtime_irq_i) and (not irq_ack(interrupt_mtime_irq_c));
|
else
|
|
irq_buf(interrupt_mtime_irq_c) <= '0';
|
|
end if;
|
|
|
|
-- exception control --
|
-- exception control --
|
if (exc_cpu_start = '0') then --
|
if (exc_cpu_start = '0') then --
|
-- exception/interrupt triggered, waiting for IRQ in EXECUTE (make sure at least 1 instr. is executed even for a continous IRQ)
|
-- exception/interrupt triggered, waiting for IRQ in EXECUTE (make sure at least 1 instr. is executed even for a continous IRQ)
|
if (exc_fire = '1') or ((irq_fire = '1') and ((state = EXECUTE) or (state = SLEEP))) then
|
if (exc_fire = '1') or ((irq_fire = '1') and ((state = EXECUTE) or (state = SLEEP))) then
|
exc_cause <= exc_cause_nxt; -- capture source for program
|
exc_cause <= exc_cause_nxt; -- capture source for program
|
mtinst <= i_reg; -- MTINST NOT FOULLY IMPLEMENTED YET! FIXME
|
mtinst <= i_reg; -- MTINST NOT FOULLY IMPLEMENTED YET! FIXME
|
mtinst(1) <= not is_ci; -- bit is set for uncompressed instruction
|
mtinst(1) <= not is_ci; -- bit is set for uncompressed instruction
|
exc_src <= exc_buf; -- capture source for hardware
|
exc_src <= exc_buf; -- capture source for hardware
|
exc_ack <= exc_ack_nxt; -- capture and clear with exception ACK mask
|
exc_ack <= '1'; -- clear execption
|
irq_ack <= irq_ack_nxt; -- capture and clear with interrupt ACK mask
|
irq_ack <= irq_ack_nxt; -- capture and clear with interrupt ACK mask
|
exc_cpu_start <= '1';
|
exc_cpu_start <= '1';
|
end if;
|
end if;
|
else -- waiting for exception handler to get started
|
else -- waiting for exception handler to get started
|
if (exc_cpu_ack = '1') then -- handler started?
|
if (exc_cpu_ack = '1') then -- handler started?
|
exc_ack <= (others => '0');
|
exc_ack <= '0';
|
irq_ack <= (others => '0');
|
irq_ack <= (others => '0');
|
exc_cpu_start <= '0';
|
exc_cpu_start <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
else -- (CPU_EXTENSION_RISCV_Zicsr = false)
|
else -- (CPU_EXTENSION_RISCV_Zicsr = false)
|
exc_buf <= (others => '0');
|
exc_buf <= (others => '0');
|
irq_buf <= (others => '0');
|
irq_buf <= (others => '0');
|
exc_ack <= (others => '0');
|
exc_ack <= '0';
|
irq_ack <= (others => '0');
|
irq_ack <= (others => '0');
|
exc_src <= (others => '0');
|
exc_src <= (others => '0');
|
exc_cpu_start <= '0';
|
exc_cpu_start <= '0';
|
exc_cause <= (others => '0');
|
exc_cause <= (others => '0');
|
mtinst <= (others => '0');
|
mtinst <= (others => '0');
|
Line 977... |
Line 961... |
-- exception priority encoder --
|
-- exception priority encoder --
|
exc_priority: process(exc_buf, irq_buf)
|
exc_priority: process(exc_buf, irq_buf)
|
begin
|
begin
|
-- defaults --
|
-- defaults --
|
exc_cause_nxt <= (others => '0');
|
exc_cause_nxt <= (others => '0');
|
exc_ack_nxt <= (others => '0');
|
|
irq_ack_nxt <= (others => '0');
|
irq_ack_nxt <= (others => '0');
|
|
|
-- interrupt: 1.11 machine external interrupt --
|
-- interrupt: 1.11 machine external interrupt --
|
if (irq_buf(interrupt_mext_irq_c) = '1') then
|
if (irq_buf(interrupt_mext_irq_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '1';
|
exc_cause_nxt(exc_cause_nxt'left) <= '1';
|
Line 999... |
Line 982... |
exc_cause_nxt(exc_cause_nxt'left) <= '1';
|
exc_cause_nxt(exc_cause_nxt'left) <= '1';
|
exc_cause_nxt(3 downto 0) <= "0011";
|
exc_cause_nxt(3 downto 0) <= "0011";
|
irq_ack_nxt(interrupt_msw_irq_c) <= '1';
|
irq_ack_nxt(interrupt_msw_irq_c) <= '1';
|
|
|
|
|
|
-- the following traps are caused by synchronous exceptions
|
|
-- here we do not need an acknowledge mask since only one exception can trigger at the same time
|
|
|
-- trap/fault: 0.0 instruction address misaligned --
|
-- trap/fault: 0.0 instruction address misaligned --
|
elsif (exc_buf(exception_ialign_c) = '1') then
|
elsif (exc_buf(exception_ialign_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0000";
|
exc_cause_nxt(3 downto 0) <= "0000";
|
exc_ack_nxt(exception_ialign_c) <= '1';
|
|
exc_ack_nxt(exception_iaccess_c) <= '1';
|
|
exc_ack_nxt(exception_iillegal_c) <= '1';
|
|
|
|
-- trap/fault: 0.1 instruction access fault --
|
-- trap/fault: 0.1 instruction access fault --
|
elsif (exc_buf(exception_iaccess_c) = '1') then
|
elsif (exc_buf(exception_iaccess_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0001";
|
exc_cause_nxt(3 downto 0) <= "0001";
|
exc_ack_nxt(exception_ialign_c) <= '1';
|
|
exc_ack_nxt(exception_iaccess_c) <= '1';
|
|
exc_ack_nxt(exception_iillegal_c) <= '1';
|
|
|
|
-- trap/fault: 0.2 illegal instruction --
|
-- trap/fault: 0.2 illegal instruction --
|
elsif (exc_buf(exception_iillegal_c) = '1') then
|
elsif (exc_buf(exception_iillegal_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0010";
|
exc_cause_nxt(3 downto 0) <= "0010";
|
exc_ack_nxt(exception_ialign_c) <= '1';
|
|
exc_ack_nxt(exception_iaccess_c) <= '1';
|
|
exc_ack_nxt(exception_iillegal_c) <= '1';
|
|
|
|
|
|
-- trap/fault: 0.11 environment call from M-mode --
|
-- trap/fault: 0.11 environment call from M-mode --
|
elsif (exc_buf(exception_m_envcall_c) = '1') then
|
elsif (exc_buf(exception_m_envcall_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "1011";
|
exc_cause_nxt(3 downto 0) <= "1011";
|
exc_ack_nxt(exception_m_envcall_c) <= '1';
|
|
|
|
-- trap/fault: 0.3 breakpoint --
|
-- trap/fault: 0.3 breakpoint --
|
elsif (exc_buf(exception_break_c) = '1') then
|
elsif (exc_buf(exception_break_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0011";
|
exc_cause_nxt(3 downto 0) <= "0011";
|
exc_ack_nxt(exception_break_c) <= '1';
|
|
|
|
|
|
-- trap/fault: 0.6 store address misaligned -
|
-- trap/fault: 0.6 store address misaligned -
|
elsif (exc_buf(exception_salign_c) = '1') then
|
elsif (exc_buf(exception_salign_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0110";
|
exc_cause_nxt(3 downto 0) <= "0110";
|
exc_ack_nxt(exception_salign_c) <= '1';
|
|
exc_ack_nxt(exception_lalign_c) <= '1';
|
|
exc_ack_nxt(exception_saccess_c) <= '1';
|
|
exc_ack_nxt(exception_laccess_c) <= '1';
|
|
|
|
-- trap/fault: 0.4 load address misaligned --
|
-- trap/fault: 0.4 load address misaligned --
|
elsif (exc_buf(exception_lalign_c) = '1') then
|
elsif (exc_buf(exception_lalign_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0100";
|
exc_cause_nxt(3 downto 0) <= "0100";
|
exc_ack_nxt(exception_salign_c) <= '1';
|
|
exc_ack_nxt(exception_lalign_c) <= '1';
|
|
exc_ack_nxt(exception_saccess_c) <= '1';
|
|
exc_ack_nxt(exception_laccess_c) <= '1';
|
|
|
|
-- trap/fault: 0.7 store access fault --
|
-- trap/fault: 0.7 store access fault --
|
elsif (exc_buf(exception_saccess_c) = '1') then
|
elsif (exc_buf(exception_saccess_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0111";
|
exc_cause_nxt(3 downto 0) <= "0111";
|
exc_ack_nxt(exception_salign_c) <= '1';
|
|
exc_ack_nxt(exception_lalign_c) <= '1';
|
|
exc_ack_nxt(exception_saccess_c) <= '1';
|
|
exc_ack_nxt(exception_laccess_c) <= '1';
|
|
|
|
-- trap/fault: 0.5 load access fault --
|
-- trap/fault: 0.5 load access fault --
|
elsif (exc_buf(exception_laccess_c) = '1') then
|
elsif (exc_buf(exception_laccess_c) = '1') then
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(exc_cause_nxt'left) <= '0';
|
exc_cause_nxt(3 downto 0) <= "0101";
|
exc_cause_nxt(3 downto 0) <= "0101";
|
exc_ack_nxt(exception_salign_c) <= '1';
|
|
exc_ack_nxt(exception_lalign_c) <= '1';
|
|
exc_ack_nxt(exception_saccess_c) <= '1';
|
|
exc_ack_nxt(exception_laccess_c) <= '1';
|
|
|
|
-- undefined / not implemented --
|
-- undefined / not implemented --
|
else
|
else
|
exc_cause_nxt <= (others => '0'); -- default
|
exc_cause_nxt <= (others => '0');
|
exc_ack_nxt <= (others => '0'); -- default
|
irq_ack_nxt <= (others => '0');
|
end if;
|
end if;
|
end process exc_priority;
|
end process exc_priority;
|
|
|
|
|
-- Control and Status Registers Write Access ----------------------------------------------
|
-- Control and Status Registers Write Access ----------------------------------------------
|
Line 1098... |
Line 1057... |
mepc <= (others => '0');
|
mepc <= (others => '0');
|
mip_msip <= '0';
|
mip_msip <= '0';
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then
|
mip_msip <= '0';
|
mip_msip <= '0';
|
|
|
-- register that can be modified by user --
|
-- register that can be modified by user --
|
if (ctrl(ctrl_csr_we_c) = '1') then -- manual update
|
if (ctrl(ctrl_csr_we_c) = '1') then -- manual update
|
case i_reg(31 downto 20) is
|
|
-- machine trap setup --
|
-- machine trap setup --
|
when x"300" => -- R/W: mstatus - machine status register
|
if (i_reg(31 downto 24) = x"30") then
|
|
if (i_reg(23 downto 20) = x"0") then -- R/W: mstatus - machine status register
|
mstatus_mie <= csr_wdata_i(03);
|
mstatus_mie <= csr_wdata_i(03);
|
mstatus_mpie <= csr_wdata_i(07);
|
mstatus_mpie <= csr_wdata_i(07);
|
when x"304" => -- R/W: mie - machine interrupt-enable register
|
end if;
|
|
if (i_reg(23 downto 20) = x"4") then -- R/W: mie - machine interrupt-enable register
|
mie_msie <= csr_wdata_i(03); -- SW IRQ enable
|
mie_msie <= csr_wdata_i(03); -- SW IRQ enable
|
if (IO_MTIME_USE = true) then
|
|
mie_mtie <= csr_wdata_i(07); -- TIMER IRQ enable
|
mie_mtie <= csr_wdata_i(07); -- TIMER IRQ enable
|
end if;
|
|
if (IO_CLIC_USE = true) then
|
|
mie_meie <= csr_wdata_i(11); -- EXT IRQ enable
|
mie_meie <= csr_wdata_i(11); -- EXT IRQ enable
|
end if;
|
end if;
|
when x"305" => -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
if (i_reg(23 downto 20) = x"5") then -- R/W: mtvec - machine trap-handler base address (for ALL exceptions)
|
mtvec <= csr_wdata_i;
|
mtvec <= csr_wdata_i;
|
|
end if;
|
|
end if;
|
|
|
-- machine trap handling --
|
-- machine trap handling --
|
when x"340" => -- R/W: mscratch - machine scratch register
|
if (i_reg(31 downto 24) = x"34") then
|
|
if (i_reg(23 downto 20) = x"0") then -- R/W: mscratch - machine scratch register
|
mscratch <= csr_wdata_i;
|
mscratch <= csr_wdata_i;
|
when x"344" => -- R/W: mip - machine interrupt pending
|
end if;
|
mip_msip <= csr_wdata_i(03); -- manual SW IRQ trigger
|
if (i_reg(23 downto 20) = x"1") then-- R/W: mepc - machine exception program counter
|
-- machine trap handling --
|
|
when x"341" => -- R/W: mepc - machine exception program counter
|
|
mepc <= csr_wdata_i;
|
mepc <= csr_wdata_i;
|
-- undefined/unavailable --
|
end if;
|
when others =>
|
if (i_reg(23 downto 20) = x"4") then -- R/W: mip - machine interrupt pending
|
NULL;
|
mip_msip <= csr_wdata_i(03); -- manual SW IRQ trigger
|
end case;
|
end if;
|
|
end if;
|
|
|
else -- automatic update by hardware
|
else -- automatic update by hardware
|
-- machine exception PC & exception value register --
|
-- machine exception PC & exception value register --
|
if (exc_cpu_ack = '1') then -- exception start?
|
if (exc_cpu_ack = '1') then -- exception start?
|
if (exc_cause(exc_cause_nxt'left) = '1') then -- for INTERRUPTs: mepc = address of next (unclompeted) instruction
|
if (exc_cause(exc_cause_nxt'left) = '1') then -- for INTERRUPTs: mepc = address of next (unclompeted) instruction
|