From: Michael Nolan Date: Sun, 26 Jan 2020 20:37:16 +0000 (-0500) Subject: Add basic test for fsignj pipe X-Git-Tag: ls180-24jan2020~339 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=089a005078774bbf6dd83c85ef2c5a3cde1c7775;p=ieee754fpu.git Add basic test for fsignj pipe This adds a bare bones unit test for the fsignj module, and fixes the errors generated when trying to elaborate the module in the unit test --- diff --git a/src/ieee754/fsgnj/fsgnj.py b/src/ieee754/fsgnj/fsgnj.py index fa21d39f..4bb03734 100644 --- a/src/ieee754/fsgnj/fsgnj.py +++ b/src/ieee754/fsgnj/fsgnj.py @@ -7,7 +7,7 @@ from nmigen.cli import main, verilog from nmutil.pipemodbase import PipeModBase from ieee754.fpcommon.basedata import FPBaseData from ieee754.fpcommon.postcalc import FPPostCalcData -from ieee754.fpcommon.msbhigh import FPMSBHigh +from ieee754.fpcommon.packdata import FPPackData from ieee754.fpcommon.fpbase import FPNumBaseRecord @@ -27,7 +27,7 @@ class FSGNJPipeMod(PipeModBase): return FPBaseData(self.in_pspec) def ospec(self): - return FPBaseData(self.in_pspec) + return FPPackData(self.in_pspec) def elaborate(self, platform): m = Module() @@ -38,95 +38,8 @@ class FSGNJPipeMod(PipeModBase): # decode: XXX really should move to separate stage z1 = self.o.z a = self.i.a - print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end) - - me = self.in_pspec.width - mz = z1.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]) - - # mantissa (one less bit if signed), and sign - mantissa = Signal(me, reset_less=True) - sign = Signal(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. - comb += sign.eq(Mux(signed, a[-1], 0)) # sign in top bit of a - comb += mantissa.eq(Mux(signed, - Mux(sign, -a, # invert input if sign -ve - a), # leave as-is - a)) # unsigned, use full a - - # 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:]) - - # XXX there is some weirdness involving the sign looping back - # see graphviz output - # http://bugs.libre-riscv.org/show_bug.cgi?id=135 - comb += z1.s.eq(sign) - comb += z1.create(sign, 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]) - - a_nonzero = Signal(reset_less=True) - comb += a_nonzero.eq(~a.bool()) - - # prepare zero - z_zero = FPNumBaseRecord(z1.width, False, name="z_zero") - comb += z_zero.zero(0) - - # special cases? - comb += self.o.out_do_z.eq(a_nonzero) - - # detect zero - comb += self.o.oz.eq(Mux(a_nonzero, z1.v, z_zero.v)) + + comb += z1.eq(a) # copy the context (muxid, operator) comb += self.o.ctx.eq(self.i.ctx) diff --git a/src/ieee754/fsgnj/pipeline.py b/src/ieee754/fsgnj/pipeline.py index a6e717e8..f9e803fe 100644 --- a/src/ieee754/fsgnj/pipeline.py +++ b/src/ieee754/fsgnj/pipeline.py @@ -16,15 +16,6 @@ from ieee754.pipeline import PipelineSpec, DynamicPipe from ieee754.fsgnj.fsgnj import FSGNJPipeMod -# not used, yet -# from nmigen import Signal -class SignedOp: - def __init__(self): - self.signed = Signal(reset_less=True) - - def eq(self, i): - return [self.signed.eq(i)] - class FSGNJStage(DynamicPipe): """ FPConversion and De-norm diff --git a/src/ieee754/fsgnj/test/test_fsgnj_pipe.py b/src/ieee754/fsgnj/test/test_fsgnj_pipe.py new file mode 100644 index 00000000..d75d30d4 --- /dev/null +++ b/src/ieee754/fsgnj/test/test_fsgnj_pipe.py @@ -0,0 +1,27 @@ +""" test of FPCVTMuxInOut +""" + +from ieee754.fsgnj.pipeline import (FSGNJMuxInOut) +from ieee754.fpcommon.test.fpmux import runfp + +import sfpy +from sfpy import Float64, Float32, Float16 + + + +###################### +# signed int to fp +###################### + +def fsgnj_abs(x): + return x.__abs__() + +def test_fsgnj_abs(): + dut = FSGNJMuxInOut(32, 4) + runfp(dut, 32, "test_fsgnj_abs", Float32, fsgnj_abs, + True, n_vals=10, opcode=0x0) + + +if __name__ == '__main__': + for i in range(200): + test_fsgnj_abs()