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 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
78 exp_gt127
= Signal(reset_less
=True)
79 # constants from z1, at the bit-width of a1.
80 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
81 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
82 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
83 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> P127
)
86 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[-self
.o
.z
.rmw
-2])
87 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[-self
.o
.z
.rmw
-3])
88 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:-self
.o
.z
.rmw
-1] != 0)
89 m
.d
.comb
+= self
.o
.of
.m0
.eq(self
.o
.z
.m
[0])
91 # if a zero, return zero (signed)
92 with m
.If(a1
.exp_n127
):
93 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
94 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
96 # if a range outside z's min range (-126)
97 with m
.Elif(exp_sub_n126
< 0):
98 m
.d
.comb
+= self
.o
.z
.s
.eq(a1
.s
)
99 m
.d
.comb
+= self
.o
.z
.e
.eq(a1
.e
)
100 m
.d
.comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
101 m
.d
.comb
+= self
.o
.z
.m
[-1].eq(1)
103 # if a is inf return inf
104 with m
.Elif(a1
.is_inf
):
105 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
106 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
108 # if a is NaN return NaN
109 with m
.Elif(a1
.is_nan
):
110 m
.d
.comb
+= self
.o
.z
.nan(0)
111 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
113 # if a mantissa greater than 127, return inf
114 with m
.Elif(exp_gt127
):
115 print ("inf", self
.o
.z
.inf(a1
.s
))
116 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
117 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
119 # ok after all that, anything else should fit fine (whew)
121 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
122 print ("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
123 print ("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
124 mo
= Signal(self
.o
.z
.m_width
-1)
125 m
.d
.comb
+= mo
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
126 with m
.If(self
.o
.of
.roundz
):
127 with m
.If((~mo
== 0)): # all 1s
128 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
130 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
132 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
133 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
135 # copy the context (muxid, operator)
136 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
137 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
142 class FPCVTSpecialCases(FPState
):
143 """ special cases: NaNs, infs, zeros, denormalised
146 def __init__(self
, in_width
, out_width
, id_wid
):
147 FPState
.__init
__(self
, "special_cases")
148 self
.mod
= FPCVTSpecialCasesMod(in_width
, out_width
)
149 self
.out_z
= self
.mod
.ospec()
150 self
.out_do_z
= Signal(reset_less
=True)
152 def setup(self
, m
, i
):
153 """ links module to inputs and outputs
155 self
.mod
.setup(m
, i
, self
.out_do_z
)
156 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
157 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and context)
161 with m
.If(self
.out_do_z
):
164 m
.next
= "denormalise"
167 class FPCVTSpecialCasesDeNorm(FPState
, SimpleHandshake
):
168 """ special cases: NaNs, infs, zeros, denormalised
171 def __init__(self
, in_pspec
, out_pspec
):
172 FPState
.__init
__(self
, "special_cases")
173 sc
= FPCVTSpecialCasesMod(in_pspec
, out_pspec
)
174 SimpleHandshake
.__init
__(self
, sc
)
175 self
.out
= self
.ospec(None)
178 class FPCVTBasePipe(ControlBase
):
179 def __init__(self
, in_pspec
, out_pspec
):
180 ControlBase
.__init
__(self
)
181 self
.pipe1
= FPCVTSpecialCasesDeNorm(in_pspec
, out_pspec
)
182 self
.pipe2
= FPNormToPack(out_pspec
, e_extra
=True)
184 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
186 def elaborate(self
, platform
):
187 m
= ControlBase
.elaborate(self
, platform
)
188 m
.submodules
.scnorm
= self
.pipe1
189 m
.submodules
.normpack
= self
.pipe2
190 m
.d
.comb
+= self
._eqs
194 class FPCVTMuxInOut(ReservationStations
):
195 """ Reservation-Station version of FPCVT pipeline.
197 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
198 * 2-stage multiplier pipeline
199 * fan-out on outputs (an array of FPPackData: z,mid)
201 Fan-in and Fan-out are combinatorial.
203 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
205 self
.id_wid
= num_bits(in_width
)
206 self
.out_id_wid
= num_bits(out_width
)
209 self
.in_pspec
['id_wid'] = self
.id_wid
210 self
.in_pspec
['op_wid'] = self
.op_wid
211 self
.in_pspec
['width'] = in_width
214 self
.out_pspec
['id_wid'] = self
.out_id_wid
215 self
.out_pspec
['op_wid'] = op_wid
216 self
.out_pspec
['width'] = out_width
218 self
.alu
= FPCVTBasePipe(self
.in_pspec
, self
.out_pspec
)
219 ReservationStations
.__init
__(self
, num_rows
)
222 return FPADDBaseData(self
.in_pspec
)
225 return FPPackData(self
.out_pspec
)