start putting LDSTSplitter together
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 22 Mar 2020 11:33:44 +0000 (11:33 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 22 Mar 2020 11:33:44 +0000 (11:33 +0000)
src/soc/scoreboard/addr_split.py

index ef136763b303ced28b355e9916843c511fe1ecf3..40f4569c38defa7fbf31b68f186f064d2df3e732 100644 (file)
 # LDST Address Splitter.  For misaligned address crossing cache line boundary
 
-from nmigen import Elaboratable, Module, Signal, Record
+from nmigen import Elaboratable, Module, Signal, Record, Array
 from nmutil.latch import SRLatch, latchregister
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
 
-from soc.scoreboard.addr_match import LenSplitter
-from nmutil.queue import Queue
+from soc.scoreboard.addr_match import LenExpand
+#from nmutil.queue import Queue
 
+class LDData(Record):
+    def __init__(self, dwidth):
+        Record.__init__(self, (('err', 1), ('data', dwidth)))
 
-class LDQueue(Elaboratable):
+
+class LDLatch(Elaboratable):
 
     def __init__(self, dwidth, awidth, mlen):
         self.addr_i = Signal(awidth, reset_less=True)
         self.mask_i = Signal(mlen, reset_less=True)
-        self.ld_i = Record((('err', 1), ('data', dwidth))
-        self.ld_o = Record((('err', 1), ('data', dwidth))
+        self.valid_i = Signal(reset_less=True)
+        self.ld_i = LDData(dwidth)
+        self.ld_o = LDData(dwidth)
+        self.valid_o = Signal(reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
-        m.submodules.q = q = Queue(width=self.ld_o.shape()[0], 1, fwft=True)
+        m.submodules.in_l = in_l = SRLatch(sync=False, name="in_l")
+
+        comb += self.valid_o.eq(in_l.q & self.valid_i)
+        latchregister(m, self.ld_i, self.ld_o, in_l.q & self.valid_o, "ld_i_r")
+
+        return m
 
 
 class LDSTSplitter(Elaboratable):
 
     def __init__(self, dwidth, awidth, dlen):
+        self.dwidth, self.awidth, self.dlen = dwidth, awidth, dlen
         self.addr_i = Signal(awidth, reset_less=True)
         self.len_i = Signal(dlen, reset_less=True)
         self.is_ld_i = Signal(reset_less=True)
-        self.ld_data_o = Signal(dwidth, reset_less=True)
+        self.ld_data_o = LDData(dwidth)
+        self.ld_valid_i = Signal(reset_less=True)
+        self.valid_o = Signal(2, reset_less=True)
+        self.ld_data_i = Array((LDData(dwidth), LDData(dwidth)))
+
+        #self.is_st_i = Signal(reset_less=True)
+        #self.st_data_i = Signal(dwidth, reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        dlen = self.dlen
+        mlen = 1 << dlen
+        m.submodules.ld1 = ld1 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
+        m.submodules.ld2 = ld2 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
+        m.submodules.lenexp = lenexp = LenExpand(self.dlen)
+
+        # set up len-expander, len to mask.  ld1 gets first bit, ld2 gets rest
+        comb += lenexp.addr_i.eq(self.addr_i)
+        comb += lenexp.len_i.eq(self.len_i)
+        mask1 = lenexp.lexp_o[0:mlen]
+        mask2 = lenexp.lexp_o[mlen:]
+
+        # set up new address records: addr1 is "as-is", addr2 is +1
+        comb += ld1.addr_i.eq(self.addr_i[dlen:])
+        comb += ld2.addr_i.eq(self.addr_i[dlen:] + 1) # TODO exception if rolls
+
+        # set up connections to LD-split.  note: not active if mask is zero
+        for i, (ld, mask) in enumerate(((ld1, mask1),
+                                        (ld2, mask2))):
+            comb += ld.valid_i.eq(self.ld_valid_i)
+            comb += self.valid_o[i].eq(ld.valid_o & (mask != 0))
+
+        return m
+
+    def __iter__(self):
+        yield self.addr_i
+        yield self.len_i
+        yield self.is_ld_i
+        yield self.ld_data_o.err
+        yield self.ld_data_o.data
+        yield self.ld_valid_i
+        yield self.valid_o
+        for i in range(2):
+            yield self.ld_data_i[i].err
+            yield self.ld_data_i[i].data
+
+    def ports(self):
+        return list(self)
+
+
+if __name__ == '__main__':
+    dut = LDSTSplitter(32, 48, 3)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("ldst_splitter.il", "w") as f:
+        f.write(vl)
 
-        self.is_st_i = Signal(reset_less=True)
-        self.st_data_i = Signal(dwidth, reset_less=True)