2e61dcfb2fe4d8d9a80ef605a97a531a7d4563f6
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
):
33 print("in_width out", self
.in_pspec
.width
, self
.out_pspec
.width
)
35 # here we make room (in temporary constants / ospec) for extra
36 # bits in the exponent, at the size of the *incoming* number
37 # bitwidth. in this way it is possible to detect, in the
38 # *outgoing* number, if the exponent is too large and needs
39 # adjustment. otherwise we have to mess about with all sorts
40 # of width-detection and the normalisation, special cases etc.
41 # all become horribly complicated.
43 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
44 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
45 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
46 comb
+= a1
.v
.eq(self
.i
.a
)
48 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
51 ms
= a1
.rmw
- self
.o
.z
.rmw
52 print("ms-me", ms
, me
)
55 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
56 exp_gt127
= Signal(reset_less
=True)
57 # constants from z1, at the bit-width of a1.
58 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
59 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
60 comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
61 comb
+= exp_gt127
.eq(a1
.e
> P127
)
63 # bypass (always enabled except for normalisation, below)
64 comb
+= self
.o
.out_do_z
.eq(1)
66 # if a zero, return zero (signed)
67 with m
.If(a1
.exp_n127
):
68 comb
+= self
.o
.z
.zero(a1
.s
)
70 # if a range outside z's min range (-126)
71 with m
.Elif(exp_sub_n126
< 0):
72 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
73 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
74 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
75 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
77 comb
+= self
.o
.z
.s
.eq(a1
.s
)
78 comb
+= self
.o
.z
.e
.eq(a1
.e
)
79 comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
80 comb
+= self
.o
.z
.m
[-1].eq(1)
82 # normalisation required
83 comb
+= self
.o
.out_do_z
.eq(0)
85 # if a is inf return inf
86 with m
.Elif(a1
.is_inf
):
87 comb
+= self
.o
.z
.inf(a1
.s
)
89 # if a is NaN return NaN
90 with m
.Elif(a1
.is_nan
):
91 comb
+= self
.o
.z
.nan(0)
93 # if a mantissa greater than 127, return inf
94 with m
.Elif(exp_gt127
):
95 print("inf", self
.o
.z
.inf(a1
.s
))
96 comb
+= self
.o
.z
.inf(a1
.s
)
98 # ok after all that, anything else should fit fine (whew)
100 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
101 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
102 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
103 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
105 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
106 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
107 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
108 mo
= Signal(self
.o
.z
.m_width
-1)
109 comb
+= mo
.eq(a1
.m
[ms
:me
])
110 with m
.If(self
.o
.of
.roundz
):
111 with m
.If((mo
.bool())): # mantissa-out is all 1s
112 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
114 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
116 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
118 # copy the context (muxid, operator)
119 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
120 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)