add fpclass pipeline (1st version)
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Jul 2019 05:21:39 +0000 (06:21 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Jul 2019 05:21:39 +0000 (06:21 +0100)
src/ieee754/fclass/pipeline.py [new file with mode: 0644]
src/ieee754/fcvt/pipeline.py
src/ieee754/fpcommon/test/fpmux.py

diff --git a/src/ieee754/fclass/pipeline.py b/src/ieee754/fclass/pipeline.py
new file mode 100644 (file)
index 0000000..6b489b2
--- /dev/null
@@ -0,0 +1,183 @@
+# IEEE Floating Point Adder (Single Precision)
+# Copyright (C) Jonathan P Dawson 2013
+# 2013-12-12
+
+import sys
+import functools
+
+from nmigen import Module, Signal, Cat, Const, Mux, Elaboratable
+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 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
+
+
+class FPClassMod(Elaboratable):
+    """ obtains floating point information (zero, nan, inf etc.)
+    """
+    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()
+
+    def ispec(self):
+        return FPADDBaseData(self.in_pspec)
+
+    def ospec(self):
+        return FPPackData(self.out_pspec)
+
+    def setup(self, m, i):
+        """ links module to inputs and outputs
+        """
+        m.submodules.upconvert = self
+        m.d.comb += self.i.eq(i)
+
+    def process(self, i):
+        return self.o
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # decode incoming FP number
+        print("in_width out", self.in_pspec.width,
+              self.out_pspec.width)
+        a1 = FPNumBaseRecord(self.in_pspec.width, False)
+        print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
+        m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
+        m.d.comb += a1.v.eq(self.i.a)
+
+        # FCLASS: work out the "type" of the FP number
+
+        # Inf
+        with m.If(a1.is_inf):
+            with m.If(a1.s):
+                m.d.comb += self.o.z.eq(1<<0) # | −inf.
+            with m.Else():
+                m.d.comb += self.o.z.eq(1<<7) # | +inf.
+
+        # Zero
+        with m.Elif(a1.is_zero):
+            with m.If(a1.s):
+                m.d.comb += self.o.z.eq(1<<3) # | −0.
+            with m.Else():
+                m.d.comb += self.o.z.eq(1<<4) # | +0.
+
+        # NaN
+        with m.Elif(a1.exp_gt127): 
+            with m.If(a1.m_msbzero): # signalling NaN
+                m.d.comb += self.o.z.eq(1<<8) # | a signaling NaN.
+            with m.Else():
+                m.d.comb += self.o.z.eq(1<<9) # | a quiet NaN
+
+        # subnormal
+        with m.Elif(a1.exp_n126): 
+            with m.If(a1.s):
+                m.d.comb += self.o.z.eq(1<<2) # | a negative subnormal number.
+            with m.Else():
+                m.d.comb += self.o.z.eq(1<<5) # | a positive subnormal number.
+
+        # normal
+        with m.Elif(a1.s):
+            m.d.comb += self.o.z.eq(1<<1) # | a negative normal number.
+        with m.Else():
+            m.d.comb += self.o.z.eq(1<<6) # | a positive normal number.
+
+        m.d.comb += self.o.ctx.eq(self.i.ctx)
+
+        return m
+
+
+class FPFClassPipe(FPState, SimpleHandshake):
+    """ FPConversion and De-norm
+    """
+
+    def __init__(self, modkls, in_pspec, out_pspec):
+        FPState.__init__(self, "cvt")
+        sc = modkls(in_pspec, out_pspec)
+        SimpleHandshake.__init__(self, sc)
+        self.out = self.ospec(None)
+
+
+class FPClassBasePipe(ControlBase):
+    def __init__(self, modkls, e_extra, in_pspec, out_pspec):
+        ControlBase.__init__(self)
+        self.pipe1 = FPFClassPipe(modkls, in_pspec, out_pspec)
+        self._eqs = self.connect([self.pipe1, ])
+
+    def elaborate(self, platform):
+        m = ControlBase.elaborate(self, platform)
+        m.submodules.down = self.pipe1
+        m.d.comb += self._eqs
+        return m
+
+
+
+
+class FPClassMuxInOutBase(ReservationStations):
+    """ Reservation-Station version of FPClass pipeline.
+
+        * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
+        * 2-stage multiplier pipeline
+        * fan-out on outputs (an array of FPPackData: z,mid)
+
+        Fan-in and Fan-out are combinatorial.
+    """
+
+    def __init__(self, modkls, e_extra, in_width, out_width,
+                       num_rows, op_wid=0, pkls=FPClassBasePipe):
+        self.op_wid = op_wid
+        self.id_wid = num_bits(in_width)
+        self.out_id_wid = num_bits(out_width)
+
+        self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
+        self.out_pspec = PipelineSpec(out_width, self.out_id_wid, op_wid)
+
+        self.alu = pkls(modkls, e_extra, self.in_pspec, self.out_pspec)
+        ReservationStations.__init__(self, num_rows)
+
+    def i_specfn(self):
+        return FPADDBaseData(self.in_pspec)
+
+    def o_specfn(self):
+        return FPPackData(self.out_pspec)
+
+
+class FPClassMuxInOut(FPClassMuxInOutBase):
+    """ Reservation-Station version of FPClass pipeline.
+
+        * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
+        * 2-stage multiplier pipeline
+        * fan-out on outputs (an array of FPPackData: z,mid)
+
+        Fan-in and Fan-out are combinatorial.
+    """
+
+    def __init__(self, in_width, out_width, num_rows, op_wid=0):
+        FPClassMuxInOutBase.__init__(self, FPClassMod, False,
+                                         in_width, out_width,
+                                         num_rows, op_wid,
+                                         pkls=FPClassBasePipe)
+
index 05ad924150666efc3b090ff05f071f23f4d5276b..f4c70d78e6d52e1bd70fc9f6d7b3700b0e34d43e 100644 (file)
@@ -116,14 +116,14 @@ class FPCVTFloatToIntMod(Elaboratable):
             with m.If(a1.s): # negative FP, so negative overrun
                 m.d.comb += self.o.z.eq(-(1<<(mz-1)))
             with m.Else(): # positive FP, so positive overrun
-                m.d.comb += self.o.z.eq((1<<(mz-1)-1))
+                m.d.comb += self.o.z.eq((1<<(mz-1))-1)
 
         # unsigned, exp too big
         with m.Elif((~signed) & (a1.e > Const(mz, espec))):
             with m.If(a1.s): # negative FP, so negative overrun (zero)
                 m.d.comb += self.o.z.eq(0)
             with m.Else(): # positive FP, so positive overrun (max INT)
-                m.d.comb += self.o.z.eq((1<<(mz)-1))
+                m.d.comb += self.o.z.eq((1<<(mz))-1)
 
         # ok exp should be in range: shift and round it
         with m.Else():
@@ -146,7 +146,11 @@ class FPCVTFloatToIntMod(Elaboratable):
             m.d.comb += of.round_bit.eq(msr.m_out[1])
             m.d.comb += of.sticky.eq(msr.m_out[0])
             m.d.comb += of.m0.eq(msr.m_out[3])
-            m.d.comb += self.o.z.eq(msr.m_out[3:])
+
+            with m.If(of.roundz):
+                m.d.comb += self.o.z.eq(msr.m_out[3:]+1)
+            with m.Else():
+                m.d.comb += self.o.z.eq(msr.m_out[3:])
 
         # copy the context (muxid, operator)
         #m.d.comb += self.o.oz.eq(self.o.z.v)
index ef4fbdd08a7af394840e7ecdc1de5d3274cba62f..86f808e1de34a82e669573dc0fa7f43e0b298275 100644 (file)
@@ -184,7 +184,8 @@ def create_random(num_rows, width, single_op=False, n_vals=10):
 
                 # f2int
                 #op1 = 0x4dc0
-                op1 = 0x3b81
+                #op1 = 0x3b81
+                op1 = 0xfcb6
 
                 vals.append((op1,))
             else: