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 m
.d
.comb
+= self
.o
.z
.s
.eq(a1
.s
)
80 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
81 exp_gt127
= Signal(reset_less
=True)
82 # constants from z1, at the bit-width of a1.
83 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
84 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
85 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
86 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> P127
)
88 # if a zero, return zero (signed)
89 with m
.If(a1
.exp_n127
):
90 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
91 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
93 # if a range outside z's min range (-126)
94 with m
.Elif(exp_sub_n126
< 0):
95 m
.d
.comb
+= self
.o
.z
.e
.eq(a1
.e
)
96 m
.d
.comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
97 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[-self
.o
.z
.rmw
-2])
98 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[-self
.o
.z
.rmw
-3])
99 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:-self
.o
.z
.rmw
-3] != 0)
101 # if a is inf return inf
102 with m
.Elif(a1
.is_inf
):
103 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
104 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
106 # if a is NaN return NaN
107 with m
.Elif(a1
.is_nan
):
108 m
.d
.comb
+= self
.o
.z
.nan(a1
.s
)
109 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
111 # if a mantissa greater than 127, return inf
112 with m
.Elif(exp_gt127
):
113 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
114 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
116 # ok after all that, anything else should fit fine (whew)
118 m
.d
.comb
+= self
.o
.z
.e
.eq(a1
.e
)
119 print ("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
120 print ("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
121 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
122 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
124 # copy the context (muxid, operator)
125 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
126 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
131 class FPCVTSpecialCases(FPState
):
132 """ special cases: NaNs, infs, zeros, denormalised
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)
141 def setup(self
, m
, i
):
142 """ links module to inputs and outputs
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)
150 with m
.If(self
.out_do_z
):
153 m
.next
= "denormalise"
156 class FPCVTSpecialCasesDeNorm(FPState
, SimpleHandshake
):
157 """ special cases: NaNs, infs, zeros, denormalised
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)
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
)
173 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
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
183 class FPCVTMuxInOut(ReservationStations
):
184 """ Reservation-Station version of FPCVT pipeline.
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)
190 Fan-in and Fan-out are combinatorial.
192 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
194 self
.id_wid
= num_bits(in_width
)
195 self
.out_id_wid
= num_bits(out_width
)
198 self
.in_pspec
['id_wid'] = self
.id_wid
199 self
.in_pspec
['op_wid'] = self
.op_wid
200 self
.in_pspec
['width'] = in_width
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
207 self
.alu
= FPCVTBasePipe(self
.in_pspec
, self
.out_pspec
)
208 ReservationStations
.__init
__(self
, num_rows
)
211 return FPADDBaseData(self
.in_pspec
)
214 return FPPackData(self
.out_pspec
)