1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
, Array
, Const
6 from nmigen
.lib
.coding
import PriorityEncoder
7 from nmigen
.cli
import main
, verilog
10 from fpbase
import FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPNumBase
11 from fpbase
import MultiShiftRMerge
, Trigger
12 from singlepipe
import (ControlBase
, StageChain
, UnbufferedPipeline
,
14 from multipipe
import CombMuxOutPipe
15 from multipipe
import PriorityCombMuxInPipe
17 from fpbase
import FPState
, FPID
18 from fpcommon
.getop
import (FPGetOpMod
, FPGetOp
, FPNumBase2Ops
, FPADDBaseData
,
19 FPGet2OpMod
, FPGet2Op
)
20 from fpadd
.specialcases
import (FPAddSpecialCasesMod
, FPAddSpecialCases
,
21 FPAddSpecialCasesDeNorm
)
22 from fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
, FPAddDeNorm
)
23 from fpcommon
.postcalc
import FPAddStage1Data
24 from fpcommon
.postnormalise
import (FPNorm1Data
, FPNorm1ModSingle
,
25 FPNorm1ModMulti
, FPNorm1Single
, FPNorm1Multi
)
26 from fpcommon
.roundz
import (FPRoundData
, FPRoundMod
, FPRound
)
27 from fpcommon
.corrections
import (FPCorrectionsMod
, FPCorrections
)
28 from fpcommon
.pack
import (FPPackData
, FPPackMod
, FPPack
)
29 from fpcommon
.normtopack
import FPNormToPack
30 from fpcommon
.putz
import (FPPutZ
, FPPutZIdx
)
35 def __init__(self
, width
, id_wid
):
36 self
.a
= FPNumIn(None, width
)
37 self
.b
= FPNumIn(None, width
)
38 self
.z
= FPNumOut(width
, False)
39 self
.out_do_z
= Signal(reset_less
=True)
40 self
.oz
= Signal(width
, reset_less
=True)
41 self
.mid
= Signal(id_wid
, reset_less
=True)
44 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
45 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
49 class FPAddAlignMultiMod(FPState
):
51 def __init__(self
, width
):
52 self
.in_a
= FPNumBase(width
)
53 self
.in_b
= FPNumBase(width
)
54 self
.out_a
= FPNumIn(None, width
)
55 self
.out_b
= FPNumIn(None, width
)
56 self
.exp_eq
= Signal(reset_less
=True)
58 def elaborate(self
, platform
):
59 # This one however (single-cycle) will do the shift
64 m
.submodules
.align_in_a
= self
.in_a
65 m
.submodules
.align_in_b
= self
.in_b
66 m
.submodules
.align_out_a
= self
.out_a
67 m
.submodules
.align_out_b
= self
.out_b
69 # NOTE: this does *not* do single-cycle multi-shifting,
70 # it *STAYS* in the align state until exponents match
72 # exponent of a greater than b: shift b down
73 m
.d
.comb
+= self
.exp_eq
.eq(0)
74 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
75 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
76 agtb
= Signal(reset_less
=True)
77 altb
= Signal(reset_less
=True)
78 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
79 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
81 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
82 # exponent of b greater than a: shift a down
84 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
85 # exponents equal: move to next stage.
87 m
.d
.comb
+= self
.exp_eq
.eq(1)
91 class FPAddAlignMulti(FPState
):
93 def __init__(self
, width
, id_wid
):
94 FPState
.__init
__(self
, "align")
95 self
.mod
= FPAddAlignMultiMod(width
)
96 self
.out_a
= FPNumIn(None, width
)
97 self
.out_b
= FPNumIn(None, width
)
98 self
.exp_eq
= Signal(reset_less
=True)
100 def setup(self
, m
, in_a
, in_b
):
101 """ links module to inputs and outputs
103 m
.submodules
.align
= self
.mod
104 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
105 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
106 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
107 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
108 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
111 with m
.If(self
.exp_eq
):
115 class FPAddAlignSingleMod
:
117 def __init__(self
, width
, id_wid
):
120 self
.i
= self
.ispec()
121 self
.o
= self
.ospec()
124 return FPSCData(self
.width
, self
.id_wid
)
127 return FPNumIn2Ops(self
.width
, self
.id_wid
)
129 def process(self
, i
):
132 def setup(self
, m
, i
):
133 """ links module to inputs and outputs
135 m
.submodules
.align
= self
136 m
.d
.comb
+= self
.i
.eq(i
)
138 def elaborate(self
, platform
):
139 """ Aligns A against B or B against A, depending on which has the
140 greater exponent. This is done in a *single* cycle using
141 variable-width bit-shift
143 the shifter used here is quite expensive in terms of gates.
144 Mux A or B in (and out) into temporaries, as only one of them
145 needs to be aligned against the other
149 m
.submodules
.align_in_a
= self
.i
.a
150 m
.submodules
.align_in_b
= self
.i
.b
151 m
.submodules
.align_out_a
= self
.o
.a
152 m
.submodules
.align_out_b
= self
.o
.b
154 # temporary (muxed) input and output to be shifted
155 t_inp
= FPNumBase(self
.width
)
156 t_out
= FPNumIn(None, self
.width
)
157 espec
= (len(self
.i
.a
.e
), True)
158 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
159 m
.submodules
.align_t_in
= t_inp
160 m
.submodules
.align_t_out
= t_out
161 m
.submodules
.multishift_r
= msr
163 ediff
= Signal(espec
, reset_less
=True)
164 ediffr
= Signal(espec
, reset_less
=True)
165 tdiff
= Signal(espec
, reset_less
=True)
166 elz
= Signal(reset_less
=True)
167 egz
= Signal(reset_less
=True)
169 # connect multi-shifter to t_inp/out mantissa (and tdiff)
170 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
171 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
172 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
173 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
174 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
176 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
177 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
178 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
179 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
181 # default: A-exp == B-exp, A and B untouched (fall through)
182 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
183 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
184 # only one shifter (muxed)
185 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
186 # exponent of a greater than b: shift b down
187 with m
.If(~self
.i
.out_do_z
):
189 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
192 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
194 # exponent of b greater than a: shift a down
196 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
199 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
202 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
203 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
204 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
205 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
210 class FPAddAlignSingle(FPState
):
212 def __init__(self
, width
, id_wid
):
213 FPState
.__init
__(self
, "align")
214 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
215 self
.out_a
= FPNumIn(None, width
)
216 self
.out_b
= FPNumIn(None, width
)
218 def setup(self
, m
, i
):
219 """ links module to inputs and outputs
223 # NOTE: could be done as comb
224 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
225 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)