-- Cache version 2.0
-- This is a completely configurable cache in the sense of cache line and
-- cache size
-- 1, 2, or 4-way set associative
-- Pseudo LRU replacement technique is used
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
LIBRARY WORK;
USE WORK.cache_pack.ALL;
ENTITY cache IS
GENERIC ( NoOfAddressBits : POSITIVE := 12; -- physical memory's size
Log2LineSize : POSITIVE := 2; -- by byte
Associativity : POSITIVE := 2 ;
NoOfCacheAddressBits: POSITIVE := 8 -- this is the size of each associativity
);
PORT ( AddressIn : IN std_logic_vector(NoOfAddressBits-1 DOWNTO 0):=(others=>'Z');
AddressOut : OUT std_logic_vector(NoOfAddressBits-1 DOWNTO 0):=(others=>'Z');
ReadIn : IN std_logic := '0';
ReadOut : OUT std_logic := '0';
WriteIn : IN std_logic := '0';
WriteOut : OUT std_logic := '0';
DataIn : INOUT std_logic_vector(7 DOWNTO 0):=(OTHERS=>'Z');
DataOut : INOUT std_logic_vector(7 DOWNTO 0):=(OTHERS=>'Z');
DumpIn : IN std_logic := '0';
DumpOut : OUT std_logic := '0';
ready : OUT std_logic := '0'
);
CONSTANT TagSize : NATURAL := NoOfAddressBits - Log2LineSize - NoOfCacheAddressBits;
SUBTYPE byte IS std_logic_vector(7 DOWNTO 0);
TYPE LineType IS ARRAY (0 TO (2**Log2LineSize)-1) OF byte;
TYPE LineRec IS RECORD
tag : std_logic_vector(TagSize-1 DOWNTO 0);
bytes : LineType;
-- lru : INTEGER;
dirty : BOOLEAN;
valid : BOOLEAN;
END RECORD;
SUBTYPE bintree IS std_logic_vector(afunc(Associativity) DOWNTO 0);
Type PseudoLru IS ARRAY (0 TO (2**NoOfCacheAddressBits)-1) OF bintree;
TYPE CacheType IS ARRAY (1 TO Associativity, 0 TO (2**NoOfCacheAddressBits)-1) OF LineRec; --EachAssociativity;
END cache;
ARCHITECTURE general OF cache IS
BEGIN
PROCESS
VARIABLE TheCache : CacheType;
VARIABLE hit : BOOLEAN := FALSE;
VARIABLE WhichSet : INTEGER := 0;
VARIABLE GotALine,GetALine : LineType;
VARIABLE LineAddress : INTEGER;
VARIABLE AddressTag : std_logic_vector(TagSize-1 DOWNTO 0);
VARIABLE LineCnt : std_logic_vector(Log2LineSize-1 DOWNTO 0);
VARIABLE TheLruTree : PseudoLru;
PROCEDURE UpdatePseudoLru(UsedSet : IN INTEGER) IS -- THIS NEEDS RIGHT INITIAL VALUES TO WORK!!!!
BEGIN
IF (Associativity=2) THEN
TheLruTree(LineAddress) := NOT TheLruTree(LineAddress);
ELSIF (Associativity=4) THEN
CASE UsedSet IS
WHEN 0 =>
TheLruTree(LineAddress) := TheLruTree(LineAddress) OR "110";
WHEN 1 =>
TheLruTree(LineAddress) := TheLruTree(LineAddress) OR "100";
TheLruTree(LineAddress) := TheLruTree(LineAddress) AND "101";
WHEN 2 =>
TheLruTree(LineAddress) := TheLruTree(LineAddress) OR "001";
TheLruTree(LineAddress) := TheLruTree(LineAddress) AND "011";
WHEN 3 =>
TheLruTree(LineAddress) := TheLruTree(LineAddress) AND "010";
WHEN OTHERS=> NULL;
END CASE;
END IF;
END UpdatePseudoLru;
PROCEDURE ChooseASet(ASet : OUT INTEGER) IS
VARIABLE temp : bintree := TheLruTree(LineAddress);
BEGIN
IF Associativity=2 THEN
IF temp = "0" THEN ASet := 1;
ELSIF temp ="1" THEN ASet := 0;
END IF;
ELSIF Associativity=4 THEN
IF temp ="000" THEN ASet := 0;
ELSIF temp ="001" THEN ASet := 0;
ELSIF temp ="010" THEN ASet := 1;
ELSIF temp ="011" THEN ASet := 1;
ELSIF temp ="100" THEN ASet := 2;
ELSIF temp ="101" THEN ASet := 3;
ELSIF temp ="110" THEN ASet := 2;
ELSIF temp ="111" THEN ASet := 3;
END IF;
END IF;
END ChooseASet;
BEGIN
WAIT ON AddressIn, ReadIn, WriteIn, DumpIn;
ready <= '0';
IF DumpIn = '0' THEN
IF AddressIn'Event THEN
LineAddress := std_logic2int(AddressIn(NoOfCacheAddressBits+Log2LineSize-1 DOWNTO Log2LineSize));
AddressTag := AddressIn(NoOfAddressBits-1 DOWNTO NoOfCacheAddressBits+Log2LineSize);
hit := FALSE:
END IF;
FOR i IN 1 to Associativity LOOP
IF (TheCache(i, LineAddress).tag = AddressTag AND TheCache(i, LineAddress).valid) THEN
WhichSet := i;
IF Associativity>1 THEN
UpdatePseudoLru(i);
END IF;
hit := TRUE;
ready <='1';
EXIT;
END IF;
END LOOP;
IF (NOT hit) THEN -- In case of a miss
FOR i IN 0 TO (2**Log2LineSize)-1 LOOP
int2std_logic(i, LineCnt);
AddressOut <= AddressIn(NoOfAddressBits-1 DOWNTO Log2LineSize) & LineCnt;
ReadOut <= '1', '0' AFTER 1 NS;
WAIT ON DataOut; --OR WAIT UNTIL DATAOUT/="Zs"
GotAline(i) := DataOut;
END LOOP;
IF Associativity>1 THEN
ChooseASet(WhichSet);
ELSE
WhichSet := 0;
END IF;
-- write back if dirty
IF TheCache(WhichSet, LineAddress).dirty THEN
GetAline := TheCache(WhichSet, LineAddress).bytes;
FOR i IN 0 TO (2**Log2LineSize)-1 LOOP
int2std_logic(i, LineCnt);
AddressOut <= AddressIn(NoOfAddressBits-1 DOWNTO Log2LineSize) & LineCnt;
DataOut <= GetALine(i);
WriteOut <= '1', '0' AFTER 1 NS;
WAIT FOR 2 NS;
END LOOP;
END IF;
TheCache(WhichSet, LineAddress).bytes := GotALine;
TheCache(WhichSet, LineAddress).valid := TRUE;
IF Associativity>1 THEN
UpdatePseudoLru(WhichSet);
END IF;
ready <= '1';
END IF;
IF ReadIn = '1' THEN
GotALine := TheCache(WhichSet, LineAddress).bytes;
DataIn <= GotAline(std_logic2int(AddressIn(Log2LineSize-1 DOWNTO 0)));
ELSIF WriteIn = '1' THEN
GotALine := TheCache(WhichSet, LineAddress).bytes;
GotAline(std_logic2int(AddressIn(Log2LineSize-1 DOWNTO 0))) := DataIn;
TheCache(WhichSet, LineAddress).bytes := GotALine;
TheCache(WhichSet, LineAddress).dirty := TRUE;
END IF;
ELSE -- write back all the dirty lines and assert DumpOut
FOR i IN 1 to Associativity LOOP
FOR j IN 0 TO (2**Log2LineSize)-1 LOOP
IF TheCache(i, j).dirty THEN
GetAline := TheCache(i, j).bytes;
FOR i IN 0 TO (2**Log2LineSize)-1 LOOP
int2std_logic(i, LineCnt);
AddressOut <= AddressIn(NoOfAddressBits-1 DOWNTO Log2LineSize) & LineCnt;
DataOut <= GetALine(i);
WriteOut <= '1', '0' AFTER 1 NS;
WAIT FOR 1 NS;
END LOOP;
END IF;
END LOOP;
END LOOP;
END IF;
END PROCESS;
END general;
|