From 918358a4ef51efd3f458f4c9aec45f827020130f Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 31 Jul 2019 12:39:44 +0100 Subject: [PATCH] cleanup and add a new common class, FPModBase --- src/ieee754/fpadd/add0.py | 19 ++----- src/ieee754/fpadd/add1.py | 16 ++---- src/ieee754/fpadd/align.py | 19 ++----- src/ieee754/fpadd/specialcases.py | 86 +++++++++++++------------------ src/ieee754/fpcommon/modbase.py | 20 +++++++ 5 files changed, 67 insertions(+), 93 deletions(-) create mode 100644 src/ieee754/fpcommon/modbase.py diff --git a/src/ieee754/fpadd/add0.py b/src/ieee754/fpadd/add0.py index 6ad76c3d..0c1820e8 100644 --- a/src/ieee754/fpadd/add0.py +++ b/src/ieee754/fpadd/add0.py @@ -4,9 +4,11 @@ Copyright (C) 2019 Luke Kenneth Casson Leighton """ -from nmigen import Module, Signal, Cat, Elaboratable +from nmigen import Module, Signal, Cat from nmigen.cli import main, verilog +from ieee754.fpcommon.modbase import FPModBase + from ieee754.fpcommon.fpbase import FPNumBase, FPNumBaseRecord from ieee754.fpcommon.denorm import FPSCData from ieee754.fpcommon.getop import FPPipeContext @@ -28,12 +30,10 @@ class FPAddStage0Data: self.tot.eq(i.tot), self.ctx.eq(i.ctx)] -class FPAddStage0Mod(Elaboratable): +class FPAddStage0Mod(FPModBase): def __init__(self, pspec): - self.pspec = pspec - self.i = self.ispec() - self.o = self.ospec() + super().__init__(pspec, "add0") def ispec(self): return FPSCData(self.pspec, True) @@ -41,15 +41,6 @@ class FPAddStage0Mod(Elaboratable): def ospec(self): return FPAddStage0Data(self.pspec) - def process(self, i): - return self.o - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.add0 = self - m.d.comb += self.i.eq(i) - def elaborate(self, platform): m = Module() comb = m.d.comb diff --git a/src/ieee754/fpadd/add1.py b/src/ieee754/fpadd/add1.py index 15ca3c5e..6b51e1e2 100644 --- a/src/ieee754/fpadd/add1.py +++ b/src/ieee754/fpadd/add1.py @@ -8,19 +8,18 @@ from nmigen import Module, Signal, Elaboratable from nmigen.cli import main, verilog from math import log +from ieee754.fpcommon.modbase import FPModBase from ieee754.fpcommon.postcalc import FPAddStage1Data from ieee754.fpadd.add0 import FPAddStage0Data -class FPAddStage1Mod(Elaboratable): +class FPAddStage1Mod(FPModBase): """ Second stage of add: preparation for normalisation. detects when tot sum is too big (tot[27] is kinda a carry bit) """ def __init__(self, pspec): - self.pspec = pspec - self.i = self.ispec() - self.o = self.ospec() + super().__init__(pspec, "add1") def ispec(self): return FPAddStage0Data(self.pspec) @@ -28,15 +27,6 @@ class FPAddStage1Mod(Elaboratable): def ospec(self): return FPAddStage1Data(self.pspec) - def process(self, i): - return self.o - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.add1 = self - m.d.comb += self.i.eq(i) - def elaborate(self, platform): m = Module() comb = m.d.comb diff --git a/src/ieee754/fpadd/align.py b/src/ieee754/fpadd/align.py index c8405af1..bd1b4c06 100644 --- a/src/ieee754/fpadd/align.py +++ b/src/ieee754/fpadd/align.py @@ -2,10 +2,10 @@ # Copyright (C) Jonathan P Dawson 2013 # 2013-12-12 -from nmigen import Module, Signal, Elaboratable +from nmigen import Module, Signal from nmigen.cli import main, verilog -from ieee754.fpcommon.fpbase import FPNumOut, FPNumIn, FPNumBase +from ieee754.fpcommon.modbase import FPModBase from ieee754.fpcommon.fpbase import FPNumBaseRecord from ieee754.fpcommon.fpbase import MultiShiftRMerge from ieee754.fpcommon.denorm import FPSCData @@ -71,12 +71,10 @@ class FPAddAlignMultiMod: return m -class FPAddAlignSingleMod(Elaboratable): +class FPAddAlignSingleMod(FPModBase): def __init__(self, pspec): - self.pspec = pspec - self.i = self.ispec() - self.o = self.ospec() + super().__init__(pspec, "align") def ispec(self): return FPSCData(self.pspec, True) @@ -84,15 +82,6 @@ class FPAddAlignSingleMod(Elaboratable): def ospec(self): return FPNumIn2Ops(self.pspec) - def process(self, i): - return self.o - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.align = self - m.d.comb += self.i.eq(i) - def elaborate(self, platform): """ Aligns A against B or B against A, depending on which has the greater exponent. This is done in a *single* cycle using diff --git a/src/ieee754/fpadd/specialcases.py b/src/ieee754/fpadd/specialcases.py index 33b1811a..13d4c182 100644 --- a/src/ieee754/fpadd/specialcases.py +++ b/src/ieee754/fpadd/specialcases.py @@ -2,10 +2,11 @@ # Copyright (C) Jonathan P Dawson 2013 # 2013-12-12 -from nmigen import Module, Signal, Cat, Const, Elaboratable +from nmigen import Module, Signal, Cat, Const from nmigen.cli import main, verilog from math import log +from ieee754.fpcommon.modbase import FPModBase from ieee754.fpcommon.fpbase import FPNumDecode from nmutil.singlepipe import StageChain from ieee754.pipeline import DynamicPipe @@ -15,16 +16,14 @@ from ieee754.fpcommon.getop import FPADDBaseData from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod) -class FPAddSpecialCasesMod(Elaboratable): +class FPAddSpecialCasesMod(FPModBase): """ 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, pspec): - self.pspec = pspec - self.i = self.ispec() - self.o = self.ospec() + super().__init__(pspec, "specialcases") def ispec(self): return FPADDBaseData(self.pspec) @@ -32,19 +31,9 @@ class FPAddSpecialCasesMod(Elaboratable): def ospec(self): return FPSCData(self.pspec, True) - 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 + comb = m.d.comb # decode: XXX really should move to separate stage width = self.pspec.width @@ -52,96 +41,92 @@ class FPAddSpecialCasesMod(Elaboratable): b1 = FPNumBaseRecord(width) 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), + comb += [a1.v.eq(self.i.a), b1.v.eq(self.i.b), self.o.a.eq(a1), self.o.b.eq(b1) ] + # temporaries used below 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) - abz = Signal(reset_less=True) - m.d.comb += abz.eq(a1.is_zero & b1.is_zero) - abnan = Signal(reset_less=True) - m.d.comb += abnan.eq(a1.is_nan | b1.is_nan) - bexp128s = Signal(reset_less=True) - m.d.comb += bexp128s.eq(b1.exp_128 & s_nomatch) + + comb += s_nomatch.eq(a1.s != b1.s) + comb += m_match.eq(a1.m == b1.m) + comb += e_match.eq(a1.e == b1.e) + comb += aeqmb.eq(s_nomatch & m_match & e_match) + comb += abz.eq(a1.is_zero & b1.is_zero) + comb += abnan.eq(a1.is_nan | b1.is_nan) + comb += bexp128s.eq(b1.exp_128 & s_nomatch) # default bypass - m.d.comb += self.o.out_do_z.eq(1) + comb += self.o.out_do_z.eq(1) # if a is NaN or b is NaN return NaN with m.If(abnan): - m.d.comb += self.o.z.nan(0) + comb += self.o.z.nan(0) # XXX WEIRDNESS for FP16 non-canonical NaN handling # under review ## if a is zero and b is NaN return -b #with m.If(a.is_zero & (a.s==0) & b.is_nan): - # m.d.comb += self.o.out_do_z.eq(1) - # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0])) + # comb += self.o.out_do_z.eq(1) + # comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0])) ## if b is zero and a is NaN return -a #with m.Elif(b.is_zero & (b.s==0) & a.is_nan): - # m.d.comb += self.o.out_do_z.eq(1) - # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0])) + # comb += self.o.out_do_z.eq(1) + # comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0])) ## if a is -zero and b is NaN return -b #with m.Elif(a.is_zero & (a.s==1) & b.is_nan): - # m.d.comb += self.o.out_do_z.eq(1) - # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1)) + # comb += self.o.out_do_z.eq(1) + # comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1)) ## if b is -zero and a is NaN return -a #with m.Elif(b.is_zero & (b.s==1) & a.is_nan): - # m.d.comb += self.o.out_do_z.eq(1) - # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1)) + # comb += self.o.out_do_z.eq(1) + # comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1)) # if a is inf return inf (or NaN) with m.Elif(a1.is_inf): - m.d.comb += self.o.z.inf(a1.s) + comb += self.o.z.inf(a1.s) # if a is inf and signs don't match return NaN with m.If(bexp128s): - m.d.comb += self.o.z.nan(0) + comb += self.o.z.nan(0) # if b is inf return inf with m.Elif(b1.is_inf): - m.d.comb += self.o.z.inf(b1.s) + comb += self.o.z.inf(b1.s) # if a is zero and b zero return signed-a/b with m.Elif(abz): - m.d.comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1]) + comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1]) # if a is zero return b with m.Elif(a1.is_zero): - m.d.comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1]) + comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1]) # if b is zero return a with m.Elif(b1.is_zero): - m.d.comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1]) + comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1]) # if a equal to -b return zero (+ve zero) with m.Elif(aeqmb): - m.d.comb += self.o.z.zero(0) + comb += self.o.z.zero(0) # Denormalised Number checks next, so pass a/b data through with m.Else(): - m.d.comb += self.o.out_do_z.eq(0) + comb += self.o.out_do_z.eq(0) - m.d.comb += self.o.oz.eq(self.o.z.v) - m.d.comb += self.o.ctx.eq(self.i.ctx) + comb += self.o.oz.eq(self.o.z.v) + comb += self.o.ctx.eq(self.i.ctx) return m @@ -155,7 +140,6 @@ class FPAddSpecialCasesDeNorm(DynamicPipe): def __init__(self, pspec): self.pspec = pspec super().__init__(pspec) - self.out = self.ospec() def ispec(self): return FPADDBaseData(self.pspec) # SC ispec diff --git a/src/ieee754/fpcommon/modbase.py b/src/ieee754/fpcommon/modbase.py new file mode 100644 index 00000000..0daa6f63 --- /dev/null +++ b/src/ieee754/fpcommon/modbase.py @@ -0,0 +1,20 @@ +from nmigen import Elaboratable + +class FPModBase(Elaboratable): + """FPModBase: common code between nearly every pipeline module + """ + def __init__(self, pspec, modname): + self.modname = modname + self.pspec = pspec + self.i = self.ispec() + self.o = self.ospec() + + def process(self, i): + return self.o + + def setup(self, m, i): + """ links module to inputs and outputs + """ + setattr(m.submodules, self.modname, self) + m.d.comb += self.i.eq(i) + -- 2.30.2