Line 1... |
Line 1... |
-- #################################################################################################
|
-- #################################################################################################
|
-- # << NEORV32 - CPU Control >> #
|
-- # << NEORV32 - CPU Control >> #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # CPU operation is split into a fetch engine (responsible for fetching an decompressing instr- #
|
-- # CPU operation is split into a fetch engine (responsible for fetching instruction data), an #
|
-- # uctions), an execute engine (responsible for actually executing the instructions), an inter- #
|
-- # issue engine (for recoding compressed instructions and for constructing 32-bit instruction #
|
-- # rupt and exception handling controller and the RISC-V status and control registers (CSRs). #
|
-- # words) and an execute engine (responsible for actually executing the instructions), a trap #
|
|
-- # handling controller and the RISC-V status and control register set (CSRs). #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # BSD 3-Clause License #
|
-- # BSD 3-Clause License #
|
-- # #
|
-- # #
|
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
-- # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
-- # #
|
-- # #
|
Line 103... |
Line 104... |
end neorv32_cpu_control;
|
end neorv32_cpu_control;
|
|
|
architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
|
architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
|
|
|
-- instruction fetch enginge --
|
-- instruction fetch enginge --
|
type fetch_engine_state_t is (IFETCH_RESET, IFETCH_0, IFETCH_1, IFETCH_2);
|
type fetch_engine_state_t is (IFETCH_RESET, IFETCH_REQUEST, IFETCH_ISSUE);
|
type fetch_engine_t is record
|
type fetch_engine_t is record
|
state : fetch_engine_state_t;
|
state : fetch_engine_state_t;
|
state_nxt : fetch_engine_state_t;
|
state_nxt : fetch_engine_state_t;
|
i_buf : std_ulogic_vector(33 downto 0);
|
|
i_buf_nxt : std_ulogic_vector(33 downto 0);
|
|
i_buf2 : 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
|
|
i_buf_state : std_ulogic_vector(01 downto 0);
|
|
i_buf_state_nxt : std_ulogic_vector(01 downto 0);
|
|
pc : std_ulogic_vector(data_width_c-1 downto 0);
|
pc : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_add : std_ulogic_vector(data_width_c-1 downto 0);
|
pc_nxt : 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 --
|
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
|
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_data_fifo_t is array (0 to ipb_entries_c-1) of std_ulogic_vector(2+31 downto 0);
|
type ipb_t is record
|
type ipb_t is record
|
wdata : std_ulogic_vector(35 downto 0); -- data (+ status) to be written
|
wdata : std_ulogic_vector(2+31 downto 0); -- write status (bus_error, align_error) + 32-bit instruction data
|
we : std_ulogic; -- trigger write
|
we : std_ulogic; -- trigger write
|
free : std_ulogic; -- free entry available?
|
free : std_ulogic; -- free entry available?
|
|
clear : std_ulogic; -- clear all entries
|
--
|
--
|
rdata : std_ulogic_vector(35 downto 0); -- read data (+ status)
|
rdata : std_ulogic_vector(2+31 downto 0); -- read data: status (bus_error, align_error) + 32-bit instruction data
|
re : std_ulogic; -- trigger read
|
re : std_ulogic; -- read enable
|
avail : std_ulogic; -- data available?
|
avail : std_ulogic; -- data available?
|
--
|
--
|
clear : std_ulogic; -- clear all entries
|
|
--
|
|
data : ipb_dbuf_t; -- the data fifo
|
|
w_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- write pointer
|
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
|
r_pnt : std_ulogic_vector(index_size_f(ipb_entries_c) downto 0); -- read pointer
|
empty : std_ulogic;
|
empty : std_ulogic;
|
full : std_ulogic;
|
full : std_ulogic;
|
|
--
|
|
data : ipb_data_fifo_t; -- fifo memory
|
end record;
|
end record;
|
signal ipb : ipb_t;
|
signal ipb : ipb_t;
|
|
|
|
-- pre-decoder --
|
|
signal ci_instr16 : std_ulogic_vector(15 downto 0);
|
|
signal ci_instr32 : std_ulogic_vector(31 downto 0);
|
|
signal ci_illegal : std_ulogic;
|
|
|
|
-- instruction issue enginge --
|
|
type issue_engine_state_t is (ISSUE_ACTIVE, ISSUE_REALIGN);
|
|
type issue_engine_t is record
|
|
state : issue_engine_state_t;
|
|
state_nxt : issue_engine_state_t;
|
|
align : std_ulogic;
|
|
align_nxt : std_ulogic;
|
|
buf : std_ulogic_vector(2+15 downto 0);
|
|
buf_nxt : std_ulogic_vector(2+15 downto 0);
|
|
end record;
|
|
signal issue_engine : issue_engine_t;
|
|
|
|
-- instruction buffer --
|
|
type i_buf_t is record
|
|
wdata : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction
|
|
rdata : std_ulogic_vector(35 downto 0); -- 4-bit status + 32-bit instruction
|
|
status : std_ulogic;
|
|
clear : std_ulogic;
|
|
we : std_ulogic;
|
|
re : std_ulogic;
|
|
free : std_ulogic;
|
|
avail : std_ulogic;
|
|
end record;
|
|
signal i_buf : i_buf_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);
|
type execute_engine_t is record
|
type execute_engine_t is record
|
state : execute_engine_state_t;
|
state : execute_engine_state_t;
|
state_prev : execute_engine_state_t;
|
state_prev : execute_engine_state_t;
|
Line 255... |
Line 275... |
signal csr_acc_valid : std_ulogic; -- valid CSR access (implemented and valid access rights)
|
signal csr_acc_valid : std_ulogic; -- valid CSR access (implemented and valid access rights)
|
|
|
begin
|
begin
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Instruction Fetch
|
-- Instruction Fetch (always fetches aligned 32-bit chunks of data)
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
-- Fetch Engine FSM Sync ------------------------------------------------------------------
|
-- Fetch Engine FSM Sync ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- registers that require a specific reset state --
|
fetch_engine_fsm_sync: process(rstn_i, clk_i)
|
fetch_engine_fsm_sync_rst: process(rstn_i, clk_i)
|
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
fetch_engine.state <= IFETCH_RESET;
|
fetch_engine.state <= IFETCH_RESET;
|
|
fetch_engine.pc <= (others => '0');
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
if (fetch_engine.reset = '1') then
|
if (fetch_engine.reset = '1') then
|
fetch_engine.state <= IFETCH_RESET;
|
fetch_engine.state <= IFETCH_RESET;
|
else
|
else
|
fetch_engine.state <= fetch_engine.state_nxt;
|
fetch_engine.state <= fetch_engine.state_nxt;
|
end if;
|
end if;
|
end if;
|
fetch_engine.pc <= fetch_engine.pc_nxt;
|
end process fetch_engine_fsm_sync_rst;
|
|
|
|
|
|
-- registers that DO NOT require a specific reset state --
|
|
fetch_engine_fsm_sync: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (fetch_engine.state = IFETCH_RESET) then
|
|
fetch_engine.pc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
|
else
|
|
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'));
|
|
end if;
|
|
--
|
|
fetch_engine.i_buf <= fetch_engine.i_buf_nxt;
|
|
fetch_engine.i_buf2 <= fetch_engine.i_buf2_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(data_width_c-1 downto 1) & '0';
|
fetch_pc_o <= fetch_engine.pc(data_width_c-1 downto 1) & '0'; -- half-word aligned
|
|
|
|
|
-- 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, execute_engine, ipb, instr_i, bus_i_wait_i, 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_add <= (others => '0');
|
fetch_engine.pc_nxt <= fetch_engine.pc;
|
fetch_engine.i_buf_nxt <= fetch_engine.i_buf;
|
|
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf2;
|
|
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state;
|
|
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.wdata <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store exception info and instruction word
|
ipb.clear <= '0';
|
ipb.clear <= '0';
|
ipb.wdata <= (others => '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 and prefetch buffer, get appilcation PC
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.i_buf_state_nxt <= (others => '0');
|
|
ipb.clear <= '1'; -- clear instruction prefetch buffer
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
|
fetch_engine.pc_nxt <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC
|
|
ipb.clear <= '1'; -- clear prefetch buffer
|
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
|
|
when IFETCH_0 => -- output current PC to bus system, request 32-bit word
|
when IFETCH_REQUEST => -- output current PC to bus system and request 32-bit (aligned!) instruction data
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
if (ipb.free = '1') then -- free entry in buffer?
|
bus_fast_ir <= '1'; -- fast instruction fetch request
|
bus_fast_ir <= '1'; -- fast instruction fetch request
|
fetch_engine.state_nxt <= IFETCH_1;
|
fetch_engine.state_nxt <= IFETCH_ISSUE;
|
|
|
when IFETCH_1 => -- store data from memory to buffer(s)
|
|
-- ------------------------------------------------------------
|
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
|
fetch_engine.i_buf_nxt <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store data word and exception info
|
|
fetch_engine.i_buf2_nxt <= fetch_engine.i_buf;
|
|
fetch_engine.i_buf_state_nxt <= fetch_engine.i_buf_state(0) & '1';
|
|
if (fetch_engine.i_buf_state(0) = '1') then -- buffer filled?
|
|
fetch_engine.state_nxt <= IFETCH_2;
|
|
else
|
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0; -- get another instruction word
|
|
end if;
|
|
end if;
|
end if;
|
|
|
when IFETCH_2 => -- construct instruction word and issue
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
fetch_engine.bus_err_ack <= '1'; -- acknowledge any instruction bus errors, the execute engine has to take care of them / terminate current transfer
|
if (fetch_engine.pc(1) = '0') or (CPU_EXTENSION_RISCV_C = false) then -- 32-bit aligned
|
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4);
|
fetch_engine.ci_input <= fetch_engine.i_buf2(15 downto 00);
|
|
|
|
if (ipb.free = '1') then -- free entry in buffer?
|
|
ipb.we <= '1';
|
|
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);
|
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
|
else -- compressed
|
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf2(33 downto 32) & '1' & ci_instr32;
|
|
fetch_engine.pc_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
|
|
end if;
|
|
end if;
|
|
|
|
else -- 16-bit aligned
|
|
fetch_engine.ci_input <= fetch_engine.i_buf2(31 downto 16);
|
|
|
|
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 and "unaligned"
|
fetch_engine.state_nxt <= IFETCH_REQUEST;
|
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_add <= std_ulogic_vector(to_unsigned(4, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
|
else -- compressed
|
|
ipb.wdata <= ci_illegal & fetch_engine.i_buf(33 downto 32) & '1' & ci_instr32;
|
|
fetch_engine.pc_add <= std_ulogic_vector(to_unsigned(2, data_width_c));
|
|
fetch_engine.state_nxt <= IFETCH_0;
|
|
end if;
|
|
end if;
|
|
end if;
|
end if;
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
fetch_engine.state_nxt <= IFETCH_RESET;
|
fetch_engine.state_nxt <= IFETCH_RESET;
|
|
|
end case;
|
end case;
|
end process fetch_engine_fsm_comb;
|
end process fetch_engine_fsm_comb;
|
|
|
|
|
-- Compressed Instructions Recoding -------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
neorv32_cpu_decompressor_inst_true:
|
|
if (CPU_EXTENSION_RISCV_C = true) generate
|
|
neorv32_cpu_decompressor_inst: neorv32_cpu_decompressor
|
|
port map (
|
|
-- instruction input --
|
|
ci_instr16_i => fetch_engine.ci_input, -- compressed instruction input
|
|
-- instruction output --
|
|
ci_illegal_o => ci_illegal, -- is an illegal compressed instruction
|
|
ci_instr32_o => ci_instr32 -- 32-bit decompressed instruction
|
|
);
|
|
end generate;
|
|
|
|
neorv32_cpu_decompressor_inst_false:
|
|
if (CPU_EXTENSION_RISCV_C = false) generate
|
|
ci_instr32 <= (others => '0');
|
|
ci_illegal <= '0';
|
|
end generate;
|
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
-- Instruction Prefetch Buffer
|
-- Instruction Prefetch Buffer
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
Line 427... |
Line 367... |
if (ipb.clear = '1') then
|
if (ipb.clear = '1') then
|
ipb.w_pnt <= (others => '0');
|
ipb.w_pnt <= (others => '0');
|
elsif (ipb.we = '1') then
|
elsif (ipb.we = '1') then
|
ipb.w_pnt <= std_ulogic_vector(unsigned(ipb.w_pnt) + 1);
|
ipb.w_pnt <= std_ulogic_vector(unsigned(ipb.w_pnt) + 1);
|
end if;
|
end if;
|
-- read port --
|
-- read ports --
|
if (ipb.clear = '1') then
|
if (ipb.clear = '1') then
|
ipb.r_pnt <= (others => '0');
|
ipb.r_pnt <= (others => '0');
|
elsif (ipb.re = '1') then
|
elsif (ipb.re = '1') then
|
ipb.r_pnt <= std_ulogic_vector(unsigned(ipb.r_pnt) + 1);
|
ipb.r_pnt <= std_ulogic_vector(unsigned(ipb.r_pnt) + 1);
|
end if;
|
end if;
|
Line 446... |
Line 386... |
end if;
|
end if;
|
end if;
|
end if;
|
end process instr_prefetch_buffer_data;
|
end process instr_prefetch_buffer_data;
|
|
|
-- async read --
|
-- async read --
|
ipb.rdata <= ipb.data(to_integer(unsigned(ipb.r_pnt(ipb.w_pnt'left-1 downto 0))));
|
ipb.rdata <= ipb.data(to_integer(unsigned(ipb.r_pnt(ipb.r_pnt'left-1 downto 0))));
|
|
|
-- status --
|
-- 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.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.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.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.free <= not ipb.full;
|
ipb.avail <= not ipb.empty;
|
ipb.avail <= not ipb.empty;
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
-- Instruction Issue (recoding of compressed instructions and 32-bit instruction word construction)
|
|
-- ****************************************************************************************************************************
|
|
|
|
|
|
-- Issue Engine FSM Sync ------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
issue_engine_fsm_sync: process(rstn_i, clk_i)
|
|
begin
|
|
if (rstn_i = '0') then
|
|
issue_engine.state <= ISSUE_ACTIVE;
|
|
issue_engine.align <= CPU_BOOT_ADDR(1);
|
|
issue_engine.buf <= (others => '0');
|
|
elsif rising_edge(clk_i) then
|
|
if (ipb.clear = '1') then
|
|
if (CPU_EXTENSION_RISCV_C = true) then
|
|
if (execute_engine.pc(1) = '1') then -- branch to unaligned address?
|
|
issue_engine.state <= ISSUE_REALIGN;
|
|
issue_engine.align <= '1'; -- aligned on 16-bit boundary
|
|
else
|
|
issue_engine.state <= issue_engine.state_nxt;
|
|
issue_engine.align <= '0'; -- aligned on 32-bit boundary
|
|
end if;
|
|
else
|
|
issue_engine.state <= issue_engine.state_nxt;
|
|
issue_engine.align <= '0'; -- always aligned on 32-bit boundaries
|
|
end if;
|
|
else
|
|
issue_engine.state <= issue_engine.state_nxt;
|
|
issue_engine.align <= issue_engine.align_nxt;
|
|
end if;
|
|
issue_engine.buf <= issue_engine.buf_nxt;
|
|
end if;
|
|
end process issue_engine_fsm_sync;
|
|
|
|
|
|
-- Issue Engine FSM Comb ------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
issue_engine_fsm_comb: process(issue_engine, ipb, i_buf, execute_engine, ci_illegal, ci_instr32)
|
|
begin
|
|
-- arbiter defaults --
|
|
issue_engine.state_nxt <= issue_engine.state;
|
|
issue_engine.align_nxt <= issue_engine.align;
|
|
issue_engine.buf_nxt <= issue_engine.buf;
|
|
|
|
-- instruction prefetch buffer interface defaults --
|
|
ipb.re <= '0';
|
|
|
|
-- instruction buffer interface defaults --
|
|
i_buf.we <= '0';
|
|
i_buf.wdata <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0);
|
|
|
|
-- state machine --
|
|
case issue_engine.state is
|
|
|
|
when ISSUE_ACTIVE => -- issue instruction if available
|
|
-- ------------------------------------------------------------
|
|
if (ipb.avail = '1') then -- instructions available?
|
|
|
|
if (issue_engine.align = '0') or (CPU_EXTENSION_RISCV_C = false) then -- begin check in LOW instruction half-word
|
|
if (i_buf.free = '1') then
|
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
|
if (ipb.rdata(1 downto 0) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed and "aligned"
|
|
ipb.re <= '1';
|
|
i_buf.wdata <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0);
|
|
i_buf.we <= '1';
|
|
else -- compressed
|
|
ipb.re <= '1';
|
|
i_buf.wdata <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32;
|
|
i_buf.we <= '1';
|
|
issue_engine.align_nxt <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
else -- begin check in HIGH instruction half-word
|
|
if (i_buf.free = '1') then
|
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction
|
|
if (issue_engine.buf(1 downto 0) = "11") then -- uncompressed and "unaligned"
|
|
ipb.re <= '1';
|
|
i_buf.wdata <= '0' & issue_engine.buf(17 downto 16) & '0' & (ipb.rdata(15 downto 0) & issue_engine.buf(15 downto 0));
|
|
i_buf.we <= '1';
|
|
else -- compressed
|
|
--ipb.re <= '1';
|
|
i_buf.wdata <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32;
|
|
i_buf.we <= '1';
|
|
issue_engine.align_nxt <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
when ISSUE_REALIGN => -- re-align input fifos after a branch to an unaligned address
|
|
-- ------------------------------------------------------------
|
|
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16);
|
|
if (ipb.avail = '1') then -- instructions available?
|
|
ipb.re <= '1';
|
|
issue_engine.state_nxt <= ISSUE_ACTIVE;
|
|
end if;
|
|
|
|
when others => -- undefined
|
|
-- ------------------------------------------------------------
|
|
issue_engine.state_nxt <= ISSUE_ACTIVE;
|
|
|
|
end case;
|
|
end process issue_engine_fsm_comb;
|
|
|
|
-- 16-bit instruction: half-word select --
|
|
ci_instr16 <= ipb.rdata(15 downto 0) when (issue_engine.align = '0') else issue_engine.buf(15 downto 0);
|
|
|
|
|
|
-- Compressed Instructions Recoding -------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
neorv32_cpu_decompressor_inst_true:
|
|
if (CPU_EXTENSION_RISCV_C = true) generate
|
|
neorv32_cpu_decompressor_inst: neorv32_cpu_decompressor
|
|
port map (
|
|
-- instruction input --
|
|
ci_instr16_i => ci_instr16, -- compressed instruction input
|
|
-- instruction output --
|
|
ci_illegal_o => ci_illegal, -- is an illegal compressed instruction
|
|
ci_instr32_o => ci_instr32 -- 32-bit decompressed instruction
|
|
);
|
|
end generate;
|
|
|
|
neorv32_cpu_decompressor_inst_false:
|
|
if (CPU_EXTENSION_RISCV_C = false) generate
|
|
ci_instr32 <= (others => '0');
|
|
ci_illegal <= '0';
|
|
end generate;
|
|
|
|
|
|
-- Instruction Buffer ---------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
instruction_buffer_ctrl: process(rstn_i, clk_i)
|
|
begin
|
|
if (rstn_i = '0') then
|
|
i_buf.status <= '0';
|
|
elsif rising_edge(clk_i) then
|
|
if (i_buf.clear = '1') then
|
|
i_buf.status <= '0';
|
|
elsif (i_buf.we = '1') then
|
|
i_buf.status <= '1';
|
|
elsif (i_buf.re = '1') then
|
|
i_buf.status <= '0';
|
|
end if;
|
|
end if;
|
|
end process instruction_buffer_ctrl;
|
|
|
|
instruction_buffer_data: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (i_buf.we = '1') and (ipb.clear = '0') then
|
|
i_buf.rdata <= i_buf.wdata;
|
|
end if;
|
|
end if;
|
|
end process instruction_buffer_data;
|
|
|
|
-- status --
|
|
i_buf.free <= not i_buf.status;
|
|
i_buf.avail <= i_buf.status;
|
|
|
|
-- clear i_buf when clearing ipb --
|
|
i_buf.clear <= ipb.clear;
|
|
|
|
|
|
-- ****************************************************************************************************************************
|
-- Instruction Execution
|
-- Instruction Execution
|
-- ****************************************************************************************************************************
|
-- ****************************************************************************************************************************
|
|
|
|
|
-- Immediate Generator --------------------------------------------------------------------
|
-- Immediate Generator --------------------------------------------------------------------
|
Line 582... |
Line 687... |
end process ctrl_output;
|
end process ctrl_output;
|
|
|
|
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
execute_engine_fsm_comb: process(execute_engine, fetch_engine, ipb, trap_ctrl, csr, ctrl, csr_acc_valid,
|
execute_engine_fsm_comb: process(execute_engine, fetch_engine, i_buf, trap_ctrl, csr, ctrl, csr_acc_valid,
|
alu_res_i, alu_wait_i, bus_d_wait_i, ma_load_i, be_load_i, ma_store_i, be_store_i)
|
alu_res_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_immediate_v : std_ulogic;
|
variable rs1_is_r0_v : std_ulogic;
|
variable rs1_is_r0_v : std_ulogic;
|
begin
|
begin
|
-- arbiter defaults --
|
-- arbiter defaults --
|
Line 600... |
Line 705... |
execute_engine.sleep_nxt <= execute_engine.sleep;
|
execute_engine.sleep_nxt <= execute_engine.sleep;
|
execute_engine.if_rst_nxt <= execute_engine.if_rst;
|
execute_engine.if_rst_nxt <= execute_engine.if_rst;
|
|
|
-- instruction dispatch --
|
-- instruction dispatch --
|
fetch_engine.reset <= '0';
|
fetch_engine.reset <= '0';
|
ipb.re <= '0';
|
i_buf.re <= '0';
|
|
|
-- trap environment control --
|
-- trap environment control --
|
trap_ctrl.env_start_ack <= '0';
|
trap_ctrl.env_start_ack <= '0';
|
trap_ctrl.env_end <= '0';
|
trap_ctrl.env_end <= '0';
|
|
|
Line 656... |
Line 761... |
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;
|
|
|
when DISPATCH => -- Get new command from instruction prefetch buffer (IPB)
|
when DISPATCH => -- Get new command from instruction buffer (I_BUF)
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
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_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= i_buf.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_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= i_buf.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
|
ctrl_nxt(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= i_buf.rdata(instr_rs2_msb_c downto instr_rs2_lsb_c); -- rs2 addr
|
--
|
--
|
if (ipb.avail = '1') then -- instruction available?
|
if (i_buf.avail = '1') then -- instruction available?
|
ipb.re <= '1';
|
i_buf.re <= '1';
|
--
|
--
|
execute_engine.is_ci_nxt <= ipb.rdata(32); -- flag to indicate this is a de-compressed instruction beeing executed
|
execute_engine.is_ci_nxt <= i_buf.rdata(32); -- flag to indicate this is a de-compressed instruction beeing executed
|
execute_engine.i_reg_nxt <= ipb.rdata(31 downto 0);
|
execute_engine.i_reg_nxt <= i_buf.rdata(31 downto 0);
|
execute_engine.if_rst_nxt <= '0';
|
execute_engine.if_rst_nxt <= '0';
|
--
|
--
|
trap_ctrl.instr_ma <= ipb.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_ma <= i_buf.rdata(33); -- misaligned instruction fetch address
|
trap_ctrl.instr_be <= ipb.rdata(34); -- bus access fault during instrucion fetch
|
trap_ctrl.instr_be <= i_buf.rdata(34); -- bus access fault during instrucion fetch
|
illegal_compressed <= ipb.rdata(35); -- invalid decompressed instruction
|
illegal_compressed <= i_buf.rdata(35); -- invalid decompressed instruction
|
--
|
--
|
if (execute_engine.if_rst = '0') then -- if there was NO non-linear PC modification
|
if (execute_engine.if_rst = '0') then -- if there was NO non-linear PC modification
|
execute_engine.pc_nxt <= execute_engine.next_pc;
|
execute_engine.pc_nxt <= execute_engine.next_pc;
|
end if;
|
end if;
|
--
|
--
|
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 ((i_buf.rdata(33) or i_buf.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;
|