remove m.If/Elif/Elif replace with Mux
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 25 Aug 2019 15:10:11 +0000 (16:10 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 25 Aug 2019 15:10:11 +0000 (16:10 +0100)
src/ieee754/fpmul/specialcases.py

index 4fc3e3cf07a63f9dd1773a8d241035b61c1add60..066d2b9f0fc15dd153cb1c7b262901636b7fe344 100644 (file)
@@ -5,7 +5,7 @@ Copyright (C) 2019 Jake Lifshay
 
 """
 
-from nmigen import Module, Signal, Cat, Const
+from nmigen import Module, Signal, Cat, Const, Mux
 from nmigen.cli import main, verilog
 from math import log
 
@@ -36,7 +36,7 @@ class FPMulSpecialCasesMod(PipeModBase):
         m = Module()
         comb = m.d.comb
 
-        # decode: XXX really should move to separate stage
+        # decode a/b
         width = self.pspec.width
         a1 = FPNumBaseRecord(width, False)
         b1 = FPNumBaseRecord(width, False)
@@ -48,45 +48,49 @@ class FPMulSpecialCasesMod(PipeModBase):
                      self.o.b.eq(b1)
                     ]
 
-        obz = Signal(reset_less=True)
-        comb += obz.eq(a1.is_zero | b1.is_zero)
-
+        # intermediaries / tests
+        t_obz = Signal(reset_less=True)
+        t_a1inf = Signal(reset_less=True)
+        t_b1inf = Signal(reset_less=True)
+        t_abnan = Signal(reset_less=True)
+        t_special = Signal(reset_less=True)
         sabx = Signal(reset_less=True)   # sign a xor b (sabx, get it?)
-        comb += sabx.eq(a1.s ^ b1.s)
 
-        abnan = Signal(reset_less=True)
-        comb += abnan.eq(a1.is_nan | b1.is_nan)
-
-        # initialise and override if needed
-        comb += self.o.out_do_z.eq(1)
+        comb += sabx.eq(a1.s ^ b1.s)
+        comb += t_obz.eq(a1.is_zero | b1.is_zero)
+        comb += t_a1inf.eq(a1.is_inf)
+        comb += t_b1inf.eq(b1.is_inf)
+        comb += t_abnan.eq(a1.is_nan | b1.is_nan)
+        comb += t_special.eq(Cat(t_obz, t_abnan, t_b1inf, t_a1inf).bool())
+
+        # prepare inf/zero/nans
+        z_zero = FPNumBaseRecord(width, False, name="z_zero")
+        z_nan = FPNumBaseRecord(width, False, name="z_nan")
+        z_inf = FPNumBaseRecord(width, False, name="z_inf")
+        comb += z_zero.zero(sabx)
+        comb += z_nan.nan(0)
+        comb += z_inf.inf(sabx)
+
+        # special case pipeline bypass enabled y/n
+        comb += self.o.out_do_z.eq(t_special)
 
         # if a is NaN or b is NaN return NaN
-        with m.If(abnan):
-            comb += self.o.z.nan(0)
-
         # if a is inf return inf (or NaN)
-        with m.Elif(a1.is_inf):
-            comb += self.o.z.inf(sabx)
-            # b is zero return NaN
-            with m.If(b1.is_zero):
-                comb += self.o.z.nan(0)
-
+        #   if b is zero return NaN
         # if b is inf return inf (or NaN)
-        with m.Elif(b1.is_inf):
-            comb += self.o.z.inf(sabx)
-            # a is zero return NaN
-            with m.If(a1.is_zero):
-                comb += self.o.z.nan(0)
-
+        #   if a is zero return NaN
         # if a is zero or b zero return signed-a/b
-        with m.Elif(obz):
-            comb += self.o.z.zero(sabx)
 
-        # Denormalised Number checks next, so pass a/b data through
-        with m.Else():
-            comb += self.o.out_do_z.eq(0)
+        # invert the sequence above to create the Mux tree
+        # XXX TODO: use PriorityPicker?
+        oz = 0
+        oz = Mux(t_obz, z_zero.v, oz)
+        oz = Mux(t_b1inf, Mux(a1.is_zero, z_nan.v, z_inf.v), oz)
+        oz = Mux(t_a1inf, Mux(b1.is_zero, z_nan.v, z_inf.v), oz)
+        oz = Mux(t_abnan, z_nan.v, oz)
+        comb += self.o.oz.eq(oz)
 
-        comb += self.o.oz.eq(self.o.z.v)
+        # pass through context
         comb += self.o.ctx.eq(self.i.ctx)
 
         return m