1 # IEEE754 Floating Point Conversion
2 # Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
8 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
, Elaboratable
9 from nmigen
.cli
import main
, verilog
11 from nmutil
.singlepipe
import ControlBase
12 from nmutil
.concurrentunit
import ReservationStations
, num_bits
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
23 from nmigen
import Module
, Signal
, Elaboratable
26 from ieee754
.fpcommon
.fpbase
import FPNumIn
, FPNumOut
, FPNumBaseRecord
27 from ieee754
.fpcommon
.fpbase
import FPState
, FPNumBase
28 from ieee754
.fpcommon
.getop
import FPPipeContext
30 from ieee754
.fpcommon
.fpbase
import FPNumDecode
, FPNumBaseRecord
31 from nmutil
.singlepipe
import SimpleHandshake
, StageChain
33 from ieee754
.fpcommon
.fpbase
import FPState
34 from ieee754
.pipeline
import PipelineSpec
37 class FPCVTDownConvertMod(Elaboratable
):
38 """ FP down-conversion (higher to lower bitwidth)
40 def __init__(self
, in_pspec
, out_pspec
):
41 self
.in_pspec
= in_pspec
42 self
.out_pspec
= out_pspec
47 return FPADDBaseData(self
.in_pspec
)
50 return FPAddStage1Data(self
.out_pspec
, e_extra
=True)
52 def setup(self
, m
, i
):
53 """ links module to inputs and outputs
55 m
.submodules
.downconvert
= self
56 m
.d
.comb
+= self
.i
.eq(i
)
61 def elaborate(self
, platform
):
65 #m.submodules.sc_out_z = self.o.z
67 # decode: XXX really should move to separate stage
68 print("in_width out", self
.in_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
)
75 print("z1", z1
.width
, z1
.rmw
, z1
.e_width
, z1
.e_start
, z1
.e_end
)
78 ms
= a1
.rmw
- self
.o
.z
.rmw
79 print("ms-me", ms
, me
)
82 exp_sub_n126
= Signal((a1
.e_width
, True), reset_less
=True)
83 exp_gt127
= Signal(reset_less
=True)
84 # constants from z1, at the bit-width of a1.
85 N126
= Const(z1
.fp
.N126
.value
, (a1
.e_width
, True))
86 P127
= Const(z1
.fp
.P127
.value
, (a1
.e_width
, True))
87 comb
+= exp_sub_n126
.eq(a1
.e
- N126
)
88 comb
+= exp_gt127
.eq(a1
.e
> P127
)
90 # if a zero, return zero (signed)
91 with m
.If(a1
.exp_n127
):
92 comb
+= self
.o
.z
.zero(a1
.s
)
93 comb
+= self
.o
.out_do_z
.eq(1)
95 # if a range outside z's min range (-126)
96 with m
.Elif(exp_sub_n126
< 0):
97 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
98 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
99 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
100 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
102 comb
+= self
.o
.z
.s
.eq(a1
.s
)
103 comb
+= self
.o
.z
.e
.eq(a1
.e
)
104 comb
+= self
.o
.z
.m
.eq(a1
.m
[-self
.o
.z
.rmw
-1:])
105 comb
+= self
.o
.z
.m
[-1].eq(1)
107 # if a is inf return inf
108 with m
.Elif(a1
.is_inf
):
109 comb
+= self
.o
.z
.inf(a1
.s
)
110 comb
+= self
.o
.out_do_z
.eq(1)
112 # if a is NaN return NaN
113 with m
.Elif(a1
.is_nan
):
114 comb
+= self
.o
.z
.nan(0)
115 comb
+= self
.o
.out_do_z
.eq(1)
117 # if a mantissa greater than 127, return inf
118 with m
.Elif(exp_gt127
):
119 print("inf", self
.o
.z
.inf(a1
.s
))
120 comb
+= self
.o
.z
.inf(a1
.s
)
121 comb
+= self
.o
.out_do_z
.eq(1)
123 # ok after all that, anything else should fit fine (whew)
125 comb
+= self
.o
.of
.guard
.eq(a1
.m
[ms
-1])
126 comb
+= self
.o
.of
.round_bit
.eq(a1
.m
[ms
-2])
127 comb
+= self
.o
.of
.sticky
.eq(a1
.m
[:ms
-2].bool())
128 comb
+= self
.o
.of
.m0
.eq(a1
.m
[ms
]) # bit of a1
130 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
131 print("alen", a1
.e_start
, z1
.fp
.N126
, N126
)
132 print("m1", self
.o
.z
.rmw
, a1
.m
[-self
.o
.z
.rmw
-1:])
133 mo
= Signal(self
.o
.z
.m_width
-1)
134 comb
+= mo
.eq(a1
.m
[ms
:me
])
135 with m
.If(self
.o
.of
.roundz
):
136 with m
.If((~mo
== 0)): # all 1s
137 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
+1, mo
+1)
139 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, mo
+1)
141 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[-self
.o
.z
.rmw
-1:])
142 comb
+= self
.o
.out_do_z
.eq(1)
144 # copy the context (muxid, operator)
145 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
146 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)