From 35e8a7871e6fb0a7cc8b599eb3f77228a80e3348 Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Tue, 28 Jan 2020 11:32:40 -0500 Subject: [PATCH] Add FPMAX module --- src/ieee754/fpmax/fpmax.py | 68 +++++++++++++++++++++++ src/ieee754/fpmax/pipeline.py | 56 +++++++++++++++++++ src/ieee754/fpmax/test/test_fpmax_pipe.py | 32 +++++++++++ 3 files changed, 156 insertions(+) create mode 100644 src/ieee754/fpmax/fpmax.py create mode 100644 src/ieee754/fpmax/pipeline.py create mode 100644 src/ieee754/fpmax/test/test_fpmax_pipe.py diff --git a/src/ieee754/fpmax/fpmax.py b/src/ieee754/fpmax/fpmax.py new file mode 100644 index 00000000..1987d8ee --- /dev/null +++ b/src/ieee754/fpmax/fpmax.py @@ -0,0 +1,68 @@ +# IEEE Floating Point Conversion, FSGNJ +# Copyright (C) 2019 Luke Kenneth Casson Leighton +# Copyright (C) 2020 Michael Nolan + + +from nmigen import Module, Signal, Cat, Mux + +from nmutil.pipemodbase import PipeModBase +from ieee754.fpcommon.basedata import FPBaseData +from ieee754.fpcommon.packdata import FPPackData +from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord + + +class FPMAXPipeMod(PipeModBase): + """ FP Sign injection - replaces operand A's sign bit with one + generated from operand B + + self.ctx.i.op & 0x3 == 0x0 : Copy sign bit from operand B + self.ctx.i.op & 0x3 == 0x1 : Copy inverted sign bit from operand B + self.ctx.i.op & 0x3 == 0x2 : Sign bit is A's sign XOR B's sign + """ + def __init__(self, in_pspec): + self.in_pspec = in_pspec + super().__init__(in_pspec, "fpmax") + + def ispec(self): + return FPBaseData(self.in_pspec) + + def ospec(self): + return FPPackData(self.in_pspec) + + def elaborate(self, platform): + m = Module() + + # useful clarity variables + comb = m.d.comb + width = self.pspec.width + opcode = self.i.ctx.op + z1 = self.o.z + + a1 = FPNumBaseRecord(width, False) + b1 = FPNumBaseRecord(width, False) + m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1) + m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1) + + m.d.comb += [a1.v.eq(self.i.a), + b1.v.eq(self.i.b)] + + has_nan = Signal() + comb += has_nan.eq(a1.is_nan | b1.is_nan) + with m.If(has_nan): + comb += z1.eq(Mux(a1.is_nan, self.i.b, self.i.a)) + with m.Else(): + with m.If(a1.s != b1.s): + + comb += z1.eq(Mux(a1.s, self.i.b, self.i.a)) + with m.Else(): + gt = Signal() + sign = Signal() + comb += sign.eq(a1.s) + comb += gt.eq(a1.v > b1.v) + comb += z1.eq(Mux(gt ^ sign, self.i.a, self.i.b)) + + + # copy the context (muxid, operator) + comb += self.o.ctx.eq(self.i.ctx) + + return m diff --git a/src/ieee754/fpmax/pipeline.py b/src/ieee754/fpmax/pipeline.py new file mode 100644 index 00000000..aca2d087 --- /dev/null +++ b/src/ieee754/fpmax/pipeline.py @@ -0,0 +1,56 @@ +"""IEEE754 Floating Point Conversion + +Copyright (C) 2019 Luke Kenneth Casson Leighton +Copyright (C) 2020 Michael Nolan + +""" + +from nmutil.singlepipe import ControlBase +from nmutil.concurrentunit import ReservationStations, num_bits + +from ieee754.pipeline import PipelineSpec, DynamicPipe + +from ieee754.fpmax.fpmax import FPMAXPipeMod + + +class FPMAXStage(DynamicPipe): + """ FPConversion and De-norm + """ + + def __init__(self, in_pspec): + stage = FPMAXPipeMod(in_pspec) + in_pspec.stage = stage + super().__init__(in_pspec) + + +class FPMAXBasePipe(ControlBase): + def __init__(self, pspec): + ControlBase.__init__(self) + self.pipe1 = FPMAXStage(pspec) + self._eqs = self.connect([self.pipe1, ]) + + def elaborate(self, platform): + m = ControlBase.elaborate(self, platform) + m.submodules.fpmax = self.pipe1 + m.d.comb += self._eqs + return m + + +class FPMAXMuxInOut(ReservationStations): + """ Reservation-Station version of FPCVT pipeline. + + * fan-in on inputs (an array of FPBaseData: a,b,mid) + * converter pipeline (alu) + * fan-out on outputs (an array of FPPackData: z,mid) + + Fan-in and Fan-out are combinatorial. + """ + + def __init__(self, in_width, num_rows, op_wid=1): + self.op_wid = op_wid + self.id_wid = num_bits(num_rows) + + self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid) + + self.alu = FPMAXBasePipe(self.in_pspec) + ReservationStations.__init__(self, num_rows) diff --git a/src/ieee754/fpmax/test/test_fpmax_pipe.py b/src/ieee754/fpmax/test/test_fpmax_pipe.py new file mode 100644 index 00000000..65823f3f --- /dev/null +++ b/src/ieee754/fpmax/test/test_fpmax_pipe.py @@ -0,0 +1,32 @@ +""" test of FPCVTMuxInOut +""" + +from ieee754.fpmax.pipeline import (FPMAXMuxInOut) +from ieee754.fpcommon.test.fpmux import runfp + +from sfpy import Float16, Float32, Float64 +import math + +def fpmax_f32_max(a, b): + + if math.isnan(a) or math.isnan(b): + if math.isnan(a) and math.isnan(b): + return Float32(float('nan')) + else: + return b if math.isnan(a) else a + + if a > b: + return a + else: + return b + + +def test_fpmax_f32_max(): + dut = FPMAXMuxInOut(32, 4) + runfp(dut, 32, "test_fpmax_f32_max", Float32, fpmax_f32_max, + n_vals=100, opcode=0x0) + + +if __name__ == '__main__': + for i in range(50): + test_fpmax_f32_max() -- 2.30.2