1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Elaboratable
6 from nmigen
.cli
import main
, verilog
8 from ieee754
.fpcommon
.fpbase
import FPNumOut
, FPNumIn
, FPNumBase
9 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
10 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
11 from ieee754
.fpcommon
.fpbase
import FPState
12 from ieee754
.fpcommon
.denorm
import FPSCData
17 def __init__(self
, width
, id_wid
):
18 self
.a
= FPNumBaseRecord(width
)
19 self
.b
= FPNumBaseRecord(width
)
20 self
.z
= FPNumBaseRecord(width
, False)
21 self
.out_do_z
= Signal(reset_less
=True)
22 self
.oz
= Signal(width
, reset_less
=True)
23 self
.mid
= Signal(id_wid
, reset_less
=True)
26 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
27 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
31 class FPAddAlignMultiMod(FPState
):
33 def __init__(self
, width
):
34 self
.in_a
= FPNumBaseRecord(width
)
35 self
.in_b
= FPNumBaseRecord(width
)
36 self
.out_a
= FPNumBaseRecord(width
)
37 self
.out_b
= FPNumBaseRecord(width
)
38 self
.exp_eq
= Signal(reset_less
=True)
40 def elaborate(self
, platform
):
41 # This one however (single-cycle) will do the shift
46 #m.submodules.align_in_a = self.in_a
47 #m.submodules.align_in_b = self.in_b
48 #m.submodules.align_out_a = self.out_a
49 #m.submodules.align_out_b = self.out_b
51 # NOTE: this does *not* do single-cycle multi-shifting,
52 # it *STAYS* in the align state until exponents match
54 # exponent of a greater than b: shift b down
55 m
.d
.comb
+= self
.exp_eq
.eq(0)
56 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
57 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
58 agtb
= Signal(reset_less
=True)
59 altb
= Signal(reset_less
=True)
60 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
61 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
63 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
64 # exponent of b greater than a: shift a down
66 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
67 # exponents equal: move to next stage.
69 m
.d
.comb
+= self
.exp_eq
.eq(1)
73 class FPAddAlignMulti(FPState
):
75 def __init__(self
, width
, id_wid
):
76 FPState
.__init
__(self
, "align")
77 self
.mod
= FPAddAlignMultiMod(width
)
78 self
.out_a
= FPNumBaseRecord(width
)
79 self
.out_b
= FPNumBaseRecord(width
)
80 self
.exp_eq
= Signal(reset_less
=True)
82 def setup(self
, m
, in_a
, in_b
):
83 """ links module to inputs and outputs
85 m
.submodules
.align
= self
.mod
86 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
87 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
88 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
89 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
90 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
93 with m
.If(self
.exp_eq
):
97 class FPAddAlignSingleMod(Elaboratable
):
99 def __init__(self
, width
, id_wid
):
102 self
.i
= self
.ispec()
103 self
.o
= self
.ospec()
106 return FPSCData(self
.width
, self
.id_wid
)
109 return FPNumIn2Ops(self
.width
, self
.id_wid
)
111 def process(self
, i
):
114 def setup(self
, m
, i
):
115 """ links module to inputs and outputs
117 m
.submodules
.align
= self
118 m
.d
.comb
+= self
.i
.eq(i
)
120 def elaborate(self
, platform
):
121 """ Aligns A against B or B against A, depending on which has the
122 greater exponent. This is done in a *single* cycle using
123 variable-width bit-shift
125 the shifter used here is quite expensive in terms of gates.
126 Mux A or B in (and out) into temporaries, as only one of them
127 needs to be aligned against the other
131 #m.submodules.align_in_a = self.i.a
132 #m.submodules.align_in_b = self.i.b
133 #m.submodules.align_out_a = self.o.a
134 #m.submodules.align_out_b = self.o.b
136 # temporary (muxed) input and output to be shifted
137 t_inp
= FPNumBaseRecord(self
.width
)
138 t_out
= FPNumBaseRecord(self
.width
)
139 espec
= (len(self
.i
.a
.e
), True)
140 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
141 #m.submodules.align_t_in = t_inp
142 #m.submodules.align_t_out = t_out
143 m
.submodules
.multishift_r
= msr
145 ediff
= Signal(espec
, reset_less
=True)
146 ediffr
= Signal(espec
, reset_less
=True)
147 tdiff
= Signal(espec
, reset_less
=True)
148 elz
= Signal(reset_less
=True)
149 egz
= Signal(reset_less
=True)
151 # connect multi-shifter to t_inp/out mantissa (and tdiff)
152 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
153 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
154 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
155 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
156 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
158 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
159 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
160 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
161 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
163 # default: A-exp == B-exp, A and B untouched (fall through)
164 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
165 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
166 # only one shifter (muxed)
167 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
168 # exponent of a greater than b: shift b down
169 with m
.If(~self
.i
.out_do_z
):
171 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
174 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
176 # exponent of b greater than a: shift a down
178 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
181 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
184 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
185 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
186 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
187 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
192 class FPAddAlignSingle(FPState
):
194 def __init__(self
, width
, id_wid
):
195 FPState
.__init
__(self
, "align")
196 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
197 self
.out_a
= FPNumIn(None, width
)
198 self
.out_b
= FPNumIn(None, width
)
200 def setup(self
, m
, i
):
201 """ links module to inputs and outputs
205 # NOTE: could be done as comb
206 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
207 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)