From: Luke Kenneth Casson Leighton Date: Fri, 3 May 2019 02:06:01 +0000 (+0100) Subject: add mul pipeline version of specialcases X-Git-Tag: ls180-24jan2020~1052 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=da22010ce8433e32f65b53de9388fb0f67a98c64;p=ieee754fpu.git add mul pipeline version of specialcases --- diff --git a/src/ieee754/fpmul/specialcases.py b/src/ieee754/fpmul/specialcases.py new file mode 100644 index 00000000..fec43fab --- /dev/null +++ b/src/ieee754/fpmul/specialcases.py @@ -0,0 +1,181 @@ +# IEEE Floating Point Multiplier + +from nmigen import Module, Signal, Cat, Const +from nmigen.cli import main, verilog +from math import log + +from ieee754.fpcommon.fpbase import FPNumDecode +from nmutil.singlepipe import SimpleHandshake, StageChain + +from ieee754.fpcommon.fpbase import FPState, FPID +from ieee754.fpcommon.getop import FPADDBaseData +from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod) + + +class FPMulSpecialCasesMod: + """ special cases: NaNs, infs, zeros, denormalised + see "Special Operations" + https://steve.hollasch.net/cgindex/coding/ieeefloat.html + """ + + def __init__(self, width, id_wid): + self.width = width + self.id_wid = id_wid + self.i = self.ispec() + self.o = self.ospec() + + def ispec(self): + return FPADDBaseData(self.width, self.id_wid) + + def ospec(self): + return FPSCData(self.width, self.id_wid) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.specialcases = 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 + a1 = FPNumDecode(None, self.width) + b1 = FPNumDecode(None, self.width) + m.submodules.sc_decode_a = a1 + m.submodules.sc_decode_b = b1 + m.d.comb += [a1.v.eq(self.i.a), + b1.v.eq(self.i.b), + self.o.a.eq(a1), + self.o.b.eq(b1) + ] + + s_nomatch = Signal(reset_less=True) + m.d.comb += s_nomatch.eq(a1.s != b1.s) + + m_match = Signal(reset_less=True) + m.d.comb += m_match.eq(a1.m == b1.m) + + e_match = Signal(reset_less=True) + m.d.comb += e_match.eq(a1.e == b1.e) + + aeqmb = Signal(reset_less=True) + m.d.comb += aeqmb.eq(s_nomatch & m_match & e_match) + + obz = Signal(reset_less=True) + m.d.comb += obz.eq(a1.is_zero & b1.is_zero) + + sabx = Signal(reset_less=True) # sign a xor b (sabx, get it?) + m.d.comb += sabx.eq(a1.s ^ b1.s) + + # if a is NaN or b is NaN return NaN + with m.If(abnan): + m.d.comb += self.o.out_do_z.eq(1) + m.d.comb += self.o.z.nan(1) + + # if a is inf return inf (or NaN) + with m.Elif(a1.is_inf): + m.d.comb += self.o.out_do_z.eq(1) + m.d.comb += self.o.z.inf(sabx) + # b is zero return NaN + with m.If(b1.is_zero): + m.d.comb += self.o.z.nan(1) + + # if b is inf return inf (or NaN) + with m.Elif(b1.is_inf): + m.d.comb += self.o.out_do_z.eq(1) + m.d.comb += self.o.z.inf(sabx) + # a is zero return NaN + with m.If(a1.is_zero): + m.d.comb += self.o.z.nan(1) + + # if a is zero or b zero return signed-a/b + with m.Elif(obz): + m.d.comb += self.o.out_do_z.eq(1) + m.d.comb += self.o.z.zero(sabx) + + # Denormalised Number checks next, so pass a/b data through + with m.Else(): + m.d.comb += self.o.out_do_z.eq(0) + + m.d.comb += self.o.oz.eq(self.o.z.v) + m.d.comb += self.o.mid.eq(self.i.mid) + + return m + + +class FPMulSpecialCases(FPState): + """ special cases: NaNs, infs, zeros, denormalised + NOTE: some of these are unique to add. see "Special Operations" + https://steve.hollasch.net/cgindex/coding/ieeefloat.html + """ + + def __init__(self, width, id_wid): + FPState.__init__(self, "special_cases") + self.mod = FPAddSpecialCasesMod(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.mid.eq(self.mod.o.mid) # (and mid) + + 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 FPMulSpecialCasesDeNorm(FPState, SimpleHandshake): + """ special cases: NaNs, infs, zeros, denormalised + """ + + def __init__(self, width, id_wid): + FPState.__init__(self, "special_cases") + self.width = width + self.id_wid = id_wid + SimpleHandshake.__init__(self, self) # pipe is its own stage + self.out = self.ospec() + + def ispec(self): + return FPADDBaseData(self.width, self.id_wid) # SpecialCases ispec + + def ospec(self): + return FPSCData(self.width, self.id_wid) # DeNorm ospec + + def setup(self, m, i): + """ links module to inputs and outputs + """ + smod = FPMulSpecialCasesMod(self.width, self.id_wid) + dmod = FPAddDeNormMod(self.width, self.id_wid) + + chain = StageChain([smod, dmod]) + chain.setup(m, i) + + # only needed for break-out (early-out) + # self.out_do_z = smod.o.out_do_z + + self.o = dmod.o + + def process(self, i): + return self.o + + def action(self, m): + # for break-out (early-out) + #with m.If(self.out_do_z): + # m.next = "put_z" + #with m.Else(): + m.d.sync += self.out.eq(self.process(None)) + m.next = "align" + +