copy context/roundz, a and b manually in fpmul align
[ieee754fpu.git] / src / ieee754 / fpmul / align.py
1 # IEEE Floating Point Multiplier
2
3 from nmigen import Module, Signal, Cat, Mux, Elaboratable
4 from nmigen.lib.coding import PriorityEncoder
5 from nmigen.cli import main, verilog
6 from math import log
7
8 from nmutil.singlepipe import (StageChain, SimpleHandshake)
9
10 from ieee754.fpcommon.fpbase import (Overflow, OverflowMod,
11 FPNumBase, FPNumBaseRecord)
12 from ieee754.fpcommon.fpbase import MultiShiftRMerge
13 from ieee754.fpcommon.fpbase import FPState
14 from ieee754.fpcommon.getop import FPPipeContext
15
16
17 from ieee754.fpcommon.fpbase import FPState
18 from ieee754.fpcommon.denorm import FPSCData
19 from ieee754.fpcommon.postcalc import FPAddStage1Data
20
21
22 class FPAlignModSingle(Elaboratable):
23
24 def __init__(self, pspec, e_extra=False):
25 self.pspec = pspec
26 self.e_extra = e_extra
27 self.i = self.ispec()
28 self.o = self.ospec()
29
30 def ispec(self):
31 return FPSCData(self.pspec, False)
32
33 def ospec(self):
34 return FPSCData(self.pspec, False)
35
36 def setup(self, m, i):
37 """ links module to inputs and outputs
38 """
39 m.submodules.align = self
40 m.d.comb += self.i.eq(i)
41
42 def process(self, i):
43 return self.o
44
45 def elaborate(self, platform):
46 m = Module()
47
48 mwid = self.o.z.m_width
49 pe_a = PriorityEncoder(mwid)
50 pe_b = PriorityEncoder(mwid)
51 m.submodules.norm_pe_a = pe_a
52 m.submodules.norm_pe_b = pe_b
53
54 self.o.a.m.name = "o_a_m"
55 self.o.b.m.name = "o_b_m"
56
57 m.submodules.norm1_insel_a = insel_a = FPNumBase(self.i.a)
58 m.submodules.norm1_insel_b = insel_b = FPNumBase(self.i.b)
59 insel_a.m.name = "i_a_m"
60 insel_b.m.name = "i_b_m"
61
62 # copy input to output (overridden below)
63 m.d.comb += self.o.a.eq(insel_a)
64 m.d.comb += self.o.b.eq(insel_b)
65
66 # normalisation increase/decrease conditions
67 decrease_a = Signal(reset_less=True)
68 decrease_b = Signal(reset_less=True)
69 m.d.comb += decrease_a.eq(insel_a.m_msbzero)
70 m.d.comb += decrease_b.eq(insel_b.m_msbzero)
71
72 # ok this is near-identical to FPNorm. TODO: modularise
73 with m.If(~self.i.out_do_z):
74 with m.If(decrease_a):
75 # *sigh* not entirely obvious: count leading zeros (clz)
76 # with a PriorityEncoder: to find from the MSB
77 # we reverse the order of the bits.
78 temp_a = Signal(mwid, reset_less=True)
79 clz_a = Signal((len(insel_a.e), True), reset_less=True)
80 m.d.comb += [
81 pe_a.i.eq(insel_a.m[::-1]), # inverted
82 clz_a.eq(pe_a.o), # count zeros from MSB down
83 temp_a.eq((insel_a.m << clz_a)), # shift mantissa UP
84 self.o.a.e.eq(insel_a.e - clz_a), # DECREASE exponent
85 self.o.a.m.eq(temp_a),
86 ]
87
88 with m.If(decrease_b):
89 # *sigh* not entirely obvious: count leading zeros (clz)
90 # with a PriorityEncoder: to find from the MSB
91 # we reverse the order of the bits.
92 temp_b = Signal(mwid, reset_less=True)
93 clz_b = Signal((len(insel_b.e), True), reset_less=True)
94 m.d.comb += [
95 pe_b.i.eq(insel_b.m[::-1]), # inverted
96 clz_b.eq(pe_b.o), # count zeros from MSB down
97 temp_b.eq((insel_b.m << clz_b)), # shift mantissa UP
98 self.o.b.e.eq(insel_b.e - clz_b), # DECREASE exponent
99 self.o.b.m.eq(temp_b),
100 ]
101
102 m.d.comb += self.o.ctx.eq(self.i.ctx)
103 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
104 m.d.comb += self.o.oz.eq(self.i.oz)
105
106 return m
107
108