remove redundant imports
[ieee754fpu.git] / src / ieee754 / fcvt / downsize.py
1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3
4 from nmigen import Module, Signal, Cat, Const, Mux, Elaboratable
5 from nmigen.cli import main, verilog
6
7 from ieee754.fpcommon.getop import FPADDBaseData
8 from ieee754.fpcommon.postcalc import FPAddStage1Data
9 from ieee754.fpcommon.msbhigh import FPMSBHigh
10 from ieee754.fpcommon.exphigh import FPEXPHigh
11
12 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
13
14
15 class FPCVTDownConvertMod(Elaboratable):
16 """ FP down-conversion (higher to lower bitwidth)
17 """
18 def __init__(self, in_pspec, out_pspec):
19 self.in_pspec = in_pspec
20 self.out_pspec = out_pspec
21 self.i = self.ispec()
22 self.o = self.ospec()
23
24 def ispec(self):
25 return FPADDBaseData(self.in_pspec)
26
27 def ospec(self):
28 return FPAddStage1Data(self.out_pspec, e_extra=True)
29
30 def setup(self, m, i):
31 """ links module to inputs and outputs
32 """
33 m.submodules.downconvert = self
34 m.d.comb += self.i.eq(i)
35
36 def process(self, i):
37 return self.o
38
39 def elaborate(self, platform):
40 m = Module()
41 comb = m.d.comb
42
43 #m.submodules.sc_out_z = self.o.z
44
45 # decode: XXX really should move to separate stage
46 print("in_width out", self.in_pspec.width,
47 self.out_pspec.width)
48 a1 = FPNumBaseRecord(self.in_pspec.width, False)
49 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
50 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
51 comb += a1.v.eq(self.i.a)
52 z1 = self.o.z
53 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
54
55 me = a1.rmw
56 ms = a1.rmw - self.o.z.rmw
57 print("ms-me", ms, me)
58
59 # intermediaries
60 exp_sub_n126 = Signal((a1.e_width, True), reset_less=True)
61 exp_gt127 = Signal(reset_less=True)
62 # constants from z1, at the bit-width of a1.
63 N126 = Const(z1.fp.N126.value, (a1.e_width, True))
64 P127 = Const(z1.fp.P127.value, (a1.e_width, True))
65 comb += exp_sub_n126.eq(a1.e - N126)
66 comb += exp_gt127.eq(a1.e > P127)
67
68 # if a zero, return zero (signed)
69 with m.If(a1.exp_n127):
70 comb += self.o.z.zero(a1.s)
71 comb += self.o.out_do_z.eq(1)
72
73 # if a range outside z's min range (-126)
74 with m.Elif(exp_sub_n126 < 0):
75 comb += self.o.of.guard.eq(a1.m[ms-1])
76 comb += self.o.of.round_bit.eq(a1.m[ms-2])
77 comb += self.o.of.sticky.eq(a1.m[:ms-2].bool())
78 comb += self.o.of.m0.eq(a1.m[ms]) # bit of a1
79
80 comb += self.o.z.s.eq(a1.s)
81 comb += self.o.z.e.eq(a1.e)
82 comb += self.o.z.m.eq(a1.m[-self.o.z.rmw-1:])
83 comb += self.o.z.m[-1].eq(1)
84
85 # if a is inf return inf
86 with m.Elif(a1.is_inf):
87 comb += self.o.z.inf(a1.s)
88 comb += self.o.out_do_z.eq(1)
89
90 # if a is NaN return NaN
91 with m.Elif(a1.is_nan):
92 comb += self.o.z.nan(0)
93 comb += self.o.out_do_z.eq(1)
94
95 # if a mantissa greater than 127, return inf
96 with m.Elif(exp_gt127):
97 print("inf", self.o.z.inf(a1.s))
98 comb += self.o.z.inf(a1.s)
99 comb += self.o.out_do_z.eq(1)
100
101 # ok after all that, anything else should fit fine (whew)
102 with m.Else():
103 comb += self.o.of.guard.eq(a1.m[ms-1])
104 comb += self.o.of.round_bit.eq(a1.m[ms-2])
105 comb += self.o.of.sticky.eq(a1.m[:ms-2].bool())
106 comb += self.o.of.m0.eq(a1.m[ms]) # bit of a1
107
108 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
109 print("alen", a1.e_start, z1.fp.N126, N126)
110 print("m1", self.o.z.rmw, a1.m[-self.o.z.rmw-1:])
111 mo = Signal(self.o.z.m_width-1)
112 comb += mo.eq(a1.m[ms:me])
113 with m.If(self.o.of.roundz):
114 with m.If((~mo == 0)): # all 1s
115 comb += self.o.z.create(a1.s, a1.e+1, mo+1)
116 with m.Else():
117 comb += self.o.z.create(a1.s, a1.e, mo+1)
118 with m.Else():
119 comb += self.o.z.create(a1.s, a1.e, a1.m[-self.o.z.rmw-1:])
120 comb += self.o.out_do_z.eq(1)
121
122 # copy the context (muxid, operator)
123 comb += self.o.oz.eq(self.o.z.v)
124 comb += self.o.ctx.eq(self.i.ctx)
125
126 return m
127
128