From 5cfe0e08c1b8d57164ff6b4901743b8088bb8d74 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Mon, 15 Jul 2019 17:06:07 +0100 Subject: [PATCH] add first version of FCVT upconvert --- src/ieee754/fcvt/pipeline.py | 176 +++++++++++++++++++-- src/ieee754/fcvt/test/test_fcvt_pipe.py | 26 +-- src/ieee754/fcvt/test/test_fcvt_up_pipe.py | 31 ++++ src/ieee754/fpcommon/fpbase.py | 2 + 4 files changed, 211 insertions(+), 24 deletions(-) create mode 100644 src/ieee754/fcvt/test/test_fcvt_up_pipe.py diff --git a/src/ieee754/fcvt/pipeline.py b/src/ieee754/fcvt/pipeline.py index d3e30e40..785ab5e7 100644 --- a/src/ieee754/fcvt/pipeline.py +++ b/src/ieee754/fcvt/pipeline.py @@ -28,12 +28,87 @@ from ieee754.fpcommon.fpbase import FPState from ieee754.pipeline import PipelineSpec -class FPCVTDownConvertMod(Elaboratable): - """ special cases: NaNs, infs, zeros, denormalised - see "Special Operations" - https://steve.hollasch.net/cgindex/coding/ieeefloat.html +class FPCVTUpConvertMod(Elaboratable): + """ FP up-conversion (lower to higher bitwidth) """ + 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 FPAddStage1Data(self.out_pspec, e_extra=True) + + 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() + + #m.submodules.sc_out_z = self.o.z + + # decode: XXX really should move to separate stage + 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) + z1 = self.o.z + print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end) + + me = a1.rmw + ms = self.o.z.rmw - a1.rmw + print("ms-me", ms, me) + + # intermediaries + exp_sub_n126 = Signal((a1.e_width, True), reset_less=True) + exp_gt127 = Signal(reset_less=True) + # constants from z1, at the bit-width of a1. + N126 = Const(z1.fp.N126.value, (a1.e_width, True)) + P127 = Const(z1.fp.P127.value, (a1.e_width, True)) + m.d.comb += exp_sub_n126.eq(a1.e - N126) + m.d.comb += exp_gt127.eq(a1.e > P127) + + m.d.comb += self.o.z.s.eq(a1.s) + m.d.comb += self.o.z.e.eq(a1.e) + m.d.comb += self.o.z.m[-self.o.z.rmw-1:].eq(a1.m) + m.d.comb += self.o.z.create(a1.s, a1.e, self.o.z.m) + + # if exp == top + with m.If(a1.exp_128): + m.d.comb += self.o.z.create(a1.s, self.o.z.P128, self.o.z.m) + m.d.comb += self.o.out_do_z.eq(1) + with m.Else(): + with m.If(a1.exp_zero): + with m.If(a1.m[:a1.rmw].bool()): + m.d.comb += self.o.of.guard.eq(a1.m[a1.rmw-1]) + m.d.comb += self.o.of.round_bit.eq(a1.m[a1.rmw-2]) + m.d.comb += self.o.of.sticky.eq(1) + m.d.comb += self.o.of.m0.eq(a1.m[a1.rmw]) # bit of a1 + with m.Else(): + m.d.comb += self.o.out_do_z.eq(1) + + # copy the context (muxid, operator) + m.d.comb += self.o.oz.eq(self.o.z.v) + m.d.comb += self.o.ctx.eq(self.i.ctx) + + return m + + +class FPCVTDownConvertMod(Elaboratable): + """ FP down-conversion (higher to lower bitwidth) + """ def __init__(self, in_pspec, out_pspec): self.in_pspec = in_pspec self.out_pspec = out_pspec @@ -49,7 +124,7 @@ class FPCVTDownConvertMod(Elaboratable): def setup(self, m, i): """ links module to inputs and outputs """ - m.submodules.specialcases = self + m.submodules.downconvert = self m.d.comb += self.i.eq(i) def process(self, i): @@ -144,6 +219,31 @@ class FPCVTDownConvertMod(Elaboratable): return m +class FPCVTUpConvert(FPState): + """ Up-conversion + """ + + def __init__(self, in_width, out_width, id_wid): + FPState.__init__(self, "upconvert") + self.mod = FPCVTUpConvertMod(in_width, out_width) + self.out_z = self.mod.ospec() + self.out_do_z = Signal(reset_less=True) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + self.mod.setup(m, i, self.out_do_z) + m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output + m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context) + + def action(self, m): + self.idsync(m) + with m.If(self.out_do_z): + m.next = "put_z" + with m.Else(): + m.next = "denormalise" + + class FPCVTDownConvert(FPState): """ special cases: NaNs, infs, zeros, denormalised """ @@ -169,18 +269,45 @@ class FPCVTDownConvert(FPState): m.next = "denormalise" +class FPCVTUpConvertDeNorm(FPState, SimpleHandshake): + """ Upconvert + """ + + def __init__(self, in_pspec, out_pspec): + FPState.__init__(self, "upconvert") + sc = FPCVTUpConvertMod(in_pspec, out_pspec) + SimpleHandshake.__init__(self, sc) + self.out = self.ospec(None) + + class FPCVTDownConvertDeNorm(FPState, SimpleHandshake): - """ special cases: NaNs, infs, zeros, denormalised + """ downconvert """ def __init__(self, in_pspec, out_pspec): - FPState.__init__(self, "special_cases") + FPState.__init__(self, "downconvert") sc = FPCVTDownConvertMod(in_pspec, out_pspec) SimpleHandshake.__init__(self, sc) self.out = self.ospec(None) -class FPCVTBasePipe(ControlBase): +class FPCVTUpBasePipe(ControlBase): + def __init__(self, in_pspec, out_pspec): + ControlBase.__init__(self) + self.pipe1 = FPCVTUpConvertDeNorm(in_pspec, out_pspec) + self.pipe2 = FPNormToPack(out_pspec, e_extra=True) + + self._eqs = self.connect([self.pipe1, self.pipe2]) + + def elaborate(self, platform): + m = ControlBase.elaborate(self, platform) + m.submodules.up = self.pipe1 + m.submodules.normpack = self.pipe2 + m.d.comb += self._eqs + return m + + +class FPCVTDownBasePipe(ControlBase): def __init__(self, in_pspec, out_pspec): ControlBase.__init__(self) self.pipe1 = FPCVTDownConvertDeNorm(in_pspec, out_pspec) @@ -190,13 +317,40 @@ class FPCVTBasePipe(ControlBase): def elaborate(self, platform): m = ControlBase.elaborate(self, platform) - m.submodules.scnorm = self.pipe1 + m.submodules.down = self.pipe1 m.submodules.normpack = self.pipe2 m.d.comb += self._eqs return m -class FPCVTMuxInOut(ReservationStations): +class FPCVTUpMuxInOut(ReservationStations): + """ Reservation-Station version of FPCVT up 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): + 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 = FPCVTUpBasePipe(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 FPCVTDownMuxInOut(ReservationStations): """ Reservation-Station version of FPCVT pipeline. * fan-in on inputs (an array of FPADDBaseData: a,b,mid) @@ -214,7 +368,7 @@ class FPCVTMuxInOut(ReservationStations): 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 = FPCVTBasePipe(self.in_pspec, self.out_pspec) + self.alu = FPCVTDownBasePipe(self.in_pspec, self.out_pspec) ReservationStations.__init__(self, num_rows) def i_specfn(self): diff --git a/src/ieee754/fcvt/test/test_fcvt_pipe.py b/src/ieee754/fcvt/test/test_fcvt_pipe.py index ee5ed3a5..4041ddd6 100644 --- a/src/ieee754/fcvt/test/test_fcvt_pipe.py +++ b/src/ieee754/fcvt/test/test_fcvt_pipe.py @@ -1,7 +1,7 @@ """ test of FPCVTMuxInOut """ -from ieee754.fcvt.pipeline import (FPCVTMuxInOut,) +from ieee754.fcvt.pipeline import (FPCVTDownMuxInOut,) from ieee754.fpcommon.test.fpmux import runfp from sfpy import Float64, Float32, Float16 @@ -12,20 +12,20 @@ def fcvt_16(x): def fcvt_32(x): return Float32(x) -def test_pipe_fp32_16(): - dut = FPCVTMuxInOut(32, 16, 4) - runfp(dut, 32, "test_fcvt_pipe_fp32_16", Float32, fcvt_16, True) +def test_down_pipe_fp32_16(): + dut = FPCVTDownMuxInOut(32, 16, 4) + runfp(dut, 32, "test_fcvt_down_pipe_fp32_16", Float32, fcvt_16, True) -def test_pipe_fp64_16(): - dut = FPCVTMuxInOut(64, 16, 4) - runfp(dut, 64, "test_fcvt_pipe_fp64_16", Float64, fcvt_16, True) +def test_down_pipe_fp64_16(): + dut = FPCVTDownMuxInOut(64, 16, 4) + runfp(dut, 64, "test_fcvt_down_pipe_fp64_16", Float64, fcvt_16, True) -def test_pipe_fp64_32(): - dut = FPCVTMuxInOut(64, 32, 4) - runfp(dut, 64, "test_fcvt_pipe_fp64_32", Float64, fcvt_32, True) +def test_down_pipe_fp64_32(): + dut = FPCVTDownMuxInOut(64, 32, 4) + runfp(dut, 64, "test_fcvt_down_pipe_fp64_32", Float64, fcvt_32, True) if __name__ == '__main__': - test_pipe_fp64_16() - test_pipe_fp32_16() - test_pipe_fp64_32() + test_down_pipe_fp64_16() + test_down_pipe_fp32_16() + test_down_pipe_fp64_32() diff --git a/src/ieee754/fcvt/test/test_fcvt_up_pipe.py b/src/ieee754/fcvt/test/test_fcvt_up_pipe.py new file mode 100644 index 00000000..d0512fb8 --- /dev/null +++ b/src/ieee754/fcvt/test/test_fcvt_up_pipe.py @@ -0,0 +1,31 @@ +""" test of FPCVTMuxInOut +""" + +from ieee754.fcvt.pipeline import (FPCVTUpMuxInOut,) +from ieee754.fpcommon.test.fpmux import runfp + +from sfpy import Float64, Float32, Float16 + +def fcvt_64(x): + return Float64(x) + +def fcvt_32(x): + return Float32(x) + +def test_down_pipe_fp16_32(): + dut = FPCVTUpMuxInOut(16, 32, 4) + runfp(dut, 16, "test_fcvt_down_pipe_fp16_32", Float16, fcvt_32, True) + +def test_down_pipe_fp16_64(): + dut = FPCVTUpMuxInOut(16, 64, 4) + runfp(dut, 16, "test_fcvt_down_pipe_fp16_64", Float16, fcvt_64, True) + +def test_down_pipe_fp32_64(): + dut = FPCVTUpMuxInOut(32, 64, 4) + runfp(dut, 32, "test_fcvt_down_pipe_fp32_64", Float32, fcvt_64, True) + +if __name__ == '__main__': + test_down_pipe_fp16_64() + test_down_pipe_fp16_32() + test_down_pipe_fp32_64() + diff --git a/src/ieee754/fpcommon/fpbase.py b/src/ieee754/fpcommon/fpbase.py index b8deab02..f6923c8c 100644 --- a/src/ieee754/fpcommon/fpbase.py +++ b/src/ieee754/fpcommon/fpbase.py @@ -298,6 +298,7 @@ class FPNumBase(FPNumBaseRecord, Elaboratable): self.exp_128 = Signal(reset_less=True) self.exp_sub_n126 = Signal((e_width, True), reset_less=True) self.exp_lt_n126 = Signal(reset_less=True) + self.exp_zero = Signal(reset_less=True) self.exp_gt_n126 = Signal(reset_less=True) self.exp_gt127 = Signal(reset_less=True) self.exp_n127 = Signal(reset_less=True) @@ -316,6 +317,7 @@ class FPNumBase(FPNumBaseRecord, Elaboratable): m.d.comb += self.exp_sub_n126.eq(self.e - self.fp.N126) m.d.comb += self.exp_gt_n126.eq(self.exp_sub_n126 > 0) m.d.comb += self.exp_lt_n126.eq(self.exp_sub_n126 < 0) + m.d.comb += self.exp_zero.eq(self.e == 0) m.d.comb += self.exp_gt127.eq(self.e > self.fp.P127) m.d.comb += self.exp_n127.eq(self.e == self.fp.N127) m.d.comb += self.exp_n126.eq(self.e == self.fp.N126) -- 2.30.2