limit count leading zeros to stop exponent shift-amount going below min exp
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 3 Mar 2019 09:55:44 +0000 (09:55 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 3 Mar 2019 09:55:44 +0000 (09:55 +0000)
src/add/nmigen_add_experiment.py

index 13c76d2bec0d453ba626d91ab698843334708797..6e797c016f1845b9e82df7fe61088bedfd842b53 100644 (file)
@@ -2,12 +2,12 @@
 # Copyright (C) Jonathan P Dawson 2013
 # 2013-12-12
 
 # Copyright (C) Jonathan P Dawson 2013
 # 2013-12-12
 
-from nmigen import Module, Signal, Cat
+from nmigen import Module, Signal, Cat, Mux
 from nmigen.lib.coding import PriorityEncoder
 from nmigen.cli import main, verilog
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
 from nmigen.lib.coding import PriorityEncoder
 from nmigen.cli import main, verilog
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
-
+from fpbase import FPNumShiftMultiRight
 
 class FPState(FPBase):
     def __init__(self, state_from):
 
 class FPState(FPBase):
     def __init__(self, state_from):
@@ -550,19 +550,27 @@ class FPNorm1Mod:
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
+
         mwid = self.out_z.m_width+2
         pe = PriorityEncoder(mwid)
         m.submodules.norm_pe = pe
         mwid = self.out_z.m_width+2
         pe = PriorityEncoder(mwid)
         m.submodules.norm_pe = pe
+
         m.submodules.norm1_out_z = self.out_z
         m.submodules.norm1_out_overflow = self.out_of
         m.submodules.norm1_temp_z = self.temp_z
         m.submodules.norm1_temp_of = self.temp_of
         m.submodules.norm1_in_z = self.in_z
         m.submodules.norm1_in_overflow = self.in_of
         m.submodules.norm1_out_z = self.out_z
         m.submodules.norm1_out_overflow = self.out_of
         m.submodules.norm1_temp_z = self.temp_z
         m.submodules.norm1_temp_of = self.temp_of
         m.submodules.norm1_in_z = self.in_z
         m.submodules.norm1_in_overflow = self.in_of
+
         in_z = FPNumBase(self.width, False)
         in_of = Overflow()
         m.submodules.norm1_insel_z = in_z
         m.submodules.norm1_insel_overflow = in_of
         in_z = FPNumBase(self.width, False)
         in_of = Overflow()
         m.submodules.norm1_insel_z = in_z
         m.submodules.norm1_insel_overflow = in_of
+
+        ediff_n126 = Signal((len(in_z.e), True), reset_less=True)
+        smr = FPNumShiftMultiRight(in_z, ediff_n126, in_z.m_width+2)
+        m.submodules.norm1_smr = smr
+
         # select which of temp or in z/of to use
         with m.If(self.in_select):
             m.d.comb += in_z.copy(self.in_z)
         # select which of temp or in z/of to use
         with m.If(self.in_select):
             m.d.comb += in_z.copy(self.in_z)
@@ -578,7 +586,10 @@ class FPNorm1Mod:
         increase = Signal(reset_less=True)
         m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
         m.d.comb += increase.eq(in_z.exp_lt_n126)
         increase = Signal(reset_less=True)
         m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
         m.d.comb += increase.eq(in_z.exp_lt_n126)
-        m.d.comb += self.out_norm.eq(decrease | increase) # loop-end condition
+        if not self.single_cycle:
+            m.d.comb += self.out_norm.eq(decrease | increase) # loop-end 
+        else:
+            m.d.comb += self.out_norm.eq(increase) # loop-end condition
         # decrease exponent
         with m.If(decrease):
             if not self.single_cycle:
         # decrease exponent
         with m.If(decrease):
             if not self.single_cycle:
@@ -597,13 +608,17 @@ class FPNorm1Mod:
                 temp_m = Signal(mwid, reset_less=True)
                 temp_s = Signal(mwid+1, reset_less=True)
                 clz = Signal((len(in_z.e), True), reset_less=True)
                 temp_m = Signal(mwid, reset_less=True)
                 temp_s = Signal(mwid+1, reset_less=True)
                 clz = Signal((len(in_z.e), True), reset_less=True)
+                # make sure that the amount to decrease by does NOT
+                # go below the minimum non-INF/NaN exponent
+                limclz = Mux(in_z.e - pe.o - in_z.N126 > 0, pe.o,
+                             in_z.e - in_z.N126)
                 m.d.comb += [
                     # cat round and guard bits back into the mantissa
                     temp_m.eq(Cat(in_of.round_bit,
                                   in_of.guard,
                                   in_z.m)),
                     pe.i.eq(temp_m[::-1]),          # inverted
                 m.d.comb += [
                     # cat round and guard bits back into the mantissa
                     temp_m.eq(Cat(in_of.round_bit,
                                   in_of.guard,
                                   in_z.m)),
                     pe.i.eq(temp_m[::-1]),          # inverted
-                    clz.eq(pe.o),                   # count zeros from MSB down
+                    clz.eq(limclz),                 # count zeros from MSB down
                     temp_s.eq(temp_m << clz),       # shift mantissa UP
                     self.out_z.e.eq(in_z.e - clz),  # DECREASE exponent
                     self.out_z.m.eq(temp_s[2:]),    # exclude bits 0&1
                     temp_s.eq(temp_m << clz),       # shift mantissa UP
                     self.out_z.e.eq(in_z.e - clz),  # DECREASE exponent
                     self.out_z.m.eq(temp_s[2:]),    # exclude bits 0&1
@@ -613,15 +628,20 @@ class FPNorm1Mod:
                     self.out_of.round_bit.eq(temp_s[0]), # round
                 ]
         # increase exponent
                     self.out_of.round_bit.eq(temp_s[0]), # round
                 ]
         # increase exponent
-        with m.If(increase):
-            m.d.comb += [
+        with m.Elif(increase):
+            if self.single_cycle:
+                m.d.comb += [
                 self.out_z.e.eq(in_z.e + 1),  # INCREASE exponent
                 self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN
                 self.out_of.guard.eq(in_z.m[0]),
                 self.out_of.m0.eq(in_z.m[1]),
                 self.out_of.round_bit.eq(in_of.guard),
                 self.out_of.sticky.eq(in_of.sticky | in_of.round_bit)
                 self.out_z.e.eq(in_z.e + 1),  # INCREASE exponent
                 self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN
                 self.out_of.guard.eq(in_z.m[0]),
                 self.out_of.m0.eq(in_z.m[1]),
                 self.out_of.round_bit.eq(in_of.guard),
                 self.out_of.sticky.eq(in_of.sticky | in_of.round_bit)
-            ]
+                ]
+            else:
+                m.d.comb += [
+                    ediff_n126.eq(in_z.N126 - in_z.e),
+                ]
 
         return m
 
 
         return m