From 52513ce2ab03235d0d4c447253ca58fa63e79611 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sun, 28 Jul 2019 21:11:47 +0100 Subject: [PATCH] split out int2float fcvt to separate module --- src/ieee754/fcvt/int2float.py | 164 ++++++++++++++++++++++++++++++++++ src/ieee754/fcvt/pipeline.py | 136 +--------------------------- 2 files changed, 168 insertions(+), 132 deletions(-) create mode 100644 src/ieee754/fcvt/int2float.py diff --git a/src/ieee754/fcvt/int2float.py b/src/ieee754/fcvt/int2float.py new file mode 100644 index 00000000..78b51b34 --- /dev/null +++ b/src/ieee754/fcvt/int2float.py @@ -0,0 +1,164 @@ +# IEEE Floating Point Conversion +# Copyright (C) 2019 Luke Kenneth Casson Leighton + +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 FPCVTIntToFloatMod(Elaboratable): + """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp. + + self.ctx.i.op & 0x1 == 0x1 : SIGNED int + self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int + """ + 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.intconvert = self + m.d.comb += self.i.eq(i) + + def process(self, i): + return self.o + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + + #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) + print("a1", self.in_pspec.width) + z1 = self.o.z + 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 + ms = mz - me + print("ms-me", ms, me, mz) + + # 3 extra bits for guard/round/sticky + msb = FPMSBHigh(me+3, z1.e_width) + m.submodules.norm_msb = msb + + # signed or unsigned, use operator context + signed = Signal(reset_less=True) + comb += signed.eq(self.i.ctx.op[0]) + + # copy of mantissa (one less bit if signed) + mantissa = Signal(me, 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) + + # set input from full INT + comb += msb.m_in.eq(Cat(0, 0, 0, mantissa)) # g/r/s + input + comb += msb.e_in.eq(me) # exp = int width + + # to do with FP16... not yet resolved why + alternative = ms < 0 + + if alternative: + comb += z1.e.eq(msb.e_out-1) + mmsb = msb.m_out[-mz-1:] + if mz == 16: + # larger int to smaller FP (uint32/64 -> fp16 most likely) + comb += z1.m[ms-1:].eq(mmsb) + else: # 32? XXX weirdness... + comb += z1.m.eq(mmsb) + else: + # 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 + + # note: post-normalisation actually appears to be capable of + # detecting overflow to infinity (FPPackMod). so it's ok to + # drop the bits into the mantissa (with a fixed exponent), + # do some rounding (which might result in exceeding the + # range of the target FP by re-increasing the exponent), + # and basically *not* have to do any kind of range-checking + # here: just set up guard/round/sticky, drop the INT into the + # mantissa, and away we go. XXX TODO: see if FPNormaliseMod + # is even necessary. it probably isn't + + # initialise rounding (but only activate if needed) + if alternative: + # larger int to smaller FP (uint32/64 -> fp16 most likely) + comb += self.o.of.guard.eq(msb.m_out[-mz-2]) + comb += self.o.of.round_bit.eq(msb.m_out[-mz-3]) + comb += self.o.of.sticky.eq(msb.m_out[:-mz-3].bool()) + comb += self.o.of.m0.eq(msb.m_out[-mz-1]) + else: + # smaller int to larger FP + comb += self.o.of.guard.eq(msb.m_out[2]) + comb += self.o.of.round_bit.eq(msb.m_out[1]) + 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) + + # 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 + + # copy the context (muxid, operator) + comb += self.o.oz.eq(self.o.z.v) + comb += self.o.ctx.eq(self.i.ctx) + + return m + + diff --git a/src/ieee754/fcvt/pipeline.py b/src/ieee754/fcvt/pipeline.py index ac2f726e..8b17e7a2 100644 --- a/src/ieee754/fcvt/pipeline.py +++ b/src/ieee754/fcvt/pipeline.py @@ -1,6 +1,6 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 +# IEEE754 Floating Point Conversion +# Copyright (C) 2019 Luke Kenneth Casson Leighton + import sys import functools @@ -34,6 +34,7 @@ from ieee754.fpcommon.fpbase import FPState from ieee754.pipeline import PipelineSpec from ieee754.fcvt.float2int import FPCVTFloatToIntMod +from ieee754.fcvt.int2float import FPCVTIntToFloatMod class SignedOp: @@ -44,135 +45,6 @@ class SignedOp: return [self.signed.eq(i)] -class FPCVTIntToFloatMod(Elaboratable): - """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp. - - self.ctx.i.op & 0x1 == 0x1 : SIGNED int - self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int - """ - 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.intconvert = self - comb += self.i.eq(i) - - def process(self, i): - return self.o - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - - #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) - print("a1", self.in_pspec.width) - z1 = self.o.z - 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 - ms = mz - me - print("ms-me", ms, me, mz) - - # 3 extra bits for guard/round/sticky - msb = FPMSBHigh(me+3, z1.e_width) - m.submodules.norm_msb = msb - - # signed or unsigned, use operator context - signed = Signal(reset_less=True) - comb += signed.eq(self.i.ctx.op[0]) - - # copy of mantissa (one less bit if signed) - mantissa = Signal(me, 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) - - # set input from full INT - comb += msb.m_in.eq(Cat(0, 0, 0, mantissa)) # g/r/s + input - comb += msb.e_in.eq(me) # exp = int width - - # to do with FP16... not yet resolved why - alternative = ms < 0 - - if alternative: - comb += z1.e.eq(msb.e_out-1) - mmsb = msb.m_out[-mz-1:] - if mz == 16: - # larger int to smaller FP (uint32/64 -> fp16 most likely) - comb += z1.m[ms-1:].eq(mmsb) - else: # 32? XXX weirdness... - comb += z1.m.eq(mmsb) - else: - # 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 - - # note: post-normalisation actually appears to be capable of - # detecting overflow to infinity (FPPackMod). so it's ok to - # drop the bits into the mantissa (with a fixed exponent), - # do some rounding (which might result in exceeding the - # range of the target FP by re-increasing the exponent), - # and basically *not* have to do any kind of range-checking - # here: just set up guard/round/sticky, drop the INT into the - # mantissa, and away we go. XXX TODO: see if FPNormaliseMod - # is even necessary. it probably isn't - - # initialise rounding (but only activate if needed) - if alternative: - # larger int to smaller FP (uint32/64 -> fp16 most likely) - comb += self.o.of.guard.eq(msb.m_out[-mz-2]) - comb += self.o.of.round_bit.eq(msb.m_out[-mz-3]) - comb += self.o.of.sticky.eq(msb.m_out[:-mz-3].bool()) - comb += self.o.of.m0.eq(msb.m_out[-mz-1]) - else: - # smaller int to larger FP - comb += self.o.of.guard.eq(msb.m_out[2]) - comb += self.o.of.round_bit.eq(msb.m_out[1]) - 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) - - # 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 - - # copy the context (muxid, operator) - comb += self.o.oz.eq(self.o.z.v) - comb += self.o.ctx.eq(self.i.ctx) - - return m - - class FPCVTUpConvertMod(Elaboratable): """ FP up-conversion (lower to higher bitwidth) """ -- 2.30.2