Line 117... |
Line 117... |
i_buf2 : std_ulogic_vector(33 downto 0);
|
i_buf2 : std_ulogic_vector(33 downto 0);
|
i_buf2_nxt : std_ulogic_vector(33 downto 0);
|
i_buf2_nxt : std_ulogic_vector(33 downto 0);
|
ci_input : std_ulogic_vector(15 downto 0); -- input to compressed instr. decoder
|
ci_input : std_ulogic_vector(15 downto 0); -- input to compressed instr. decoder
|
i_buf_state : std_ulogic_vector(01 downto 0);
|
i_buf_state : std_ulogic_vector(01 downto 0);
|
i_buf_state_nxt : std_ulogic_vector(01 downto 0);
|
i_buf_state_nxt : std_ulogic_vector(01 downto 0);
|
pc_real : std_ulogic_vector(data_width_c-1 downto 0);
|
pc : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_real_add : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_add : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_fetch : std_ulogic_vector(data_width_c-1 downto 0);
|
|
pc_fetch_add : std_ulogic_vector(data_width_c-1 downto 0);
|
|
reset : std_ulogic;
|
reset : std_ulogic;
|
bus_err_ack : std_ulogic;
|
bus_err_ack : std_ulogic;
|
end record;
|
end record;
|
signal fetch_engine : fetch_engine_t;
|
signal fetch_engine : fetch_engine_t;
|
|
|
-- pre-decoder --
|
-- pre-decoder --
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
signal ci_illegal : std_ulogic;
|
signal ci_illegal : std_ulogic;
|
|
|
-- instrucion prefetch buffer (IPB) --
|
-- instrucion prefetch buffer (IPB) --
|
|
type ipb_dbuf_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(35 downto 0);
|
type ipb_t is record
|
type ipb_t is record
|
wdata : std_ulogic_vector(35 downto 0);
|
wdata : std_ulogic_vector(35 downto 0); -- data (+ status) to be written
|
rdata : std_ulogic_vector(35 downto 0);
|
we : std_ulogic; -- trigger write
|
waddr : std_ulogic_vector(31 downto 0);
|
free : std_ulogic; -- free entry available?
|
raddr : std_ulogic_vector(31 downto 0);
|
--
|
status : std_ulogic;
|
rdata : std_ulogic_vector(35 downto 0); -- read data (+ status)
|
free : std_ulogic;
|
re : std_ulogic; -- trigger read
|
avail : std_ulogic;
|
avail : std_ulogic; -- data available?
|
we : std_ulogic;
|
--
|
re : std_ulogic;
|
clear : std_ulogic; -- clear all entries
|
clear : std_ulogic;
|
--
|
|
data : ipb_dbuf_t; -- the data fifo
|
|
w_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- write pointer
|
|
r_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- read pointer
|
|
empty : std_ulogic;
|
|
full : std_ulogic;
|
end record;
|
end record;
|
signal ipb : ipb_t;
|
signal ipb : ipb_t;
|
|
|
-- instruction execution engine --
|
-- instruction execution engine --
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, CSR_ACCESS);
|
type execute_engine_state_t is (SYS_WAIT, DISPATCH, TRAP, EXECUTE, ALU_WAIT, BRANCH, LOADSTORE_0, LOADSTORE_1, LOADSTORE_2, CSR_ACCESS);
|
Line 164... |
Line 168... |
pc_nxt : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_nxt : std_ulogic_vector(data_width_c-1 downto 0);
|
next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next PC, corresponding to next instruction to be executed
|
next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next PC, corresponding to next instruction to be executed
|
last_pc : std_ulogic_vector(data_width_c-1 downto 0); -- PC of last executed instruction
|
last_pc : std_ulogic_vector(data_width_c-1 downto 0); -- PC of last executed instruction
|
sleep : std_ulogic; -- CPU in sleep mode
|
sleep : std_ulogic; -- CPU in sleep mode
|
sleep_nxt : std_ulogic; -- CPU in sleep mode
|
sleep_nxt : std_ulogic; -- CPU in sleep mode
|
|
if_rst : std_ulogic; -- instruction fetch was reset
|
|
if_rst_nxt : std_ulogic; -- instruction fetch was reset
|
end record;
|
end record;
|
signal execute_engine : execute_engine_t;
|
signal execute_engine : execute_engine_t;
|
|
|
signal next_pc_tmp : std_ulogic_vector(data_width_c-1 downto 0);
|
signal next_pc_tmp : std_ulogic_vector(data_width_c-1 downto 0);
|
|
|
Line 290... |
Line 296... |
-- for registers that DO NOT require a specific reset state --
|
-- for registers that DO NOT require a specific reset state --
|
fetch_engine_fsm_sync: process(clk_i)
|
fetch_engine_fsm_sync: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if (fetch_engine.state = IFETCH_RESET) then
|
if (fetch_engine.state = IFETCH_RESET) then
|
fetch_engine.pc_fetch <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
fetch_engine.pc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
fetch_engine.pc_real <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
|
else
|
else
|
fetch_engine.pc_real <= std_ulogic_vector(unsigned(fetch_engine.pc_real(data_width_c-1 downto 1) & '0') + unsigned(fetch_engine.pc_real_add(data_width_c-1 downto 1) & '0'));
|
fetch_engine.pc <= std_ulogic_vector(unsigned(fetch_engine.pc(data_width_c-1 downto 1) & '0') + unsigned(fetch_engine.pc_add(data_width_c-1 downto 1) & '0'));
|
fetch_engine.pc_fetch <= std_ulogic_vector(unsigned(fetch_engine.pc_fetch(data_width_c-1 downto 1) & '0') + unsigned(fetch_engine.pc_fetch_add(data_width_c-1 downto 1) & '0'));
|
|
end if;
|
end if;
|
--
|
--
|
fetch_engine.i_buf <= fetch_engine.i_buf_nxt;
|
fetch_engine.i_buf <= fetch_engine.i_buf_nxt;
|
fetch_engine.i_buf2 <= fetch_engine.i_buf2_nxt;
|
fetch_engine.i_buf2 <= fetch_engine.i_buf2_nxt;
|
fetch_engine.i_buf_state <= fetch_engine.i_buf_state_nxt;
|
fetch_engine.i_buf_state <= fetch_engine.i_buf_state_nxt;
|
end if;
|
end if;
|
end process fetch_engine_fsm_sync;
|
end process fetch_engine_fsm_sync;
|
|
|
-- PC output --
|
-- PC output --
|
fetch_pc_o <= fetch_engine.pc_fetch(data_width_c-1 downto 1) & '0';
|
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0';
|
|
|
|
|
-- Fetch Engine FSM Comb ------------------------------------------------------------------
|
-- Fetch Engine FSM Comb ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
fetch_engine_fsm_comb: process(fetch_engine, csr, ipb, instr_i, bus_i_wait_i, ci_instr32, ci_illegal, be_instr_i, ma_instr_i)
|
fetch_engine_fsm_comb: process(fetch_engine, csr, ipb, instr_i, bus_i_wait_i, ci_instr32, ci_illegal, be_instr_i, ma_instr_i)
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
bus_fast_ir <= '0';
|
bus_fast_ir <= '0';
|
fetch_engine.state_nxt <= fetch_engine.state;
|
fetch_engine.state_nxt <= fetch_engine.state;
|
fetch_engine.pc_fetch_add <= (others => '0');
|
fetch_engine.pc_add <= (others => '0');
|
fetch_engine.pc_real_add <= (others => '0');
|
|
fetch_engine.i_buf_nxt <= fetch_engine.i_buf;
|
fetch_engine.i_buf_nxt <= fetch_engine.i_buf;
|
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf2;
|
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf2;
|
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state;
|
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state;
|
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00);
|
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00);
|
fetch_engine.bus_err_ack <= '0';
|
fetch_engine.bus_err_ack <= '0';
|
|
|
-- instruction prefetch buffer interface --
|
-- instruction prefetch buffer interface --
|
ipb.we <= '0';
|
ipb.we <= '0';
|
ipb.clear <= '0';
|
ipb.clear <= '0';
|
ipb.wdata <= (others => '0');
|
ipb.wdata <= (others => '0');
|
ipb.waddr <= fetch_engine.pc_real(data_width_c-1 downto 1) & '0';
|
|
|
|
-- state machine --
|
-- state machine --
|
case fetch_engine.state is
|
case fetch_engine.state is
|
|
|
when IFETCH_RESET => -- reset engine, prefetch buffer, get appilcation PC
|
when IFETCH_RESET => -- reset engine, prefetch buffer, get appilcation PC
|
Line 352... |
Line 354... |
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state(0) & '1';
|
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state(0) & '1';
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them
|
if (fetch_engine.i_buf_state(0) = '1') then -- buffer filled?
|
if (fetch_engine.i_buf_state(0) = '1') then -- buffer filled?
|
fetch_engine.state_nxt <= IFETCH_2;
|
fetch_engine.state_nxt <= IFETCH_2;
|
else
|
else
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.state_nxt <= IFETCH_0; -- get another instruction word
|
fetch_engine.state_nxt <= IFETCH_0; -- get another instruction word
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when IFETCH_2 => -- construct instruction word and issue
|
when IFETCH_2 => -- construct instruction word and issue
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (fetch_engine.pc_fetch(1) = '0') or (CPU_EXTENSION_RISCV_C = false) then -- 32-bit aligned
|
if (fetch_engine.pc(1) = '0') or (CPU_EXTENSION_RISCV_C = false) then -- 32-bit aligned
|
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00);
|
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00);
|
|
|
if (ipb.free = '1') then -- free entry in buffer?
|
if (ipb.free = '1') then -- free entry in buffer?
|
ipb.we <= '1';
|
ipb.we <= '1';
|
if (fetch_engine.i_buf2(01 downto 00) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed
|
if (fetch_engine.i_buf2(01 downto 00) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed
|
ipb.wdata <= '0' & fetch_engine.i_buf2(33 downto 32) & '0' & fetch_engine.i_buf2(31 downto 0);
|
ipb.wdata <= '0' & fetch_engine.i_buf2(33 downto 32) & '0' & fetch_engine.i_buf2(31 downto 0);
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
fetch_engine.state_nxt <= IFETCH_0;
|
else -- compressed
|
else -- compressed
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf2(33 downto 32) & '1' & ci_instr32;
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf2(33 downto 32) & '1' & ci_instr32;
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_2; -- try to get another 16-bit instruction word in next round
|
fetch_engine.state_nxt <= IFETCH_2; -- try to get another 16-bit instruction word in next round
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
else -- 16-bit aligned
|
else -- 16-bit aligned
|
Line 384... |
Line 384... |
|
|
if (ipb.free = '1') then -- free entry in buffer?
|
if (ipb.free = '1') then -- free entry in buffer?
|
ipb.we <= '1';
|
ipb.we <= '1';
|
if (fetch_engine.i_buf2(17 downto 16) = "11") then -- uncompressed
|
if (fetch_engine.i_buf2(17 downto 16) = "11") then -- uncompressed
|
ipb.wdata <= '0' & fetch_engine.i_buf(33 downto 32) & '0' & fetch_engine.i_buf(15 downto 00) & fetch_engine.i_buf2(31 downto 16);
|
ipb.wdata <= '0' & fetch_engine.i_buf(33 downto 32) & '0' & fetch_engine.i_buf(15 downto 00) & fetch_engine.i_buf2(31 downto 16);
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
fetch_engine.state_nxt <= IFETCH_0;
|
else -- compressed
|
else -- compressed
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32;
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32;
|
fetch_engine.pc_fetch_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
fetch_engine.pc_real_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
fetch_engine.state_nxt <= IFETCH_0;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
Line 409... |
Line 407... |
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Instruction Prefetch Buffer
|
-- Instruction Prefetch Buffer
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
-- Instruction Prefetch Buffer Stage ------------------------------------------------------
|
-- Instruction Prefetch Buffer (FIFO) -----------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
instr_prefetch_buffer: process(rstn_i, clk_i) -- once upon a time, this was a fifo with 8 entries
|
instr_prefetch_buffer_ctrl: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
ipb.status <= '0';
|
ipb.w_pnt <= (others => '0');
|
ipb.rdata <= (others => '0');
|
ipb.r_pnt <= (others => '0');
|
ipb.raddr <= (others => '0');
|
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
|
-- write port --
|
if (ipb.clear = '1') then
|
if (ipb.clear = '1') then
|
ipb.status <= '0';
|
ipb.w_pnt <= (others => '0');
|
elsif (ipb.we = '1') then
|
elsif (ipb.we = '1') then
|
ipb.status <= '1';
|
ipb.w_pnt <= std_ulogic_vector(unsigned(ipb.w_pnt) + 1);
|
|
end if;
|
|
-- read port --
|
|
if (ipb.clear = '1') then
|
|
ipb.r_pnt <= (others => '0');
|
elsif (ipb.re = '1') then
|
elsif (ipb.re = '1') then
|
ipb.status <= '0';
|
ipb.r_pnt <= std_ulogic_vector(unsigned(ipb.r_pnt) + 1);
|
end if;
|
end if;
|
if (ipb.we = '1') then
|
|
ipb.rdata <= ipb.wdata;
|
|
ipb.raddr <= ipb.waddr;
|
|
end if;
|
end if;
|
|
end process instr_prefetch_buffer_ctrl;
|
|
|
|
instr_prefetch_buffer_data: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (ipb.we = '1') then -- write port
|
|
ipb.data(to_integer(unsigned(ipb.w_pnt(ipb.w_pnt'left-1 downto 0)))) <= ipb.wdata;
|
end if;
|
end if;
|
end process instr_prefetch_buffer;
|
end if;
|
|
end process instr_prefetch_buffer_data;
|
|
|
|
-- async read --
|
|
ipb.rdata <= ipb.data(to_integer(unsigned(ipb.r_pnt(ipb.w_pnt'left-1 downto 0))));
|
|
|
-- status --
|
-- status --
|
ipb.free <= not ipb.status;
|
ipb.full <= '1' when (ipb.r_pnt(ipb.r_pnt'left) /= ipb.w_pnt(ipb.w_pnt'left)) and (ipb.r_pnt(ipb.r_pnt'left-1 downto 0) = ipb.w_pnt(ipb.w_pnt'left-1 downto 0)) else '0';
|
ipb.avail <= ipb.status;
|
ipb.empty <= '1' when (ipb.r_pnt(ipb.r_pnt'left) = ipb.w_pnt(ipb.w_pnt'left)) and (ipb.r_pnt(ipb.r_pnt'left-1 downto 0) = ipb.w_pnt(ipb.w_pnt'left-1 downto 0)) else '0';
|
|
|
|
ipb.free <= not ipb.full;
|
|
ipb.avail <= not ipb.empty;
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Instruction Execution
|
-- Instruction Execution
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
Line 512... |
Line 525... |
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.last_pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.last_pc <= CPU_BOOT_ADDR(data_width_c-1 downto 1) & '0';
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.state <= SYS_WAIT;
|
execute_engine.sleep <= '0';
|
execute_engine.sleep <= '0';
|
|
execute_engine.if_rst <= '1'; -- IF is reset after system reset
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
execute_engine.pc <= execute_engine.pc_nxt(data_width_c-1 downto 1) & '0';
|
execute_engine.pc <= execute_engine.pc_nxt(data_width_c-1 downto 1) & '0';
|
if (execute_engine.state = EXECUTE) then
|
if (execute_engine.state = EXECUTE) then
|
execute_engine.last_pc <= execute_engine.pc(data_width_c-1 downto 1) & '0';
|
execute_engine.last_pc <= execute_engine.pc(data_width_c-1 downto 1) & '0';
|
end if;
|
end if;
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.state <= execute_engine.state_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
execute_engine.sleep <= execute_engine.sleep_nxt;
|
|
execute_engine.if_rst <= execute_engine.if_rst_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync_rst;
|
end process execute_engine_fsm_sync_rst;
|
|
|
|
|
-- for registers that do NOT require a specific reset state --
|
-- for registers that do NOT require a specific reset state --
|
Line 536... |
Line 551... |
--
|
--
|
ctrl <= ctrl_nxt;
|
ctrl <= ctrl_nxt;
|
end if;
|
end if;
|
end process execute_engine_fsm_sync;
|
end process execute_engine_fsm_sync;
|
|
|
-- PC output --
|
-- next PC --
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0';
|
|
next_pc_tmp <= std_ulogic_vector(unsigned(execute_engine.pc) + 2) when (execute_engine.is_ci = '1') else std_ulogic_vector(unsigned(execute_engine.pc) + 4);
|
next_pc_tmp <= std_ulogic_vector(unsigned(execute_engine.pc) + 2) when (execute_engine.is_ci = '1') else std_ulogic_vector(unsigned(execute_engine.pc) + 4);
|
execute_engine.next_pc <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
execute_engine.next_pc <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
|
|
|
-- PC output --
|
|
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0';
|
next_pc_o <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
next_pc_o <= next_pc_tmp(data_width_c-1 downto 1) & '0';
|
|
|
|
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- CPU Control Bus Output -----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 575... |
Line 592... |
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
execute_engine.i_reg_nxt <= execute_engine.i_reg;
|
execute_engine.is_jump_nxt <= '0';
|
execute_engine.is_jump_nxt <= '0';
|
execute_engine.is_ci_nxt <= execute_engine.is_ci;
|
execute_engine.is_ci_nxt <= execute_engine.is_ci;
|
execute_engine.pc_nxt <= execute_engine.pc;
|
execute_engine.pc_nxt <= execute_engine.pc;
|
execute_engine.sleep_nxt <= execute_engine.sleep;
|
execute_engine.sleep_nxt <= execute_engine.sleep;
|
|
execute_engine.if_rst_nxt <= execute_engine.if_rst;
|
|
|
-- instruction dispatch --
|
-- instruction dispatch --
|
fetch_engine.reset <= '0';
|
fetch_engine.reset <= '0';
|
ipb.re <= '0';
|
ipb.re <= '0';
|
|
|
Line 652... |
Line 670... |
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?
|
if (ipb.avail = '1') then -- instruction available?
|
ipb.re <= '1';
|
ipb.re <= '1';
|
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault druing instrucion fetch
|
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch
|
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction
|
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction
|
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a compressed instruction beeing executed
|
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.i_reg_nxt <= ipb.rdata(31 downto 0);
|
execute_engine.pc_nxt <= ipb.raddr; -- the PC according to the current instruction
|
execute_engine.if_rst_nxt <= '0';
|
-- ipb.rdata(35) is not immediately checked here!
|
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;
|
|
-- ipb.rdata(35) (invalid decompressed instruction) is not immediately checked here!
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((ipb.rdata(33) or ipb.rdata(34)) = '1') then
|
if (execute_engine.sleep = '1') or (trap_ctrl.env_start = '1') or ((ipb.rdata(33) or ipb.rdata(34)) = '1') then
|
execute_engine.state_nxt <= TRAP;
|
execute_engine.state_nxt <= TRAP;
|
else
|
else
|
execute_engine.state_nxt <= EXECUTE;
|
execute_engine.state_nxt <= EXECUTE;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when TRAP => -- Start trap environment (also used as cpu sleep state)
|
when TRAP => -- Start trap environment (also used as cpu sleep state)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
if (trap_ctrl.env_start = '1') then -- check here again if we came directly from DISPATCH
|
if (trap_ctrl.env_start = '1') then -- check here again if we came directly from DISPATCH
|
trap_ctrl.env_start_ack <= '1';
|
trap_ctrl.env_start_ack <= '1';
|
execute_engine.pc_nxt <= csr.mtvec;
|
execute_engine.pc_nxt <= csr.mtvec;
|
execute_engine.sleep_nxt <= '0'; -- waky waky
|
execute_engine.sleep_nxt <= '0'; -- waky waky
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
Line 749... |
Line 771... |
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
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.pc_nxt <= execute_engine.next_pc; -- "refetch" next instruction (only relevant for fencei)
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCE.I
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCEI
|
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
|
execute_engine.pc_nxt <= execute_engine.next_pc; -- "refetch" next instruction (only relevant for fence.i)
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
|
end if;
|
end if;
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
|
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
ctrl_nxt(ctrl_bus_fence_c) <= '1';
|
end if;
|
end if;
|
Line 772... |
Line 795... |
trap_ctrl.break_point <= '1';
|
trap_ctrl.break_point <= '1';
|
when funct12_mret_c => -- MRET
|
when funct12_mret_c => -- MRET
|
trap_ctrl.env_end <= '1';
|
trap_ctrl.env_end <= '1';
|
execute_engine.pc_nxt <= csr.mepc;
|
execute_engine.pc_nxt <= csr.mepc;
|
fetch_engine.reset <= '1';
|
fetch_engine.reset <= '1';
|
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
when funct12_wfi_c => -- WFI = "CPU sleep"
|
when funct12_wfi_c => -- WFI = "CPU sleep"
|
execute_engine.sleep_nxt <= '1'; -- good night
|
execute_engine.sleep_nxt <= '1'; -- good night
|
when others => -- undefined
|
when others => -- undefined
|
NULL;
|
NULL;
|
end case;
|
end case;
|
Line 854... |
Line 878... |
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
when BRANCH => -- update PC for taken branches and jumps
|
when BRANCH => -- update PC for taken branches and jumps
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
execute_engine.pc_nxt <= alu_add_i; -- branch/jump destination
|
|
if (execute_engine.is_jump = '1') or (execute_engine.branch_taken = '1') then
|
if (execute_engine.is_jump = '1') or (execute_engine.branch_taken = '1') then
|
|
execute_engine.pc_nxt <= alu_add_i; -- branch/jump destination
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
fetch_engine.reset <= '1'; -- trigger new instruction fetch from modified PC
|
|
execute_engine.if_rst_nxt <= '1'; -- this is a non-linear PC modification
|
execute_engine.state_nxt <= SYS_WAIT;
|
execute_engine.state_nxt <= SYS_WAIT;
|
else
|
else
|
execute_engine.state_nxt <= DISPATCH;
|
execute_engine.state_nxt <= DISPATCH;
|
end if;
|
end if;
|
|
|
Line 1389... |
Line 1414... |
end if;
|
end if;
|
-- pmpaddr --
|
-- pmpaddr --
|
if (execute_engine.i_reg(27 downto 24) = x"b") then
|
if (execute_engine.i_reg(27 downto 24) = x"b") then
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
for i in 0 to PMP_NUM_REGIONS-1 loop
|
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
if (execute_engine.i_reg(23 downto 20) = std_ulogic_vector(to_unsigned(i, 4))) and (csr.pmpcfg(i)(7) = '0') then -- unlocked pmpaddr access
|
csr.pmpaddr(i) <= csr_wdata_i;
|
csr.pmpaddr(i) <= csr_wdata_i(31 downto 1) & '0'; -- min granularity is 8 bytes -> bit zero cannot be configured
|
end if;
|
end if;
|
end loop; -- i (CSRs)
|
end loop; -- i (CSRs)
|
end if;
|
end if;
|
end if; -- implement PMP at all?
|
end if; -- implement PMP at all?
|
end if;
|
end if;
|