09b5d478ed2dab1b88eea0b710eb46f04cf75d8f
[ieee754fpu.git] / src / ieee754 / fclass / fclass.py
1 # IEEE754 FCLASS Module
2 # Copyright (C) 2019 Luke Kenneth Casson Leighon <lkcl@lkcl.net>
3
4 from nmigen import Module, Signal, Cat
5
6 from nmutil.pipemodbase import PipeModBase
7 from ieee754.fpcommon.getop import FPADDBaseData
8 from ieee754.fpcommon.pack import FPPackData
9 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
10
11
12 class FPClassMod(PipeModBase):
13 """ obtains floating point information (zero, nan, inf etc.)
14 """
15 def __init__(self, in_pspec, out_pspec):
16 self.in_pspec = in_pspec
17 self.out_pspec = out_pspec
18 super().__init__(in_pspec, "fclass")
19
20 def ispec(self):
21 return FPADDBaseData(self.in_pspec)
22
23 def ospec(self):
24 return FPPackData(self.out_pspec)
25
26 def elaborate(self, platform):
27 m = Module()
28 comb = m.d.comb
29
30 # decode incoming FP number
31 print("in_width out", self.in_pspec.width,
32 self.out_pspec.width)
33 a1 = FPNumBaseRecord(self.in_pspec.width, False)
34 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
35 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
36 comb += a1.v.eq(self.i.a)
37
38 # FCLASS: work out the "type" of the FP number
39
40 finite_nzero = Signal(reset_less=True)
41 msbzero = Signal(reset_less=True)
42 is_sig_nan = Signal(reset_less=True)
43 # XXX use *REAL* mantissa width to detect msb.
44 # XXX do NOT use a1.m_msbzero because it has extra bitspace
45 comb += msbzero.eq(a1.m[a1.rmw-1] == 0) # sigh, 1 extra msb bit
46 comb += finite_nzero.eq(~a1.is_nan & ~a1.is_inf & ~a1.is_zero)
47 comb += is_sig_nan.eq(a1.exp_128 & (msbzero) & (~a1.m_zero))
48 subnormal = a1.exp_n127
49
50 # this is hardware-optimal but very hard to understand.
51 # see unit test test_fclass_pipe.py fclass() for what's
52 # going on.
53 comb += self.o.z.eq(Cat(
54 a1.s & a1.is_inf, # | −inf.
55 a1.s & finite_nzero & ~subnormal, # | -normal number.
56 a1.s & finite_nzero & subnormal, # | -subnormal number.
57 a1.s & a1.is_zero, # | −0.
58 ~a1.s & a1.is_zero, # | +0.
59 ~a1.s & finite_nzero & subnormal, # | +subnormal number.
60 ~a1.s & finite_nzero & ~subnormal, # | +normal number.
61 ~a1.s & a1.is_inf, # | +inf.
62 is_sig_nan, # | a signaling NaN.
63 a1.is_nan & ~is_sig_nan)) # | a quiet NaN
64
65 comb += self.o.ctx.eq(self.i.ctx)
66
67 return m