sigh. convert INT regfile to binary addressing
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 13 Aug 2020 11:25:32 +0000 (12:25 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 13 Aug 2020 11:45:55 +0000 (12:45 +0100)
src/soc/decoder/power_regspec_map.py
src/soc/regfile/regfile.py
src/soc/regfile/regfiles.py
src/soc/simple/core.py
src/soc/simple/issuer.py
src/soc/simple/test/test_core.py
src/soc/simple/test/test_issuer.py

index 1dd3f0e442457b8639b9e00160eabcd1031759ed..74a955cb7e917306f1b51a29e8b142c8f215e48a 100644 (file)
@@ -48,11 +48,11 @@ def regspec_decode_read(e, regfile, name):
     if regfile == 'INT':
         # Int register numbering is *unary* encoded
         if name == 'ra': # RA
-            return e.read_reg1.ok, 1<<e.read_reg1.data
+            return e.read_reg1.ok, e.read_reg1.data
         if name == 'rb': # RB
-            return e.read_reg2.ok, 1<<e.read_reg2.data
+            return e.read_reg2.ok, e.read_reg2.data
         if name == 'rc': # RS
-            return e.read_reg3.ok, 1<<e.read_reg3.data
+            return e.read_reg3.ok, e.read_reg3.data
 
     # CR regfile
 
@@ -126,9 +126,9 @@ def regspec_decode_write(e, regfile, name):
     if regfile == 'INT':
         # Int register numbering is *unary* encoded
         if name == 'o': # RT
-            return e.write_reg, 1<<e.write_reg.data
+            return e.write_reg, e.write_reg.data
         if name == 'o1': # RA (update mode: LD/ST EA)
-            return e.write_ea, 1<<e.write_ea.data
+            return e.write_ea, e.write_ea.data
 
     # CR regfile
 
@@ -169,11 +169,6 @@ def regspec_decode_write(e, regfile, name):
 
     if regfile == 'FAST':
         # FAST register numbering is *unary* encoded
-        CTR = 1<<FastRegs.CTR
-        LR = 1<<FastRegs.LR
-        TAR = 1<<FastRegs.TAR
-        SRR0 = 1<<FastRegs.SRR0
-        SRR1 = 1<<FastRegs.SRR1
         if name == 'fast1':
             return e.write_fast1, 1<<e.write_fast1.data
         if name == 'fast2':
index be1c76937e800f6c06c7c6ba5f95d7529bd2d8dd..503ce8ee289b920f4d34d6f05bc82190733c0977 100644 (file)
@@ -24,6 +24,7 @@ from nmigen.cli import verilog, rtlil
 from nmigen import Cat, Const, Array, Signal, Elaboratable, Module
 from nmutil.iocontrol import RecordObject
 from nmutil.util import treereduce
+from nmigen.utils import log2_int
 from nmigen import Memory
 
 from math import log
@@ -171,24 +172,54 @@ class RegFileArray(Elaboratable):
 class RegFileMem(Elaboratable):
     unary = False
     def __init__(self, width, depth):
+        self.width, self.depth = width, depth
         self.memory = Memory(width=width, depth=depth)
         self._rdports = {}
         self._wrports = {}
 
     def read_port(self, name=None):
-        port = self._rdports[name] = self.memory.read_port()
+        bsz = log2_int(self.depth, False)
+        port = RecordObject([("addr", bsz),
+                             ("ren", 1),
+                             ("data_o", self.width)], name=name)
+        self._rdports[name] = (port, self.memory.read_port(domain="comb"))
         return port
 
     def write_port(self, name=None):
-        port = self._wrports[name] = self.memory.write_port()
+        bsz = log2_int(self.depth, False)
+        port = RecordObject([("addr", bsz),
+                             ("wen", 1),
+                             ("data_i", self.width)], name=name)
+        self._wrports[name] = (port, self.memory.write_port())
         return port
 
     def elaborate(self, platform):
         m = Module()
-        for name, rp in self._rdports.items():
-            setattr(m.submodules, "rp_"+name, rp)
-        for name, wp in self._wrports.items():
+        comb = m.d.comb
+
+        # read ports. has write-through detection (returns data written)
+        for name, (rp, rport) in self._rdports.items():
+            setattr(m.submodules, "rp_"+name, rport)
+            wr_detect = Signal(reset_less=False)
+            comb += rport.addr.eq(rp.addr)
+            with m.If(rp.ren):
+                m.d.comb += wr_detect.eq(0)
+                for _, (wp, wport) in self._wrports.items():
+                    addrmatch = Signal(reset_less=False)
+                    m.d.comb += addrmatch.eq(wp.addr == rp.addr)
+                    with m.If(wp.wen & addrmatch):
+                        m.d.comb += rp.data_o.eq(wp.data_i)
+                        m.d.comb += wr_detect.eq(1)
+                with m.If(~wr_detect):
+                    m.d.comb += rp.data_o.eq(rport.data)
+
+        # write ports, delayed by one cycle (in the memory itself)
+        for name, (port, wp) in self._wrports.items():
             setattr(m.submodules, "wp_"+name, wp)
+            comb += wp.addr.eq(port.addr)
+            comb += wp.en.eq(port.wen)
+            comb += wp.data.eq(port.data_i)
+
         return m
 
 
@@ -202,7 +233,7 @@ class RegFile(Elaboratable):
 
     def read_port(self, name=None):
         bsz = int(log(self.width) / log(2))
-        port = RecordObject([("raddr", bsz),
+        port = RecordObject([("addr", bsz),
                              ("ren", 1),
                              ("data_o", self.width)], name=name)
         self._rdports.append(port)
@@ -210,7 +241,7 @@ class RegFile(Elaboratable):
 
     def write_port(self, name=None):
         bsz = int(log(self.width) / log(2))
-        port = RecordObject([("waddr", bsz),
+        port = RecordObject([("addr", bsz),
                              ("wen", 1),
                              ("data_i", self.width)], name=name)
         self._wrports.append(port)
@@ -228,17 +259,17 @@ class RegFile(Elaboratable):
                 m.d.comb += wr_detect.eq(0)
                 for wp in self._wrports:
                     addrmatch = Signal(reset_less=False)
-                    m.d.comb += addrmatch.eq(wp.waddr == rp.raddr)
+                    m.d.comb += addrmatch.eq(wp.addr == rp.addr)
                     with m.If(wp.wen & addrmatch):
                         m.d.comb += rp.data_o.eq(wp.data_i)
                         m.d.comb += wr_detect.eq(1)
                 with m.If(~wr_detect):
-                    m.d.comb += rp.data_o.eq(regs[rp.raddr])
+                    m.d.comb += rp.data_o.eq(regs[rp.addr])
 
         # write ports, delayed by one cycle
         for wp in self._wrports:
             with m.If(wp.wen):
-                m.d.sync += regs[wp.waddr].eq(wp.data_i)
+                m.d.sync += regs[wp.addr].eq(wp.data_i)
 
         return m
 
@@ -256,32 +287,41 @@ class RegFile(Elaboratable):
 
 
 def regfile_sim(dut, rp, wp):
-    yield wp.waddr.eq(1)
+    yield wp.addr.eq(1)
     yield wp.data_i.eq(2)
     yield wp.wen.eq(1)
     yield
     yield wp.wen.eq(0)
+    yield wp.addr.eq(0)
+    yield
+    yield
     yield rp.ren.eq(1)
-    yield rp.raddr.eq(1)
+    yield rp.addr.eq(1)
     yield Settle()
     data = yield rp.data_o
     print(data)
+    yield
+    data = yield rp.data_o
+    print(data)
+    yield
+    data2 = yield rp.data_o
+    print(data2)
     assert data == 2
     yield
 
-    yield wp.waddr.eq(5)
-    yield rp.raddr.eq(5)
+    yield wp.addr.eq(5)
+    yield rp.addr.eq(5)
     yield rp.ren.eq(1)
     yield wp.wen.eq(1)
     yield wp.data_i.eq(6)
-    yield Settle()
+    yield
     data = yield rp.data_o
     print(data)
     assert data == 6
     yield
     yield wp.wen.eq(0)
     yield rp.ren.eq(0)
-    yield Settle()
+    yield
     data = yield rp.data_o
     print(data)
     assert data == 0
@@ -333,12 +373,21 @@ def test_regfile():
     dut = RegFile(32, 8)
     rp = dut.read_port()
     wp = dut.write_port()
-    vl = rtlil.convert(dut, ports=dut.ports())
+    vl = rtlil.convert(dut)#, ports=dut.ports())
     with open("test_regfile.il", "w") as f:
         f.write(vl)
 
     run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regfile.vcd')
 
+    dut = RegFileMem(32, 8)
+    rp = dut.read_port("rp1")
+    wp = dut.write_port("wp1")
+    vl = rtlil.convert(dut)#, ports=dut.ports())
+    with open("test_regmem.il", "w") as f:
+        f.write(vl)
+
+    run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regmem.vcd')
+
     dut = RegFileArray(32, 8)
     rp1 = dut.read_port("read1")
     rp2 = dut.read_port("read2")
index 318878fa077cd27027223db1c2430a58cacfbcad..d088fe600a466ffd9b39aa01e0152f7a2208844c 100644 (file)
@@ -56,7 +56,7 @@ class StateRegs(RegFileArray):
 
 
 # Integer Regfile
-class IntRegs(RegFileArray):
+class IntRegs(RegFileMem): #class IntRegs(RegFileArray):
     """IntRegs
 
     * QTY 32of 64-bit registers
@@ -157,13 +157,6 @@ class SPRRegs(RegFileMem):
         self.w_ports = {'spr1': self.write_port("spr1")}
         self.r_ports = {'spr1': self.read_port("spr1")}
 
-        # make read/write ports look like RegFileArray
-        self.w_ports['spr1'].wen = self.w_ports['spr1'].en
-        self.w_ports['spr1'].data_i = self.w_ports['spr1'].data
-
-        self.r_ports['spr1'].ren = self.w_ports['spr1'].en
-        self.r_ports['spr1'].data_o = self.w_ports['spr1'].data
-
 
 # class containing all regfiles: int, cr, xer, fast, spr
 class RegFiles:
index 421180850201345b767f4432c9c28cbe7f767cf4..a44f4d797a4c4beb499996ca1c4a5761beb244d4 100644 (file)
@@ -181,8 +181,10 @@ class NonProductionCore(Elaboratable):
         rpidx = regname
 
         # select the required read port.  these are pre-defined sizes
-        print(rpidx, regfile, regs.rf.keys())
-        rport = regs.rf[regfile.lower()].r_ports[rpidx]
+        rfile = regs.rf[regfile.lower()]
+        rport = rfile.r_ports[rpidx]
+        print("read regfile", rpidx, regfile, regs.rf.keys(),
+                              rfile, rfile.unary)
 
         fspecs = fspec
         if not isinstance(fspecs, list):
@@ -211,6 +213,7 @@ class NonProductionCore(Elaboratable):
         setattr(m.submodules, "rdpick_%s_%s" % (regfile, rpidx), rdpick)
 
         rens = []
+        addrs = []
         for i, fspec in enumerate(fspecs):
             (rf, read, write, wid, fuspec) = fspec
             # connect up the FU req/go signals, and the reg-read to the FU
@@ -229,12 +232,20 @@ class NonProductionCore(Elaboratable):
                 comb += fu.go_rd_i[idx].eq(rdpick.o[pi])
 
                 # if picked, select read-port "reg select" number to port
-                read_en = Signal.like(reads[i])
-                comb += read_en.eq(Mux(rdpick.o[pi] & rdpick.en_o, reads[i], 0))
-                rens.append(read_en)
+                name = "%s_%s_%s_%i" % (regfile, rpidx, funame, pi)
+                addr_en = Signal.like(reads[i])
+                rp = Signal(name="rp_"+name)
+                addr_en.name = "addr_en_"+name
+                comb += rp.eq(rdpick.o[pi] & rdpick.en_o)
+                comb += addr_en.eq(Mux(rp, reads[i], 0))
+                if rfile.unary:
+                    rens.append(addr_en)
+                else:
+                    addrs.append(addr_en)
+                    rens.append(rp)
 
-                with m.If(rdpick.o[pi] & rdpick.en_o):
-                    # connect regfile port to input, creating a Broadcast Bus
+                with m.If(rp):
+                    # connect regfile port to input, creating fan-out Bus
                     print("reg connect widths",
                           regfile, regname, pi, funame,
                           src.shape(), rport.data_o.shape())
@@ -242,7 +253,14 @@ class NonProductionCore(Elaboratable):
                     comb += src.eq(rport.data_o)
 
         # or-reduce the muxed read signals
-        comb += rport.ren.eq(ortreereduce_sig(rens))
+        if rfile.unary:
+            # for unary-addressed
+            comb += rport.ren.eq(ortreereduce_sig(rens))
+        else:
+            # for binary-addressed
+            comb += rport.addr.eq(ortreereduce_sig(addrs))
+            comb += rport.ren.eq(Cat(*rens).bool())
+            print ("binary", regfile, rpidx, rport, rport.ren, rens, addrs)
 
     def connect_rdports(self, m, fu_bitdict):
         """connect read ports
@@ -291,7 +309,8 @@ class NonProductionCore(Elaboratable):
 
         # select the required write port.  these are pre-defined sizes
         print(regfile, regs.rf.keys())
-        wport = regs.rf[regfile.lower()].w_ports[rpidx]
+        rfile = regs.rf[regfile.lower()]
+        wport = rfile.w_ports[rpidx]
 
         fspecs = fspec
         if not isinstance(fspecs, list):
@@ -313,6 +332,7 @@ class NonProductionCore(Elaboratable):
 
         wsigs = []
         wens = []
+        addrs = []
         for i, fspec in enumerate(fspecs):
             # connect up the FU req/go signals and the reg-read to the FU
             # these are arbitrated by Data.ok signals
@@ -339,9 +359,15 @@ class NonProductionCore(Elaboratable):
                 # connect the regspec write "reg select" number to this port
                 # only if one FU actually requests (and is granted) the port
                 # will the write-enable be activated
-                write_en = Signal.like(write)
-                comb += write_en.eq(Mux(wr_pick & wrpick.en_o, write, 0))
-                wens.append(write_en)
+                addr_en = Signal.like(write)
+                wp = Signal()
+                comb += wp.eq(wr_pick & wrpick.en_o)
+                comb += addr_en.eq(Mux(wp, write, 0))
+                if rfile.unary:
+                    wens.append(addr_en)
+                else:
+                    addrs.append(addr_en)
+                    wens.append(wp)
 
                 # connect regfile port to input
                 print("reg connect widths",
@@ -351,7 +377,13 @@ class NonProductionCore(Elaboratable):
 
         # here is where we create the Write Broadcast Bus. simple, eh?
         comb += wport.data_i.eq(ortreereduce_sig(wsigs))
-        comb += wport.wen.eq(ortreereduce_sig(wens))
+        if rfile.unary:
+            # for unary-addressed
+            comb += wport.wen.eq(ortreereduce_sig(wens))
+        else:
+            # for binary-addressed
+            comb += wport.addr.eq(ortreereduce_sig(addrs))
+            comb += wport.wen.eq(ortreereduce_sig(wens))
 
     def connect_wrports(self, m, fu_bitdict):
         """connect write ports
index 64f203088ee74072a6810f2d9f9a4d6566085641..d0a837a14e730f42cb10aaadc313342f55f50b0f 100644 (file)
@@ -225,7 +225,11 @@ class TestIssuer(Elaboratable):
         with m.If(d_reg.req): # request for regfile access being made
             # TODO: error-check this
             # XXX should this be combinatorial?  sync better?
-            comb += self.int_r.ren.eq(1<<d_reg.addr)
+            if hasattr(self.int_r, "ren"):
+                comb += self.int_r.ren.eq(1<<d_reg.addr)
+            else:
+                comb += self.int_r.addr.eq(d_reg.addr)
+                comb += self.int_r.en.eq(1)
             comb += d_reg.data.eq(self.int_r.data_o)
             comb += d_reg.ack.eq(1)
 
index 984a3db48c5fa8bab2f8bbed5a71d207400d2600..21ffa2e8a0a0e269749f7cf756a96e807b03bd10 100644 (file)
@@ -39,7 +39,11 @@ def setup_regs(core, test):
     # set up INT regfile, "direct" write (bypass rd/write ports)
     intregs = core.regs.int
     for i in range(32):
-        yield intregs.regs[i].reg.eq(test.regs[i])
+        if intregs.unary:
+            yield intregs.regs[i].reg.eq(test.regs[i])
+        else:
+            yield intregs.memory._array[i].eq(test.regs[i])
+    yield Settle()
 
     # set up CR regfile, "direct" write across all CRs
     cr = test.cr
@@ -123,7 +127,10 @@ def check_regs(dut, sim, core, test, code):
     # int regs
     intregs = []
     for i in range(32):
-        rval = yield core.regs.int.regs[i].reg
+        if core.regs.int.unary:
+            rval = yield core.regs.int.regs[i].reg
+        else:
+            rval = yield core.regs.int.memory._array[i]
         intregs.append(rval)
     print("int regs", list(map(hex, intregs)))
     for i in range(32):
index 960a405d0e2845bc86e9071a86a4b48b1c0c50ff..270416a586fd8628eaca2d44ecd6a408b71c84f5 100644 (file)
@@ -26,7 +26,7 @@ from soc.fu.compunits.test.test_compunit import (setup_test_memory,
 from soc.debug.dmi import DBGCore, DBGCtrl, DBGStat
 
 # test with ALU data and Logical data
-#from soc.fu.alu.test.test_pipe_caller import ALUTestCase
+from soc.fu.alu.test.test_pipe_caller import ALUTestCase
 from soc.fu.div.test.test_pipe_caller import DivTestCases
 from soc.fu.logical.test.test_pipe_caller import LogicalTestCase
 #from soc.fu.shift_rot.test.test_pipe_caller import ShiftRotTestCase
@@ -267,7 +267,7 @@ if __name__ == "__main__":
     # suite.addTest(TestRunner(CRTestCase().test_data))
     # suite.addTest(TestRunner(ShiftRotTestCase.test_data))
     suite.addTest(TestRunner(LogicalTestCase().test_data))
-    # suite.addTest(TestRunner(ALUTestCase.test_data))
+    suite.addTest(TestRunner(ALUTestCase().test_data))
     # suite.addTest(TestRunner(BranchTestCase.test_data))
     # suite.addTest(TestRunner(SPRTestCase.test_data))