resolve awful meta-class hacking (with thanks to jsbueno on stackexchange)
[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, Const, Mux, Elaboratable
9 from nmigen.cli import main, verilog
10
11 from nmutil.singlepipe import ControlBase
12 from nmutil.concurrentunit import ReservationStations, num_bits
13
14 from ieee754.fpcommon.fpbase import Overflow
15 from ieee754.fpcommon.getop import FPADDBaseData
16 from ieee754.fpcommon.pack import FPPackData
17 from ieee754.fpcommon.normtopack import FPNormToPack
18 from ieee754.fpcommon.postcalc import FPAddStage1Data
19 from ieee754.fpcommon.msbhigh import FPMSBHigh
20 from ieee754.fpcommon.exphigh import FPEXPHigh
21
22
23 from nmigen import Module, Signal, Elaboratable
24 from math import log
25
26 from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPNumBaseRecord
27 from ieee754.fpcommon.fpbase import FPState, FPNumBase
28 from ieee754.fpcommon.getop import FPPipeContext
29
30 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
31 from nmutil.singlepipe import SimpleHandshake, StageChain
32
33 from ieee754.fpcommon.fpbase import FPState
34 from ieee754.pipeline import PipelineSpec
35
36
37 class FPCVTUpConvertMod(Elaboratable):
38 """ FP up-conversion (lower to higher bitwidth)
39 """
40 def __init__(self, in_pspec, out_pspec):
41 self.in_pspec = in_pspec
42 self.out_pspec = out_pspec
43 self.i = self.ispec()
44 self.o = self.ospec()
45
46 def ispec(self):
47 return FPADDBaseData(self.in_pspec)
48
49 def ospec(self):
50 return FPAddStage1Data(self.out_pspec, e_extra=False)
51
52 def setup(self, m, i):
53 """ links module to inputs and outputs
54 """
55 m.submodules.upconvert = self
56 m.d.comb += self.i.eq(i)
57
58 def process(self, i):
59 return self.o
60
61 def elaborate(self, platform):
62 m = Module()
63 comb = m.d.comb
64
65 #m.submodules.sc_out_z = self.o.z
66
67 # decode: XXX really should move to separate stage
68 print("in_width out", self.in_pspec.width,
69 self.out_pspec.width)
70 a1 = FPNumBaseRecord(self.in_pspec.width, False)
71 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
72 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
73 comb += a1.v.eq(self.i.a)
74 z1 = self.o.z
75 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
76
77 me = a1.rmw
78 ms = self.o.z.rmw - a1.rmw
79 print("ms-me", ms, me, self.o.z.rmw, a1.rmw)
80
81 # conversion can mostly be done manually...
82 comb += self.o.z.s.eq(a1.s)
83 comb += self.o.z.e.eq(a1.e)
84 comb += self.o.z.m[ms:].eq(a1.m)
85 comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
86
87 # initialise rounding to all zeros (deactivate)
88 comb += self.o.of.guard.eq(0)
89 comb += self.o.of.round_bit.eq(0)
90 comb += self.o.of.sticky.eq(0)
91 comb += self.o.of.m0.eq(a1.m[0])
92
93 # most special cases active (except tiny-number normalisation, below)
94 comb += self.o.out_do_z.eq(1)
95
96 # detect NaN/Inf first
97 with m.If(a1.exp_128):
98 with m.If(~a1.m_zero):
99 comb += self.o.z.nan(0) # RISC-V wants normalised NaN
100 with m.Else():
101 comb += self.o.z.inf(a1.s) # RISC-V wants signed INF
102 with m.Else():
103 with m.If(a1.exp_n127):
104 with m.If(~a1.m_zero):
105 comb += self.o.z.m[ms:].eq(Cat(0, a1.m))
106 comb += self.o.out_do_z.eq(0) # activate normalisation
107 with m.Else():
108 # RISC-V zero needs actual zero
109 comb += self.o.z.zero(a1.s)
110
111 # copy the context (muxid, operator)
112 comb += self.o.oz.eq(self.o.z.v)
113 comb += self.o.ctx.eq(self.i.ctx)
114
115 return m