1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
8 from nmigen
import Module
, Signal
, Cat
9 from nmigen
.cli
import main
, verilog
11 from nmutil
.pipemodbase
import PipeModBase
12 from ieee754
.fpcommon
.basedata
import FPBaseData
13 from ieee754
.fpcommon
.postcalc
import FPPostCalcData
14 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
17 class FPCVTUpConvertMod(PipeModBase
):
18 """ FP up-conversion (lower to higher bitwidth)
20 def __init__(self
, in_pspec
, out_pspec
):
21 self
.in_pspec
= in_pspec
22 self
.out_pspec
= out_pspec
23 super().__init
__(in_pspec
, "upconvert")
26 return FPBaseData(self
.in_pspec
)
29 return FPPostCalcData(self
.out_pspec
, e_extra
=False)
31 def elaborate(self
, platform
):
34 print("in_width out", self
.in_pspec
.width
, self
.out_pspec
.width
)
36 # this is quite straightforward as there is plenty of space in
37 # the larger format to fit the smaller-bit-width exponent+mantissa
38 # the special cases are detecting Inf and NaN and de-normalised
39 # "tiny" numbers. the "subnormal" numbers (ones at the limit of
40 # the smaller exponent range) need to be normalised to fit into
41 # the (larger) exponent.
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
)
49 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
52 ms
= self
.o
.z
.rmw
- a1
.rmw
53 print("ms-me", ms
, me
, self
.o
.z
.rmw
, a1
.rmw
)
55 # conversion can mostly be done manually...
56 comb
+= self
.o
.z
.s
.eq(a1
.s
)
57 comb
+= self
.o
.z
.e
.eq(a1
.e
)
58 comb
+= self
.o
.z
.m
[ms
:].eq(a1
.m
)
59 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, self
.o
.z
.m
) # ... here
61 # special cases active (except tiny-number normalisation, below)
62 comb
+= self
.o
.out_do_z
.eq(1)
64 # detect NaN/Inf first
65 with m
.If(a1
.exp_128
):
66 with m
.If(~a1
.m_zero
):
67 comb
+= self
.o
.z
.nan(0) # RISC-V wants normalised NaN
69 comb
+= self
.o
.z
.inf(a1
.s
) # RISC-V wants signed INF
71 # now check zero (or subnormal)
72 with m
.If(a1
.exp_n127
): # subnormal number detected (or zero)
73 with m
.If(~a1
.m_zero
):
74 # non-zero mantissa: needs normalisation
75 comb
+= self
.o
.z
.m
[ms
:].eq(Cat(0, a1
.m
))
76 comb
+= self
.o
.of
.m0
.eq(a1
.m
[0]) # Overflow needs LSB
77 comb
+= self
.o
.out_do_z
.eq(0) # activate normalisation
79 # RISC-V zero needs actual zero
80 comb
+= self
.o
.z
.zero(a1
.s
)
81 # anything else, amazingly, is fine as-is.
83 # copy the context (muxid, operator)
84 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
85 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)