1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
, Elaboratable
5 from nmigen
.cli
import main
, verilog
7 from ieee754
.fpcommon
.getop
import FPADDBaseData
8 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
9 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
10 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
12 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
15 class FPCVTDownConvertMod(Elaboratable
):
16 """ FP down-conversion (higher to lower bitwidth)
18 def __init__(self
, in_pspec
, out_pspec
):
19 self
.in_pspec
= in_pspec
20 self
.out_pspec
= out_pspec
25 return FPADDBaseData(self
.in_pspec
)
28 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
30 def setup(self
, m
, i
):
31 """ links module to inputs and outputs
33 m
.submodules
.downconvert
= self
34 m
.d
.comb
+= self
.i
.eq(i
)
39 def elaborate(self
, platform
):
43 #m.submodules.sc_out_z = self.o.z
45 # decode: XXX really should move to separate stage
46 print("in_width out", self
.in_pspec
.width
,
48 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
49 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
50 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
51 comb
+= a1
.v
.eq(self
.i
.a
)
53 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
56 ms
= a1
.rmw
- self
.o
.z
.rmw
57 print("ms-me", ms
, me
)
60 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
61 exp_gt127
= Signal(reset_less
=True)
62 # constants from z1, at the bit-width of a1.
63 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
64 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
65 comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
66 comb
+= exp_gt127
.eq(a1
.e
> P127
)
68 # if a zero, return zero (signed)
69 with m
.If(a1
.exp_n127
):
70 comb
+= self
.o
.z
.zero(a1
.s
)
71 comb
+= self
.o
.out_do_z
.eq(1)
73 # if a range outside z's min range (-126)
74 with m
.Elif(exp_sub_n126
< 0):
75 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
76 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
77 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
78 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
80 comb
+= self
.o
.z
.s
.eq(a1
.s
)
81 comb
+= self
.o
.z
.e
.eq(a1
.e
)
82 comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
83 comb
+= self
.o
.z
.m
[-1].eq(1)
85 # if a is inf return inf
86 with m
.Elif(a1
.is_inf
):
87 comb
+= self
.o
.z
.inf(a1
.s
)
88 comb
+= self
.o
.out_do_z
.eq(1)
90 # if a is NaN return NaN
91 with m
.Elif(a1
.is_nan
):
92 comb
+= self
.o
.z
.nan(0)
93 comb
+= self
.o
.out_do_z
.eq(1)
95 # if a mantissa greater than 127, return inf
96 with m
.Elif(exp_gt127
):
97 print("inf", self
.o
.z
.inf(a1
.s
))
98 comb
+= self
.o
.z
.inf(a1
.s
)
99 comb
+= self
.o
.out_do_z
.eq(1)
101 # ok after all that, anything else should fit fine (whew)
103 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
104 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
105 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
106 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
108 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
109 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
110 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
111 mo
= Signal(self
.o
.z
.m_width
-1)
112 comb
+= mo
.eq(a1
.m
[ms
:me
])
113 with m
.If(self
.o
.of
.roundz
):
114 with m
.If((~mo
== 0)): # all 1s
115 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
117 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
119 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
120 comb
+= self
.o
.out_do_z
.eq(1)
122 # copy the context (muxid, operator)
123 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
124 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)