From: Luke Kenneth Casson Leighton Date: Thu, 2 May 2019 12:47:35 +0000 (+0100) Subject: move fpcommon to separate subdir X-Git-Tag: ls180-24jan2020~1086 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cdc6a64b6ec2d9bd883eea099d9fbb53296e5347;p=ieee754fpu.git move fpcommon to separate subdir --- diff --git a/src/ieee754/add/fpcommon/__init__.py b/src/ieee754/add/fpcommon/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/ieee754/add/fpcommon/corrections.py b/src/ieee754/add/fpcommon/corrections.py deleted file mode 100644 index ce9ba3cd..00000000 --- a/src/ieee754/add/fpcommon/corrections.py +++ /dev/null @@ -1,69 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Elaboratable -from nmigen.cli import main, verilog -from fpbase import FPState -from fpcommon.roundz import FPRoundData - - -class FPCorrectionsMod(Elaboratable): - - def __init__(self, width, id_wid): - self.width = width - self.id_wid = id_wid - self.i = self.ispec() - self.out_z = self.ospec() - - def ispec(self): - return FPRoundData(self.width, self.id_wid) - - def ospec(self): - return FPRoundData(self.width, self.id_wid) - - def process(self, i): - return self.out_z - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.corrections = self - m.d.comb += self.i.eq(i) - - def elaborate(self, platform): - m = Module() - m.submodules.corr_in_z = self.i.z - m.submodules.corr_out_z = self.out_z.z - m.d.comb += self.out_z.eq(self.i) # copies mid, z, out_do_z - with m.If(~self.i.out_do_z): - with m.If(self.i.z.is_denormalised): - m.d.comb += self.out_z.z.e.eq(self.i.z.N127) - return m - - -class FPCorrections(FPState): - - def __init__(self, width, id_wid): - FPState.__init__(self, "corrections") - self.mod = FPCorrectionsMod(width) - self.out_z = self.ospec() - - def ispec(self): - return self.mod.ispec() - - def ospec(self): - return self.mod.ospec() - - def setup(self, m, in_z): - """ links module to inputs and outputs - """ - self.mod.setup(m, in_z) - - m.d.sync += self.out_z.eq(self.mod.out_z) - m.d.sync += self.out_z.mid.eq(self.mod.o.mid) - - def action(self, m): - m.next = "pack" - - diff --git a/src/ieee754/add/fpcommon/denorm.py b/src/ieee754/add/fpcommon/denorm.py deleted file mode 100644 index 9fbbc976..00000000 --- a/src/ieee754/add/fpcommon/denorm.py +++ /dev/null @@ -1,108 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal -from nmigen.cli import main, verilog -from math import log - -from fpbase import FPNumIn, FPNumOut, FPNumBase -from fpbase import FPState - - -class FPSCData: - - def __init__(self, width, id_wid): - self.a = FPNumBase(width, True) - self.b = FPNumBase(width, True) - self.z = FPNumOut(width, False) - self.oz = Signal(width, reset_less=True) - self.out_do_z = Signal(reset_less=True) - self.mid = Signal(id_wid, reset_less=True) - - def __iter__(self): - yield from self.a - yield from self.b - yield from self.z - yield self.oz - yield self.out_do_z - yield self.mid - - def eq(self, i): - return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), - self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] - - -class FPAddDeNormMod(FPState): - - 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 FPSCData(self.width, self.id_wid) - - def ospec(self): - return FPSCData(self.width, self.id_wid) - - def process(self, i): - return self.o - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.denormalise = self - m.d.comb += self.i.eq(i) - - def elaborate(self, platform): - m = Module() - m.submodules.denorm_in_a = self.i.a - m.submodules.denorm_in_b = self.i.b - m.submodules.denorm_out_a = self.o.a - m.submodules.denorm_out_b = self.o.b - - with m.If(~self.i.out_do_z): - # XXX hmmm, don't like repeating identical code - m.d.comb += self.o.a.eq(self.i.a) - with m.If(self.i.a.exp_n127): - m.d.comb += self.o.a.e.eq(self.i.a.N126) # limit a exponent - with m.Else(): - m.d.comb += self.o.a.m[-1].eq(1) # set top mantissa bit - - m.d.comb += self.o.b.eq(self.i.b) - with m.If(self.i.b.exp_n127): - m.d.comb += self.o.b.e.eq(self.i.b.N126) # limit a exponent - with m.Else(): - m.d.comb += self.o.b.m[-1].eq(1) # set top mantissa bit - - m.d.comb += self.o.mid.eq(self.i.mid) - m.d.comb += self.o.z.eq(self.i.z) - m.d.comb += self.o.out_do_z.eq(self.i.out_do_z) - m.d.comb += self.o.oz.eq(self.i.oz) - - return m - - -class FPAddDeNorm(FPState): - - def __init__(self, width, id_wid): - FPState.__init__(self, "denormalise") - self.mod = FPAddDeNormMod(width) - self.out_a = FPNumBase(width) - self.out_b = FPNumBase(width) - - def setup(self, m, i): - """ links module to inputs and outputs - """ - self.mod.setup(m, i) - - m.d.sync += self.out_a.eq(self.mod.out_a) - m.d.sync += self.out_b.eq(self.mod.out_b) - - def action(self, m): - # Denormalised Number checks - m.next = "align" - - diff --git a/src/ieee754/add/fpcommon/getop.py b/src/ieee754/add/fpcommon/getop.py deleted file mode 100644 index 1988997a..00000000 --- a/src/ieee754/add/fpcommon/getop.py +++ /dev/null @@ -1,174 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal, Cat, Mux, Array, Const, Elaboratable -from nmigen.lib.coding import PriorityEncoder -from nmigen.cli import main, verilog -from math import log - -from fpbase import FPNumIn, FPNumOut, FPOpIn, Overflow, FPBase, FPNumBase -from fpbase import MultiShiftRMerge, Trigger -from singlepipe import (ControlBase, StageChain, SimpleHandshake, - PassThroughStage, PrevControl) -from multipipe import CombMuxOutPipe -from multipipe import PriorityCombMuxInPipe - -from fpbase import FPState -import nmoperator - - -class FPGetOpMod(Elaboratable): - def __init__(self, width): - self.in_op = FPOpIn(width) - self.in_op.data_i = Signal(width) - self.out_op = Signal(width) - self.out_decode = Signal(reset_less=True) - - def elaborate(self, platform): - m = Module() - m.d.comb += self.out_decode.eq((self.in_op.ready_o) & \ - (self.in_op.valid_i_test)) - m.submodules.get_op_in = self.in_op - #m.submodules.get_op_out = self.out_op - with m.If(self.out_decode): - m.d.comb += [ - self.out_op.eq(self.in_op.v), - ] - return m - - -class FPGetOp(FPState): - """ gets operand - """ - - def __init__(self, in_state, out_state, in_op, width): - FPState.__init__(self, in_state) - self.out_state = out_state - self.mod = FPGetOpMod(width) - self.in_op = in_op - self.out_op = Signal(width) - self.out_decode = Signal(reset_less=True) - - def setup(self, m, in_op): - """ links module to inputs and outputs - """ - setattr(m.submodules, self.state_from, self.mod) - m.d.comb += nmoperator.eq(self.mod.in_op, in_op) - m.d.comb += self.out_decode.eq(self.mod.out_decode) - - def action(self, m): - with m.If(self.out_decode): - m.next = self.out_state - m.d.sync += [ - self.in_op.ready_o.eq(0), - self.out_op.eq(self.mod.out_op) - ] - with m.Else(): - m.d.sync += self.in_op.ready_o.eq(1) - - -class FPNumBase2Ops: - - def __init__(self, width, id_wid, m_extra=True): - self.a = FPNumBase(width, m_extra) - self.b = FPNumBase(width, m_extra) - self.mid = Signal(id_wid, reset_less=True) - - def eq(self, i): - return [self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] - - def ports(self): - return [self.a, self.b, self.mid] - - -class FPADDBaseData: - - def __init__(self, width, id_wid): - self.width = width - self.id_wid = id_wid - self.a = Signal(width) - self.b = Signal(width) - self.mid = Signal(id_wid, reset_less=True) - - def eq(self, i): - return [self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] - - def ports(self): - return [self.a, self.b, self.mid] - - -class FPGet2OpMod(PrevControl): - def __init__(self, width, id_wid): - PrevControl.__init__(self) - self.width = width - self.id_wid = id_wid - self.data_i = self.ispec() - self.i = self.data_i - self.o = self.ospec() - - def ispec(self): - return FPADDBaseData(self.width, self.id_wid) - - def ospec(self): - return FPADDBaseData(self.width, self.id_wid) - - def process(self, i): - return self.o - - def elaborate(self, platform): - m = PrevControl.elaborate(self, platform) - with m.If(self.trigger): - m.d.comb += [ - self.o.eq(self.data_i), - ] - return m - - -class FPGet2Op(FPState): - """ gets operands - """ - - def __init__(self, in_state, out_state, width, id_wid): - FPState.__init__(self, in_state) - self.out_state = out_state - self.mod = FPGet2OpMod(width, id_wid) - self.o = self.ospec() - self.in_stb = Signal(reset_less=True) - self.out_ack = Signal(reset_less=True) - self.out_decode = Signal(reset_less=True) - - def ispec(self): - return self.mod.ispec() - - def ospec(self): - return self.mod.ospec() - - def trigger_setup(self, m, in_stb, in_ack): - """ links stb/ack - """ - m.d.comb += self.mod.valid_i.eq(in_stb) - m.d.comb += in_ack.eq(self.mod.ready_o) - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.get_ops = self.mod - m.d.comb += self.mod.i.eq(i) - m.d.comb += self.out_ack.eq(self.mod.ready_o) - m.d.comb += self.out_decode.eq(self.mod.trigger) - - def process(self, i): - return self.o - - def action(self, m): - with m.If(self.out_decode): - m.next = self.out_state - m.d.sync += [ - self.mod.ready_o.eq(0), - self.o.eq(self.mod.o), - ] - with m.Else(): - m.d.sync += self.mod.ready_o.eq(1) - - diff --git a/src/ieee754/add/fpcommon/normtopack.py b/src/ieee754/add/fpcommon/normtopack.py deleted file mode 100644 index 87d08125..00000000 --- a/src/ieee754/add/fpcommon/normtopack.py +++ /dev/null @@ -1,52 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -#from nmigen.cli import main, verilog - -from singlepipe import StageChain, SimpleHandshake - -from fpbase import FPState, FPID -from fpcommon.postcalc import FPAddStage1Data -from fpcommon.postnormalise import FPNorm1ModSingle -from fpcommon.roundz import FPRoundMod -from fpcommon.corrections import FPCorrectionsMod -from fpcommon.pack import FPPackData, FPPackMod - - -class FPNormToPack(FPState, SimpleHandshake): - - def __init__(self, width, id_wid): - FPState.__init__(self, "normalise_1") - self.id_wid = id_wid - self.width = width - SimpleHandshake.__init__(self, self) # pipeline is its own stage - - def ispec(self): - return FPAddStage1Data(self.width, self.id_wid) # Norm1ModSingle ispec - - def ospec(self): - return FPPackData(self.width, self.id_wid) # FPPackMod ospec - - def setup(self, m, i): - """ links module to inputs and outputs - """ - - # Normalisation, Rounding Corrections, Pack - in a chain - nmod = FPNorm1ModSingle(self.width, self.id_wid) - rmod = FPRoundMod(self.width, self.id_wid) - cmod = FPCorrectionsMod(self.width, self.id_wid) - pmod = FPPackMod(self.width, self.id_wid) - stages = [nmod, rmod, cmod, pmod] - chain = StageChain(stages) - chain.setup(m, i) - self.out_z = pmod.ospec() - - self.o = pmod.o - - def process(self, i): - return self.o - - def action(self, m): - m.d.sync += self.out_z.eq(self.process(None)) - m.next = "pack_put_z" diff --git a/src/ieee754/add/fpcommon/pack.py b/src/ieee754/add/fpcommon/pack.py deleted file mode 100644 index 1464883c..00000000 --- a/src/ieee754/add/fpcommon/pack.py +++ /dev/null @@ -1,84 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal, Elaboratable -from nmigen.cli import main, verilog - -from fpbase import FPNumOut -from fpbase import FPState -from fpcommon.roundz import FPRoundData -from singlepipe import Object - - -class FPPackData(Object): - - def __init__(self, width, id_wid): - Object.__init__(self) - self.z = Signal(width, reset_less=True) - self.mid = Signal(id_wid, reset_less=True) - - -class FPPackMod(Elaboratable): - - 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 FPRoundData(self.width, self.id_wid) - - def ospec(self): - return FPPackData(self.width, self.id_wid) - - def process(self, i): - return self.o - - def setup(self, m, in_z): - """ links module to inputs and outputs - """ - m.submodules.pack = self - m.d.comb += self.i.eq(in_z) - - def elaborate(self, platform): - m = Module() - z = FPNumOut(self.width, False) - m.submodules.pack_in_z = self.i.z - m.submodules.pack_out_z = z - m.d.comb += self.o.mid.eq(self.i.mid) - with m.If(~self.i.out_do_z): - with m.If(self.i.z.is_overflowed): - m.d.comb += z.inf(self.i.z.s) - with m.Else(): - m.d.comb += z.create(self.i.z.s, self.i.z.e, self.i.z.m) - with m.Else(): - m.d.comb += z.v.eq(self.i.oz) - m.d.comb += self.o.z.eq(z.v) - return m - - -class FPPack(FPState): - - def __init__(self, width, id_wid): - FPState.__init__(self, "pack") - self.mod = FPPackMod(width) - self.out_z = self.ospec() - - def ispec(self): - return self.mod.ispec() - - def ospec(self): - return self.mod.ospec() - - def setup(self, m, in_z): - """ links module to inputs and outputs - """ - self.mod.setup(m, in_z) - - m.d.sync += self.out_z.v.eq(self.mod.out_z.v) - m.d.sync += self.out_z.mid.eq(self.mod.o.mid) - - def action(self, m): - m.next = "pack_put_z" diff --git a/src/ieee754/add/fpcommon/postcalc.py b/src/ieee754/add/fpcommon/postcalc.py deleted file mode 100644 index 7111dc8a..00000000 --- a/src/ieee754/add/fpcommon/postcalc.py +++ /dev/null @@ -1,26 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Signal -from fpbase import Overflow, FPNumBase - -class FPAddStage1Data: - - def __init__(self, width, id_wid): - self.z = FPNumBase(width, False) - self.out_do_z = Signal(reset_less=True) - self.oz = Signal(width, reset_less=True) - self.of = Overflow() - self.mid = Signal(id_wid, reset_less=True) - - def __iter__(self): - yield from self.z - yield self.out_do_z - yield self.oz - yield from self.of - yield self.mid - - def eq(self, i): - return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), - self.of.eq(i.of), self.mid.eq(i.mid)] diff --git a/src/ieee754/add/fpcommon/postnormalise.py b/src/ieee754/add/fpcommon/postnormalise.py deleted file mode 100644 index b072490f..00000000 --- a/src/ieee754/add/fpcommon/postnormalise.py +++ /dev/null @@ -1,270 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal, Cat, Mux, Elaboratable -from nmigen.lib.coding import PriorityEncoder -from nmigen.cli import main, verilog -from math import log - -from fpbase import Overflow, FPNumBase -from fpbase import MultiShiftRMerge -from fpbase import FPState -from .postcalc import FPAddStage1Data - - -class FPNorm1Data: - - def __init__(self, width, id_wid): - self.roundz = Signal(reset_less=True) - self.z = FPNumBase(width, False) - self.out_do_z = Signal(reset_less=True) - self.oz = Signal(width, reset_less=True) - self.mid = Signal(id_wid, reset_less=True) - - def eq(self, i): - return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), - self.roundz.eq(i.roundz), self.mid.eq(i.mid)] - - -class FPNorm1ModSingle(Elaboratable): - - 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 FPAddStage1Data(self.width, self.id_wid) - - def ospec(self): - return FPNorm1Data(self.width, self.id_wid) - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.normalise_1 = self - m.d.comb += self.i.eq(i) - - def process(self, i): - return self.o - - def elaborate(self, platform): - m = Module() - - mwid = self.o.z.m_width+2 - pe = PriorityEncoder(mwid) - m.submodules.norm_pe = pe - - of = Overflow() - m.d.comb += self.o.roundz.eq(of.roundz) - - m.submodules.norm1_out_z = self.o.z - m.submodules.norm1_out_overflow = of - m.submodules.norm1_in_z = self.i.z - m.submodules.norm1_in_overflow = self.i.of - - i = self.ispec() - m.submodules.norm1_insel_z = i.z - m.submodules.norm1_insel_overflow = i.of - - espec = (len(i.z.e), True) - ediff_n126 = Signal(espec, reset_less=True) - msr = MultiShiftRMerge(mwid, espec) - m.submodules.multishift_r = msr - - m.d.comb += i.eq(self.i) - # initialise out from in (overridden below) - m.d.comb += self.o.z.eq(i.z) - m.d.comb += of.eq(i.of) - # normalisation increase/decrease conditions - decrease = Signal(reset_less=True) - increase = Signal(reset_less=True) - m.d.comb += decrease.eq(i.z.m_msbzero & i.z.exp_gt_n126) - m.d.comb += increase.eq(i.z.exp_lt_n126) - # decrease exponent - with m.If(~self.i.out_do_z): - with m.If(decrease): - # *sigh* not entirely obvious: count leading zeros (clz) - # with a PriorityEncoder: to find from the MSB - # we reverse the order of the bits. - temp_m = Signal(mwid, reset_less=True) - temp_s = Signal(mwid+1, reset_less=True) - clz = Signal((len(i.z.e), True), reset_less=True) - # make sure that the amount to decrease by does NOT - # go below the minimum non-INF/NaN exponent - limclz = Mux(i.z.exp_sub_n126 > pe.o, pe.o, - i.z.exp_sub_n126) - m.d.comb += [ - # cat round and guard bits back into the mantissa - temp_m.eq(Cat(i.of.round_bit, i.of.guard, i.z.m)), - pe.i.eq(temp_m[::-1]), # inverted - clz.eq(limclz), # count zeros from MSB down - temp_s.eq(temp_m << clz), # shift mantissa UP - self.o.z.e.eq(i.z.e - clz), # DECREASE exponent - self.o.z.m.eq(temp_s[2:]), # exclude bits 0&1 - of.m0.eq(temp_s[2]), # copy of mantissa[0] - # overflow in bits 0..1: got shifted too (leave sticky) - of.guard.eq(temp_s[1]), # guard - of.round_bit.eq(temp_s[0]), # round - ] - # increase exponent - with m.Elif(increase): - temp_m = Signal(mwid+1, reset_less=True) - m.d.comb += [ - temp_m.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard, - i.z.m)), - ediff_n126.eq(i.z.N126 - i.z.e), - # connect multi-shifter to inp/out mantissa (and ediff) - msr.inp.eq(temp_m), - msr.diff.eq(ediff_n126), - self.o.z.m.eq(msr.m[3:]), - of.m0.eq(temp_s[3]), # copy of mantissa[0] - # overflow in bits 0..1: got shifted too (leave sticky) - of.guard.eq(temp_s[2]), # guard - of.round_bit.eq(temp_s[1]), # round - of.sticky.eq(temp_s[0]), # sticky - self.o.z.e.eq(i.z.e + ediff_n126), - ] - - m.d.comb += self.o.mid.eq(self.i.mid) - m.d.comb += self.o.out_do_z.eq(self.i.out_do_z) - m.d.comb += self.o.oz.eq(self.i.oz) - - return m - - -class FPNorm1ModMulti: - - def __init__(self, width, single_cycle=True): - self.width = width - self.in_select = Signal(reset_less=True) - self.in_z = FPNumBase(width, False) - self.in_of = Overflow() - self.temp_z = FPNumBase(width, False) - self.temp_of = Overflow() - self.out_z = FPNumBase(width, False) - self.out_of = Overflow() - - def elaborate(self, platform): - m = Module() - - m.submodules.norm1_out_z = self.out_z - m.submodules.norm1_out_overflow = self.out_of - m.submodules.norm1_temp_z = self.temp_z - m.submodules.norm1_temp_of = self.temp_of - m.submodules.norm1_in_z = self.in_z - m.submodules.norm1_in_overflow = self.in_of - - in_z = FPNumBase(self.width, False) - in_of = Overflow() - m.submodules.norm1_insel_z = in_z - m.submodules.norm1_insel_overflow = in_of - - # select which of temp or in z/of to use - with m.If(self.in_select): - m.d.comb += in_z.eq(self.in_z) - m.d.comb += in_of.eq(self.in_of) - with m.Else(): - m.d.comb += in_z.eq(self.temp_z) - m.d.comb += in_of.eq(self.temp_of) - # initialise out from in (overridden below) - m.d.comb += self.out_z.eq(in_z) - m.d.comb += self.out_of.eq(in_of) - # normalisation increase/decrease conditions - decrease = Signal(reset_less=True) - increase = Signal(reset_less=True) - m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126) - m.d.comb += increase.eq(in_z.exp_lt_n126) - m.d.comb += self.out_norm.eq(decrease | increase) # loop-end - # decrease exponent - with m.If(decrease): - m.d.comb += [ - self.out_z.e.eq(in_z.e - 1), # DECREASE exponent - self.out_z.m.eq(in_z.m << 1), # shift mantissa UP - self.out_z.m[0].eq(in_of.guard), # steal guard (was tot[2]) - self.out_of.guard.eq(in_of.round_bit), # round (was tot[1]) - self.out_of.round_bit.eq(0), # reset round bit - self.out_of.m0.eq(in_of.guard), - ] - # increase exponent - with m.Elif(increase): - m.d.comb += [ - self.out_z.e.eq(in_z.e + 1), # INCREASE exponent - self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN - self.out_of.guard.eq(in_z.m[0]), - self.out_of.m0.eq(in_z.m[1]), - self.out_of.round_bit.eq(in_of.guard), - self.out_of.sticky.eq(in_of.sticky | in_of.round_bit) - ] - - return m - - -class FPNorm1Single(FPState): - - def __init__(self, width, id_wid, single_cycle=True): - FPState.__init__(self, "normalise_1") - self.mod = FPNorm1ModSingle(width) - self.o = self.ospec() - self.out_z = FPNumBase(width, False) - self.out_roundz = Signal(reset_less=True) - - def ispec(self): - return self.mod.ispec() - - def ospec(self): - return self.mod.ospec() - - def setup(self, m, i): - """ links module to inputs and outputs - """ - self.mod.setup(m, i) - - def action(self, m): - m.next = "round" - - -class FPNorm1Multi(FPState): - - def __init__(self, width, id_wid): - FPState.__init__(self, "normalise_1") - self.mod = FPNorm1ModMulti(width) - self.stb = Signal(reset_less=True) - self.ack = Signal(reset=0, reset_less=True) - self.out_norm = Signal(reset_less=True) - self.in_accept = Signal(reset_less=True) - self.temp_z = FPNumBase(width) - self.temp_of = Overflow() - self.out_z = FPNumBase(width) - self.out_roundz = Signal(reset_less=True) - - def setup(self, m, in_z, in_of, norm_stb): - """ links module to inputs and outputs - """ - self.mod.setup(m, in_z, in_of, norm_stb, - self.in_accept, self.temp_z, self.temp_of, - self.out_z, self.out_norm) - - m.d.comb += self.stb.eq(norm_stb) - m.d.sync += self.ack.eq(0) # sets to zero when not in normalise_1 state - - def action(self, m): - m.d.comb += self.in_accept.eq((~self.ack) & (self.stb)) - m.d.sync += self.temp_of.eq(self.mod.out_of) - m.d.sync += self.temp_z.eq(self.out_z) - with m.If(self.out_norm): - with m.If(self.in_accept): - m.d.sync += [ - self.ack.eq(1), - ] - with m.Else(): - m.d.sync += self.ack.eq(0) - with m.Else(): - # normalisation not required (or done). - m.next = "round" - m.d.sync += self.ack.eq(1) - m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz) - - diff --git a/src/ieee754/add/fpcommon/prenormalise.py b/src/ieee754/add/fpcommon/prenormalise.py deleted file mode 100644 index 0b3a65cb..00000000 --- a/src/ieee754/add/fpcommon/prenormalise.py +++ /dev/null @@ -1,83 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal, Cat, -from nmigen.lib.coding import PriorityEncoder -from nmigen.cli import main, verilog -from math import log - -from fpbase import Overflow, FPNumBase -from fpbase import MultiShiftRMerge - -from fpbase import FPState - - -class FPNormaliseModSingle: - - def __init__(self, width): - self.width = width - self.in_z = self.ispec() - self.out_z = self.ospec() - - def ispec(self): - return FPNumBase(self.width, False) - - def ospec(self): - return FPNumBase(self.width, False) - - def setup(self, m, i): - """ links module to inputs and outputs - """ - m.submodules.normalise = self - m.d.comb += self.i.eq(i) - - def elaborate(self, platform): - m = Module() - - mwid = self.out_z.m_width+2 - pe = PriorityEncoder(mwid) - m.submodules.norm_pe = pe - - m.submodules.norm1_out_z = self.out_z - m.submodules.norm1_in_z = self.in_z - - in_z = FPNumBase(self.width, False) - in_of = Overflow() - m.submodules.norm1_insel_z = in_z - m.submodules.norm1_insel_overflow = in_of - - espec = (len(in_z.e), True) - ediff_n126 = Signal(espec, reset_less=True) - msr = MultiShiftRMerge(mwid, espec) - m.submodules.multishift_r = msr - - m.d.comb += in_z.eq(self.in_z) - m.d.comb += in_of.eq(self.in_of) - # initialise out from in (overridden below) - m.d.comb += self.out_z.eq(in_z) - m.d.comb += self.out_of.eq(in_of) - # normalisation decrease condition - decrease = Signal(reset_less=True) - m.d.comb += decrease.eq(in_z.m_msbzero) - # decrease exponent - with m.If(decrease): - # *sigh* not entirely obvious: count leading zeros (clz) - # with a PriorityEncoder: to find from the MSB - # we reverse the order of the bits. - temp_m = Signal(mwid, reset_less=True) - temp_s = Signal(mwid+1, reset_less=True) - clz = Signal((len(in_z.e), True), reset_less=True) - m.d.comb += [ - # cat round and guard bits back into the mantissa - temp_m.eq(Cat(in_of.round_bit, in_of.guard, in_z.m)), - pe.i.eq(temp_m[::-1]), # inverted - clz.eq(pe.o), # count zeros from MSB down - temp_s.eq(temp_m << clz), # shift mantissa UP - self.out_z.e.eq(in_z.e - clz), # DECREASE exponent - self.out_z.m.eq(temp_s[2:]), # exclude bits 0&1 - ] - - return m - - diff --git a/src/ieee754/add/fpcommon/putz.py b/src/ieee754/add/fpcommon/putz.py deleted file mode 100644 index 8173ed85..00000000 --- a/src/ieee754/add/fpcommon/putz.py +++ /dev/null @@ -1,60 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Signal -from nmigen.cli import main, verilog -from fpbase import FPState - - -class FPPutZ(FPState): - - def __init__(self, state, in_z, out_z, in_mid, out_mid, to_state=None): - FPState.__init__(self, state) - if to_state is None: - to_state = "get_ops" - self.to_state = to_state - self.in_z = in_z - self.out_z = out_z - self.in_mid = in_mid - self.out_mid = out_mid - - def action(self, m): - if self.in_mid is not None: - m.d.sync += self.out_mid.eq(self.in_mid) - m.d.sync += [ - self.out_z.z.v.eq(self.in_z) - ] - with m.If(self.out_z.z.valid_o & self.out_z.z.ready_i_test): - m.d.sync += self.out_z.z.valid_o.eq(0) - m.next = self.to_state - with m.Else(): - m.d.sync += self.out_z.z.valid_o.eq(1) - - -class FPPutZIdx(FPState): - - def __init__(self, state, in_z, out_zs, in_mid, to_state=None): - FPState.__init__(self, state) - if to_state is None: - to_state = "get_ops" - self.to_state = to_state - self.in_z = in_z - self.out_zs = out_zs - self.in_mid = in_mid - - def action(self, m): - outz_stb = Signal(reset_less=True) - outz_ack = Signal(reset_less=True) - m.d.comb += [outz_stb.eq(self.out_zs[self.in_mid].valid_o), - outz_ack.eq(self.out_zs[self.in_mid].ready_i_test), - ] - m.d.sync += [ - self.out_zs[self.in_mid].v.eq(self.in_z.v) - ] - with m.If(outz_stb & outz_ack): - m.d.sync += self.out_zs[self.in_mid].valid_o.eq(0) - m.next = self.to_state - with m.Else(): - m.d.sync += self.out_zs[self.in_mid].valid_o.eq(1) - diff --git a/src/ieee754/add/fpcommon/roundz.py b/src/ieee754/add/fpcommon/roundz.py deleted file mode 100644 index 420d6669..00000000 --- a/src/ieee754/add/fpcommon/roundz.py +++ /dev/null @@ -1,82 +0,0 @@ -# IEEE Floating Point Adder (Single Precision) -# Copyright (C) Jonathan P Dawson 2013 -# 2013-12-12 - -from nmigen import Module, Signal, Elaboratable -from nmigen.cli import main, verilog - -from fpbase import FPNumBase -from fpbase import FPState -from fpcommon.postnormalise import FPNorm1Data - - -class FPRoundData: - - def __init__(self, width, id_wid): - self.z = FPNumBase(width, False) - self.out_do_z = Signal(reset_less=True) - self.oz = Signal(width, reset_less=True) - self.mid = Signal(id_wid, reset_less=True) - - def eq(self, i): - return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), - self.mid.eq(i.mid)] - - -class FPRoundMod(Elaboratable): - - def __init__(self, width, id_wid): - self.width = width - self.id_wid = id_wid - self.i = self.ispec() - self.out_z = self.ospec() - - def ispec(self): - return FPNorm1Data(self.width, self.id_wid) - - def ospec(self): - return FPRoundData(self.width, self.id_wid) - - def process(self, i): - return self.out_z - - def setup(self, m, i): - m.submodules.roundz = self - m.d.comb += self.i.eq(i) - - def elaborate(self, platform): - m = Module() - m.d.comb += self.out_z.eq(self.i) # copies mid, z, out_do_z - with m.If(~self.i.out_do_z): - with m.If(self.i.roundz): - m.d.comb += self.out_z.z.m.eq(self.i.z.m + 1) # mantissa up - with m.If(self.i.z.m == self.i.z.m1s): # all 1s - m.d.comb += self.out_z.z.e.eq(self.i.z.e + 1) # exponent up - - return m - - -class FPRound(FPState): - - def __init__(self, width, id_wid): - FPState.__init__(self, "round") - self.mod = FPRoundMod(width) - self.out_z = self.ospec() - - def ispec(self): - return self.mod.ispec() - - def ospec(self): - return self.mod.ospec() - - def setup(self, m, i): - """ links module to inputs and outputs - """ - self.mod.setup(m, i) - - self.idsync(m) - m.d.sync += self.out_z.eq(self.mod.out_z) - m.d.sync += self.out_z.mid.eq(self.mod.o.mid) - - def action(self, m): - m.next = "corrections" diff --git a/src/ieee754/fpcommon/__init__.py b/src/ieee754/fpcommon/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/ieee754/fpcommon/corrections.py b/src/ieee754/fpcommon/corrections.py new file mode 100644 index 00000000..ce9ba3cd --- /dev/null +++ b/src/ieee754/fpcommon/corrections.py @@ -0,0 +1,69 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Elaboratable +from nmigen.cli import main, verilog +from fpbase import FPState +from fpcommon.roundz import FPRoundData + + +class FPCorrectionsMod(Elaboratable): + + def __init__(self, width, id_wid): + self.width = width + self.id_wid = id_wid + self.i = self.ispec() + self.out_z = self.ospec() + + def ispec(self): + return FPRoundData(self.width, self.id_wid) + + def ospec(self): + return FPRoundData(self.width, self.id_wid) + + def process(self, i): + return self.out_z + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.corrections = self + m.d.comb += self.i.eq(i) + + def elaborate(self, platform): + m = Module() + m.submodules.corr_in_z = self.i.z + m.submodules.corr_out_z = self.out_z.z + m.d.comb += self.out_z.eq(self.i) # copies mid, z, out_do_z + with m.If(~self.i.out_do_z): + with m.If(self.i.z.is_denormalised): + m.d.comb += self.out_z.z.e.eq(self.i.z.N127) + return m + + +class FPCorrections(FPState): + + def __init__(self, width, id_wid): + FPState.__init__(self, "corrections") + self.mod = FPCorrectionsMod(width) + self.out_z = self.ospec() + + def ispec(self): + return self.mod.ispec() + + def ospec(self): + return self.mod.ospec() + + def setup(self, m, in_z): + """ links module to inputs and outputs + """ + self.mod.setup(m, in_z) + + m.d.sync += self.out_z.eq(self.mod.out_z) + m.d.sync += self.out_z.mid.eq(self.mod.o.mid) + + def action(self, m): + m.next = "pack" + + diff --git a/src/ieee754/fpcommon/denorm.py b/src/ieee754/fpcommon/denorm.py new file mode 100644 index 00000000..9fbbc976 --- /dev/null +++ b/src/ieee754/fpcommon/denorm.py @@ -0,0 +1,108 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal +from nmigen.cli import main, verilog +from math import log + +from fpbase import FPNumIn, FPNumOut, FPNumBase +from fpbase import FPState + + +class FPSCData: + + def __init__(self, width, id_wid): + self.a = FPNumBase(width, True) + self.b = FPNumBase(width, True) + self.z = FPNumOut(width, False) + self.oz = Signal(width, reset_less=True) + self.out_do_z = Signal(reset_less=True) + self.mid = Signal(id_wid, reset_less=True) + + def __iter__(self): + yield from self.a + yield from self.b + yield from self.z + yield self.oz + yield self.out_do_z + yield self.mid + + def eq(self, i): + return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), + self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] + + +class FPAddDeNormMod(FPState): + + 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 FPSCData(self.width, self.id_wid) + + def ospec(self): + return FPSCData(self.width, self.id_wid) + + def process(self, i): + return self.o + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.denormalise = self + m.d.comb += self.i.eq(i) + + def elaborate(self, platform): + m = Module() + m.submodules.denorm_in_a = self.i.a + m.submodules.denorm_in_b = self.i.b + m.submodules.denorm_out_a = self.o.a + m.submodules.denorm_out_b = self.o.b + + with m.If(~self.i.out_do_z): + # XXX hmmm, don't like repeating identical code + m.d.comb += self.o.a.eq(self.i.a) + with m.If(self.i.a.exp_n127): + m.d.comb += self.o.a.e.eq(self.i.a.N126) # limit a exponent + with m.Else(): + m.d.comb += self.o.a.m[-1].eq(1) # set top mantissa bit + + m.d.comb += self.o.b.eq(self.i.b) + with m.If(self.i.b.exp_n127): + m.d.comb += self.o.b.e.eq(self.i.b.N126) # limit a exponent + with m.Else(): + m.d.comb += self.o.b.m[-1].eq(1) # set top mantissa bit + + m.d.comb += self.o.mid.eq(self.i.mid) + m.d.comb += self.o.z.eq(self.i.z) + m.d.comb += self.o.out_do_z.eq(self.i.out_do_z) + m.d.comb += self.o.oz.eq(self.i.oz) + + return m + + +class FPAddDeNorm(FPState): + + def __init__(self, width, id_wid): + FPState.__init__(self, "denormalise") + self.mod = FPAddDeNormMod(width) + self.out_a = FPNumBase(width) + self.out_b = FPNumBase(width) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + self.mod.setup(m, i) + + m.d.sync += self.out_a.eq(self.mod.out_a) + m.d.sync += self.out_b.eq(self.mod.out_b) + + def action(self, m): + # Denormalised Number checks + m.next = "align" + + diff --git a/src/ieee754/fpcommon/getop.py b/src/ieee754/fpcommon/getop.py new file mode 100644 index 00000000..1988997a --- /dev/null +++ b/src/ieee754/fpcommon/getop.py @@ -0,0 +1,174 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal, Cat, Mux, Array, Const, Elaboratable +from nmigen.lib.coding import PriorityEncoder +from nmigen.cli import main, verilog +from math import log + +from fpbase import FPNumIn, FPNumOut, FPOpIn, Overflow, FPBase, FPNumBase +from fpbase import MultiShiftRMerge, Trigger +from singlepipe import (ControlBase, StageChain, SimpleHandshake, + PassThroughStage, PrevControl) +from multipipe import CombMuxOutPipe +from multipipe import PriorityCombMuxInPipe + +from fpbase import FPState +import nmoperator + + +class FPGetOpMod(Elaboratable): + def __init__(self, width): + self.in_op = FPOpIn(width) + self.in_op.data_i = Signal(width) + self.out_op = Signal(width) + self.out_decode = Signal(reset_less=True) + + def elaborate(self, platform): + m = Module() + m.d.comb += self.out_decode.eq((self.in_op.ready_o) & \ + (self.in_op.valid_i_test)) + m.submodules.get_op_in = self.in_op + #m.submodules.get_op_out = self.out_op + with m.If(self.out_decode): + m.d.comb += [ + self.out_op.eq(self.in_op.v), + ] + return m + + +class FPGetOp(FPState): + """ gets operand + """ + + def __init__(self, in_state, out_state, in_op, width): + FPState.__init__(self, in_state) + self.out_state = out_state + self.mod = FPGetOpMod(width) + self.in_op = in_op + self.out_op = Signal(width) + self.out_decode = Signal(reset_less=True) + + def setup(self, m, in_op): + """ links module to inputs and outputs + """ + setattr(m.submodules, self.state_from, self.mod) + m.d.comb += nmoperator.eq(self.mod.in_op, in_op) + m.d.comb += self.out_decode.eq(self.mod.out_decode) + + def action(self, m): + with m.If(self.out_decode): + m.next = self.out_state + m.d.sync += [ + self.in_op.ready_o.eq(0), + self.out_op.eq(self.mod.out_op) + ] + with m.Else(): + m.d.sync += self.in_op.ready_o.eq(1) + + +class FPNumBase2Ops: + + def __init__(self, width, id_wid, m_extra=True): + self.a = FPNumBase(width, m_extra) + self.b = FPNumBase(width, m_extra) + self.mid = Signal(id_wid, reset_less=True) + + def eq(self, i): + return [self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] + + def ports(self): + return [self.a, self.b, self.mid] + + +class FPADDBaseData: + + def __init__(self, width, id_wid): + self.width = width + self.id_wid = id_wid + self.a = Signal(width) + self.b = Signal(width) + self.mid = Signal(id_wid, reset_less=True) + + def eq(self, i): + return [self.a.eq(i.a), self.b.eq(i.b), self.mid.eq(i.mid)] + + def ports(self): + return [self.a, self.b, self.mid] + + +class FPGet2OpMod(PrevControl): + def __init__(self, width, id_wid): + PrevControl.__init__(self) + self.width = width + self.id_wid = id_wid + self.data_i = self.ispec() + self.i = self.data_i + self.o = self.ospec() + + def ispec(self): + return FPADDBaseData(self.width, self.id_wid) + + def ospec(self): + return FPADDBaseData(self.width, self.id_wid) + + def process(self, i): + return self.o + + def elaborate(self, platform): + m = PrevControl.elaborate(self, platform) + with m.If(self.trigger): + m.d.comb += [ + self.o.eq(self.data_i), + ] + return m + + +class FPGet2Op(FPState): + """ gets operands + """ + + def __init__(self, in_state, out_state, width, id_wid): + FPState.__init__(self, in_state) + self.out_state = out_state + self.mod = FPGet2OpMod(width, id_wid) + self.o = self.ospec() + self.in_stb = Signal(reset_less=True) + self.out_ack = Signal(reset_less=True) + self.out_decode = Signal(reset_less=True) + + def ispec(self): + return self.mod.ispec() + + def ospec(self): + return self.mod.ospec() + + def trigger_setup(self, m, in_stb, in_ack): + """ links stb/ack + """ + m.d.comb += self.mod.valid_i.eq(in_stb) + m.d.comb += in_ack.eq(self.mod.ready_o) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.get_ops = self.mod + m.d.comb += self.mod.i.eq(i) + m.d.comb += self.out_ack.eq(self.mod.ready_o) + m.d.comb += self.out_decode.eq(self.mod.trigger) + + def process(self, i): + return self.o + + def action(self, m): + with m.If(self.out_decode): + m.next = self.out_state + m.d.sync += [ + self.mod.ready_o.eq(0), + self.o.eq(self.mod.o), + ] + with m.Else(): + m.d.sync += self.mod.ready_o.eq(1) + + diff --git a/src/ieee754/fpcommon/normtopack.py b/src/ieee754/fpcommon/normtopack.py new file mode 100644 index 00000000..87d08125 --- /dev/null +++ b/src/ieee754/fpcommon/normtopack.py @@ -0,0 +1,52 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +#from nmigen.cli import main, verilog + +from singlepipe import StageChain, SimpleHandshake + +from fpbase import FPState, FPID +from fpcommon.postcalc import FPAddStage1Data +from fpcommon.postnormalise import FPNorm1ModSingle +from fpcommon.roundz import FPRoundMod +from fpcommon.corrections import FPCorrectionsMod +from fpcommon.pack import FPPackData, FPPackMod + + +class FPNormToPack(FPState, SimpleHandshake): + + def __init__(self, width, id_wid): + FPState.__init__(self, "normalise_1") + self.id_wid = id_wid + self.width = width + SimpleHandshake.__init__(self, self) # pipeline is its own stage + + def ispec(self): + return FPAddStage1Data(self.width, self.id_wid) # Norm1ModSingle ispec + + def ospec(self): + return FPPackData(self.width, self.id_wid) # FPPackMod ospec + + def setup(self, m, i): + """ links module to inputs and outputs + """ + + # Normalisation, Rounding Corrections, Pack - in a chain + nmod = FPNorm1ModSingle(self.width, self.id_wid) + rmod = FPRoundMod(self.width, self.id_wid) + cmod = FPCorrectionsMod(self.width, self.id_wid) + pmod = FPPackMod(self.width, self.id_wid) + stages = [nmod, rmod, cmod, pmod] + chain = StageChain(stages) + chain.setup(m, i) + self.out_z = pmod.ospec() + + self.o = pmod.o + + def process(self, i): + return self.o + + def action(self, m): + m.d.sync += self.out_z.eq(self.process(None)) + m.next = "pack_put_z" diff --git a/src/ieee754/fpcommon/pack.py b/src/ieee754/fpcommon/pack.py new file mode 100644 index 00000000..1464883c --- /dev/null +++ b/src/ieee754/fpcommon/pack.py @@ -0,0 +1,84 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal, Elaboratable +from nmigen.cli import main, verilog + +from fpbase import FPNumOut +from fpbase import FPState +from fpcommon.roundz import FPRoundData +from singlepipe import Object + + +class FPPackData(Object): + + def __init__(self, width, id_wid): + Object.__init__(self) + self.z = Signal(width, reset_less=True) + self.mid = Signal(id_wid, reset_less=True) + + +class FPPackMod(Elaboratable): + + 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 FPRoundData(self.width, self.id_wid) + + def ospec(self): + return FPPackData(self.width, self.id_wid) + + def process(self, i): + return self.o + + def setup(self, m, in_z): + """ links module to inputs and outputs + """ + m.submodules.pack = self + m.d.comb += self.i.eq(in_z) + + def elaborate(self, platform): + m = Module() + z = FPNumOut(self.width, False) + m.submodules.pack_in_z = self.i.z + m.submodules.pack_out_z = z + m.d.comb += self.o.mid.eq(self.i.mid) + with m.If(~self.i.out_do_z): + with m.If(self.i.z.is_overflowed): + m.d.comb += z.inf(self.i.z.s) + with m.Else(): + m.d.comb += z.create(self.i.z.s, self.i.z.e, self.i.z.m) + with m.Else(): + m.d.comb += z.v.eq(self.i.oz) + m.d.comb += self.o.z.eq(z.v) + return m + + +class FPPack(FPState): + + def __init__(self, width, id_wid): + FPState.__init__(self, "pack") + self.mod = FPPackMod(width) + self.out_z = self.ospec() + + def ispec(self): + return self.mod.ispec() + + def ospec(self): + return self.mod.ospec() + + def setup(self, m, in_z): + """ links module to inputs and outputs + """ + self.mod.setup(m, in_z) + + m.d.sync += self.out_z.v.eq(self.mod.out_z.v) + m.d.sync += self.out_z.mid.eq(self.mod.o.mid) + + def action(self, m): + m.next = "pack_put_z" diff --git a/src/ieee754/fpcommon/postcalc.py b/src/ieee754/fpcommon/postcalc.py new file mode 100644 index 00000000..7111dc8a --- /dev/null +++ b/src/ieee754/fpcommon/postcalc.py @@ -0,0 +1,26 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Signal +from fpbase import Overflow, FPNumBase + +class FPAddStage1Data: + + def __init__(self, width, id_wid): + self.z = FPNumBase(width, False) + self.out_do_z = Signal(reset_less=True) + self.oz = Signal(width, reset_less=True) + self.of = Overflow() + self.mid = Signal(id_wid, reset_less=True) + + def __iter__(self): + yield from self.z + yield self.out_do_z + yield self.oz + yield from self.of + yield self.mid + + def eq(self, i): + return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), + self.of.eq(i.of), self.mid.eq(i.mid)] diff --git a/src/ieee754/fpcommon/postnormalise.py b/src/ieee754/fpcommon/postnormalise.py new file mode 100644 index 00000000..b072490f --- /dev/null +++ b/src/ieee754/fpcommon/postnormalise.py @@ -0,0 +1,270 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal, Cat, Mux, Elaboratable +from nmigen.lib.coding import PriorityEncoder +from nmigen.cli import main, verilog +from math import log + +from fpbase import Overflow, FPNumBase +from fpbase import MultiShiftRMerge +from fpbase import FPState +from .postcalc import FPAddStage1Data + + +class FPNorm1Data: + + def __init__(self, width, id_wid): + self.roundz = Signal(reset_less=True) + self.z = FPNumBase(width, False) + self.out_do_z = Signal(reset_less=True) + self.oz = Signal(width, reset_less=True) + self.mid = Signal(id_wid, reset_less=True) + + def eq(self, i): + return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), + self.roundz.eq(i.roundz), self.mid.eq(i.mid)] + + +class FPNorm1ModSingle(Elaboratable): + + 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 FPAddStage1Data(self.width, self.id_wid) + + def ospec(self): + return FPNorm1Data(self.width, self.id_wid) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.normalise_1 = self + m.d.comb += self.i.eq(i) + + def process(self, i): + return self.o + + def elaborate(self, platform): + m = Module() + + mwid = self.o.z.m_width+2 + pe = PriorityEncoder(mwid) + m.submodules.norm_pe = pe + + of = Overflow() + m.d.comb += self.o.roundz.eq(of.roundz) + + m.submodules.norm1_out_z = self.o.z + m.submodules.norm1_out_overflow = of + m.submodules.norm1_in_z = self.i.z + m.submodules.norm1_in_overflow = self.i.of + + i = self.ispec() + m.submodules.norm1_insel_z = i.z + m.submodules.norm1_insel_overflow = i.of + + espec = (len(i.z.e), True) + ediff_n126 = Signal(espec, reset_less=True) + msr = MultiShiftRMerge(mwid, espec) + m.submodules.multishift_r = msr + + m.d.comb += i.eq(self.i) + # initialise out from in (overridden below) + m.d.comb += self.o.z.eq(i.z) + m.d.comb += of.eq(i.of) + # normalisation increase/decrease conditions + decrease = Signal(reset_less=True) + increase = Signal(reset_less=True) + m.d.comb += decrease.eq(i.z.m_msbzero & i.z.exp_gt_n126) + m.d.comb += increase.eq(i.z.exp_lt_n126) + # decrease exponent + with m.If(~self.i.out_do_z): + with m.If(decrease): + # *sigh* not entirely obvious: count leading zeros (clz) + # with a PriorityEncoder: to find from the MSB + # we reverse the order of the bits. + temp_m = Signal(mwid, reset_less=True) + temp_s = Signal(mwid+1, reset_less=True) + clz = Signal((len(i.z.e), True), reset_less=True) + # make sure that the amount to decrease by does NOT + # go below the minimum non-INF/NaN exponent + limclz = Mux(i.z.exp_sub_n126 > pe.o, pe.o, + i.z.exp_sub_n126) + m.d.comb += [ + # cat round and guard bits back into the mantissa + temp_m.eq(Cat(i.of.round_bit, i.of.guard, i.z.m)), + pe.i.eq(temp_m[::-1]), # inverted + clz.eq(limclz), # count zeros from MSB down + temp_s.eq(temp_m << clz), # shift mantissa UP + self.o.z.e.eq(i.z.e - clz), # DECREASE exponent + self.o.z.m.eq(temp_s[2:]), # exclude bits 0&1 + of.m0.eq(temp_s[2]), # copy of mantissa[0] + # overflow in bits 0..1: got shifted too (leave sticky) + of.guard.eq(temp_s[1]), # guard + of.round_bit.eq(temp_s[0]), # round + ] + # increase exponent + with m.Elif(increase): + temp_m = Signal(mwid+1, reset_less=True) + m.d.comb += [ + temp_m.eq(Cat(i.of.sticky, i.of.round_bit, i.of.guard, + i.z.m)), + ediff_n126.eq(i.z.N126 - i.z.e), + # connect multi-shifter to inp/out mantissa (and ediff) + msr.inp.eq(temp_m), + msr.diff.eq(ediff_n126), + self.o.z.m.eq(msr.m[3:]), + of.m0.eq(temp_s[3]), # copy of mantissa[0] + # overflow in bits 0..1: got shifted too (leave sticky) + of.guard.eq(temp_s[2]), # guard + of.round_bit.eq(temp_s[1]), # round + of.sticky.eq(temp_s[0]), # sticky + self.o.z.e.eq(i.z.e + ediff_n126), + ] + + m.d.comb += self.o.mid.eq(self.i.mid) + m.d.comb += self.o.out_do_z.eq(self.i.out_do_z) + m.d.comb += self.o.oz.eq(self.i.oz) + + return m + + +class FPNorm1ModMulti: + + def __init__(self, width, single_cycle=True): + self.width = width + self.in_select = Signal(reset_less=True) + self.in_z = FPNumBase(width, False) + self.in_of = Overflow() + self.temp_z = FPNumBase(width, False) + self.temp_of = Overflow() + self.out_z = FPNumBase(width, False) + self.out_of = Overflow() + + def elaborate(self, platform): + m = Module() + + m.submodules.norm1_out_z = self.out_z + m.submodules.norm1_out_overflow = self.out_of + m.submodules.norm1_temp_z = self.temp_z + m.submodules.norm1_temp_of = self.temp_of + m.submodules.norm1_in_z = self.in_z + m.submodules.norm1_in_overflow = self.in_of + + in_z = FPNumBase(self.width, False) + in_of = Overflow() + m.submodules.norm1_insel_z = in_z + m.submodules.norm1_insel_overflow = in_of + + # select which of temp or in z/of to use + with m.If(self.in_select): + m.d.comb += in_z.eq(self.in_z) + m.d.comb += in_of.eq(self.in_of) + with m.Else(): + m.d.comb += in_z.eq(self.temp_z) + m.d.comb += in_of.eq(self.temp_of) + # initialise out from in (overridden below) + m.d.comb += self.out_z.eq(in_z) + m.d.comb += self.out_of.eq(in_of) + # normalisation increase/decrease conditions + decrease = Signal(reset_less=True) + increase = Signal(reset_less=True) + m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126) + m.d.comb += increase.eq(in_z.exp_lt_n126) + m.d.comb += self.out_norm.eq(decrease | increase) # loop-end + # decrease exponent + with m.If(decrease): + m.d.comb += [ + self.out_z.e.eq(in_z.e - 1), # DECREASE exponent + self.out_z.m.eq(in_z.m << 1), # shift mantissa UP + self.out_z.m[0].eq(in_of.guard), # steal guard (was tot[2]) + self.out_of.guard.eq(in_of.round_bit), # round (was tot[1]) + self.out_of.round_bit.eq(0), # reset round bit + self.out_of.m0.eq(in_of.guard), + ] + # increase exponent + with m.Elif(increase): + m.d.comb += [ + self.out_z.e.eq(in_z.e + 1), # INCREASE exponent + self.out_z.m.eq(in_z.m >> 1), # shift mantissa DOWN + self.out_of.guard.eq(in_z.m[0]), + self.out_of.m0.eq(in_z.m[1]), + self.out_of.round_bit.eq(in_of.guard), + self.out_of.sticky.eq(in_of.sticky | in_of.round_bit) + ] + + return m + + +class FPNorm1Single(FPState): + + def __init__(self, width, id_wid, single_cycle=True): + FPState.__init__(self, "normalise_1") + self.mod = FPNorm1ModSingle(width) + self.o = self.ospec() + self.out_z = FPNumBase(width, False) + self.out_roundz = Signal(reset_less=True) + + def ispec(self): + return self.mod.ispec() + + def ospec(self): + return self.mod.ospec() + + def setup(self, m, i): + """ links module to inputs and outputs + """ + self.mod.setup(m, i) + + def action(self, m): + m.next = "round" + + +class FPNorm1Multi(FPState): + + def __init__(self, width, id_wid): + FPState.__init__(self, "normalise_1") + self.mod = FPNorm1ModMulti(width) + self.stb = Signal(reset_less=True) + self.ack = Signal(reset=0, reset_less=True) + self.out_norm = Signal(reset_less=True) + self.in_accept = Signal(reset_less=True) + self.temp_z = FPNumBase(width) + self.temp_of = Overflow() + self.out_z = FPNumBase(width) + self.out_roundz = Signal(reset_less=True) + + def setup(self, m, in_z, in_of, norm_stb): + """ links module to inputs and outputs + """ + self.mod.setup(m, in_z, in_of, norm_stb, + self.in_accept, self.temp_z, self.temp_of, + self.out_z, self.out_norm) + + m.d.comb += self.stb.eq(norm_stb) + m.d.sync += self.ack.eq(0) # sets to zero when not in normalise_1 state + + def action(self, m): + m.d.comb += self.in_accept.eq((~self.ack) & (self.stb)) + m.d.sync += self.temp_of.eq(self.mod.out_of) + m.d.sync += self.temp_z.eq(self.out_z) + with m.If(self.out_norm): + with m.If(self.in_accept): + m.d.sync += [ + self.ack.eq(1), + ] + with m.Else(): + m.d.sync += self.ack.eq(0) + with m.Else(): + # normalisation not required (or done). + m.next = "round" + m.d.sync += self.ack.eq(1) + m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz) + + diff --git a/src/ieee754/fpcommon/prenormalise.py b/src/ieee754/fpcommon/prenormalise.py new file mode 100644 index 00000000..0b3a65cb --- /dev/null +++ b/src/ieee754/fpcommon/prenormalise.py @@ -0,0 +1,83 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal, Cat, +from nmigen.lib.coding import PriorityEncoder +from nmigen.cli import main, verilog +from math import log + +from fpbase import Overflow, FPNumBase +from fpbase import MultiShiftRMerge + +from fpbase import FPState + + +class FPNormaliseModSingle: + + def __init__(self, width): + self.width = width + self.in_z = self.ispec() + self.out_z = self.ospec() + + def ispec(self): + return FPNumBase(self.width, False) + + def ospec(self): + return FPNumBase(self.width, False) + + def setup(self, m, i): + """ links module to inputs and outputs + """ + m.submodules.normalise = self + m.d.comb += self.i.eq(i) + + def elaborate(self, platform): + m = Module() + + mwid = self.out_z.m_width+2 + pe = PriorityEncoder(mwid) + m.submodules.norm_pe = pe + + m.submodules.norm1_out_z = self.out_z + m.submodules.norm1_in_z = self.in_z + + in_z = FPNumBase(self.width, False) + in_of = Overflow() + m.submodules.norm1_insel_z = in_z + m.submodules.norm1_insel_overflow = in_of + + espec = (len(in_z.e), True) + ediff_n126 = Signal(espec, reset_less=True) + msr = MultiShiftRMerge(mwid, espec) + m.submodules.multishift_r = msr + + m.d.comb += in_z.eq(self.in_z) + m.d.comb += in_of.eq(self.in_of) + # initialise out from in (overridden below) + m.d.comb += self.out_z.eq(in_z) + m.d.comb += self.out_of.eq(in_of) + # normalisation decrease condition + decrease = Signal(reset_less=True) + m.d.comb += decrease.eq(in_z.m_msbzero) + # decrease exponent + with m.If(decrease): + # *sigh* not entirely obvious: count leading zeros (clz) + # with a PriorityEncoder: to find from the MSB + # we reverse the order of the bits. + temp_m = Signal(mwid, reset_less=True) + temp_s = Signal(mwid+1, reset_less=True) + clz = Signal((len(in_z.e), True), reset_less=True) + m.d.comb += [ + # cat round and guard bits back into the mantissa + temp_m.eq(Cat(in_of.round_bit, in_of.guard, in_z.m)), + pe.i.eq(temp_m[::-1]), # inverted + clz.eq(pe.o), # count zeros from MSB down + temp_s.eq(temp_m << clz), # shift mantissa UP + self.out_z.e.eq(in_z.e - clz), # DECREASE exponent + self.out_z.m.eq(temp_s[2:]), # exclude bits 0&1 + ] + + return m + + diff --git a/src/ieee754/fpcommon/putz.py b/src/ieee754/fpcommon/putz.py new file mode 100644 index 00000000..8173ed85 --- /dev/null +++ b/src/ieee754/fpcommon/putz.py @@ -0,0 +1,60 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Signal +from nmigen.cli import main, verilog +from fpbase import FPState + + +class FPPutZ(FPState): + + def __init__(self, state, in_z, out_z, in_mid, out_mid, to_state=None): + FPState.__init__(self, state) + if to_state is None: + to_state = "get_ops" + self.to_state = to_state + self.in_z = in_z + self.out_z = out_z + self.in_mid = in_mid + self.out_mid = out_mid + + def action(self, m): + if self.in_mid is not None: + m.d.sync += self.out_mid.eq(self.in_mid) + m.d.sync += [ + self.out_z.z.v.eq(self.in_z) + ] + with m.If(self.out_z.z.valid_o & self.out_z.z.ready_i_test): + m.d.sync += self.out_z.z.valid_o.eq(0) + m.next = self.to_state + with m.Else(): + m.d.sync += self.out_z.z.valid_o.eq(1) + + +class FPPutZIdx(FPState): + + def __init__(self, state, in_z, out_zs, in_mid, to_state=None): + FPState.__init__(self, state) + if to_state is None: + to_state = "get_ops" + self.to_state = to_state + self.in_z = in_z + self.out_zs = out_zs + self.in_mid = in_mid + + def action(self, m): + outz_stb = Signal(reset_less=True) + outz_ack = Signal(reset_less=True) + m.d.comb += [outz_stb.eq(self.out_zs[self.in_mid].valid_o), + outz_ack.eq(self.out_zs[self.in_mid].ready_i_test), + ] + m.d.sync += [ + self.out_zs[self.in_mid].v.eq(self.in_z.v) + ] + with m.If(outz_stb & outz_ack): + m.d.sync += self.out_zs[self.in_mid].valid_o.eq(0) + m.next = self.to_state + with m.Else(): + m.d.sync += self.out_zs[self.in_mid].valid_o.eq(1) + diff --git a/src/ieee754/fpcommon/roundz.py b/src/ieee754/fpcommon/roundz.py new file mode 100644 index 00000000..420d6669 --- /dev/null +++ b/src/ieee754/fpcommon/roundz.py @@ -0,0 +1,82 @@ +# IEEE Floating Point Adder (Single Precision) +# Copyright (C) Jonathan P Dawson 2013 +# 2013-12-12 + +from nmigen import Module, Signal, Elaboratable +from nmigen.cli import main, verilog + +from fpbase import FPNumBase +from fpbase import FPState +from fpcommon.postnormalise import FPNorm1Data + + +class FPRoundData: + + def __init__(self, width, id_wid): + self.z = FPNumBase(width, False) + self.out_do_z = Signal(reset_less=True) + self.oz = Signal(width, reset_less=True) + self.mid = Signal(id_wid, reset_less=True) + + def eq(self, i): + return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz), + self.mid.eq(i.mid)] + + +class FPRoundMod(Elaboratable): + + def __init__(self, width, id_wid): + self.width = width + self.id_wid = id_wid + self.i = self.ispec() + self.out_z = self.ospec() + + def ispec(self): + return FPNorm1Data(self.width, self.id_wid) + + def ospec(self): + return FPRoundData(self.width, self.id_wid) + + def process(self, i): + return self.out_z + + def setup(self, m, i): + m.submodules.roundz = self + m.d.comb += self.i.eq(i) + + def elaborate(self, platform): + m = Module() + m.d.comb += self.out_z.eq(self.i) # copies mid, z, out_do_z + with m.If(~self.i.out_do_z): + with m.If(self.i.roundz): + m.d.comb += self.out_z.z.m.eq(self.i.z.m + 1) # mantissa up + with m.If(self.i.z.m == self.i.z.m1s): # all 1s + m.d.comb += self.out_z.z.e.eq(self.i.z.e + 1) # exponent up + + return m + + +class FPRound(FPState): + + def __init__(self, width, id_wid): + FPState.__init__(self, "round") + self.mod = FPRoundMod(width) + self.out_z = self.ospec() + + def ispec(self): + return self.mod.ispec() + + def ospec(self): + return self.mod.ospec() + + def setup(self, m, i): + """ links module to inputs and outputs + """ + self.mod.setup(m, i) + + self.idsync(m) + m.d.sync += self.out_z.eq(self.mod.out_z) + m.d.sync += self.out_z.mid.eq(self.mod.o.mid) + + def action(self, m): + m.next = "corrections"