add additional CR regression tests
[soc.git] / src / soc / fu / cr / main_stage.py
index efb821e5bcee6588357d5a638d0b7b5225a295f5..eced9c3460b4ae58d09c59ba5e7c44bd9463f2b9 100644 (file)
@@ -1,4 +1,8 @@
-# This stage is intended to do Condition Register instructions
+# License: LGPLv3
+# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+# Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+# This stage is intended to do Condition Register instructions (and ISEL)
 # and output, as well as carry and overflow generation.
 # NOTE: with the exception of mtcrf and mfcr, we really should be doing
 # the field decoding which
@@ -12,7 +16,7 @@
 from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
 from nmutil.pipemodbase import PipeModBase
 from soc.fu.cr.pipe_data import CRInputData, CROutputData
-from soc.decoder.power_enums import InternalOp
+from soc.decoder.power_enums import MicrOp
 
 from soc.decoder.power_fields import DecodeFields
 from soc.decoder.power_fieldsn import SignalBitRange
@@ -34,18 +38,11 @@ class CRMainStage(PipeModBase):
         m = Module()
         comb = m.d.comb
         op = self.i.ctx.op
-        a, full_cr = self.i.a, self.i.full_cr
+        a, b, full_cr = self.i.a, self.i.b, self.i.full_cr
         cr_a, cr_b, cr_c = self.i.cr_a, self.i.cr_b, self.i.cr_c
-        cr_o, full_cr_o, rt_o = self.o.cr_o, self.o.full_cr, self.o.o
+        cr_o, full_cr_o, rt_o = self.o.cr, self.o.full_cr, self.o.o
 
         xl_fields = self.fields.FormXL
-        xfx_fields = self.fields.FormXFX
-
-        # Generate the mask for mtcrf, mtocrf, and mfocrf
-        # replicate every fxm field in the insn to 4-bit, as a mask
-        FXM = xfx_fields.FXM[0:-1]
-        mask = Signal(32, reset_less=True)
-        comb += mask.eq(Cat(*[Repl(FXM[i], 4) for i in range(8)]))
 
         # Generate array of bits for cr_a, cr_b and cr_c
         cr_a_arr = Array([cr_a[i] for i in range(4)])
@@ -54,7 +51,7 @@ class CRMainStage(PipeModBase):
 
         with m.Switch(op.insn_type):
             ##### mcrf #####
-            with m.Case(InternalOp.OP_MCRF):
+            with m.Case(MicrOp.OP_MCRF):
                 # MCRF copies the 4 bits of crA to crB (for instance
                 # copying cr2 to cr1)
                 # Since it takes in a 4 bit cr, and outputs a 4 bit
@@ -63,7 +60,7 @@ class CRMainStage(PipeModBase):
                 comb += cr_o.ok.eq(1) # indicate "this CR has changed"
 
             # ##### crand, cror, crnor etc. #####
-            with m.Case(InternalOp.OP_CROP):
+            with m.Case(MicrOp.OP_CROP):
                 # crand/cror and friends get decoded to the same opcode, but
                 # one of the fields inside the instruction is a 4 bit lookup
                 # table. This lookup table gets indexed by bits a and b from
@@ -109,29 +106,47 @@ class CRMainStage(PipeModBase):
                 comb += cr_o.ok.eq(1) # indicate "this CR has changed"
 
             ##### mtcrf #####
-            with m.Case(InternalOp.OP_MTCRF):
-                # mtocrf and mtcrf are essentially identical
-                # put input (RA) - mask-selected - into output CR, leave
-                # rest of CR alone.
-                comb += full_cr_o.data.eq((a[0:32] & mask) | (full_cr & ~mask))
+            with m.Case(MicrOp.OP_MTCRF):
+                # mtocrf and mtcrf are essentially identical.  PowerDecoder2
+                # takes care of the mask, by putting FXM (as-is or one-hot)
+                # into the CR regfile "full_cr" write-enable, in conjunction
+                # with regspec_decode_write
+                comb += full_cr_o.data.eq(a[0:32])
                 comb += full_cr_o.ok.eq(1) # indicate "this CR has changed"
 
             # ##### mfcr #####
-            with m.Case(InternalOp.OP_MFCR):
-                # Ugh. mtocrf and mtcrf have one random bit differentiating
-                # them. This bit is not in any particular field, so this
-                # extracts that bit from the instruction
-                move_one = Signal(reset_less=True)
-                comb += move_one.eq(op.insn[20])
-
-                # mfocrf
-                with m.If(move_one):
-                    # output register RT
-                    comb += rt_o.eq(full_cr & mask)
-                # mfcrf
+            with m.Case(MicrOp.OP_MFCR):
+                # output register RT.  again, like mtocrf/mtcrf, PowerDecoder2
+                # takes care of the masking, this time by putting FXM (or 1hot)
+                # into the CR regfile "full_cr" *read* enable, in conjunction
+                # with regspect_decode_read.
+                comb += rt_o.data.eq(full_cr)
+                comb += rt_o.ok.eq(1) # indicate "INT reg changed"
+
+            # ##### isel #####
+            with m.Case(MicrOp.OP_ISEL):
+                # just like in branch, CR0-7 is incoming into cr_a, we
+                # need to select from the last 2 bits of BC
+                a_fields = self.fields.FormA
+                BC = a_fields.BC[0:2]
+                cr_bits = Array([cr_a[3-i] for i in range(4)])
+
+                # The bit of (cr_a=CR0-7) selected by BC
+                cr_bit = Signal(reset_less=True)
+                comb += cr_bit.eq(cr_bits[BC])
+
+                # select a or b as output
+                comb += rt_o.eq(Mux(cr_bit, a, b))
+                comb += rt_o.ok.eq(1) # indicate "INT reg changed"
+
+            with m.Case(MicrOp.OP_SETB):
+                with m.If(cr_a[3]):
+                    comb += rt_o.data.eq(-1)
+                with m.Elif(cr_a[2]):
+                    comb += rt_o.data.eq(1)
                 with m.Else():
-                    # output register RT
-                    comb += rt_o.eq(full_cr)
+                    comb += rt_o.data.eq(0)
+                comb += rt_o.ok.eq(1)
 
         comb += self.o.ctx.eq(self.i.ctx)