1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import Module
, Signal
, Const
5 from nmigen
.cli
import main
, verilog
7 from nmutil
.pipemodbase
import PipeModBase
8 from ieee754
.fpcommon
.basedata
import FPBaseData
9 from ieee754
.fpcommon
.postcalc
import FPPostCalcData
10 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
11 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
13 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
16 class FPCVTDownConvertMod(PipeModBase
):
17 """ FP down-conversion (higher to lower bitwidth)
19 def __init__(self
, in_pspec
, out_pspec
):
20 self
.in_pspec
= in_pspec
21 self
.out_pspec
= out_pspec
22 super().__init
__(in_pspec
, "downconvert")
25 return FPBaseData(self
.in_pspec
)
28 return FPPostCalcData(self
.out_pspec
, e_extra
=True)
30 def elaborate(self
, platform
):
34 #m.submodules.sc_out_z = self.o.z
36 # decode: XXX really should move to separate stage
37 print("in_width out", self
.in_pspec
.width
,
39 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
40 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
41 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
42 comb
+= a1
.v
.eq(self
.i
.a
)
44 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
47 ms
= a1
.rmw
- self
.o
.z
.rmw
48 print("ms-me", ms
, me
)
51 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
52 exp_gt127
= Signal(reset_less
=True)
53 # constants from z1, at the bit-width of a1.
54 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
55 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
56 comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
57 comb
+= exp_gt127
.eq(a1
.e
> P127
)
59 # if a zero, return zero (signed)
60 with m
.If(a1
.exp_n127
):
61 comb
+= self
.o
.z
.zero(a1
.s
)
62 comb
+= self
.o
.out_do_z
.eq(1)
64 # if a range outside z's min range (-126)
65 with m
.Elif(exp_sub_n126
< 0):
66 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
67 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
68 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
69 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
71 comb
+= self
.o
.z
.s
.eq(a1
.s
)
72 comb
+= self
.o
.z
.e
.eq(a1
.e
)
73 comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
74 comb
+= self
.o
.z
.m
[-1].eq(1)
76 # if a is inf return inf
77 with m
.Elif(a1
.is_inf
):
78 comb
+= self
.o
.z
.inf(a1
.s
)
79 comb
+= self
.o
.out_do_z
.eq(1)
81 # if a is NaN return NaN
82 with m
.Elif(a1
.is_nan
):
83 comb
+= self
.o
.z
.nan(0)
84 comb
+= self
.o
.out_do_z
.eq(1)
86 # if a mantissa greater than 127, return inf
87 with m
.Elif(exp_gt127
):
88 print("inf", self
.o
.z
.inf(a1
.s
))
89 comb
+= self
.o
.z
.inf(a1
.s
)
90 comb
+= self
.o
.out_do_z
.eq(1)
92 # ok after all that, anything else should fit fine (whew)
94 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
95 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
96 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
97 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
99 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
100 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
101 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
102 mo
= Signal(self
.o
.z
.m_width
-1)
103 comb
+= mo
.eq(a1
.m
[ms
:me
])
104 with m
.If(self
.o
.of
.roundz
):
105 with m
.If((~mo
== 0)): # all 1s
106 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
108 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
110 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
111 comb
+= self
.o
.out_do_z
.eq(1)
113 # copy the context (muxid, operator)
114 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
115 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)