add PLRU microwatt conversion
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 10 Sep 2020 22:21:47 +0000 (23:21 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 10 Sep 2020 22:21:47 +0000 (23:21 +0100)
src/soc/experiment/cache_ram.py
src/soc/experiment/dcache.py
src/soc/experiment/plru.py [new file with mode: 0644]

index 848582a6611c00cc32b254ffec53f757cae81282..e139546e15ea34517db5eb8a531101aa797c1c22 100644 (file)
@@ -1,80 +1,56 @@
-# entity cache_ram is
-#     generic(
-#      ROW_BITS : integer := 16;
-#      WIDTH    : integer := 64;
-#      TRACE    : boolean := false;
-#      ADD_BUF  : boolean := false
-#      );
-# 
-#     port(
-#      clk     : in  std_logic;
-#      rd_en   : in  std_logic;
-#      rd_addr : in  std_logic_vector(ROW_BITS - 1 downto 0);
-#      rd_data : out std_logic_vector(WIDTH - 1 downto 0);
-#      wr_sel  : in  std_logic_vector(WIDTH/8 - 1 downto 0);
-#      wr_addr : in  std_logic_vector(ROW_BITS - 1 downto 0);
-#      wr_data : in  std_logic_vector(WIDTH - 1 downto 0)
-#      );
-# 
-# end cache_ram;
-# 
-# architecture rtl of cache_ram is
-#     constant SIZE : integer := 2**ROW_BITS;
-# 
-#     type ram_type is array (0 to SIZE - 1) of std_logic_vector(WIDTH - 1 downto 0);
-#     signal ram : ram_type;
-#     attribute ram_style : string;
-#     attribute ram_style of ram : signal is "block";
-# 
-#     signal rd_data0 : std_logic_vector(WIDTH - 1 downto 0);
-# 
-# begin
-#     process(clk)
-#      variable lbit : integer range 0 to WIDTH - 1;
-#      variable mbit : integer range 0 to WIDTH - 1;
-#      variable widx : integer range 0 to SIZE - 1;
-#      constant sel0 : std_logic_vector(WIDTH/8 - 1 downto 0)
-#             := (others => '0');
-#     begin
-#      if rising_edge(clk) then
-#             with m.If( TRACE then
-#                 with m.If( wr_sel /= sel0 then
-#                     report "write a:" & to_hstring(wr_addr) &
-#                         " sel:" & to_hstring(wr_sel) &
-#                         " dat:" & to_hstring(wr_data);
-#                 end with m.If(;
-#             end with m.If(;
-#             for i in 0 to WIDTH/8-1 loop
-#                 lbit := i * 8;
-#                 mbit := lbit + 7;
-#                 widx := to_integer(unsigned(wr_addr));
-#                 with m.If( wr_sel(i) = '1' then
-#                     ram(widx)(mbit downto lbit) <= wr_data(mbit downto lbit);
-#                 end with m.If(;
-#             end loop;
-#          with m.If( rd_en = '1' then
-#              rd_data0 <= ram(to_integer(unsigned(rd_addr)));
-#              if TRACE then
-#                  report "read a:" & to_hstring(rd_addr) &
-#                      " dat:" & to_hstring(ram(to_integer(unsigned(rd_addr))));
-#              end with m.If(;
-#          end with m.If(;
-#      end with m.If(;
-#     end process;
-# 
-#     buf: with m.If( ADD_BUF generate
-#     begin
-#      process(clk)
-#      begin
-#          with m.If( rising_edge(clk) then
-#              rd_data <= rd_data0;
-#          end with m.If(;
-#      end process;
-#     end generate;
-# 
-#     nobuf: with m.If( not ADD_BUF generate
-#     begin
-#      rd_data <= rd_data0;
-#     end generate;
-# 
-# end;
+# TODO: replace with Memory at some point
+from nmigen import Elaboratable, Signal, Array, Module
+
+class CacheRam(Elaboratable):
+
+    def __init__(self, ROW_BITS=16, WIDTH = 64, TRACE=False, ADD_BUF=False):
+        self.ROW_BITS = ROW_BITS
+        self.WIDTH = WIDTH
+        self.TRACE = TRACE
+        self.ADD_BUF = ADD_BUF
+        self.rd_en     = Signal()
+        self.rd_addr   = Signal(ROW_BITS)
+        self.rd_data_o = Signal(WIDTH)
+        self.wr_sel    = Signal(WIDTH//8)
+        self.wr_addr   = Signal(ROW_BITS)
+        self.wr_data   = Signal(WIDTH)
+    def elaborate(self, platform):
+        m = Module()
+
+        ROW_BITS = self.ROW_BITS
+        WIDTH = self.WIDTH
+        TRACE = self.TRACE
+        ADD_BUF = self.ADD_BUF
+        SIZE = 2**ROW_BITS
+     
+        ram = Array(Signal(WIDTH) for i in range(SIZE))
+        #attribute ram_style of ram : signal is "block";
+     
+        rd_data0 = Signal(WIDTH)
+     
+        sel0 = Signal(WIDTH//8) # defaults to zero
+
+        with m.If(TRACE):
+            with m.If(self.wr_sel != sel0):
+                #Display( "write a:" & to_hstring(wr_addr) &
+                #    " sel:" & to_hstring(wr_sel) &
+                #    " dat:" & to_hstring(wr_data))
+               pass
+        for i in range(WIDTH//8):
+            lbit = i * 8;
+            mbit = lbit + 8;
+            with m.If(self.wr_sel[i]):
+                sync += ram[self.wr_addr][lbit:mbit].eq(wr_data(lbit:mbit]))
+        with m.If(self.rd_en):
+            if ADD_BUF:
+                sync += self.rd_data_o.eq(ram[rd_addr])
+            else:
+                comb += self.rd_data_o.eq(ram[rd_addr])
+
+        if TRACE:
+            # Display( "read a:" & to_hstring(rd_addr) &
+            #" dat:" & to_hstring(ram(to_integer(unsigned(rd_addr))));
+            pass
+
+        return m
index 891ae27a100fe7f6cc36cac709d742fd4c18f624..110c7eac57b4a856767b4b6b47376cbbe624d9fb 100644 (file)
@@ -12,17 +12,19 @@ from nmigen.cli import main
 from nmigen.iocontrol import RecordObject
 from nmigen.util import log2_int
 
-from experiment.mem_types import LoadStore1ToDCacheType,
+from soc.experiment.mem_types import LoadStore1ToDCacheType,
                                  DCacheToLoadStore1Type,
                                  MMUToDCacheType,
                                  DCacheToMMUType
 
-from experiment.wb_types import WB_ADDR_BITS, WB_DATA_BITS, WB_SEL_BITS,
+from soc.experiment.wb_types import WB_ADDR_BITS, WB_DATA_BITS, WB_SEL_BITS,
                                 WBAddrType, WBDataType, WBSelType,
                                 WbMasterOut, WBSlaveOut,
                                 WBMasterOutVector, WBSlaveOutVector,
                                 WBIOMasterOut, WBIOSlaveOut
 
+from soc.experiment.cache_ram import CacheRam
+
 # TODO: make these parameters of DCache at some point
 LINE_SIZE = 64    # Line size in bytes
 NUM_LINES = 32    # Number of lines in a set
diff --git a/src/soc/experiment/plru.py b/src/soc/experiment/plru.py
new file mode 100644 (file)
index 0000000..51128c7
--- /dev/null
@@ -0,0 +1,57 @@
+# based on microwatt plru.vhdl
+
+from nmigen import Elaboratable, Signal, Array, Module
+
+class PLRU(Elaboratable):
+
+    def __init__(self, BITS=2):
+        self.BITS = BITS
+        self.acc = Signal(BITS)
+        self.acc_en = Signal()
+        self.lru_o = Signal(BITS)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        tree = Array(Signal() for i in range(self.BITS))
+
+        # XXX Check if we can turn that into a little ROM instead that
+        # takes the tree bit vector and returns the LRU. See if it's better
+        # in term of FPGA resouces usage...
+        node = Signal(self.BITS)
+        for i in range(self.BITS):
+            node_next = Signal(self.BITS)
+            node2 = Signal(self.BITS)
+            # report "GET: i:" & integer'image(i) & " node:" & 
+            # integer'image(node) & " val:" & Signal()'image(tree(node))
+            comb += self.lru_o[self.BITS-1-i].eq(tree[node])
+            if i != BITS-1:
+                comb += node2.eq(node << 1)
+            else:
+                comb += node2.eq(node)
+            with m.If(tree[node]):
+                comb += node_next.eq(node2 + 2)
+            with m.Else():
+                comb += node_next.eq(node2 + 1)
+            node = node_next
+
+        with m.If(self.acc_en):
+            node = Signal(self.BITS)
+            for i in range(self.BITS):
+                node_next = Signal(self.BITS)
+                node2 = Signal(self.BITS)
+                # report "GET: i:" & integer'image(i) & " node:" & 
+                # integer'image(node) & " val:" & Signal()'image(tree(node))
+                abit = self.acc[self.BITS-1-i]
+                sync += tree[node].eq(~abit)
+                if i != BITS-1:
+                    comb += node2.eq(node << 1)
+                else:
+                    comb += node2.eq(node)
+                with m.If(abit):
+                    comb += node_next.eq(node2 + 2)
+                with m.Else():
+                    comb += node_next.eq(node2 + 1)
+                node = node_next
+
+        return m