forked from cores/microwatt
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.6 KiB
VHDL
174 lines
5.6 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.common.all;
|
|
use work.wishbone_types.all;
|
|
|
|
-- 64 bit direct mapped icache. All instructions are 4B aligned.
|
|
|
|
entity icache is
|
|
generic (
|
|
-- Line size in 64bit doublewords
|
|
LINE_SIZE_DW : natural := 8;
|
|
-- Number of lines
|
|
NUM_LINES : natural := 32
|
|
);
|
|
port (
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
|
|
i_in : in Fetch2ToIcacheType;
|
|
i_out : out IcacheToFetch2Type;
|
|
|
|
wishbone_out : out wishbone_master_out;
|
|
wishbone_in : in wishbone_slave_out
|
|
);
|
|
end entity icache;
|
|
|
|
architecture rtl of icache is
|
|
function log2(i : natural) return integer is
|
|
variable tmp : integer := i;
|
|
variable ret : integer := 0;
|
|
begin
|
|
while tmp > 1 loop
|
|
ret := ret + 1;
|
|
tmp := tmp / 2;
|
|
end loop;
|
|
return ret;
|
|
end function;
|
|
|
|
function ispow2(i : integer) return boolean is
|
|
begin
|
|
if to_integer(to_unsigned(i, 32) and to_unsigned(i - 1, 32)) = 0 then
|
|
return true;
|
|
else
|
|
return false;
|
|
end if;
|
|
end function;
|
|
|
|
constant LINE_SIZE : natural := LINE_SIZE_DW*8;
|
|
constant OFFSET_BITS : natural := log2(LINE_SIZE);
|
|
constant INDEX_BITS : natural := log2(NUM_LINES);
|
|
constant TAG_BITS : natural := 64 - OFFSET_BITS - INDEX_BITS;
|
|
|
|
subtype cacheline_type is std_logic_vector((LINE_SIZE*8)-1 downto 0);
|
|
type cacheline_array is array(0 to NUM_LINES-1) of cacheline_type;
|
|
|
|
subtype cacheline_tag_type is std_logic_vector(TAG_BITS-1 downto 0);
|
|
type cacheline_tag_array is array(0 to NUM_LINES-1) of cacheline_tag_type;
|
|
|
|
signal cachelines : cacheline_array := (others => (others => '0'));
|
|
signal tags : cacheline_tag_array := (others => (others => '0'));
|
|
signal tags_valid : std_ulogic_vector(NUM_LINES-1 downto 0) := (others => '0');
|
|
|
|
attribute ram_style : string;
|
|
attribute ram_style of cachelines : signal is "block";
|
|
|
|
attribute ram_decomp : string;
|
|
attribute ram_decomp of cachelines : signal is "power";
|
|
|
|
type state_type is (IDLE, WAIT_ACK);
|
|
|
|
type reg_internal_type is record
|
|
state : state_type;
|
|
w : wishbone_master_out;
|
|
store_index : integer range 0 to (NUM_LINES-1);
|
|
store_word : integer range 0 to (LINE_SIZE-1);
|
|
end record;
|
|
|
|
signal r : reg_internal_type;
|
|
|
|
signal read_index : integer range 0 to NUM_LINES-1;
|
|
signal read_tag : std_ulogic_vector(63-OFFSET_BITS-INDEX_BITS downto 0);
|
|
signal read_miss : boolean;
|
|
|
|
function get_index(addr: std_ulogic_vector(63 downto 0)) return integer is
|
|
begin
|
|
return to_integer(unsigned(addr((OFFSET_BITS+INDEX_BITS-1) downto OFFSET_BITS)));
|
|
end;
|
|
|
|
function get_word(addr: std_ulogic_vector(63 downto 0); data: cacheline_type) return std_ulogic_vector is
|
|
variable word : integer;
|
|
begin
|
|
word := to_integer(unsigned(addr(OFFSET_BITS-1 downto 2)));
|
|
return data((word+1)*32-1 downto word*32);
|
|
end;
|
|
|
|
function get_tag(addr: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
|
|
begin
|
|
return addr(63 downto OFFSET_BITS+INDEX_BITS);
|
|
end;
|
|
begin
|
|
assert ispow2(LINE_SIZE) report "LINE_SIZE not power of 2" severity FAILURE;
|
|
assert ispow2(NUM_LINES) report "NUM_LINES not power of 2" severity FAILURE;
|
|
|
|
icache_read : process(all)
|
|
begin
|
|
read_index <= get_index(i_in.addr);
|
|
read_tag <= get_tag(i_in.addr);
|
|
read_miss <= false;
|
|
|
|
i_out.ack <= '0';
|
|
i_out.insn <= get_word(i_in.addr, cachelines(read_index));
|
|
|
|
if i_in.req = '1' then
|
|
if (tags_valid(read_index) = '1') and (tags(read_index) = read_tag) then
|
|
-- report hit asynchronously
|
|
i_out.ack <= '1';
|
|
else
|
|
read_miss <= true;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
wishbone_out <= r.w;
|
|
|
|
icache_write : process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if rst = '1' then
|
|
tags_valid <= (others => '0');
|
|
r.state <= IDLE;
|
|
r.w.cyc <= '0';
|
|
r.w.stb <= '0';
|
|
end if;
|
|
|
|
r.w.dat <= (others => '0');
|
|
r.w.sel <= "11111111";
|
|
r.w.we <= '0';
|
|
|
|
case r.state is
|
|
when IDLE =>
|
|
if read_miss = true then
|
|
r.state <= WAIT_ACK;
|
|
r.store_word <= 0;
|
|
r.store_index <= read_index;
|
|
|
|
tags(read_index) <= read_tag;
|
|
tags_valid(read_index) <= '0';
|
|
|
|
r.w.adr <= i_in.addr(63 downto OFFSET_BITS) & (OFFSET_BITS-1 downto 0 => '0');
|
|
r.w.cyc <= '1';
|
|
r.w.stb <= '1';
|
|
end if;
|
|
when WAIT_ACK =>
|
|
if wishbone_in.ack = '1' then
|
|
cachelines(r.store_index)((r.store_word+1)*64-1 downto ((r.store_word)*64)) <= wishbone_in.dat;
|
|
r.store_word <= r.store_word + 1;
|
|
|
|
if r.store_word = (LINE_SIZE_DW-1) then
|
|
r.state <= IDLE;
|
|
tags_valid(r.store_index) <= '1';
|
|
r.w.cyc <= '0';
|
|
r.w.stb <= '0';
|
|
else
|
|
r.w.adr(OFFSET_BITS-1 downto 3) <= std_ulogic_vector(to_unsigned(r.store_word+1, OFFSET_BITS-3));
|
|
end if;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
end;
|