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
32 from ieee754
.pipeline
import PipelineSpec
35 class FPCVTSpecialCasesMod(Elaboratable
):
36 """ special cases: NaNs, infs, zeros, denormalised
37 see "Special Operations"
38 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
41 def __init__(self
, in_pspec
, out_pspec
):
42 self
.in_pspec
= in_pspec
43 self
.out_pspec
= out_pspec
48 return FPADDBaseData(self
.in_pspec
)
51 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
53 def setup(self
, m
, i
):
54 """ links module to inputs and outputs
56 m
.submodules
.specialcases
= self
57 m
.d
.comb
+= self
.i
.eq(i
)
62 def elaborate(self
, platform
):
65 #m.submodules.sc_out_z = self.o.z
67 # decode: XXX really should move to separate stage
68 print("in_width out", self
.in_pspec
.width
,
70 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
71 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
72 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
73 m
.d
.comb
+= a1
.v
.eq(self
.i
.a
)
75 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
78 ms
= a1
.rmw
- self
.o
.z
.rmw
79 print("ms-me", ms
, me
)
82 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
83 exp_gt127
= Signal(reset_less
=True)
84 # constants from z1, at the bit-width of a1.
85 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
86 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
87 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
88 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> P127
)
90 # if a zero, return zero (signed)
91 with m
.If(a1
.exp_n127
):
92 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
93 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
95 # if a range outside z's min range (-126)
96 with m
.Elif(exp_sub_n126
< 0):
97 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
98 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
99 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
100 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
102 m
.d
.comb
+= self
.o
.z
.s
.eq(a1
.s
)
103 m
.d
.comb
+= self
.o
.z
.e
.eq(a1
.e
)
104 m
.d
.comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
105 m
.d
.comb
+= self
.o
.z
.m
[-1].eq(1)
107 # if a is inf return inf
108 with m
.Elif(a1
.is_inf
):
109 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
110 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
112 # if a is NaN return NaN
113 with m
.Elif(a1
.is_nan
):
114 m
.d
.comb
+= self
.o
.z
.nan(0)
115 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
117 # if a mantissa greater than 127, return inf
118 with m
.Elif(exp_gt127
):
119 print("inf", self
.o
.z
.inf(a1
.s
))
120 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
121 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
123 # ok after all that, anything else should fit fine (whew)
125 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
126 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
127 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
128 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
130 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
131 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
132 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
133 mo
= Signal(self
.o
.z
.m_width
-1)
134 m
.d
.comb
+= mo
.eq(a1
.m
[ms
:me
])
135 with m
.If(self
.o
.of
.roundz
):
136 with m
.If((~mo
== 0)): # all 1s
137 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
139 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
141 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
142 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
144 # copy the context (muxid, operator)
145 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
146 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
151 class FPCVTSpecialCases(FPState
):
152 """ special cases: NaNs, infs, zeros, denormalised
155 def __init__(self
, in_width
, out_width
, id_wid
):
156 FPState
.__init
__(self
, "special_cases")
157 self
.mod
= FPCVTSpecialCasesMod(in_width
, out_width
)
158 self
.out_z
= self
.mod
.ospec()
159 self
.out_do_z
= Signal(reset_less
=True)
161 def setup(self
, m
, i
):
162 """ links module to inputs and outputs
164 self
.mod
.setup(m
, i
, self
.out_do_z
)
165 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
166 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and context)
170 with m
.If(self
.out_do_z
):
173 m
.next
= "denormalise"
176 class FPCVTSpecialCasesDeNorm(FPState
, SimpleHandshake
):
177 """ special cases: NaNs, infs, zeros, denormalised
180 def __init__(self
, in_pspec
, out_pspec
):
181 FPState
.__init
__(self
, "special_cases")
182 sc
= FPCVTSpecialCasesMod(in_pspec
, out_pspec
)
183 SimpleHandshake
.__init
__(self
, sc
)
184 self
.out
= self
.ospec(None)
187 class FPCVTBasePipe(ControlBase
):
188 def __init__(self
, in_pspec
, out_pspec
):
189 ControlBase
.__init
__(self
)
190 self
.pipe1
= FPCVTSpecialCasesDeNorm(in_pspec
, out_pspec
)
191 self
.pipe2
= FPNormToPack(out_pspec
, e_extra
=True)
193 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
195 def elaborate(self
, platform
):
196 m
= ControlBase
.elaborate(self
, platform
)
197 m
.submodules
.scnorm
= self
.pipe1
198 m
.submodules
.normpack
= self
.pipe2
199 m
.d
.comb
+= self
._eqs
203 class FPCVTMuxInOut(ReservationStations
):
204 """ Reservation-Station version of FPCVT pipeline.
206 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
207 * 2-stage multiplier pipeline
208 * fan-out on outputs (an array of FPPackData: z,mid)
210 Fan-in and Fan-out are combinatorial.
213 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
215 self
.id_wid
= num_bits(in_width
)
216 self
.out_id_wid
= num_bits(out_width
)
218 self
.in_pspec
= PipelineSpec(in_width
, self
.id_wid
, self
.op_wid
)
219 self
.out_pspec
= PipelineSpec(out_width
, self
.out_id_wid
, op_wid
)
221 self
.alu
= FPCVTBasePipe(self
.in_pspec
, self
.out_pspec
)
222 ReservationStations
.__init
__(self
, num_rows
)
225 return FPADDBaseData(self
.in_pspec
)
228 return FPPackData(self
.out_pspec
)