381df1e5d7c38b44349c9b93c2cc176ed82d141f
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
6 from nmigen
.cli
import main
, verilog
8 from ieee754
.fpcommon
.fpbase
import FPNumOut
, FPNumIn
, FPNumBase
9 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
10 from ieee754
.fpcommon
.fpbase
import FPState
11 from ieee754
.fpcommon
.denorm
import FPSCData
16 def __init__(self
, width
, id_wid
):
17 self
.a
= FPNumIn(None, width
)
18 self
.b
= FPNumIn(None, width
)
19 self
.z
= FPNumOut(width
, False)
20 self
.out_do_z
= Signal(reset_less
=True)
21 self
.oz
= Signal(width
, reset_less
=True)
22 self
.mid
= Signal(id_wid
, reset_less
=True)
25 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
26 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
30 class FPAddAlignMultiMod(FPState
):
32 def __init__(self
, width
):
33 self
.in_a
= FPNumBase(width
)
34 self
.in_b
= FPNumBase(width
)
35 self
.out_a
= FPNumIn(None, width
)
36 self
.out_b
= FPNumIn(None, width
)
37 self
.exp_eq
= Signal(reset_less
=True)
39 def elaborate(self
, platform
):
40 # This one however (single-cycle) will do the shift
45 m
.submodules
.align_in_a
= self
.in_a
46 m
.submodules
.align_in_b
= self
.in_b
47 m
.submodules
.align_out_a
= self
.out_a
48 m
.submodules
.align_out_b
= self
.out_b
50 # NOTE: this does *not* do single-cycle multi-shifting,
51 # it *STAYS* in the align state until exponents match
53 # exponent of a greater than b: shift b down
54 m
.d
.comb
+= self
.exp_eq
.eq(0)
55 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
56 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
57 agtb
= Signal(reset_less
=True)
58 altb
= Signal(reset_less
=True)
59 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
60 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
62 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
63 # exponent of b greater than a: shift a down
65 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
66 # exponents equal: move to next stage.
68 m
.d
.comb
+= self
.exp_eq
.eq(1)
72 class FPAddAlignMulti(FPState
):
74 def __init__(self
, width
, id_wid
):
75 FPState
.__init
__(self
, "align")
76 self
.mod
= FPAddAlignMultiMod(width
)
77 self
.out_a
= FPNumIn(None, width
)
78 self
.out_b
= FPNumIn(None, width
)
79 self
.exp_eq
= Signal(reset_less
=True)
81 def setup(self
, m
, in_a
, in_b
):
82 """ links module to inputs and outputs
84 m
.submodules
.align
= self
.mod
85 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
86 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
87 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
88 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
89 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
92 with m
.If(self
.exp_eq
):
96 class FPAddAlignSingleMod
:
98 def __init__(self
, width
, id_wid
):
101 self
.i
= self
.ispec()
102 self
.o
= self
.ospec()
105 return FPSCData(self
.width
, self
.id_wid
)
108 return FPNumIn2Ops(self
.width
, self
.id_wid
)
110 def process(self
, i
):
113 def setup(self
, m
, i
):
114 """ links module to inputs and outputs
116 m
.submodules
.align
= self
117 m
.d
.comb
+= self
.i
.eq(i
)
119 def elaborate(self
, platform
):
120 """ Aligns A against B or B against A, depending on which has the
121 greater exponent. This is done in a *single* cycle using
122 variable-width bit-shift
124 the shifter used here is quite expensive in terms of gates.
125 Mux A or B in (and out) into temporaries, as only one of them
126 needs to be aligned against the other
130 m
.submodules
.align_in_a
= self
.i
.a
131 m
.submodules
.align_in_b
= self
.i
.b
132 m
.submodules
.align_out_a
= self
.o
.a
133 m
.submodules
.align_out_b
= self
.o
.b
135 # temporary (muxed) input and output to be shifted
136 t_inp
= FPNumBase(self
.width
)
137 t_out
= FPNumIn(None, self
.width
)
138 espec
= (len(self
.i
.a
.e
), True)
139 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
140 m
.submodules
.align_t_in
= t_inp
141 m
.submodules
.align_t_out
= t_out
142 m
.submodules
.multishift_r
= msr
144 ediff
= Signal(espec
, reset_less
=True)
145 ediffr
= Signal(espec
, reset_less
=True)
146 tdiff
= Signal(espec
, reset_less
=True)
147 elz
= Signal(reset_less
=True)
148 egz
= Signal(reset_less
=True)
150 # connect multi-shifter to t_inp/out mantissa (and tdiff)
151 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
152 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
153 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
154 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
155 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
157 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
158 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
159 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
160 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
162 # default: A-exp == B-exp, A and B untouched (fall through)
163 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
164 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
165 # only one shifter (muxed)
166 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
167 # exponent of a greater than b: shift b down
168 with m
.If(~self
.i
.out_do_z
):
170 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
173 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
175 # exponent of b greater than a: shift a down
177 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
180 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
183 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
184 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
185 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
186 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
191 class FPAddAlignSingle(FPState
):
193 def __init__(self
, width
, id_wid
):
194 FPState
.__init
__(self
, "align")
195 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
196 self
.out_a
= FPNumIn(None, width
)
197 self
.out_b
= FPNumIn(None, width
)
199 def setup(self
, m
, i
):
200 """ links module to inputs and outputs
204 # NOTE: could be done as comb
205 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
206 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)