big (single-purpose) update: move width arg into pspec
[ieee754fpu.git] / src / ieee754 / fpcommon / denorm.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, Elaboratable
6 from nmigen.cli import main, verilog
7 from math import log
8
9 from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPNumBaseRecord
10 from ieee754.fpcommon.fpbase import FPState, FPNumBase
11 from ieee754.fpcommon.getop import FPPipeContext
12
13
14 class FPSCData:
15
16 def __init__(self, pspec, m_extra):
17 width = pspec['width']
18 # NOTE: difference between z and oz is that oz is created by
19 # special-cases module(s) and will propagate, along with its
20 # "bypass" signal out_do_z, through the pipeline, *disabling*
21 # all processing of all subsequent stages.
22 self.a = FPNumBaseRecord(width, m_extra) # operand a
23 self.b = FPNumBaseRecord(width, m_extra) # operand b
24 self.z = FPNumBaseRecord(width, False) # denormed result
25 self.oz = Signal(width, reset_less=True) # "finished" (bypass) result
26 self.out_do_z = Signal(reset_less=True) # "bypass" enabled
27 self.ctx = FPPipeContext(pspec)
28 self.muxid = self.ctx.muxid
29
30 def __iter__(self):
31 yield from self.a
32 yield from self.b
33 yield from self.z
34 yield self.oz
35 yield self.out_do_z
36 yield from self.ctx
37
38 def eq(self, i):
39 ret = [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
40 self.a.eq(i.a), self.b.eq(i.b), self.ctx.eq(i.ctx)]
41 return ret
42
43
44 class FPAddDeNormMod(FPState, Elaboratable):
45
46 def __init__(self, pspec, m_extra):
47 self.pspec = pspec
48 self.m_extra = m_extra
49 self.i = self.ispec()
50 self.o = self.ospec()
51
52 def ispec(self):
53 return FPSCData(self.pspec, self.m_extra)
54
55 def ospec(self):
56 return FPSCData(self.pspec, self.m_extra)
57
58 def process(self, i):
59 return self.o
60
61 def setup(self, m, i):
62 """ links module to inputs and outputs
63 """
64 m.submodules.denormalise = self
65 m.d.comb += self.i.eq(i)
66
67 def elaborate(self, platform):
68 m = Module()
69 m.submodules.denorm_in_a = in_a = FPNumBase(self.i.a)
70 m.submodules.denorm_in_b = in_b = FPNumBase(self.i.b)
71 #m.submodules.denorm_out_a = self.o.a
72 #m.submodules.denorm_out_b = self.o.b
73 #m.submodules.denorm_out_z = self.o.z
74
75 with m.If(~self.i.out_do_z):
76 # XXX hmmm, don't like repeating identical code
77 m.d.comb += self.o.a.eq(self.i.a)
78 with m.If(in_a.exp_n127):
79 m.d.comb += self.o.a.e.eq(self.i.a.N126) # limit a exponent
80 with m.Else():
81 m.d.comb += self.o.a.m[-1].eq(1) # set top mantissa bit
82
83 m.d.comb += self.o.b.eq(self.i.b)
84 with m.If(in_b.exp_n127):
85 m.d.comb += self.o.b.e.eq(self.i.b.N126) # limit a exponent
86 with m.Else():
87 m.d.comb += self.o.b.m[-1].eq(1) # set top mantissa bit
88
89 m.d.comb += self.o.ctx.eq(self.i.ctx)
90 m.d.comb += self.o.z.eq(self.i.z)
91 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
92 m.d.comb += self.o.oz.eq(self.i.oz)
93
94 return m
95
96
97 class FPAddDeNorm(FPState):
98
99 def __init__(self, width, id_wid):
100 FPState.__init__(self, "denormalise")
101 self.mod = FPAddDeNormMod(width)
102 self.out_a = FPNumBaseRecord(width)
103 self.out_b = FPNumBaseRecord(width)
104
105 def setup(self, m, i):
106 """ links module to inputs and outputs
107 """
108 self.mod.setup(m, i)
109
110 m.d.sync += self.out_a.eq(self.mod.out_a)
111 m.d.sync += self.out_b.eq(self.mod.out_b)
112
113 def action(self, m):
114 # Denormalised Number checks
115 m.next = "align"
116
117