document weird int2float bug
[ieee754fpu.git] / src / ieee754 / fcvt / int2float.py
index 78b51b34f81b1a2fb99db8237404dcee2ca78612..fcf3e34cf3025b02995b76251d363834640b7deb 100644 (file)
@@ -1,39 +1,18 @@
 # IEEE Floating Point Conversion
 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
 
-import sys
-import functools
-
-from nmigen import Module, Signal, Cat, Const, Mux, Elaboratable
+from nmigen import Module, Signal, Cat, Mux
 from nmigen.cli import main, verilog
 
-from nmutil.singlepipe import ControlBase
-from nmutil.concurrentunit import ReservationStations, num_bits
-
-from ieee754.fpcommon.fpbase import Overflow
-from ieee754.fpcommon.getop import FPADDBaseData
-from ieee754.fpcommon.pack import FPPackData
-from ieee754.fpcommon.normtopack import FPNormToPack
-from ieee754.fpcommon.postcalc import FPAddStage1Data
+from nmutil.pipemodbase import PipeModBase
+from ieee754.fpcommon.basedata import FPBaseData
+from ieee754.fpcommon.postcalc import FPPostCalcData
 from ieee754.fpcommon.msbhigh import FPMSBHigh
-from ieee754.fpcommon.exphigh import FPEXPHigh
-
-
-from nmigen import Module, Signal, Elaboratable
-from math import log
-
-from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPNumBaseRecord
-from ieee754.fpcommon.fpbase import FPState, FPNumBase
-from ieee754.fpcommon.getop import FPPipeContext
-
-from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
-from nmutil.singlepipe import SimpleHandshake, StageChain
 
-from ieee754.fpcommon.fpbase import FPState
-from ieee754.pipeline import PipelineSpec
+from ieee754.fpcommon.fpbase import FPNumBaseRecord
 
 
-class FPCVTIntToFloatMod(Elaboratable):
+class FPCVTIntToFloatMod(PipeModBase):
     """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp.
 
         self.ctx.i.op & 0x1 == 0x1 : SIGNED int
@@ -42,23 +21,13 @@ class FPCVTIntToFloatMod(Elaboratable):
     def __init__(self, in_pspec, out_pspec):
         self.in_pspec = in_pspec
         self.out_pspec = out_pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+        super().__init__(in_pspec, "intconvert")
 
     def ispec(self):
-        return FPADDBaseData(self.in_pspec)
+        return FPBaseData(self.in_pspec)
 
     def ospec(self):
-        return FPAddStage1Data(self.out_pspec, e_extra=True)
-
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        m.submodules.intconvert = self
-        m.d.comb += self.i.eq(i)
-
-    def process(self, i):
-        return self.o
+        return FPPostCalcData(self.out_pspec, e_extra=True)
 
     def elaborate(self, platform):
         m = Module()
@@ -71,10 +40,11 @@ class FPCVTIntToFloatMod(Elaboratable):
               self.out_pspec.width)
         print("a1", self.in_pspec.width)
         z1 = self.o.z
+        a = self.i.a
         print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
 
         me = self.in_pspec.width
-        mz = self.o.z.rmw
+        mz = z1.rmw
         ms = mz - me
         print("ms-me", ms, me, mz)
 
@@ -86,20 +56,17 @@ class FPCVTIntToFloatMod(Elaboratable):
         signed = Signal(reset_less=True)
         comb += signed.eq(self.i.ctx.op[0])
 
-        # copy of mantissa (one less bit if signed)
+        # mantissa (one less bit if signed), and sign
         mantissa = Signal(me, reset_less=True)
+        sign = Signal(reset_less=True)
 
         # detect signed/unsigned.  key case: -ve numbers need inversion
         # to +ve because the FP sign says if it's -ve or not.
-        with m.If(signed):
-            comb += z1.s.eq(self.i.a[-1])      # sign in top bit of a
-            with m.If(z1.s):
-                comb += mantissa.eq(-self.i.a) # invert input if sign -ve
-            with m.Else():
-                comb += mantissa.eq(self.i.a)  # leave as-is
-        with m.Else():
-            comb += mantissa.eq(self.i.a)      # unsigned, use full a
-            comb += z1.s.eq(0)
+        comb += sign.eq(Mux(signed, a[-1], 0)) # sign in top bit of a
+        comb += mantissa.eq(Mux(signed,
+                                Mux(sign, -a,  # invert input if sign -ve
+                                           a), # leave as-is
+                                a))            # unsigned, use full a
 
         # set input from full INT
         comb += msb.m_in.eq(Cat(0, 0, 0, mantissa)) # g/r/s + input
@@ -120,7 +87,12 @@ class FPCVTIntToFloatMod(Elaboratable):
             # smaller int to larger FP
             comb += z1.e.eq(msb.e_out)
             comb += z1.m[ms:].eq(msb.m_out[3:])
-        comb += z1.create(z1.s, z1.e, z1.m) # ... here
+
+        # XXX there is some weirdness involving the sign looping back
+        # see graphviz output
+        # http://bugs.libre-riscv.org/show_bug.cgi?id=135
+        comb += z1.s.eq(sign)
+        comb += z1.create(sign, z1.e, z1.m) # ... here
 
         # note: post-normalisation actually appears to be capable of
         # detecting overflow to infinity (FPPackMod).  so it's ok to
@@ -146,17 +118,20 @@ class FPCVTIntToFloatMod(Elaboratable):
             comb += self.o.of.sticky.eq(msb.m_out[:1].bool())
             comb += self.o.of.m0.eq(msb.m_out[3])
 
-        # special cases active by default
-        comb += self.o.out_do_z.eq(1)
+        a_nonzero = Signal(reset_less=True)
+        comb += a_nonzero.eq(~a.bool())
+
+        # prepare zero
+        z_zero = FPNumBaseRecord(z1.width, False, name="z_zero")
+        comb += z_zero.zero(0)
+
+        # special cases?
+        comb += self.o.out_do_z.eq(a_nonzero)
 
         # detect zero
-        with m.If(~self.i.a.bool()):
-            comb += self.o.z.zero(0)
-        with m.Else():
-            comb += self.o.out_do_z.eq(0) # activate normalisation
+        comb += self.o.oz.eq(Mux(a_nonzero, z1.v, z_zero.v))
 
         # copy the context (muxid, operator)
-        comb += self.o.oz.eq(self.o.z.v)
         comb += self.o.ctx.eq(self.i.ctx)
 
         return m