add read-write register numbering detection
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 2 Jun 2020 16:32:12 +0000 (17:32 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 2 Jun 2020 16:32:12 +0000 (17:32 +0100)
src/soc/decoder/power_decoder2.py
src/soc/fu/compunits/test/test_branch_compunit.py
src/soc/fu/regspec.py

index b1352048b71c85da13f1e6b3ddab3334ed6a80c8..09cad542f83188573f2a06d9638a7bdd278ed54a 100644 (file)
@@ -15,6 +15,7 @@ from soc.decoder.power_enums import (InternalOp, CryIn, Function,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
                                      OutSel, SPR, RC)
 
+from soc.regfile.regfiles import FastRegs
 
 class DecodeA(Elaboratable):
     """DecodeA from instruction
@@ -60,11 +61,12 @@ class DecodeA(Elaboratable):
         with m.If((op.internal_op == InternalOp.OP_BC) |
                   (op.internal_op == InternalOp.OP_BCREG)):
             with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg
-                comb += self.spr_out.data.eq(SPR.CTR) # constant: CTR
+                comb += self.spr_out.data.eq(FastRegs.CTR) # constant: CTR
                 comb += self.spr_out.ok.eq(1)
         # MFSPR or MTSPR: move-from / move-to SPRs
         with m.If((op.internal_op == InternalOp.OP_MFSPR) |
                   (op.internal_op == InternalOp.OP_MTSPR)):
+            # XXX TODO: fast/slow SPR decoding and mapping
             comb += self.spr_out.data.eq(self.dec.SPR) # SPR field, XFX
             comb += self.spr_out.ok.eq(1)
 
@@ -154,9 +156,9 @@ class DecodeB(Elaboratable):
         # BCREG implicitly uses CTR or LR for 2nd reg
         with m.If(op.internal_op == InternalOp.OP_BCREG):
             with m.If(self.dec.FormXL.XO[9]): # 3.0B p38 top bit of XO
-                comb += self.spr_out.data.eq(SPR.CTR)
+                comb += self.spr_out.data.eq(FastRegs.CTR)
             with m.Else():
-                comb += self.spr_out.data.eq(SPR.LR)
+                comb += self.spr_out.data.eq(FastRegs.LR)
             comb += self.spr_out.ok.eq(1)
 
         return m
index d0d00f7ff4e57540aef4090f9a885a2504ac9a94..c8d02b67855e3c78ae5c6e8b6611d691c6b89173 100644 (file)
@@ -1,5 +1,5 @@
 import unittest
-from soc.decoder.power_enums import (XER_bits, Function, spr_dict)
+from soc.decoder.power_enums import (XER_bits, Function, spr_dict, SPR)
 
 # XXX bad practice: use of global variables
 from soc.fu.branch.test.test_pipe_caller import BranchTestCase
@@ -8,11 +8,20 @@ from soc.fu.branch.test.test_pipe_caller import test_data
 from soc.fu.compunits.compunits import BranchFunctionUnit
 from soc.fu.compunits.test.test_compunit import TestRunner
 
+from soc.regfile.regfiles import FastRegs
 
 """
     def assert_outputs(self, branch, dec2, sim, prev_nia, code):
 """
 
+def fast_reg_to_spr(spr_num):
+    if spr_num == FastRegs.CTR:
+        return SPR.CTR.value
+    elif spr_num == FastRegs.LR:
+        return SPR.LR.value
+    elif spr_num == FastRegs.TAR:
+        return SPR.TAR.value
+
 
 class BranchTestRunner(TestRunner):
     def __init__(self, test_data):
@@ -36,12 +45,16 @@ class BranchTestRunner(TestRunner):
         # SPR1
         spr_ok = yield dec2.e.read_spr1.ok
         spr_num = yield dec2.e.read_spr1.data
+        # HACK
+        spr_num = fast_reg_to_spr(spr_num)
         if spr_ok:
             res['spr1'] = sim.spr[spr_dict[spr_num].SPR].value
 
         # SPR2
         spr_ok = yield dec2.e.read_spr2.ok
         spr_num = yield dec2.e.read_spr2.data
+        # HACK
+        spr_num = fast_reg_to_spr(spr_num)
         if spr_ok:
             res['spr2'] = sim.spr[spr_dict[spr_num].SPR].value
 
index 0aa2842c173be5ec1daade1ef170a9014ede32e9..632c19fcbf4e741cdbb593968f811a4fd8d94f1f 100644 (file)
@@ -17,6 +17,7 @@ which MultiCompUnit port, how wide the connection is, and so on.
 
 """
 from nmigen import Const
+from soc.regfile.regfiles import XERRegs, FastRegs
 
 def get_regspec_bitwidth(regspec, srcdest, idx):
     print ("get_regspec_bitwidth", regspec, srcdest, idx)
@@ -90,28 +91,87 @@ class RegSpecALUAPI:
 
 
 # function for the relationship between regspecs and Decode2Execute1Type
-def regspec_rdmask(e, regspec, idx):
-    (regfile, name, _) = regspec[idx]
+def regspec_decode(e, regfile, name):
+    """regspec_decode
+
+    this function encodes the understanding (relationship) between
+    Regfiles, Computation Units, and the Power ISA Decoder (PowerDecoder2).
+
+    based on the regspec, which contains the register file name and register
+    name, return a tuple of:
+
+    * how the decoder should determine whether the Function Unit needs
+      a Regport or not
+    * which Regfile port should be read to get that data
+    * when it comes to writing: likewise, which Regfile port should be written
+
+    Note that some of the port numbering encoding is *unary*.  in the case
+    of "Full Condition Register", it's a full 8-bit mask of read/write-enables.
+    This actually matches directly with the XFX field in MTCR, and at
+    some point that 8-bit mask from the instruction could actually be passed        directly through to full_cr (TODO).
+
+    For the INT and CR numbering, these are expressed in binary in the
+    instruction (note however that XFX in MTCR is unary-masked!)
+
+    XER is implicitly-encoded based on whether the operation has carry or
+    overflow.
+
+    FAST regfile is, again, implicitly encoded, back in PowerDecode2, based
+    on the type of operation (see DecodeB for an example).
+
+    The SPR regfile on the other hand is *binary*-encoded, and, furthermore,
+    has to be "remapped".
+    """
+
     if regfile == 'INT':
+        # Int register numbering is *unary* encoded
         if name == 'ra': # RA
-            return e.read_reg1.ok
+            return e.read_reg1.ok, 1<<e.read_reg1.data, None
         if name == 'rb': # RB
-            return e.read_reg2.ok
+            return e.read_reg2.ok, 1<<e.read_reg2.data, None
         if name == 'rc': # RS
-            return e.read_reg3.ok
+            return e.read_reg3.ok, 1<<e.read_reg3.data, None
+
     if regfile == 'CR':
+        # CRRegs register numbering is *unary* encoded
         if name == 'full_cr': # full CR
-            return e.read_cr_whole
+            return e.read_cr_whole, 0b11111111, 0b11111111
         if name == 'cr_a': # CR A
-            return e.read_cr1.ok
+            return e.read_cr1.ok, 1<<e.read_cr1.data, 1<<e.write_cr.data
         if name == 'cr_b': # CR B
-            return e.read_cr2.ok
+            return e.read_cr2.ok, 1<<e.read_cr2.data, None
         if name == 'cr_c': # CR C
-            return e.read_cr3.ok
+            return e.read_cr3.ok, 1<<e.read_cr2.data, None
+
     if regfile == 'XER':
-        if name in ['xer_so', 'xer_ov']:
-            return e.oe.oe & e.oe.oe_ok
+        # XERRegs register numbering is *unary* encoded
+        SO = 1<<XERRegs.SO
+        CA = 1<<XERRegs.CA
+        OV = 1<<XERRegs.OV
+        if name == 'xer_so':
+            return e.oe.oe & e.oe.oe_ok, SO, SO
+        if name == 'xer_ov':
+            return e.oe.oe & e.oe.oe_ok, OV, OV
         if name == 'xer_ca':
-            return e.input_carry
-
-    assert False, "regspec rdmask not found %s %d" % (repr(regspec), idx)
+            return e.input_carry, CA, CA
+
+    if regfile == 'FAST':
+        # FAST register numbering is *unary* encoded
+        PC = 1<<FastRegs.PC
+        MSR = 1<<FastRegs.MSR
+        CTR = 1<<FastRegs.CTR
+        LR = 1<<FastRegs.LR
+        TAR = 1<<FastRegs.TAR
+        SRR1 = 1<<FastRegs.SRR1
+        SRR2 = 1<<FastRegs.SRR2
+        if name in ['cia', 'nia']:
+            return Const(1), PC, PC
+        if name == 'msr':
+            return Const(1), MSR, MSR
+        # TODO: remap the SPR numbers to FAST regs
+        if name == 'spr1':
+            return e.read_spr1.ok, 1<<e.read_spr1.data, 1<<e.write_spr.data
+        if name == 'spr2':
+            return e.read_spr2.ok, 1<<e.read_spr2.data, 1<<e.write_spr.data
+
+    assert False, "regspec not found %s %d" % (repr(regspec), idx)