1 # IEEE Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
7 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
, Elaboratable
8 from nmigen
.cli
import main
, verilog
10 from nmutil
.singlepipe
import ControlBase
11 from nmutil
.concurrentunit
import ReservationStations
, num_bits
13 from ieee754
.fpcommon
.fpbase
import Overflow
14 from ieee754
.fpcommon
.getop
import FPADDBaseData
15 from ieee754
.fpcommon
.pack
import FPPackData
16 from ieee754
.fpcommon
.normtopack
import FPNormToPack
17 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
18 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
19 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
22 from nmigen
import Module
, Signal
, Elaboratable
25 from ieee754
.fpcommon
.fpbase
import FPNumIn
, FPNumOut
, FPNumBaseRecord
26 from ieee754
.fpcommon
.fpbase
import FPState
, FPNumBase
27 from ieee754
.fpcommon
.getop
import FPPipeContext
29 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
30 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
32 from ieee754
.fpcommon
.fpbase
import FPState
33 from ieee754
.pipeline
import PipelineSpec
36 class FPCVTIntToFloatMod(Elaboratable
):
37 """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp.
39 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
40 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
42 def __init__(self
, in_pspec
, out_pspec
):
43 self
.in_pspec
= in_pspec
44 self
.out_pspec
= out_pspec
49 return FPADDBaseData(self
.in_pspec
)
52 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
54 def setup(self
, m
, i
):
55 """ links module to inputs and outputs
57 m
.submodules
.intconvert
= self
58 m
.d
.comb
+= self
.i
.eq(i
)
63 def elaborate(self
, platform
):
67 #m.submodules.sc_out_z = self.o.z
69 # decode: XXX really should move to separate stage
70 print("in_width out", self
.in_pspec
.width
,
72 print("a1", self
.in_pspec
.width
)
74 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
76 me
= self
.in_pspec
.width
79 print("ms-me", ms
, me
, mz
)
81 # 3 extra bits for guard/round/sticky
82 msb
= FPMSBHigh(me
+3, z1
.e_width
)
83 m
.submodules
.norm_msb
= msb
85 # signed or unsigned, use operator context
86 signed
= Signal(reset_less
=True)
87 comb
+= signed
.eq(self
.i
.ctx
.op
[0])
89 # copy of mantissa (one less bit if signed)
90 mantissa
= Signal(me
, reset_less
=True)
92 # detect signed/unsigned. key case: -ve numbers need inversion
93 # to +ve because the FP sign says if it's -ve or not.
95 comb
+= z1
.s
.eq(self
.i
.a
[-1]) # sign in top bit of a
97 comb
+= mantissa
.eq(-self
.i
.a
) # invert input if sign -ve
99 comb
+= mantissa
.eq(self
.i
.a
) # leave as-is
101 comb
+= mantissa
.eq(self
.i
.a
) # unsigned, use full a
104 # set input from full INT
105 comb
+= msb
.m_in
.eq(Cat(0, 0, 0, mantissa
)) # g/r/s + input
106 comb
+= msb
.e_in
.eq(me
) # exp = int width
108 # to do with FP16... not yet resolved why
112 comb
+= z1
.e
.eq(msb
.e_out
-1)
113 mmsb
= msb
.m_out
[-mz
-1:]
115 # larger int to smaller FP (uint32/64 -> fp16 most likely)
116 comb
+= z1
.m
[ms
-1:].eq(mmsb
)
117 else: # 32? XXX weirdness...
118 comb
+= z1
.m
.eq(mmsb
)
120 # smaller int to larger FP
121 comb
+= z1
.e
.eq(msb
.e_out
)
122 comb
+= z1
.m
[ms
:].eq(msb
.m_out
[3:])
123 comb
+= z1
.create(z1
.s
, z1
.e
, z1
.m
) # ... here
125 # note: post-normalisation actually appears to be capable of
126 # detecting overflow to infinity (FPPackMod). so it's ok to
127 # drop the bits into the mantissa (with a fixed exponent),
128 # do some rounding (which might result in exceeding the
129 # range of the target FP by re-increasing the exponent),
130 # and basically *not* have to do any kind of range-checking
131 # here: just set up guard/round/sticky, drop the INT into the
132 # mantissa, and away we go. XXX TODO: see if FPNormaliseMod
133 # is even necessary. it probably isn't
135 # initialise rounding (but only activate if needed)
137 # larger int to smaller FP (uint32/64 -> fp16 most likely)
138 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[-mz
-2])
139 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[-mz
-3])
140 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:-mz
-3].bool())
141 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[-mz
-1])
143 # smaller int to larger FP
144 comb
+= self
.o
.of
.guard
.eq(msb
.m_out
[2])
145 comb
+= self
.o
.of
.round_bit
.eq(msb
.m_out
[1])
146 comb
+= self
.o
.of
.sticky
.eq(msb
.m_out
[:1].bool())
147 comb
+= self
.o
.of
.m0
.eq(msb
.m_out
[3])
149 # special cases active by default
150 comb
+= self
.o
.out_do_z
.eq(1)
153 with m
.If(~self
.i
.a
.bool()):
154 comb
+= self
.o
.z
.zero(0)
156 comb
+= self
.o
.out_do_z
.eq(0) # activate normalisation
158 # copy the context (muxid, operator)
159 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
160 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)