Add support for hierarchical decoding
authorMichael Nolan <mtnolan2640@gmail.com>
Mon, 2 Mar 2020 15:24:16 +0000 (10:24 -0500)
committerMichael Nolan <mtnolan2640@gmail.com>
Mon, 2 Mar 2020 15:24:41 +0000 (10:24 -0500)
src/decoder/power_decoder.py
src/decoder/test/test_power_decoder.py

index d95facb60e34cc1983072500ee19e7442e62e911..f0d44876f95f056e32367ea367236df80f4c357d 100644 (file)
@@ -43,6 +43,21 @@ class PowerOp:
             res.append(sig.eq(int(row.get(bit, 0))))
         return res
 
+    def eq(self, otherop):
+        res = [self.function_unit.eq(otherop.function_unit),
+               self.internal_op.eq(otherop.internal_op),
+               self.in1_sel.eq(otherop.in1_sel),
+               self.in2_sel.eq(otherop.in2_sel),
+               self.in3_sel.eq(otherop.in3_sel),
+               self.out_sel.eq(otherop.out_sel),
+               self.rc_sel.eq(otherop.rc_sel),
+               self.ldst_len.eq(otherop.ldst_len),
+               self.cry_in.eq(otherop.cry_in)]
+        for bit in single_bit_flags:
+            sig = getattr(self, get_signal_name(bit))
+            res.append(sig.eq(getattr(otherop, get_signal_name(bit))))
+        return res
+
     def ports(self):
         regular = [self.function_unit,
                    self.in1_sel,
@@ -61,41 +76,76 @@ class PowerDecoder(Elaboratable):
     """PowerDecoder - decodes an incoming opcode into the type of operation
     """
 
-    def __init__(self, width, csvname, opint=True):
-        self.opint = opint # true if the opcode needs to be converted to int
-        self.opcodes = get_csv(csvname)
+    def __init__(self, width, opcodes, opint=True, suffix=None):
+        self.opint = opint  # true if the opcode needs to be converted to int
+        self.opcodes = opcodes
         self.opcode_in = Signal(width, reset_less=True)
 
         self.op = PowerOp()
+        self.suffix = suffix
+        self.width = width
+
+    def suffix_mask(self):
+        return ((1 << self.suffix[1]) - 1) - ((1 << self.suffix[0]) - 1)
+
+    def divide_opcodes(self):
+        divided = {}
+        mask = self.suffix_mask()
+        for row in self.opcodes:
+            opcode = row['opcode']
+            if self.opint:
+                opcode = int(opcode, 0)
+            key = opcode & mask >> (self.suffix[0])
+            opcode = opcode >> self.suffix[1]
+            if key not in divided:
+                divided[key] = []
+            r = row.copy()
+            r['opcode'] = opcode
+            divided[key].append(r)
+        return divided
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
 
-        with m.Switch(self.opcode_in):
-            for row in self.opcodes:
-                opcode = row['opcode']
-                if self.opint:
-                    opcode = int(opcode, 0)
-                if not row['unit']:
-                    continue
-                print ("opcode", opcode)
-                with m.Case(opcode):
-                    comb += self.op._eq(row)
-            with m.Default():
-                    comb += self.op._eq(None)
+        if self.suffix:
+            opcodes = self.divide_opcodes()
+            opc_in = Signal(self.suffix[1] - self.suffix[0], reset_less=True)
+            comb += opc_in.eq(self.opcode_in[self.suffix[0]:self.suffix[1]])
+            with m.Switch(opc_in):
+                for key, row in opcodes.items():
+                    subdecoder = PowerDecoder(width=self.width - opc_in.width,
+                                              opcodes=row,
+                                              opint=False)
+                    setattr(m.submodules, "dec%d" % key, subdecoder)
+                    comb += subdecoder.opcode_in.eq(self.opcode_in[self.suffix[1]:])
+                    with m.Case(key):
+                        comb += self.op.eq(subdecoder.op)
+
+        else:
+            with m.Switch(self.opcode_in):
+                for row in self.opcodes:
+                    opcode = row['opcode']
+                    if self.opint:
+                        opcode = int(opcode, 0)
+                    if not row['unit']:
+                        continue
+                    with m.Case(opcode):
+                        comb += self.op._eq(row)
+                with m.Default():
+                        comb += self.op._eq(None)
         return m
 
     def ports(self):
         return [self.opcode_in] + self.op.ports()
 
 # how about this?
-if False:
-    pminor = (0, 6, [(19, "minor_19", (1,11)), # pass to 'splitter' function
-                     (30, "minor_30", (1,4)),
-                     (31, "minor_31", (1,11)), # pass to 'splitter' function
-                     (58, "minor_58", (0,1)),
-                     (62, "minor_62", (0,1)),
-                    ]
-
-    pdecode = PowerDecoder(6, "major", subcoders = pminor)
+if False:
+    pminor = (0, 6, [(19, "minor_19", (1,11)), # pass to 'splitter' function
+                     (30, "minor_30", (1,4)),
+                     (31, "minor_31", (1,11)), # pass to 'splitter' function
+                     (58, "minor_58", (0,1)),
+                     (62, "minor_62", (0,1)),
+                    ]
+
+    pdecode = PowerDecoder(6, "major", subcoders = pminor)
index 9955b66665e5b28e00aa1394b2d440cb4220f488..b1851c91983c770d1d6248b02cb049762d1c2cc9 100644 (file)
@@ -9,11 +9,11 @@ sys.path.append("../")
 from power_decoder import (PowerDecoder)
 from power_enums import (Function, InternalOp, In1Sel, In2Sel, In3Sel,
                          OutSel, RC, LdstLen, CryIn, single_bit_flags,
-                         get_signal_name)
+                         get_signal_name, get_csv)
 
 
 class DecoderTestCase(FHDLTestCase):
-    def run_test(self, width, csvname, opint=True):
+    def run_test(self, width, csvname, suffix=None, opint=True):
         m = Module()
         comb = m.d.comb
         opcode = Signal(width)
@@ -27,7 +27,8 @@ class DecoderTestCase(FHDLTestCase):
         ldst_len = Signal(LdstLen)
         cry_in = Signal(CryIn)
 
-        m.submodules.dut = dut = PowerDecoder(width, csvname, opint)
+        opcodes = get_csv(csvname)
+        m.submodules.dut = dut = PowerDecoder(width, opcodes, opint, suffix=suffix)
         comb += [dut.opcode_in.eq(opcode),
                  function_unit.eq(dut.op.function_unit),
                  in1_sel.eq(dut.op.in1_sel),
@@ -77,9 +78,9 @@ class DecoderTestCase(FHDLTestCase):
                 in1_sel, in2_sel]):
             sim.run()
 
-    def generate_ilang(self, width, csvname, opint=True):
+    def generate_ilang(self, width, csvname, opint=True, suffix=None):
         prefix = os.path.splitext(csvname)[0]
-        dut = PowerDecoder(width, csvname, opint)
+        dut = PowerDecoder(width, get_csv(csvname), opint, suffix=suffix)
         vl = rtlil.convert(dut, ports=dut.ports())
         with open("%s_decoder.il" % prefix, "w") as f:
             f.write(vl)
@@ -88,19 +89,19 @@ class DecoderTestCase(FHDLTestCase):
         self.run_test(6, "major.csv")
         self.generate_ilang(6, "major.csv")
 
-    def test_minor_19(self):
-        self.run_test(3, "minor_19.csv")
-        self.generate_ilang(3, "minor_19.csv")
+    def test_minor_19(self):
+        self.run_test(3, "minor_19.csv")
+        self.generate_ilang(3, "minor_19.csv")
 
     def test_minor_30(self):
         self.run_test(4, "minor_30.csv")
         self.generate_ilang(4, "minor_30.csv")
 
     def test_minor_31(self):
-        self.run_test(10, "minor_31.csv")
-        self.generate_ilang(10, "minor_31.csv")
+        self.run_test(10, "minor_31.csv", suffix=(0, 5))
+        self.generate_ilang(10, "minor_31.csv", suffix=(0, 5))
 
-    def test_minor_31(self):
+    def test_extra(self):
         self.run_test(32, "extra.csv", False)
         self.generate_ilang(32, "extra.csv", False)