big (single-purpose) update: move width arg into pspec
[ieee754fpu.git] / src / ieee754 / fcvt / pipeline.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
6 from nmigen.cli import main, verilog
7
8 from nmutil.singlepipe import ControlBase
9 from nmutil.concurrentunit import ReservationStations, num_bits
10
11 from ieee754.fpcommon.getop import FPADDBaseData
12 from ieee754.fpcommon.denorm import FPSCData
13 from ieee754.fpcommon.pack import FPPackData
14 from ieee754.fpcommon.normtopack import FPNormToPack
15 from ieee754.fpcommon.postcalc import FPAddStage1Data
16
17
18 from nmigen import Module, Signal, Elaboratable
19 from math import log
20
21 from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPNumBaseRecord
22 from ieee754.fpcommon.fpbase import FPState, FPNumBase
23 from ieee754.fpcommon.getop import FPPipeContext
24
25 from nmigen import Module, Signal, Cat, Const, Elaboratable
26
27 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
28 from nmutil.singlepipe import SimpleHandshake, StageChain
29
30 from ieee754.fpcommon.fpbase import FPState, FPID
31 from ieee754.fpcommon.getop import FPADDBaseData
32
33
34 class FPCVTSpecialCasesMod(Elaboratable):
35 """ special cases: NaNs, infs, zeros, denormalised
36 see "Special Operations"
37 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
38 """
39
40 def __init__(self, in_pspec, out_pspec):
41 self.in_pspec = in_pspec
42 self.out_pspec = out_pspec
43 self.i = self.ispec()
44 self.o = self.ospec()
45
46 def ispec(self):
47 return FPADDBaseData(self.in_pspec)
48
49 def ospec(self):
50 return FPAddStage1Data(self.out_pspec)
51
52 def setup(self, m, i):
53 """ links module to inputs and outputs
54 """
55 m.submodules.specialcases = self
56 m.d.comb += self.i.eq(i)
57
58 def process(self, i):
59 return self.o
60
61 def elaborate(self, platform):
62 m = Module()
63
64 #m.submodules.sc_out_z = self.o.z
65
66 # decode: XXX really should move to separate stage
67 print ("in_width out", self.in_pspec['width'],
68 self.out_pspec['width'])
69 a1 = FPNumBaseRecord(self.in_pspec['width'], False)
70 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
71 m.d.comb += a1.v.eq(self.i.a)
72 z1 = self.o.z
73
74 # set sign
75 m.d.comb += self.o.z.s.eq(a1.s)
76
77 # intermediaries
78 exp_sub_n126 = Signal((a1.e_width, True), reset_less=True)
79 exp_gt127 = Signal(reset_less=True)
80 # constants from z1, at the bit-width of a1.
81 N126 = Const(z1.fp.N126.value, (a1.e_width, True))
82 P127 = Const(z1.fp.P127.value, (a1.e_width, True))
83 m.d.comb += exp_sub_n126.eq(a1.e - N126)
84 m.d.comb += exp_gt127.eq(a1.e > P127)
85
86 # if a zero, return zero (signed)
87 with m.If(a1.exp_n127):
88 _, ze, zm = self.o.z._zero(a1.s)
89 m.d.comb += self.o.z.e.eq(ze)
90 m.d.comb += self.o.z.m.eq(zm)
91
92 # if a range within z min range (-126)
93 with m.Elif(exp_sub_n126 < 0):
94 m.d.comb += self.o.z.e.eq(a1.e)
95 m.d.comb += self.o.z.m.eq(a1.m[-self.o.z.rmw:])
96 m.d.comb += self.o.of.guard.eq(a1.m[-self.o.z.rmw-1])
97 m.d.comb += self.o.of.round_bit.eq(a1.m[-self.o.z.rmw-2])
98 m.d.comb += self.o.of.sticky.eq(a1.m[:-self.o.z.rmw-2] != 0)
99
100 # if a is inf return inf
101 with m.Elif(a1.is_inf):
102 _, ze, zm = self.o.z._inf(a1.s)
103 m.d.comb += self.o.z.e.eq(ze)
104 m.d.comb += self.o.z.m.eq(zm)
105
106 # if a is NaN return NaN
107 with m.Elif(a1.is_nan):
108 _, ze, zm = self.o.z._nan(a1.s)
109 m.d.comb += self.o.z.e.eq(ze)
110 m.d.comb += self.o.z.m.eq(zm)
111
112 # if a mantissa greater than 127, return inf
113 with m.Elif(exp_gt127):
114 _, ze, zm = self.o.z._inf(a1.s)
115 m.d.comb += self.o.z.e.eq(ze)
116 m.d.comb += self.o.z.m.eq(zm)
117
118 # ok after all that, anything else should fit fine (whew)
119 with m.Else():
120 m.d.comb += self.o.z.e.eq(a1.e)
121 print ("alen", a1.e_start, z1.fp.N126, N126)
122 print ("m1", self.o.z.rmw, a1.m[-self.o.z.rmw:])
123 m.d.comb += self.o.z.m.eq(a1.m[-self.o.z.rmw:])
124
125 # copy the context (muxid, operator)
126 m.d.comb += self.o.ctx.eq(self.i.ctx)
127
128 return m
129
130
131 class FPCVTSpecialCases(FPState):
132 """ special cases: NaNs, infs, zeros, denormalised
133 """
134
135 def __init__(self, in_width, out_width, id_wid):
136 FPState.__init__(self, "special_cases")
137 self.mod = FPCVTSpecialCasesMod(in_width, out_width)
138 self.out_z = self.mod.ospec()
139 self.out_do_z = Signal(reset_less=True)
140
141 def setup(self, m, i):
142 """ links module to inputs and outputs
143 """
144 self.mod.setup(m, i, self.out_do_z)
145 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
146 m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context)
147
148 def action(self, m):
149 self.idsync(m)
150 with m.If(self.out_do_z):
151 m.next = "put_z"
152 with m.Else():
153 m.next = "denormalise"
154
155
156 class FPCVTSpecialCasesDeNorm(FPState, SimpleHandshake):
157 """ special cases: NaNs, infs, zeros, denormalised
158 """
159
160 def __init__(self, in_pspec, out_pspec):
161 FPState.__init__(self, "special_cases")
162 sc = FPCVTSpecialCasesMod(in_pspec, out_pspec)
163 SimpleHandshake.__init__(self, sc)
164 self.out = self.ospec(None)
165
166
167 class FPCVTBasePipe(ControlBase):
168 def __init__(self, in_pspec, out_pspec):
169 ControlBase.__init__(self)
170 self.pipe1 = FPCVTSpecialCasesDeNorm(in_pspec, out_pspec)
171 self.pipe2 = FPNormToPack(out_pspec)
172
173 self._eqs = self.connect([self.pipe1, self.pipe2])
174
175 def elaborate(self, platform):
176 m = ControlBase.elaborate(self, platform)
177 m.submodules.scnorm = self.pipe1
178 m.submodules.normpack = self.pipe2
179 m.d.comb += self._eqs
180 return m
181
182
183 class FPCVTMuxInOut(ReservationStations):
184 """ Reservation-Station version of FPCVT pipeline.
185
186 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
187 * 2-stage multiplier pipeline
188 * fan-out on outputs (an array of FPPackData: z,mid)
189
190 Fan-in and Fan-out are combinatorial.
191 """
192 def __init__(self, in_width, out_width, num_rows, op_wid=0):
193 self.op_wid = op_wid
194 self.id_wid = num_bits(in_width)
195 self.out_id_wid = num_bits(out_width)
196
197 self.in_pspec = {}
198 self.in_pspec['id_wid'] = self.id_wid
199 self.in_pspec['op_wid'] = self.op_wid
200 self.in_pspec['width'] = self.in_width
201
202 self.out_pspec = {}
203 self.out_pspec['id_wid'] = self.out_id_wid
204 self.out_pspec['op_wid'] = op_wid
205 self.out_pspec['width'] = out_width
206
207 self.alu = FPCVTBasePipe(self.in_pspec, self.out_pspec)
208 ReservationStations.__init__(self, num_rows)
209
210 def i_specfn(self):
211 return FPADDBaseData(self.in_pspec)
212
213 def o_specfn(self):
214 return FPPackData(self.out_pspec)