Line 58... |
Line 58... |
host_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
host_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
host_wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
host_wdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
host_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable
|
host_ben_i : in std_ulogic_vector(03 downto 0); -- byte enable
|
host_we_i : in std_ulogic; -- write enable
|
host_we_i : in std_ulogic; -- write enable
|
host_re_i : in std_ulogic; -- read enable
|
host_re_i : in std_ulogic; -- read enable
|
host_cancel_i : in std_ulogic; -- cancel current bus transaction
|
|
host_ack_o : out std_ulogic; -- bus transfer acknowledge
|
host_ack_o : out std_ulogic; -- bus transfer acknowledge
|
host_err_o : out std_ulogic; -- bus transfer error
|
host_err_o : out std_ulogic; -- bus transfer error
|
-- peripheral bus interface --
|
-- peripheral bus interface --
|
bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address
|
bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data
|
bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
bus_wdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus write data
|
bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
bus_ben_o : out std_ulogic_vector(03 downto 0); -- byte enable
|
bus_we_o : out std_ulogic; -- write enable
|
bus_we_o : out std_ulogic; -- write enable
|
bus_re_o : out std_ulogic; -- read enable
|
bus_re_o : out std_ulogic; -- read enable
|
bus_cancel_o : out std_ulogic; -- cancel current bus transaction
|
|
bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
bus_ack_i : in std_ulogic; -- bus transfer acknowledge
|
bus_err_i : in std_ulogic -- bus transfer error
|
bus_err_i : in std_ulogic -- bus transfer error
|
);
|
);
|
end neorv32_icache;
|
end neorv32_icache;
|
|
|
Line 130... |
Line 128... |
end record;
|
end record;
|
signal cache : cache_if_t;
|
signal cache : cache_if_t;
|
|
|
-- control engine --
|
-- control engine --
|
type ctrl_engine_state_t is (S_IDLE, S_CACHE_CLEAR, S_CACHE_CHECK, S_CACHE_MISS, S_BUS_DOWNLOAD_REQ, S_BUS_DOWNLOAD_GET,
|
type ctrl_engine_state_t is (S_IDLE, S_CACHE_CLEAR, S_CACHE_CHECK, S_CACHE_MISS, S_BUS_DOWNLOAD_REQ, S_BUS_DOWNLOAD_GET,
|
S_CACHE_RESYNC_0, S_CACHE_RESYNC_1, S_BUS_ERROR, S_ERROR, S_HOST_CANCEL);
|
S_CACHE_RESYNC_0, S_CACHE_RESYNC_1, S_BUS_ERROR);
|
type ctrl_t is record
|
type ctrl_t is record
|
state : ctrl_engine_state_t; -- current state
|
state : ctrl_engine_state_t; -- current state
|
state_nxt : ctrl_engine_state_t; -- next state
|
state_nxt : ctrl_engine_state_t; -- next state
|
addr_reg : std_ulogic_vector(31 downto 0); -- address register for block download
|
addr_reg : std_ulogic_vector(31 downto 0); -- address register for block download
|
addr_reg_nxt : std_ulogic_vector(31 downto 0);
|
addr_reg_nxt : std_ulogic_vector(31 downto 0);
|
--
|
--
|
re_buf : std_ulogic; -- read request buffer
|
re_buf : std_ulogic; -- read request buffer
|
re_buf_nxt : std_ulogic;
|
re_buf_nxt : std_ulogic;
|
cancel_buf : std_ulogic; -- cancel request buffer
|
|
cancel_buf_nxt : std_ulogic;
|
|
end record;
|
end record;
|
signal ctrl : ctrl_t;
|
signal ctrl : ctrl_t;
|
|
|
begin
|
begin
|
|
|
Line 165... |
Line 161... |
ctrl_engine_fsm_sync_rst: process(rstn_i, clk_i)
|
ctrl_engine_fsm_sync_rst: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
ctrl.state <= S_CACHE_CLEAR;
|
ctrl.state <= S_CACHE_CLEAR;
|
ctrl.re_buf <= '0';
|
ctrl.re_buf <= '0';
|
ctrl.cancel_buf <= '0';
|
|
elsif rising_edge(clk_i) then
|
elsif rising_edge(clk_i) then
|
ctrl.state <= ctrl.state_nxt;
|
ctrl.state <= ctrl.state_nxt;
|
ctrl.re_buf <= ctrl.re_buf_nxt;
|
ctrl.re_buf <= ctrl.re_buf_nxt;
|
ctrl.cancel_buf <= ctrl.cancel_buf_nxt;
|
|
end if;
|
end if;
|
end process ctrl_engine_fsm_sync_rst;
|
end process ctrl_engine_fsm_sync_rst;
|
|
|
-- registers that do not require a specific reset state --
|
-- registers that do not require a specific reset state --
|
ctrl_engine_fsm_sync: process(clk_i)
|
ctrl_engine_fsm_sync: process(clk_i)
|
Line 184... |
Line 178... |
end process ctrl_engine_fsm_sync;
|
end process ctrl_engine_fsm_sync;
|
|
|
|
|
-- Control Engine FSM Comb ----------------------------------------------------------------
|
-- Control Engine FSM Comb ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
ctrl_engine_fsm_comb: process(ctrl, cache, clear_i, host_addr_i, host_re_i, host_cancel_i, bus_rdata_i, bus_ack_i, bus_err_i)
|
ctrl_engine_fsm_comb: process(ctrl, cache, clear_i, host_addr_i, host_re_i, bus_rdata_i, bus_ack_i, bus_err_i)
|
begin
|
begin
|
-- control defaults --
|
-- control defaults --
|
ctrl.state_nxt <= ctrl.state;
|
ctrl.state_nxt <= ctrl.state;
|
ctrl.addr_reg_nxt <= ctrl.addr_reg;
|
ctrl.addr_reg_nxt <= ctrl.addr_reg;
|
ctrl.re_buf_nxt <= (ctrl.re_buf or host_re_i) and (not host_cancel_i);
|
ctrl.re_buf_nxt <= ctrl.re_buf or host_re_i;
|
ctrl.cancel_buf_nxt <= ctrl.cancel_buf or host_cancel_i;
|
|
|
|
-- cache defaults --
|
-- cache defaults --
|
cache.clear <= '0';
|
cache.clear <= '0';
|
cache.host_addr <= host_addr_i;
|
cache.host_addr <= host_addr_i;
|
cache.ctrl_en <= '0';
|
cache.ctrl_en <= '0';
|
Line 214... |
Line 207... |
bus_addr_o <= ctrl.addr_reg;
|
bus_addr_o <= ctrl.addr_reg;
|
bus_wdata_o <= (others => '0'); -- cache is read-only
|
bus_wdata_o <= (others => '0'); -- cache is read-only
|
bus_ben_o <= (others => '0'); -- cache is read-only
|
bus_ben_o <= (others => '0'); -- cache is read-only
|
bus_we_o <= '0'; -- cache is read-only
|
bus_we_o <= '0'; -- cache is read-only
|
bus_re_o <= '0';
|
bus_re_o <= '0';
|
bus_cancel_o <= '0';
|
|
|
|
-- fsm --
|
-- fsm --
|
case ctrl.state is
|
case ctrl.state is
|
|
|
when S_IDLE => -- wait for host access request or cache control operation
|
when S_IDLE => -- wait for host access request or cache control operation
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (clear_i = '1') then -- cache control operation?
|
if (clear_i = '1') then -- cache control operation?
|
ctrl.state_nxt <= S_CACHE_CLEAR;
|
ctrl.state_nxt <= S_CACHE_CLEAR;
|
elsif (host_re_i = '1') or (ctrl.re_buf = '1') then -- cache access
|
elsif (host_re_i = '1') or (ctrl.re_buf = '1') then -- cache access
|
ctrl.re_buf_nxt <= '0';
|
ctrl.re_buf_nxt <= '0';
|
ctrl.cancel_buf_nxt <= '0';
|
|
ctrl.state_nxt <= S_CACHE_CHECK;
|
ctrl.state_nxt <= S_CACHE_CHECK;
|
end if;
|
end if;
|
|
|
when S_CACHE_CLEAR => -- invalidate all cache entries
|
when S_CACHE_CLEAR => -- invalidate all cache entries
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
Line 237... |
Line 228... |
ctrl.state_nxt <= S_IDLE;
|
ctrl.state_nxt <= S_IDLE;
|
|
|
when S_CACHE_CHECK => -- finalize host access if cache hit
|
when S_CACHE_CHECK => -- finalize host access if cache hit
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
if (cache.hit = '1') then -- cache HIT
|
if (cache.hit = '1') then -- cache HIT
|
host_ack_o <= not ctrl.cancel_buf; -- ACK if request has not been canceled
|
host_ack_o <= '1';
|
ctrl.state_nxt <= S_IDLE;
|
ctrl.state_nxt <= S_IDLE;
|
else -- cache MISS
|
else -- cache MISS
|
ctrl.state_nxt <= S_CACHE_MISS;
|
ctrl.state_nxt <= S_CACHE_MISS;
|
end if;
|
end if;
|
|
|
Line 250... |
Line 241... |
-- compute block base address --
|
-- compute block base address --
|
ctrl.addr_reg_nxt <= host_addr_i;
|
ctrl.addr_reg_nxt <= host_addr_i;
|
ctrl.addr_reg_nxt((2+cache_offset_size_c)-1 downto 2) <= (others => '0'); -- block-aligned
|
ctrl.addr_reg_nxt((2+cache_offset_size_c)-1 downto 2) <= (others => '0'); -- block-aligned
|
ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned
|
ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned
|
--
|
--
|
if (host_cancel_i = '1') or (ctrl.cancel_buf = '1') then -- 'early' CPU cancel (abort before bus transaction has even started)
|
|
ctrl.state_nxt <= S_IDLE;
|
|
else
|
|
ctrl.state_nxt <= S_BUS_DOWNLOAD_REQ;
|
ctrl.state_nxt <= S_BUS_DOWNLOAD_REQ;
|
end if;
|
|
|
|
when S_BUS_DOWNLOAD_REQ => -- download new cache block: request new word
|
when S_BUS_DOWNLOAD_REQ => -- download new cache block: request new word
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
|
cache.ctrl_en <= '1'; -- we are in cache control mode
|
bus_re_o <= '1'; -- request new read transfer
|
bus_re_o <= '1'; -- request new read transfer
|
ctrl.state_nxt <= S_BUS_DOWNLOAD_GET;
|
ctrl.state_nxt <= S_BUS_DOWNLOAD_GET;
|
|
|
when S_BUS_DOWNLOAD_GET => -- download new cache block: wait for bus response
|
when S_BUS_DOWNLOAD_GET => -- download new cache block: wait for bus response
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
cache.ctrl_en <= '1'; -- we are in cache control mode
|
cache.ctrl_en <= '1'; -- we are in cache control mode
|
--
|
--
|
if (bus_err_i = '1') then -- bus error
|
if (bus_err_i = '1') then -- bus error
|
ctrl.state_nxt <= S_BUS_ERROR;
|
ctrl.state_nxt <= S_BUS_ERROR;
|
elsif (ctrl.cancel_buf = '1') then -- 'late' CPU cancel (timeout?)
|
|
ctrl.state_nxt <= S_HOST_CANCEL;
|
|
elsif (bus_ack_i = '1') then -- ACK = write to cache and get next word
|
elsif (bus_ack_i = '1') then -- ACK = write to cache and get next word
|
cache.ctrl_we <= '1'; -- write to cache
|
cache.ctrl_we <= '1'; -- write to cache
|
if (and_all_f(ctrl.addr_reg((2+cache_offset_size_c)-1 downto 2)) = '1') then -- block complete?
|
if (and_all_f(ctrl.addr_reg((2+cache_offset_size_c)-1 downto 2)) = '1') then -- block complete?
|
cache.ctrl_tag_we <= '1'; -- current block is valid now
|
cache.ctrl_tag_we <= '1'; -- current block is valid now
|
cache.ctrl_valid_we <= '1'; -- write tag of current address
|
cache.ctrl_valid_we <= '1'; -- write tag of current address
|
Line 287... |
Line 273... |
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl.state_nxt <= S_CACHE_RESYNC_1;
|
ctrl.state_nxt <= S_CACHE_RESYNC_1;
|
|
|
when S_CACHE_RESYNC_1 => -- re-sync host/cache access: finalize CPU request
|
when S_CACHE_RESYNC_1 => -- re-sync host/cache access: finalize CPU request
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
host_ack_o <= not ctrl.cancel_buf; -- ACK if request has not been canceled
|
host_ack_o <= '1';
|
ctrl.state_nxt <= S_IDLE;
|
ctrl.state_nxt <= S_IDLE;
|
|
|
when S_BUS_ERROR => -- bus error during download
|
when S_BUS_ERROR => -- bus error during download
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
host_err_o <= '1';
|
host_err_o <= '1';
|
ctrl.state_nxt <= S_ERROR;
|
|
|
|
when S_ERROR => -- wait for CPU to cancel faulting transfer
|
|
-- ------------------------------------------------------------
|
|
if (host_cancel_i = '1') then
|
|
bus_cancel_o <= '1';
|
|
ctrl.state_nxt <= S_IDLE;
|
|
end if;
|
|
|
|
when S_HOST_CANCEL => -- host cancels transfer
|
|
-- ------------------------------------------------------------
|
|
cache.ctrl_en <= '1'; -- we are in cache control mode
|
|
cache.ctrl_invalid_we <= '1'; -- invalidate current cache block
|
|
bus_cancel_o <= '1';
|
|
ctrl.state_nxt <= S_IDLE;
|
ctrl.state_nxt <= S_IDLE;
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
ctrl.state_nxt <= S_IDLE;
|
ctrl.state_nxt <= S_IDLE;
|
Line 501... |
Line 473... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
history.re_ff <= host_re_i;
|
history.re_ff <= host_re_i;
|
if (invalidate_i = '1') then -- invalidate whole cache
|
if (invalidate_i = '1') then -- invalidate whole cache
|
history.last_used_set <= (others => '1');
|
history.last_used_set <= (others => '1');
|
elsif (history.re_ff = '1') and (or_all_f(hit) = '1') then -- store last accessed set that caused a hit
|
elsif (history.re_ff = '1') and (or_all_f(hit) = '1') and (ctrl_en_i = '0') then -- store last accessed set that caused a hit
|
history.last_used_set(to_integer(unsigned(cache_index))) <= not hit(0);
|
history.last_used_set(to_integer(unsigned(cache_index))) <= not hit(0);
|
end if;
|
end if;
|
history.to_be_replaced <= history.last_used_set(to_integer(unsigned(cache_index)));
|
history.to_be_replaced <= history.last_used_set(to_integer(unsigned(cache_index)));
|
end if;
|
end if;
|
end process access_history;
|
end process access_history;
|