fix signed variants of cmp in alu
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 17 Aug 2020 09:57:30 +0000 (10:57 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 17 Aug 2020 09:57:30 +0000 (10:57 +0100)
src/soc/fu/alu/main_stage.py

index c7901042c963fbc48d2b598e6073b7343fe2ede2..b2d2279cf80dec3670d70e5b65359c92a9794acf 100644 (file)
@@ -10,6 +10,9 @@ from soc.fu.alu.pipe_data import ALUInputData, ALUOutputData
 from ieee754.part.partsig import PartitionedSignal
 from soc.decoder.power_enums import MicrOp
 
+from soc.decoder.power_fields import DecodeFields
+from soc.decoder.power_fieldsn import SignalBitRange
+
 
 # microwatt calc_ov function.
 def calc_ov(msb_a, msb_b, ca, msb_r):
@@ -19,6 +22,8 @@ def calc_ov(msb_a, msb_b, ca, msb_r):
 class ALUMainStage(PipeModBase):
     def __init__(self, pspec):
         super().__init__(pspec, "main")
+        self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
+        self.fields.create_specs()
 
     def ispec(self):
         return ALUInputData(self.pspec) # defines pipeline stage input format
@@ -35,22 +40,36 @@ class ALUMainStage(PipeModBase):
         ov_o = self.o.xer_ov
         a, b, cry_i, op = self.i.a, self.i.b, self.i.xer_ca, self.i.ctx.op
 
+        # get L-field for OP_CMP
+        x_fields = self.fields.FormX
+        L = x_fields.L[0]
+
         # check if op is 32-bit, and get sign bit from operand a
         is_32bit = Signal(reset_less=True)
-        sign_bit = Signal(reset_less=True)
-        comb += is_32bit.eq(op.is_32bit)
-        comb += sign_bit.eq(Mux(is_32bit, a[31], a[63]))
+
+        with m.If(op.insn_type == MicrOp.OP_CMP):
+            comb += is_32bit.eq(~L)
 
         # little trick: do the add using only one add (not 2)
         # LSB: carry-in [0].  op/result: [1:-1].  MSB: carry-out [-1]
         add_a = Signal(a.width + 2, reset_less=True)
         add_b = Signal(a.width + 2, reset_less=True)
         add_o = Signal(a.width + 2, reset_less=True)
+
+        a_i = Signal.like(a)
+        b_i = Signal.like(b)
+        with m.If(is_32bit):
+            comb += a_i.eq(exts(a, 32, 64))
+            comb += b_i.eq(exts(b, 32, 64))
+        with m.Else():
+            comb += a_i.eq(a)
+            comb += b_i.eq(b)
+
         with m.If((op.insn_type == MicrOp.OP_ADD) |
                   (op.insn_type == MicrOp.OP_CMP)):
             # in bit 0, 1+carry_in creates carry into bit 1 and above
-            comb += add_a.eq(Cat(cry_i[0], a, Const(0, 1)))
-            comb += add_b.eq(Cat(Const(1, 1), b, Const(0, 1)))
+            comb += add_a.eq(Cat(cry_i[0], a_i, Const(0, 1)))
+            comb += add_b.eq(Cat(Const(1, 1), b_i, Const(0, 1)))
             comb += add_o.eq(add_a + add_b)
 
         ##########################
@@ -81,13 +100,13 @@ class ALUMainStage(PipeModBase):
                 # https://bugs.libre-soc.org/show_bug.cgi?id=319#c5
                 ca = Signal(2, reset_less=True)
                 comb += ca[0].eq(add_o[-1])                   # XER.CA
-                comb += ca[1].eq(add_o[33] ^ (a[32] ^ b[32])) # XER.CA32
+                comb += ca[1].eq(add_o[33] ^ (a_i[32] ^ b_i[32])) # XER.CA32
                 comb += cry_o.data.eq(ca)
                 comb += cry_o.ok.eq(1)
                 # 32-bit (ov[1]) and 64-bit (ov[0]) overflow
                 ov = Signal(2, reset_less=True)
-                comb += ov[0].eq(calc_ov(a[-1], b[-1], ca[0], add_o[-2]))
-                comb += ov[1].eq(calc_ov(a[31], b[31], ca[1], add_o[32]))
+                comb += ov[0].eq(calc_ov(a_i[-1], b_i[-1], ca[0], add_o[-2]))
+                comb += ov[1].eq(calc_ov(a_i[31], b_i[31], ca[1], add_o[32]))
                 comb += ov_o.data.eq(ov)
                 comb += ov_o.ok.eq(1)