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