1 """IEEE754 Floating Point Converter
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6 * http://bugs.libre-riscv.org/show_bug.cgi?id=112
7 * http://bugs.libre-riscv.org/show_bug.cgi?id=113
11 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
12 from nmigen
.cli
import main
, verilog
14 from nmutil
.pipemodbase
import PipeModBase
15 from ieee754
.fpcommon
.fpbase
import Overflow
16 from ieee754
.fpcommon
.basedata
import FPBaseData
17 from ieee754
.fpcommon
.packdata
import FPPackData
18 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
20 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
23 class FPCVTFloatToIntMod(PipeModBase
):
24 """ integer to FP conversion: copes with 16/32/64 fp to 16/32/64 int/uint
26 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
27 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
29 Note: this is a single-stage conversion that goes direct to FPPackData
31 def __init__(self
, in_pspec
, out_pspec
):
32 self
.in_pspec
= in_pspec
33 self
.out_pspec
= out_pspec
34 super().__init
__(in_pspec
, "fp2int")
37 return FPBaseData(self
.in_pspec
)
40 return FPPackData(self
.out_pspec
)
42 def elaborate(self
, platform
):
46 # set up FP Num decoder
47 print("in_width out", self
.in_pspec
.width
,
49 a1
= FPNumBaseRecord(self
.in_pspec
.width
, False)
50 print("a1", a1
.width
, a1
.rmw
, a1
.e_width
, a1
.e_start
, a1
.e_end
)
51 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
52 comb
+= a1
.v
.eq(self
.i
.a
)
59 print("ms-me", ms
, me
)
61 espec
= (a1
.e_width
, True)
63 signed
= Signal(reset_less
=True)
64 comb
+= signed
.eq(self
.i
.ctx
.op
[0])
69 comb
+= self
.o
.z
.eq((1<<(mz
-1))-1) # signed NaN overflow
71 comb
+= self
.o
.z
.eq((1<<mz
)-1) # NaN overflow
73 # zero exponent: definitely out of range of INT. zero...
74 with m
.Elif(a1
.exp_n127
):
75 comb
+= self
.o
.z
.eq(0)
77 # unsigned, -ve, return 0
78 with m
.Elif((~signed
) & a1
.s
):
79 comb
+= self
.o
.z
.eq(0)
82 with m
.Elif(signed
& (a1
.e
>= Const(mz
-1, espec
))):
83 with m
.If(a1
.s
): # negative FP, so negative overrun
84 comb
+= self
.o
.z
.eq(-(1<<(mz
-1)))
85 with m
.Else(): # positive FP, so positive overrun
86 comb
+= self
.o
.z
.eq((1<<(mz
-1))-1)
88 # unsigned, exp too big
89 with m
.Elif((~signed
) & (a1
.e
>= Const(mz
, espec
))):
90 with m
.If(a1
.s
): # negative FP, so negative overrun (zero)
91 comb
+= self
.o
.z
.eq(0)
92 with m
.Else(): # positive FP, so positive overrun (max INT)
93 comb
+= self
.o
.z
.eq((1<<(mz
))-1)
95 # ok exp should be in range: shift and round it
99 adjust
= a1
.m_width
- mz
100 mlen
= max(a1
.m_width
, mz
) + 5
101 mantissa
= Signal(mlen
, reset_less
=True)
102 l
= [0] * 2 + [a1
.m
[:-1]] + [1]
103 comb
+= mantissa
[-a1
.m_width
-3:].eq(Cat(*l
))
104 comb
+= self
.o
.z
.eq(mantissa
)
107 msr
= FPEXPHigh(mlen
, espec
[0])
108 m
.submodules
.norm_exp
= msr
109 comb
+= [msr
.m_in
.eq(mantissa
),
111 msr
.ediff
.eq(mz
- a1
.e
+adjust
)
115 comb
+= of
.guard
.eq(msr
.m_out
[2])
116 comb
+= of
.round_bit
.eq(msr
.m_out
[1])
117 comb
+= of
.sticky
.eq(msr
.m_out
[0])
118 comb
+= of
.m0
.eq(msr
.m_out
[3])
120 # XXX TODO: check if this overflows the mantissa
121 mround
= Signal(mlen
, reset_less
=True)
122 with m
.If(of
.roundz
):
123 comb
+= mround
.eq(msr
.m_out
[3:]+1)
125 comb
+= mround
.eq(msr
.m_out
[3:])
128 with m
.If(signed
& a1
.s
):
129 comb
+= self
.o
.z
.eq(-mround
) # inverted
131 comb
+= self
.o
.z
.eq(mround
)
133 # copy the context (muxid, operator)
134 #comb += self.o.oz.eq(self.o.z.v)
135 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)