run tests in parallel
[ieee754fpu.git] / src / ieee754 / fcvt / upsize.py
1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3
4
5 import sys
6 import functools
7
8 from nmigen import Module, Signal, Cat
9 from nmigen.cli import main, verilog
10
11 from nmutil.pipemodbase import PipeModBase
12 from ieee754.fpcommon.basedata import FPBaseData
13 from ieee754.fpcommon.postcalc import FPPostCalcData
14 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
15
16
17 class FPCVTUpConvertMod(PipeModBase):
18 """ FP up-conversion (lower to higher bitwidth)
19 """
20 def __init__(self, in_pspec, out_pspec):
21 self.in_pspec = in_pspec
22 self.out_pspec = out_pspec
23 super().__init__(in_pspec, "upconvert")
24
25 def ispec(self):
26 return FPBaseData(self.in_pspec)
27
28 def ospec(self):
29 return FPPostCalcData(self.out_pspec, e_extra=False)
30
31 def elaborate(self, platform):
32 m = Module()
33 comb = m.d.comb
34 print("in_width out", self.in_pspec.width, self.out_pspec.width)
35
36 # this is quite straightforward as there is plenty of space in
37 # the larger format to fit the smaller-bit-width exponent+mantissa
38 # the special cases are detecting Inf and NaN and de-normalised
39 # "tiny" numbers. the "subnormal" numbers (ones at the limit of
40 # the smaller exponent range) need to be normalised to fit into
41 # the (larger) exponent.
42
43 a1 = FPNumBaseRecord(self.in_pspec.width, False)
44 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
45 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
46 comb += a1.v.eq(self.i.a)
47
48 z1 = self.o.z
49 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
50
51 me = a1.rmw
52 ms = self.o.z.rmw - a1.rmw
53 print("ms-me", ms, me, self.o.z.rmw, a1.rmw)
54
55 # conversion can mostly be done manually...
56 comb += self.o.z.s.eq(a1.s)
57 comb += self.o.z.e.eq(a1.e)
58 comb += self.o.z.m[ms:].eq(a1.m)
59 comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
60
61 # special cases active (except tiny-number normalisation, below)
62 comb += self.o.out_do_z.eq(1)
63
64 # detect NaN/Inf first
65 with m.If(a1.exp_128):
66 with m.If(~a1.m_zero):
67 comb += self.o.z.nan(0) # RISC-V wants normalised NaN
68 with m.Else():
69 comb += self.o.z.inf(a1.s) # RISC-V wants signed INF
70 with m.Else():
71 # now check zero (or subnormal)
72 with m.If(a1.exp_n127): # subnormal number detected (or zero)
73 with m.If(~a1.m_zero):
74 # non-zero mantissa: needs normalisation
75 comb += self.o.z.m[ms:].eq(Cat(0, a1.m))
76 comb += self.o.of.m0.eq(a1.m[0]) # Overflow needs LSB
77 comb += self.o.out_do_z.eq(0) # activate normalisation
78 with m.Else():
79 # RISC-V zero needs actual zero
80 comb += self.o.z.zero(a1.s)
81 # anything else, amazingly, is fine as-is.
82
83 # copy the context (muxid, operator)
84 comb += self.o.oz.eq(self.o.z.v)
85 comb += self.o.ctx.eq(self.i.ctx)
86
87 return m