5bd0a3a816eaa53b50396f1ac4cc792c26cc4202
[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.eq(self.i)
64
65 # normalisation increase/decrease conditions
66 decrease_a = Signal(reset_less=True)
67 decrease_b = Signal(reset_less=True)
68 m.d.comb += decrease_a.eq(insel_a.m_msbzero)
69 m.d.comb += decrease_b.eq(insel_b.m_msbzero)
70
71 # ok this is near-identical to FPNorm. TODO: modularise
72 with m.If(~self.i.out_do_z):
73 with m.If(decrease_a):
74 # *sigh* not entirely obvious: count leading zeros (clz)
75 # with a PriorityEncoder: to find from the MSB
76 # we reverse the order of the bits.
77 temp_a = Signal(mwid, reset_less=True)
78 clz_a = Signal((len(insel_a.e), True), reset_less=True)
79 m.d.comb += [
80 pe_a.i.eq(insel_a.m[::-1]), # inverted
81 clz_a.eq(pe_a.o), # count zeros from MSB down
82 temp_a.eq((insel_a.m << clz_a)), # shift mantissa UP
83 self.o.a.e.eq(insel_a.e - clz_a), # DECREASE exponent
84 self.o.a.m.eq(temp_a),
85 ]
86
87 with m.If(decrease_b):
88 # *sigh* not entirely obvious: count leading zeros (clz)
89 # with a PriorityEncoder: to find from the MSB
90 # we reverse the order of the bits.
91 temp_b = Signal(mwid, reset_less=True)
92 clz_b = Signal((len(insel_b.e), True), reset_less=True)
93 m.d.comb += [
94 pe_b.i.eq(insel_b.m[::-1]), # inverted
95 clz_b.eq(pe_b.o), # count zeros from MSB down
96 temp_b.eq((insel_b.m << clz_b)), # shift mantissa UP
97 self.o.b.e.eq(insel_b.e - clz_b), # DECREASE exponent
98 self.o.b.m.eq(temp_b),
99 ]
100
101 #m.d.comb += self.o.roundz.eq(of.roundz_out)
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