1 # IEEE Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
, Elaboratable
5 from nmigen
.cli
import main
, verilog
7 from ieee754
.fpcommon
.getop
import FPADDBaseData
8 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
9 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
11 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
14 class FPCVTIntToFloatMod(Elaboratable
):
15 """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp.
17 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
18 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
20 def __init__(self
, in_pspec
, out_pspec
):
21 self
.in_pspec
= in_pspec
22 self
.out_pspec
= out_pspec
27 return FPADDBaseData(self
.in_pspec
)
30 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
32 def setup(self
, m
, i
):
33 """ links module to inputs and outputs
35 m
.submodules
.intconvert
= self
36 m
.d
.comb
+= self
.i
.eq(i
)
41 def elaborate(self
, platform
):
45 #m.submodules.sc_out_z = self.o.z
47 # decode: XXX really should move to separate stage
48 print("in_width out", self
.in_pspec
.width
,
50 print("a1", self
.in_pspec
.width
)
52 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
54 me
= self
.in_pspec
.width
57 print("ms-me", ms
, me
, mz
)
59 # 3 extra bits for guard/round/sticky
60 msb
= FPMSBHigh(me
+3, z1
.e_width
)
61 m
.submodules
.norm_msb
= msb
63 # signed or unsigned, use operator context
64 signed
= Signal(reset_less
=True)
65 comb
+= signed
.eq(self
.i
.ctx
.op
[0])
67 # copy of mantissa (one less bit if signed)
68 mantissa
= Signal(me
, reset_less
=True)
70 # detect signed/unsigned. key case: -ve numbers need inversion
71 # to +ve because the FP sign says if it's -ve or not.
73 comb
+= z1
.s
.eq(self
.i
.a
[-1]) # sign in top bit of a
75 comb
+= mantissa
.eq(-self
.i
.a
) # invert input if sign -ve
77 comb
+= mantissa
.eq(self
.i
.a
) # leave as-is
79 comb
+= mantissa
.eq(self
.i
.a
) # unsigned, use full a
82 # set input from full INT
83 comb
+= msb
.m_in
.eq(Cat(0, 0, 0, mantissa
)) # g/r/s + input
84 comb
+= msb
.e_in
.eq(me
) # exp = int width
86 # to do with FP16... not yet resolved why
90 comb
+= z1
.e
.eq(msb
.e_out
-1)
91 mmsb
= msb
.m_out
[-mz
-1:]
93 # larger int to smaller FP (uint32/64 -> fp16 most likely)
94 comb
+= z1
.m
[ms
-1:].eq(mmsb
)
95 else: # 32? XXX weirdness...
98 # smaller int to larger FP
99 comb
+= z1
.e
.eq(msb
.e_out
)
100 comb
+= z1
.m
[ms
:].eq(msb
.m_out
[3:])
101 comb
+= z1
.create(z1
.s
, z1
.e
, z1
.m
) # ... here
103 # note: post-normalisation actually appears to be capable of
104 # detecting overflow to infinity (FPPackMod). so it's ok to
105 # drop the bits into the mantissa (with a fixed exponent),
106 # do some rounding (which might result in exceeding the
107 # range of the target FP by re-increasing the exponent),
108 # and basically *not* have to do any kind of range-checking
109 # here: just set up guard/round/sticky, drop the INT into the
110 # mantissa, and away we go. XXX TODO: see if FPNormaliseMod
111 # is even necessary. it probably isn't
113 # initialise rounding (but only activate if needed)
115 # larger int to smaller FP (uint32/64 -> fp16 most likely)
116 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[-mz
-2])
117 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[-mz
-3])
118 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:-mz
-3].bool())
119 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[-mz
-1])
121 # smaller int to larger FP
122 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[2])
123 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[1])
124 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:1].bool())
125 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[3])
127 # special cases active by default
128 comb
+= self
.o
.out_do_z
.eq(1)
131 with m
.If(~self
.i
.a
.bool()):
132 comb
+= self
.o
.z
.zero(0)
134 comb
+= self
.o
.out_do_z
.eq(0) # activate normalisation
136 # copy the context (muxid, operator)
137 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
138 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)