From 384e2c734930a3d3c4ebead972a05aea81722931 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sat, 27 Jul 2019 06:21:39 +0100 Subject: [PATCH] add fpclass pipeline (1st version) --- src/ieee754/fclass/pipeline.py | 183 +++++++++++++++++++++++++++++ src/ieee754/fcvt/pipeline.py | 10 +- src/ieee754/fpcommon/test/fpmux.py | 3 +- 3 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 src/ieee754/fclass/pipeline.py diff --git a/src/ieee754/fclass/pipeline.py b/src/ieee754/fclass/pipeline.py new file mode 100644 index 00000000..6b489b28 --- /dev/null +++ b/src/ieee754/fclass/pipeline.py @@ -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) + diff --git a/src/ieee754/fcvt/pipeline.py b/src/ieee754/fcvt/pipeline.py index 05ad9241..f4c70d78 100644 --- a/src/ieee754/fcvt/pipeline.py +++ b/src/ieee754/fcvt/pipeline.py @@ -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) diff --git a/src/ieee754/fpcommon/test/fpmux.py b/src/ieee754/fpcommon/test/fpmux.py index ef4fbdd0..86f808e1 100644 --- a/src/ieee754/fpcommon/test/fpmux.py +++ b/src/ieee754/fpcommon/test/fpmux.py @@ -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: -- 2.30.2