1 # IEEE Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import Module
, Signal
, Cat
5 from nmigen
.cli
import main
, verilog
7 from nmutil
.pipemodbase
import PipeModBase
8 from ieee754
.fpcommon
.getop
import FPADDBaseData
9 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
10 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
12 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, 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 FPADDBaseData(self
.in_pspec
)
30 return FPAddStage1Data(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
)
43 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
45 me
= self
.in_pspec
.width
48 print("ms-me", ms
, me
, mz
)
50 # 3 extra bits for guard/round/sticky
51 msb
= FPMSBHigh(me
+3, z1
.e_width
)
52 m
.submodules
.norm_msb
= msb
54 # signed or unsigned, use operator context
55 signed
= Signal(reset_less
=True)
56 comb
+= signed
.eq(self
.i
.ctx
.op
[0])
58 # copy of mantissa (one less bit if signed)
59 mantissa
= Signal(me
, reset_less
=True)
61 # detect signed/unsigned. key case: -ve numbers need inversion
62 # to +ve because the FP sign says if it's -ve or not.
64 comb
+= z1
.s
.eq(self
.i
.a
[-1]) # sign in top bit of a
66 comb
+= mantissa
.eq(-self
.i
.a
) # invert input if sign -ve
68 comb
+= mantissa
.eq(self
.i
.a
) # leave as-is
70 comb
+= mantissa
.eq(self
.i
.a
) # unsigned, use full a
73 # set input from full INT
74 comb
+= msb
.m_in
.eq(Cat(0, 0, 0, mantissa
)) # g/r/s + input
75 comb
+= msb
.e_in
.eq(me
) # exp = int width
77 # to do with FP16... not yet resolved why
81 comb
+= z1
.e
.eq(msb
.e_out
-1)
82 mmsb
= msb
.m_out
[-mz
-1:]
84 # larger int to smaller FP (uint32/64 -> fp16 most likely)
85 comb
+= z1
.m
[ms
-1:].eq(mmsb
)
86 else: # 32? XXX weirdness...
89 # smaller int to larger FP
90 comb
+= z1
.e
.eq(msb
.e_out
)
91 comb
+= z1
.m
[ms
:].eq(msb
.m_out
[3:])
92 comb
+= z1
.create(z1
.s
, z1
.e
, z1
.m
) # ... here
94 # note: post-normalisation actually appears to be capable of
95 # detecting overflow to infinity (FPPackMod). so it's ok to
96 # drop the bits into the mantissa (with a fixed exponent),
97 # do some rounding (which might result in exceeding the
98 # range of the target FP by re-increasing the exponent),
99 # and basically *not* have to do any kind of range-checking
100 # here: just set up guard/round/sticky, drop the INT into the
101 # mantissa, and away we go. XXX TODO: see if FPNormaliseMod
102 # is even necessary. it probably isn't
104 # initialise rounding (but only activate if needed)
106 # larger int to smaller FP (uint32/64 -> fp16 most likely)
107 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[-mz
-2])
108 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[-mz
-3])
109 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:-mz
-3].bool())
110 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[-mz
-1])
112 # smaller int to larger FP
113 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[2])
114 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[1])
115 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:1].bool())
116 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[3])
118 # special cases active by default
119 comb
+= self
.o
.out_do_z
.eq(1)
122 with m
.If(~self
.i
.a
.bool()):
123 comb
+= self
.o
.z
.zero(0)
125 comb
+= self
.o
.out_do_z
.eq(0) # activate normalisation
127 # copy the context (muxid, operator)
128 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
129 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)