Initial import
git-svn-id: http://moon:8086/svn/vhdl/trunk@2 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
@@ -0,0 +1,430 @@
|
||||
LIBRARY IEEE;
|
||||
USE IEEE.STD_LOGIC_1164.ALL;
|
||||
USE IEEE.NUMERIC_STD.ALL;
|
||||
use IEEE.MATH_REAL.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
ENTITY dcache IS
|
||||
Generic
|
||||
(
|
||||
cache_size : natural := 2048; -- words
|
||||
line_size : natural := 8 -- words
|
||||
);
|
||||
Port
|
||||
(
|
||||
clk : in STD_LOGIC;
|
||||
rst : in STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
cpu_en : in STD_LOGIC;
|
||||
cpu_r_wn : in STD_LOGIC;
|
||||
cpu_we : in unsigned(3 downto 0);
|
||||
cpu_addr : in word_t;
|
||||
cpu_din : in word_t;
|
||||
cpu_dout : out word_t;
|
||||
cpu_busy : out STD_LOGIC;
|
||||
mem_req : out STD_LOGIC;
|
||||
mem_gnt : in STD_LOGIC;
|
||||
mem_en : out STD_LOGIC;
|
||||
mem_addr : out word_t;
|
||||
mem_din : in word_t;
|
||||
mem_valid : in STD_LOGIC;
|
||||
mem_rdy : in STD_LOGIC
|
||||
);
|
||||
END dcache;
|
||||
|
||||
ARCHITECTURE behavior OF dcache IS
|
||||
|
||||
COMPONENT dpram_1w1r
|
||||
GENERIC
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
PORT (
|
||||
clka : in STD_LOGIC;
|
||||
clkb : in STD_LOGIC;
|
||||
en_a : in STD_LOGIC;
|
||||
en_b : in STD_LOGIC;
|
||||
we_a : in STD_LOGIC;
|
||||
addr_a : in unsigned (addr_width-1 downto 0);
|
||||
addr_b : in unsigned (addr_width-1 downto 0);
|
||||
din_a : in unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
COMPONENT dpram_2w2r is
|
||||
GENERIC
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
PORT
|
||||
(
|
||||
clk_a : in STD_LOGIC;
|
||||
clk_b : in STD_LOGIC;
|
||||
en_a : in STD_LOGIC;
|
||||
en_b : in STD_LOGIC;
|
||||
we_a : in STD_LOGIC;
|
||||
we_b : in STD_LOGIC;
|
||||
addr_a : in unsigned (addr_width-1 downto 0);
|
||||
addr_b : in unsigned (addr_width-1 downto 0);
|
||||
din_a : in unsigned (data_width-1 downto 0);
|
||||
din_b : in unsigned (data_width-1 downto 0);
|
||||
dout_a : out unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
function lg2(x : natural) return natural is
|
||||
begin
|
||||
return natural(ceil(log2(real(x))));
|
||||
end lg2;
|
||||
|
||||
function po2(x : natural) return natural is
|
||||
begin
|
||||
|
||||
return 2**lg2(x);
|
||||
end po2;
|
||||
|
||||
constant word_index_width : natural := lg2(line_size);
|
||||
constant cache_index_width : natural := lg2(cache_size) - word_index_width;
|
||||
constant tag_width : natural := 32 - word_index_width - cache_index_width - 2;
|
||||
constant tag_parity_width : natural := 3;
|
||||
constant tram_data_width : natural := 2 + tag_parity_width + tag_width;
|
||||
constant tram_addr_width : natural := cache_index_width;
|
||||
|
||||
subtype tram_data_t is unsigned (tram_data_width-1 downto 0);
|
||||
|
||||
type dcache_entry_t is record
|
||||
valid : std_logic;
|
||||
dirty : std_logic;
|
||||
tv_p : unsigned(tag_parity_width-1 downto 0);
|
||||
tag : unsigned(tag_width-1 downto 0);
|
||||
end record;
|
||||
|
||||
alias cpu_word_index is cpu_addr(word_index_width+1 downto 2);
|
||||
alias cpu_cache_index is cpu_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
|
||||
alias cpu_tag is cpu_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
|
||||
|
||||
function to_dcache_entry(x : tram_data_t) return dcache_entry_t is
|
||||
variable result : dcache_entry_t;
|
||||
begin
|
||||
result.valid := x(0);
|
||||
result.dirty := x(1);
|
||||
result.tv_p := x(4 downto 2);
|
||||
result.tag := x(tag_width+4 downto 5);
|
||||
|
||||
return result;
|
||||
end to_dcache_entry;
|
||||
|
||||
function to_tram_data(x : dcache_entry_t) return tram_data_t is
|
||||
variable result : tram_data_t;
|
||||
begin
|
||||
result(0) := x.valid;
|
||||
result(1) := x.dirty;
|
||||
result(4 downto 2) := x.tv_p;
|
||||
result(tag_width+4 downto 5) := x.tag;
|
||||
|
||||
return result;
|
||||
end to_tram_data;
|
||||
|
||||
type cache_state_t is (init, ready, flush, mem_request, mem_access, mem_wait, mem_data, upd_cache, rd_cache, wr_cache);
|
||||
signal s, sn : cache_state_t;
|
||||
|
||||
signal cache_busy : std_logic;
|
||||
signal cache_read_miss : std_logic;
|
||||
signal cache_write_miss : std_logic;
|
||||
signal tag_match : std_logic;
|
||||
signal word_index_reg : unsigned(word_index_width-1 downto 0);
|
||||
signal cache_index_reg : unsigned(cache_index_width-1 downto 0);
|
||||
signal tag_index_reg : unsigned(tag_width-1 downto 0);
|
||||
|
||||
signal cache_entry_in : dcache_entry_t;
|
||||
signal cache_entry_out : dcache_entry_t;
|
||||
signal cpu_dram_addr : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal cpu_dram_dout : word_t;
|
||||
signal cpu_dram_din : word_t;
|
||||
signal cpu_data_reg : word_t;
|
||||
signal cpu_we_reg : unsigned(3 downto 0);
|
||||
signal ctrl_force_we : unsigned(3 downto 0);
|
||||
signal cpu_was_write : std_logic;
|
||||
signal ctrl_dram_addr : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal ctrl_dram_din : word_t;
|
||||
signal ctrl_dram_we : unsigned(3 downto 0);
|
||||
signal cpu_dram_we : unsigned(3 downto 0);
|
||||
signal dram_en : std_logic;
|
||||
signal cpu_was_en : std_logic;
|
||||
|
||||
signal tram_addr_rd : unsigned(cache_index_width-1 downto 0);
|
||||
signal tram_dout : tram_data_t;
|
||||
signal tram_addr_wr : unsigned(cache_index_width-1 downto 0);
|
||||
signal tram_din : tram_data_t;
|
||||
signal tram_re : std_logic;
|
||||
signal tram_we : std_logic;
|
||||
|
||||
signal ram_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal ram_index_count_rst : std_logic;
|
||||
signal cache_index_count : natural range 0 to 2**cache_index_width-1;
|
||||
signal cache_index_count_en : std_logic;
|
||||
signal mem_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal mem_index_count_en : std_logic;
|
||||
signal mem_index_count_rst : std_logic;
|
||||
signal cpu_reg_en : std_logic;
|
||||
signal was_miss : std_logic;
|
||||
signal data_write : std_logic;
|
||||
signal cpu_we2 : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
|
||||
cpu_index_reg:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
cache_index_reg <= (others => '0');
|
||||
tag_index_reg <= (others => '0');
|
||||
cpu_was_write <= '0';
|
||||
elsif cpu_reg_en = '1' and en = '1' then
|
||||
word_index_reg <= cpu_word_index;
|
||||
cache_index_reg <= cpu_cache_index;
|
||||
tag_index_reg <= cpu_tag;
|
||||
cpu_data_reg <= cpu_din;
|
||||
cpu_we_reg <= cpu_we;
|
||||
cpu_was_write <= not cpu_r_wn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_was_wr_reg:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
cpu_was_en <= '0';
|
||||
cpu_we2 <= '0';
|
||||
if cpu_en = '1' and en = '1' then
|
||||
cpu_we2 <= not cpu_r_wn;
|
||||
cpu_was_en <= '1';
|
||||
cpu_dram_din <= cpu_din;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
inst_tag_ram : dpram_1w1r
|
||||
GENERIC MAP (
|
||||
addr_width => tram_addr_width,
|
||||
data_width => tram_data_width
|
||||
)
|
||||
PORT MAP (
|
||||
clka => clk,
|
||||
clkb => clk,
|
||||
en_a => '1',
|
||||
en_b => tram_re,
|
||||
we_a => tram_we,
|
||||
addr_a => tram_addr_wr,
|
||||
addr_b => tram_addr_rd,
|
||||
din_a => tram_din,
|
||||
dout_b => tram_dout
|
||||
);
|
||||
|
||||
gen_data_ram:
|
||||
for i in 0 to 3 generate
|
||||
begin
|
||||
|
||||
inst_data_ram : dpram_2w2r
|
||||
GENERIC MAP (
|
||||
addr_width => lg2(cache_size),
|
||||
data_width => word_t'length/4
|
||||
)
|
||||
PORT MAP (
|
||||
clk_a => clk,
|
||||
clk_b => clk,
|
||||
en_a => '1',
|
||||
en_b => dram_en,
|
||||
we_a => ctrl_dram_we(i),
|
||||
we_b => cpu_dram_we(i),
|
||||
addr_a => ctrl_dram_addr,
|
||||
addr_b => cpu_dram_addr,
|
||||
din_a => ctrl_dram_din(8*(i+1)-1 downto 8*i),
|
||||
din_b => cpu_dram_din(8*(i+1)-1 downto 8*i),
|
||||
dout_a => open,
|
||||
dout_b => cpu_dram_dout(8*(i+1)-1 downto 8*i)
|
||||
);
|
||||
end generate;
|
||||
|
||||
cache_state_next:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
s <= init;
|
||||
else
|
||||
s <= sn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_busy <= cache_busy;
|
||||
cpu_dout <= cpu_dram_dout;
|
||||
|
||||
tag_match <= '1' when tag_index_reg = cache_entry_out.tag else '0';
|
||||
cache_read_miss <= not (tag_match and cache_entry_out.valid) and not cpu_was_write;
|
||||
cache_write_miss <= not (tag_match and cache_entry_out.valid and cpu_was_write);
|
||||
tram_din <= to_tram_data(cache_entry_in);
|
||||
tram_addr_rd <= cpu_cache_index when was_miss = '0' else cache_index_reg;
|
||||
cache_entry_out <= to_dcache_entry(tram_dout);
|
||||
cpu_dram_addr <= (cpu_cache_index & cpu_word_index) when (was_miss = '0' and cpu_we2 = '0') else (cache_index_reg & word_index_reg);
|
||||
mem_addr <= tag_index_reg & cache_index_reg & to_unsigned(mem_index_count, word_index_width) & "00";
|
||||
ctrl_dram_addr <= cache_index_reg & to_unsigned(ram_index_count, word_index_width);
|
||||
ctrl_dram_din <= mem_din;
|
||||
ctrl_dram_we <= (3 downto 0 => (data_write and mem_valid)) or ctrl_force_we;
|
||||
cpu_dram_we <= cpu_we_reg when (cpu_we2 = '1' and cache_write_miss = '0') else (others => '0');
|
||||
|
||||
cache_state:
|
||||
process(s, cache_read_miss, cache_index_count, ram_index_count, mem_index_count, cache_index_reg, mem_valid, tag_index_reg, cpu_en, cpu_r_wn, mem_gnt, mem_rdy, cpu_was_en, cpu_was_write, cpu_we_reg)
|
||||
begin
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
tram_we <= '0';
|
||||
cache_index_count_en <= '0';
|
||||
ram_index_count_rst <= '0';
|
||||
mem_index_count_en <= '0';
|
||||
mem_index_count_rst <= '0';
|
||||
mem_req <= '0';
|
||||
mem_en <= '0';
|
||||
dram_en <= '0';
|
||||
tram_re <= '0';
|
||||
was_miss <= '0';
|
||||
data_write <= '0';
|
||||
tram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
cache_entry_in.tv_p <= (others => '0');
|
||||
cache_entry_in.tag <= tag_index_reg;
|
||||
cache_entry_in.valid <= '0';
|
||||
cache_entry_in.dirty <= '0';
|
||||
ctrl_force_we <= (others => '0');
|
||||
sn <= s;
|
||||
|
||||
case s is
|
||||
when init =>
|
||||
sn <= flush;
|
||||
when ready =>
|
||||
cache_busy <= '0';
|
||||
cpu_reg_en <= '1';
|
||||
dram_en <= cpu_en or cpu_was_en;
|
||||
tram_re <= cpu_en;
|
||||
if cpu_was_en = '1' then
|
||||
if cache_read_miss = '1' then
|
||||
sn <= mem_request;
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when flush =>
|
||||
cache_index_count_en <= '1';
|
||||
tram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
tram_we <= '1';
|
||||
cache_entry_in.valid <= '0';
|
||||
cache_entry_in.tag <= (others => '0');
|
||||
if cache_index_count = 0 then
|
||||
sn <= ready;
|
||||
if cpu_en = '1' then
|
||||
cpu_reg_en <= '1';
|
||||
dram_en <= '1';
|
||||
tram_re <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when mem_request =>
|
||||
ram_index_count_rst <= '1';
|
||||
mem_index_count_rst <= '1';
|
||||
mem_req <= '1';
|
||||
if mem_gnt = '1' then
|
||||
sn <= mem_access;
|
||||
end if;
|
||||
when mem_access =>
|
||||
data_write <= '1';
|
||||
mem_req <= '1';
|
||||
if mem_rdy = '1' then
|
||||
mem_index_count_en <= '1';
|
||||
mem_en <= '1';
|
||||
if mem_index_count = 2**word_index_width-1 then
|
||||
sn <= mem_data;
|
||||
end if;
|
||||
end if;
|
||||
when mem_data =>
|
||||
mem_req <= '1';
|
||||
data_write <= '1';
|
||||
if ram_index_count = 2**word_index_width-1 then
|
||||
if mem_valid = '1' then
|
||||
sn <= upd_cache;
|
||||
end if;
|
||||
end if;
|
||||
when upd_cache =>
|
||||
mem_req <= '1';
|
||||
tram_addr_wr <= cache_index_reg;
|
||||
tram_we <= '1';
|
||||
cache_entry_in.valid <= '1';
|
||||
if cpu_was_write = '1' then
|
||||
sn <= wr_cache;
|
||||
else
|
||||
sn <= rd_cache;
|
||||
end if;
|
||||
|
||||
when rd_cache =>
|
||||
tram_re <= '1';
|
||||
dram_en <= '1';
|
||||
was_miss <= '1';
|
||||
sn <= ready;
|
||||
|
||||
when wr_cache =>
|
||||
tram_re <= '1';
|
||||
ctrl_force_we <= cpu_we_reg;
|
||||
sn <= ready;
|
||||
when others =>
|
||||
sn <= ready;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
cache_index_counter:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if cache_index_count_en = '0' then
|
||||
cache_index_count <= 2**cache_index_width-1;
|
||||
elsif cache_index_count /= 0 then
|
||||
cache_index_count <= cache_index_count - 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ram_index_counter:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if ram_index_count_rst = '1' then
|
||||
ram_index_count <= 0;
|
||||
elsif data_write = '1' and mem_valid = '1' then
|
||||
if ram_index_count /= 2**word_index_width-1 then
|
||||
ram_index_count <= ram_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
mem_index_counter:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if mem_index_count_rst = '1' then
|
||||
mem_index_count <= 0;
|
||||
elsif mem_index_count_en = '1' then
|
||||
if mem_index_count /= 2**word_index_width-1 then
|
||||
mem_index_count <= mem_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end behavior;
|
||||
Reference in New Issue
Block a user