bit of reorg, trick on add - put carry in into the LSB
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 9 May 2020 18:19:20 +0000 (19:19 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 9 May 2020 18:19:20 +0000 (19:19 +0100)
src/soc/alu/main_stage.py

index 5385c5aad0a21c4877daec3affd39305f42ce612..0feb74fcf0bbf16ca40640f2f139ee94e69d43c2 100644 (file)
@@ -26,14 +26,12 @@ class ALUMainStage(PipeModBase):
         m = Module()
         comb = m.d.comb
 
+        # check if op is 32-bit, and get sign bit from operand a
         is_32bit = Signal(reset_less=True)
-        comb += is_32bit.eq(self.i.ctx.op.is_32bit)
         sign_bit = Signal(reset_less=True)
+        comb += is_32bit.eq(self.i.ctx.op.is_32bit)
         comb += sign_bit.eq(Mux(is_32bit, self.i.a[31], self.i.a[63]))
 
-        add_output = Signal(self.i.a.width + 1, reset_less=True)
-        comb += add_output.eq(self.i.a + self.i.b + self.i.carry_in)
-
         # Signals for rotates and shifts
         rotl_out = Signal.like(self.i.a)
         mask = Signal.like(self.i.a)
@@ -52,19 +50,38 @@ class ALUMainStage(PipeModBase):
             comb += rotl_out.eq(Cat(rotl32.o, Repl(0, 32)))
         with m.Else():
             comb += rotl_out.eq(rotl.o)
-            
 
+        ##########################
+        # main switch-statement for handling arithmetic and logic operations
 
         with m.Switch(self.i.ctx.op.insn_type):
+            #### add ####
             with m.Case(InternalOp.OP_ADD):
-                comb += self.o.o.eq(add_output[0:64])
-                comb += self.o.carry_out.eq(add_output[64])
+                # little trick: do the add using only one add (not 2)
+                add_a = Signal(self.i.a.width + 2, reset_less=True)
+                add_b = Signal(self.i.a.width + 2, reset_less=True)
+                add_output = Signal(self.i.a.width + 2, reset_less=True)
+                # in bit 0, 1+carry_in creates carry into bit 1 and above
+                comb += add_a.eq(Cat(self.i.carry_in, a, Const(0, 1)))
+                comb += add_b.eq(Cat(Const(1, 1), b, Const(0, 1)))
+                comb += add_output.eq(a + b)
+                # bit 0 is not part of the result, top bit is the carry-out
+                comb += self.o.o.eq(add_output[1:-1])
+                comb += self.o.carry_out.eq(add_output[-1])
+
+            #### and ####
             with m.Case(InternalOp.OP_AND):
                 comb += self.o.o.eq(self.i.a & self.i.b)
+
+            #### or ####
             with m.Case(InternalOp.OP_OR):
                 comb += self.o.o.eq(self.i.a | self.i.b)
+
+            #### xor ####
             with m.Case(InternalOp.OP_XOR):
                 comb += self.o.o.eq(self.i.a ^ self.i.b)
+
+            #### shift left ####
             with m.Case(InternalOp.OP_SHL):
                 comb += maskgen.mb.eq(Mux(is_32bit, 32, 0))
                 comb += maskgen.me.eq(63-self.i.b[0:6])
@@ -80,6 +97,8 @@ class ALUMainStage(PipeModBase):
                     with m.Else():
                         comb += mask.eq(maskgen.o)
                 comb += self.o.o.eq(rotl_out & mask)
+
+            #### shift right ####
             with m.Case(InternalOp.OP_SHR):
                 comb += maskgen.mb.eq(Mux(is_32bit, 32, 0) + self.i.b[0:6])
                 comb += maskgen.me.eq(63)
@@ -95,9 +114,10 @@ class ALUMainStage(PipeModBase):
                     with m.Else():
                         comb += mask.eq(maskgen.o)
                 with m.If(self.i.ctx.op.is_signed):
-                    comb += self.o.o.eq(rotl_out & mask |
-                                        Mux(sign_bit, ~mask, 0))
-                    comb += self.o.carry_out.eq(sign_bit & ((rotl_out & mask) != 0))
+                    out = rotl_out & mask | Mux(sign_bit, ~mask, 0))
+                    cout = sign_bit & ((rotl_out & mask) != 0))
+                    comb += self.o.o.eq(out)
+                    comb += self.o.carry_out.eq(cout)
                 with m.Else():
                     comb += self.o.o.eq(rotl_out & mask)