1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
6 from nmigen
.cli
import main
, verilog
8 from nmutil
.singlepipe
import ControlBase
9 from nmutil
.concurrentunit
import ReservationStations
, num_bits
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
18 from nmigen
import Module
, Signal
, Elaboratable
21 from ieee754
.fpcommon
.fpbase
import FPNumIn
, FPNumOut
, FPNumBaseRecord
22 from ieee754
.fpcommon
.fpbase
import FPState
, FPNumBase
23 from ieee754
.fpcommon
.getop
import FPPipeContext
25 from nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
27 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
28 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
30 from ieee754
.fpcommon
.fpbase
import FPState
, FPID
31 from ieee754
.fpcommon
.getop
import FPADDBaseData
34 class FPCVTSpecialCasesMod(Elaboratable
):
35 """ special cases: NaNs, infs, zeros, denormalised
36 see "Special Operations"
37 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
40 def __init__(self
, in_pspec
, out_pspec
):
41 self
.in_pspec
= in_pspec
42 self
.out_pspec
= out_pspec
47 return FPADDBaseData(self
.in_pspec
)
50 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
52 def setup(self
, m
, i
):
53 """ links module to inputs and outputs
55 m
.submodules
.specialcases
= self
56 m
.d
.comb
+= self
.i
.eq(i
)
61 def elaborate(self
, platform
):
64 #m.submodules.sc_out_z = self.o.z
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 print ("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
71 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
72 m
.d
.comb
+= a1
.v
.eq(self
.i
.a
)
74 print ("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
77 ms
= a1
.rmw
- self
.o
.z
.rmw
78 print ("ms-me", ms
, me
)
81 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
82 exp_gt127
= Signal(reset_less
=True)
83 # constants from z1, at the bit-width of a1.
84 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
85 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
86 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
87 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> P127
)
89 # if a zero, return zero (signed)
90 with m
.If(a1
.exp_n127
):
91 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
92 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
94 # if a range outside z's min range (-126)
95 with m
.Elif(exp_sub_n126
< 0):
96 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
97 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
98 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
99 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
101 m
.d
.comb
+= self
.o
.z
.s
.eq(a1
.s
)
102 m
.d
.comb
+= self
.o
.z
.e
.eq(a1
.e
)
103 m
.d
.comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
104 m
.d
.comb
+= self
.o
.z
.m
[-1].eq(1)
106 # if a is inf return inf
107 with m
.Elif(a1
.is_inf
):
108 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
109 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
111 # if a is NaN return NaN
112 with m
.Elif(a1
.is_nan
):
113 m
.d
.comb
+= self
.o
.z
.nan(0)
114 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
116 # if a mantissa greater than 127, return inf
117 with m
.Elif(exp_gt127
):
118 print ("inf", self
.o
.z
.inf(a1
.s
))
119 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
120 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
122 # ok after all that, anything else should fit fine (whew)
124 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
125 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
126 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
127 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
129 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
130 print ("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
131 print ("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
132 mo
= Signal(self
.o
.z
.m_width
-1)
133 m
.d
.comb
+= mo
.eq(a1
.m
[ms
:me
])
134 with m
.If(self
.o
.of
.roundz
):
135 with m
.If((~mo
== 0)): # all 1s
136 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
138 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
140 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
141 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
143 # copy the context (muxid, operator)
144 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
145 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
150 class FPCVTSpecialCases(FPState
):
151 """ special cases: NaNs, infs, zeros, denormalised
154 def __init__(self
, in_width
, out_width
, id_wid
):
155 FPState
.__init
__(self
, "special_cases")
156 self
.mod
= FPCVTSpecialCasesMod(in_width
, out_width
)
157 self
.out_z
= self
.mod
.ospec()
158 self
.out_do_z
= Signal(reset_less
=True)
160 def setup(self
, m
, i
):
161 """ links module to inputs and outputs
163 self
.mod
.setup(m
, i
, self
.out_do_z
)
164 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
165 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and context)
169 with m
.If(self
.out_do_z
):
172 m
.next
= "denormalise"
175 class FPCVTSpecialCasesDeNorm(FPState
, SimpleHandshake
):
176 """ special cases: NaNs, infs, zeros, denormalised
179 def __init__(self
, in_pspec
, out_pspec
):
180 FPState
.__init
__(self
, "special_cases")
181 sc
= FPCVTSpecialCasesMod(in_pspec
, out_pspec
)
182 SimpleHandshake
.__init
__(self
, sc
)
183 self
.out
= self
.ospec(None)
186 class FPCVTBasePipe(ControlBase
):
187 def __init__(self
, in_pspec
, out_pspec
):
188 ControlBase
.__init
__(self
)
189 self
.pipe1
= FPCVTSpecialCasesDeNorm(in_pspec
, out_pspec
)
190 self
.pipe2
= FPNormToPack(out_pspec
, e_extra
=True)
192 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
194 def elaborate(self
, platform
):
195 m
= ControlBase
.elaborate(self
, platform
)
196 m
.submodules
.scnorm
= self
.pipe1
197 m
.submodules
.normpack
= self
.pipe2
198 m
.d
.comb
+= self
._eqs
202 class FPCVTMuxInOut(ReservationStations
):
203 """ Reservation-Station version of FPCVT pipeline.
205 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
206 * 2-stage multiplier pipeline
207 * fan-out on outputs (an array of FPPackData: z,mid)
209 Fan-in and Fan-out are combinatorial.
211 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
213 self
.id_wid
= num_bits(in_width
)
214 self
.out_id_wid
= num_bits(out_width
)
217 self
.in_pspec
['id_wid'] = self
.id_wid
218 self
.in_pspec
['op_wid'] = self
.op_wid
219 self
.in_pspec
['width'] = in_width
222 self
.out_pspec
['id_wid'] = self
.out_id_wid
223 self
.out_pspec
['op_wid'] = op_wid
224 self
.out_pspec
['width'] = out_width
226 self
.alu
= FPCVTBasePipe(self
.in_pspec
, self
.out_pspec
)
227 ReservationStations
.__init
__(self
, num_rows
)
230 return FPADDBaseData(self
.in_pspec
)
233 return FPPackData(self
.out_pspec
)