1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
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
.pack
import FPPackData
13 from ieee754
.fpcommon
.normtopack
import FPNormToPack
14 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
17 from nmigen
import Module
, Signal
, Elaboratable
20 from ieee754
.fpcommon
.fpbase
import FPNumIn
, FPNumOut
, FPNumBaseRecord
21 from ieee754
.fpcommon
.fpbase
import FPState
, FPNumBase
22 from ieee754
.fpcommon
.getop
import FPPipeContext
24 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
25 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
27 from ieee754
.fpcommon
.fpbase
import FPState
28 from ieee754
.pipeline
import PipelineSpec
31 class FPCVTDownConvertMod(Elaboratable
):
32 """ special cases: NaNs, infs, zeros, denormalised
33 see "Special Operations"
34 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
37 def __init__(self
, in_pspec
, out_pspec
):
38 self
.in_pspec
= in_pspec
39 self
.out_pspec
= out_pspec
44 return FPADDBaseData(self
.in_pspec
)
47 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
49 def setup(self
, m
, i
):
50 """ links module to inputs and outputs
52 m
.submodules
.specialcases
= self
53 m
.d
.comb
+= self
.i
.eq(i
)
58 def elaborate(self
, platform
):
61 #m.submodules.sc_out_z = self.o.z
63 # decode: XXX really should move to separate stage
64 print("in_width out", self
.in_pspec
.width
,
66 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
67 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
68 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
69 m
.d
.comb
+= a1
.v
.eq(self
.i
.a
)
71 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
74 ms
= a1
.rmw
- self
.o
.z
.rmw
75 print("ms-me", ms
, me
)
78 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
79 exp_gt127
= Signal(reset_less
=True)
80 # constants from z1, at the bit-width of a1.
81 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
82 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
83 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
84 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> P127
)
86 # if a zero, return zero (signed)
87 with m
.If(a1
.exp_n127
):
88 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
89 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
91 # if a range outside z's min range (-126)
92 with m
.Elif(exp_sub_n126
< 0):
93 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
94 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
95 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
96 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
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 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
122 m
.d
.comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
123 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
124 m
.d
.comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
126 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
127 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
128 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
129 mo
= Signal(self
.o
.z
.m_width
-1)
130 m
.d
.comb
+= mo
.eq(a1
.m
[ms
:me
])
131 with m
.If(self
.o
.of
.roundz
):
132 with m
.If((~mo
== 0)): # all 1s
133 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
135 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
137 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
138 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
140 # copy the context (muxid, operator)
141 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
142 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
147 class FPCVTDownConvert(FPState
):
148 """ special cases: NaNs, infs, zeros, denormalised
151 def __init__(self
, in_width
, out_width
, id_wid
):
152 FPState
.__init
__(self
, "special_cases")
153 self
.mod
= FPCVTDownConvertMod(in_width
, out_width
)
154 self
.out_z
= self
.mod
.ospec()
155 self
.out_do_z
= Signal(reset_less
=True)
157 def setup(self
, m
, i
):
158 """ links module to inputs and outputs
160 self
.mod
.setup(m
, i
, self
.out_do_z
)
161 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
162 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and context)
166 with m
.If(self
.out_do_z
):
169 m
.next
= "denormalise"
172 class FPCVTDownConvertDeNorm(FPState
, SimpleHandshake
):
173 """ special cases: NaNs, infs, zeros, denormalised
176 def __init__(self
, in_pspec
, out_pspec
):
177 FPState
.__init
__(self
, "special_cases")
178 sc
= FPCVTDownConvertMod(in_pspec
, out_pspec
)
179 SimpleHandshake
.__init
__(self
, sc
)
180 self
.out
= self
.ospec(None)
183 class FPCVTBasePipe(ControlBase
):
184 def __init__(self
, in_pspec
, out_pspec
):
185 ControlBase
.__init
__(self
)
186 self
.pipe1
= FPCVTDownConvertDeNorm(in_pspec
, out_pspec
)
187 self
.pipe2
= FPNormToPack(out_pspec
, e_extra
=True)
189 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
191 def elaborate(self
, platform
):
192 m
= ControlBase
.elaborate(self
, platform
)
193 m
.submodules
.scnorm
= self
.pipe1
194 m
.submodules
.normpack
= self
.pipe2
195 m
.d
.comb
+= self
._eqs
199 class FPCVTMuxInOut(ReservationStations
):
200 """ Reservation-Station version of FPCVT pipeline.
202 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
203 * 2-stage multiplier pipeline
204 * fan-out on outputs (an array of FPPackData: z,mid)
206 Fan-in and Fan-out are combinatorial.
209 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
211 self
.id_wid
= num_bits(in_width
)
212 self
.out_id_wid
= num_bits(out_width
)
214 self
.in_pspec
= PipelineSpec(in_width
, self
.id_wid
, self
.op_wid
)
215 self
.out_pspec
= PipelineSpec(out_width
, self
.out_id_wid
, op_wid
)
217 self
.alu
= FPCVTBasePipe(self
.in_pspec
, self
.out_pspec
)
218 ReservationStations
.__init
__(self
, num_rows
)
221 return FPADDBaseData(self
.in_pspec
)
224 return FPPackData(self
.out_pspec
)