1 # IEEE Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import Module
, Signal
, Cat
, Mux
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
12 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
15 class FPCVTIntToFloatMod(PipeModBase
):
16 """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp.
18 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
19 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
21 def __init__(self
, in_pspec
, out_pspec
):
22 self
.in_pspec
= in_pspec
23 self
.out_pspec
= out_pspec
24 super().__init
__(in_pspec
, "intconvert")
27 return FPBaseData(self
.in_pspec
)
30 return FPPostCalcData(self
.out_pspec
, e_extra
=True)
32 def elaborate(self
, platform
):
36 #m.submodules.sc_out_z = self.o.z
38 # decode: XXX really should move to separate stage
39 print("in_width out", self
.in_pspec
.width
,
41 print("a1", self
.in_pspec
.width
)
44 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
46 me
= self
.in_pspec
.width
49 print("ms-me", ms
, me
, mz
)
51 # 3 extra bits for guard/round/sticky
52 msb
= FPMSBHigh(me
+3, z1
.e_width
)
53 m
.submodules
.norm_msb
= msb
55 # signed or unsigned, use operator context
56 signed
= Signal(reset_less
=True)
57 comb
+= signed
.eq(self
.i
.ctx
.op
[0])
59 # mantissa (one less bit if signed), and sign
60 mantissa
= Signal(me
, reset_less
=True)
61 sign
= Signal(reset_less
=True)
63 # detect signed/unsigned. key case: -ve numbers need inversion
64 # to +ve because the FP sign says if it's -ve or not.
65 comb
+= sign
.eq(Mux(signed
, a
[-1], 0)) # sign in top bit of a
66 comb
+= mantissa
.eq(Mux(signed
,
67 Mux(sign
, -a
, # invert input if sign -ve
69 a
)) # unsigned, use full a
71 # set input from full INT
72 comb
+= msb
.m_in
.eq(Cat(0, 0, 0, mantissa
)) # g/r/s + input
73 comb
+= msb
.e_in
.eq(me
) # exp = int width
75 # to do with FP16... not yet resolved why
79 comb
+= z1
.e
.eq(msb
.e_out
-1)
80 mmsb
= msb
.m_out
[-mz
-1:]
82 # larger int to smaller FP (uint32/64 -> fp16 most likely)
83 comb
+= z1
.m
[ms
-1:].eq(mmsb
)
84 else: # 32? XXX weirdness...
87 # smaller int to larger FP
88 comb
+= z1
.e
.eq(msb
.e_out
)
89 comb
+= z1
.m
[ms
:].eq(msb
.m_out
[3:])
91 comb
+= z1
.create(sign
, z1
.e
, z1
.m
) # ... here
93 # note: post-normalisation actually appears to be capable of
94 # detecting overflow to infinity (FPPackMod). so it's ok to
95 # drop the bits into the mantissa (with a fixed exponent),
96 # do some rounding (which might result in exceeding the
97 # range of the target FP by re-increasing the exponent),
98 # and basically *not* have to do any kind of range-checking
99 # here: just set up guard/round/sticky, drop the INT into the
100 # mantissa, and away we go. XXX TODO: see if FPNormaliseMod
101 # is even necessary. it probably isn't
103 # initialise rounding (but only activate if needed)
105 # larger int to smaller FP (uint32/64 -> fp16 most likely)
106 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[-mz
-2])
107 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[-mz
-3])
108 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:-mz
-3].bool())
109 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[-mz
-1])
111 # smaller int to larger FP
112 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[2])
113 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[1])
114 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:1].bool())
115 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[3])
117 a_nonzero
= Signal(reset_less
=True)
118 comb
+= a_nonzero
.eq(~a
.bool())
121 z_zero
= FPNumBaseRecord(z1
.width
, False, name
="z_zero")
122 comb
+= z_zero
.zero(0)
125 comb
+= self
.o
.out_do_z
.eq(a_nonzero
)
128 comb
+= self
.o
.oz
.eq(Mux(a_nonzero
, z1
.v
, z_zero
.v
))
130 # copy the context (muxid, operator)
131 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)