split out prenormalisation to separate module
[ieee754fpu.git] / src / add / fpcommon / prenormalise.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat, Mux, Array, Const
6 from nmigen.lib.coding import PriorityEncoder
7 from nmigen.cli import main, verilog
8 from math import log
9
10 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
11 from fpbase import MultiShiftRMerge, Trigger
12 from singlepipe import (ControlBase, StageChain, UnbufferedPipeline,
13 PassThroughStage)
14 from multipipe import CombMuxOutPipe
15 from multipipe import PriorityCombMuxInPipe
16
17 from fpbase import FPState
18 from fpcommon.getop import (FPGetOpMod, FPGetOp, FPNumBase2Ops, FPADDBaseData, FPGet2OpMod, FPGet2Op)
19 from fpcommon.denorm import (FPSCData, FPAddDeNormMod, FPAddDeNorm)
20
21
22 class FPNormaliseModSingle:
23
24 def __init__(self, width):
25 self.width = width
26 self.in_z = self.ispec()
27 self.out_z = self.ospec()
28
29 def ispec(self):
30 return FPNumBase(self.width, False)
31
32 def ospec(self):
33 return FPNumBase(self.width, False)
34
35 def setup(self, m, i):
36 """ links module to inputs and outputs
37 """
38 m.submodules.normalise = self
39 m.d.comb += self.i.eq(i)
40
41 def elaborate(self, platform):
42 m = Module()
43
44 mwid = self.out_z.m_width+2
45 pe = PriorityEncoder(mwid)
46 m.submodules.norm_pe = pe
47
48 m.submodules.norm1_out_z = self.out_z
49 m.submodules.norm1_in_z = self.in_z
50
51 in_z = FPNumBase(self.width, False)
52 in_of = Overflow()
53 m.submodules.norm1_insel_z = in_z
54 m.submodules.norm1_insel_overflow = in_of
55
56 espec = (len(in_z.e), True)
57 ediff_n126 = Signal(espec, reset_less=True)
58 msr = MultiShiftRMerge(mwid, espec)
59 m.submodules.multishift_r = msr
60
61 m.d.comb += in_z.eq(self.in_z)
62 m.d.comb += in_of.eq(self.in_of)
63 # initialise out from in (overridden below)
64 m.d.comb += self.out_z.eq(in_z)
65 m.d.comb += self.out_of.eq(in_of)
66 # normalisation decrease condition
67 decrease = Signal(reset_less=True)
68 m.d.comb += decrease.eq(in_z.m_msbzero)
69 # decrease exponent
70 with m.If(decrease):
71 # *sigh* not entirely obvious: count leading zeros (clz)
72 # with a PriorityEncoder: to find from the MSB
73 # we reverse the order of the bits.
74 temp_m = Signal(mwid, reset_less=True)
75 temp_s = Signal(mwid+1, reset_less=True)
76 clz = Signal((len(in_z.e), True), reset_less=True)
77 m.d.comb += [
78 # cat round and guard bits back into the mantissa
79 temp_m.eq(Cat(in_of.round_bit, in_of.guard, in_z.m)),
80 pe.i.eq(temp_m[::-1]), # inverted
81 clz.eq(pe.o), # count zeros from MSB down
82 temp_s.eq(temp_m << clz), # shift mantissa UP
83 self.out_z.e.eq(in_z.e - clz), # DECREASE exponent
84 self.out_z.m.eq(temp_s[2:]), # exclude bits 0&1
85 ]
86
87 return m
88
89