clarify
[soc.git] / src / soc / fu / cr / main_stage.py
index 59fc00eba7f57b2ed0b495df36b29a7dbd81697a..14828577495e1a1d76cb2097ddb83ec7825f4469 100644 (file)
@@ -1,4 +1,4 @@
-# This stage is intended to do Condition Register instructions
+# 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
@@ -34,26 +34,12 @@ class CRMainStage(PipeModBase):
         m = Module()
         comb = m.d.comb
         op = self.i.ctx.op
-        a, cr = self.i.a, self.i.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, self.o.full_cr, self.o.o
+
         xl_fields = self.fields.FormXL
         xfx_fields = self.fields.FormXFX
-        # default: cr_o remains same as cr input unless modified, below
-        cr_o = Signal.like(cr)
-        comb += cr_o.eq(cr)
-
-        ##### prepare inputs / temp #####
-
-        # Generate array for cr input so bits can be selected
-        cr_arr = Array([Signal(name=f"cr_arr_{i}") for i in range(32)])
-        for i in range(32):
-            comb += cr_arr[i].eq(cr[31-i])
-
-        # Generate array for cr output so the bit to write to can be
-        # selected by a signal
-        cr_out_arr = Array([Signal(name=f"cr_out_{i}") for i in range(32)])
-        for i in range(32):
-            comb += cr_o[31-i].eq(cr_out_arr[i])
-            comb += cr_out_arr[i].eq(cr_arr[i])
 
         # Generate the mask for mtcrf, mtocrf, and mfocrf
         # replicate every fxm field in the insn to 4-bit, as a mask
@@ -61,21 +47,22 @@ class CRMainStage(PipeModBase):
         mask = Signal(32, reset_less=True)
         comb += mask.eq(Cat(*[Repl(FXM[i], 4) for i in range(8)]))
 
-        #################################
-        ##### main switch statement #####
+        # Generate array of bits for cr_a, cr_b and cr_c
+        cr_a_arr = Array([cr_a[i] for i in range(4)])
+        cr_b_arr = Array([cr_b[i] for i in range(4)])
+        cr_o_arr = Array([cr_o[i] for i in range(4)])
 
         with m.Switch(op.insn_type):
             ##### mcrf #####
             with m.Case(InternalOp.OP_MCRF):
                 # MCRF copies the 4 bits of crA to crB (for instance
                 # copying cr2 to cr1)
-                BF = xl_fields.BF[0:-1]   # destination CR
-                BFA = xl_fields.BFA[0:-1] # source CR
+                # Since it takes in a 4 bit cr, and outputs a 4 bit
+                # cr, we don't have to do anything special
+                comb += cr_o.eq(cr_a)
+                comb += cr_o.ok.eq(1) # indicate "this CR has changed"
 
-                for i in range(4):
-                    comb += cr_out_arr[BF*4 + i].eq(cr_arr[BFA*4 + i])
-
-            ##### crand, cror, crnor etc. #####
+            # ##### crand, cror, crnor etc. #####
             with m.Case(InternalOp.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
@@ -83,27 +70,53 @@ class CRMainStage(PipeModBase):
                 # the CR to determine what the resulting bit should be.
 
                 # Grab the lookup table for cr_op type instructions
-                lut = Array([Signal(name=f"lut{i}") for i in range(4)])
+                lut = Signal(4, reset_less=True)
                 # There's no field, just have to grab it directly from the insn
-                for i in range(4):
-                    comb += lut[i].eq(op.insn[6+i])
+                comb += lut.eq(op.insn[6:10])
 
-                # Get the bit selector fields from the instruction
+                # Get the bit selector fields from the
+                # instruction. This operation takes in the little CR
+                # bitfields, so these fields need to get truncated to
+                # the least significant 2 bits
                 BT = xl_fields.BT[0:-1]
                 BA = xl_fields.BA[0:-1]
                 BB = xl_fields.BB[0:-1]
-
-                # Use the two input bits to look up the result in the LUT
-                comb += cr_out_arr[BT].eq(lut[Cat(cr_arr[BB], cr_arr[BA])])
+                bt = Signal(2, reset_less=True)
+                ba = Signal(2, reset_less=True)
+                bb = Signal(2, reset_less=True)
+
+                # Stupid bit ordering stuff.  Because POWER.
+                comb += bt.eq(3-BT[0:2])
+                comb += ba.eq(3-BA[0:2])
+                comb += bb.eq(3-BB[0:2])
+
+                # Extract the two input bits from the CRs
+                bit_a = Signal(reset_less=True)
+                bit_b = Signal(reset_less=True)
+                comb += bit_a.eq(cr_a_arr[ba])
+                comb += bit_b.eq(cr_b_arr[bb])
+
+                # look up the output bit in the lookup table
+                bit_o = Signal()
+                comb += bit_o.eq(Mux(bit_b,
+                                     Mux(bit_a, lut[3], lut[1]),
+                                     Mux(bit_a, lut[2], lut[0])))
+
+                # may have one bit modified by OP_CROP. copy the other 3
+                comb += cr_o.data.eq(cr_c)
+                # insert the (index-targetted) output bit into 4-bit CR output
+                comb += cr_o_arr[bt].eq(bit_o)
+                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 += cr_o.eq((a[0:32] & mask) | (cr & ~mask))
+                comb += full_cr_o.data.eq((a[0:32] & mask) | (full_cr & ~mask))
+                comb += full_cr_o.ok.eq(1) # indicate "this CR has changed"
 
-            ##### mfcr #####
+            # ##### 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
@@ -113,13 +126,39 @@ class CRMainStage(PipeModBase):
 
                 # mfocrf
                 with m.If(move_one):
-                    comb += self.o.o.eq(cr & mask) # output register RT
+                    # output register RT
+                    comb += rt_o.data.eq(full_cr & mask)
                 # mfcrf
                 with m.Else():
-                    comb += self.o.o.eq(cr)        # output register RT
+                    # output register RT
+                    comb += rt_o.data.eq(full_cr)
+                comb += rt_o.ok.eq(1) # indicate "INT reg changed"
+
+            # ##### isel #####
+            with m.Case(InternalOp.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:-1][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(InternalOp.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():
+                    comb += rt_o.data.eq(0)
+                comb += rt_o.ok.eq(1)
 
-        # output and context
-        comb += self.o.cr.eq(cr_o)
         comb += self.o.ctx.eq(self.i.ctx)
 
         return m