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
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 nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
26 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
27 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
29 from ieee754
.fpcommon
.fpbase
import FPState
, FPID
30 from ieee754
.fpcommon
.getop
import FPADDBaseData
33 class FPCVTSpecialCasesMod(Elaboratable
):
34 """ special cases: NaNs, infs, zeros, denormalised
35 see "Special Operations"
36 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
39 def __init__(self
, in_width
, out_width
, pspec
):
40 self
.in_width
= in_width
41 self
.out_width
= out_width
47 return FPADDBaseData(self
.in_width
, self
.pspec
)
50 return FPAddStage1Data(self
.in_width
, self
.pspec
)
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 a1
= FPNumBaseRecord(self
.width
, False)
68 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
69 m
.d
.comb
+= [a1
.v
.eq(self
.i
.a
),
74 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
75 exp_gt127
= Signal(reset_less
=True)
76 m
.d
.comb
+= exp_sub_n126
.eq(a1
.e
- z1
.fp
.N126
)
77 m
.d
.comb
+= exp_gt127
.eq(a1
.e
> z1
.fp
.P127
)
79 # if a zero, return zero (signed)
80 with m
.If(a1
.exp_n127
):
81 m
.d
.comb
+= self
.o
.z
.zero(a1
.s
)
83 # if a range within z min range (-126)
84 with m
.Elif(exp_sub_n126
< 0):
85 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
:])
86 m
.d
.comb
+= self
.o
.of
.guard
.eq(a1
.m
[-self
.o
.z
.rmw
-1])
87 m
.d
.comb
+= self
.o
.of
.round.eq(a1
.m
[-self
.o
.z
.rmw
-2])
88 m
.d
.comb
+= self
.o
.of
.sticky
.eq(a1
.m
[-self
.o
.z
.rmw
-2:] != 0)
90 # if a is inf return inf
91 with m
.Elif(a1
.is_inf
):
92 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
94 # if a is NaN return NaN
95 with m
.Elif(a1
.is_nan
):
96 m
.d
.comb
+= self
.o
.z
.nan(a1
.s
)
98 # if a mantissa greater than 127, return inf
99 with m
.Elif(exp_gt127
):
100 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
102 # ok after all that, anything else should fit fine (whew)
104 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
:])
106 # copy the context (muxid, operator)
107 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
112 class FPCVTSpecialCases(FPState
):
113 """ special cases: NaNs, infs, zeros, denormalised
116 def __init__(self
, width
, id_wid
):
117 FPState
.__init
__(self
, "special_cases")
118 self
.mod
= FPCVTSpecialCasesMod(width
)
119 self
.out_z
= self
.mod
.ospec()
120 self
.out_do_z
= Signal(reset_less
=True)
122 def setup(self
, m
, i
):
123 """ links module to inputs and outputs
125 self
.mod
.setup(m
, i
, self
.out_do_z
)
126 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
127 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and context)
131 with m
.If(self
.out_do_z
):
134 m
.next
= "denormalise"
137 class FPCVTSpecialCasesDeNorm(FPState
, SimpleHandshake
):
138 """ special cases: NaNs, infs, zeros, denormalised
141 def __init__(self
, width
, pspec
):
142 FPState
.__init
__(self
, "special_cases")
145 sc
= FPCVTSpecialCasesMod(self
.width
, self
.pspec
)
146 SimpleHandshake
.__init
__(self
, sc
)
147 self
.out
= self
.ospec()
150 class FPCVTBasePipe(ControlBase
):
151 def __init__(self
, in_width
, out_width
, in_pspec
, out_pspec
):
152 ControlBase
.__init
__(self
)
153 self
.pipe1
= FPCVTSpecialCasesDeNorm(in_width
, out_width
, in_pspec
)
154 self
.pipe2
= FPNormToPack(out_width
, out_pspec
)
156 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
])
158 def elaborate(self
, platform
):
159 m
= ControlBase
.elaborate(self
, platform
)
160 m
.submodules
.scnorm
= self
.pipe1
161 m
.submodules
.normpack
= self
.pipe2
162 m
.d
.comb
+= self
._eqs
166 class FPCVTMuxInOut(ReservationStations
):
167 """ Reservation-Station version of FPCVT pipeline.
169 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
170 * 2-stage multiplier pipeline
171 * fan-out on outputs (an array of FPPackData: z,mid)
173 Fan-in and Fan-out are combinatorial.
175 def __init__(self
, in_width
, out_width
, num_rows
, op_wid
=0):
176 self
.in_width
= in_width
177 self
.out_width
= out_width
179 self
.id_wid
= num_bits(in_width
)
180 self
.out_id_wid
= num_bits(out_width
)
183 self
.in_pspec
['id_wid'] = self
.id_wid
184 self
.in_pspec
['op_wid'] = self
.op_wid
187 self
.out_pspec
['id_wid'] = self
.out_id_wid
188 self
.out_pspec
['op_wid'] = self
.op_wid
190 self
.alu
= FPCVTBasePipe(width
, self
.in_pspec
, self
.out_pspec
)
191 ReservationStations
.__init
__(self
, num_rows
)
194 return FPADDBaseData(self
.in_width
, self
.in_pspec
)
197 return FPPackData(self
.out_width
, self
.out_pspec
)