1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Const
, Mux
6 from nmigen
.cli
import main
, verilog
9 from nmutil
.pipemodbase
import PipeModBase
, PipeModBaseChain
10 from ieee754
.fpcommon
.fpbase
import FPNumDecode
12 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
13 from ieee754
.fpcommon
.basedata
import FPBaseData
14 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
17 class FPAddSpecialCasesMod(PipeModBase
):
18 """ special cases: NaNs, infs, zeros, denormalised
19 NOTE: some of these are unique to add. see "Special Operations"
20 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
23 def __init__(self
, pspec
):
24 super().__init
__(pspec
, "specialcases")
27 return FPBaseData(self
.pspec
)
30 return FPSCData(self
.pspec
, True)
32 def elaborate(self
, platform
):
36 # decode: XXX really should move to separate stage
37 width
= self
.pspec
.width
38 a1
= FPNumBaseRecord(width
)
39 b1
= FPNumBaseRecord(width
)
40 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
41 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
42 comb
+= [a1
.v
.eq(self
.i
.a
),
48 # temporaries used below
49 s_nomatch
= Signal(reset_less
=True)
50 m_match
= Signal(reset_less
=True)
51 e_match
= Signal(reset_less
=True)
52 absa
= Signal(reset_less
=True) # a1.s & b1.s
53 t_aeqmb
= Signal(reset_less
=True)
54 t_a1inf
= Signal(reset_less
=True)
55 t_b1inf
= Signal(reset_less
=True)
56 t_a1zero
= Signal(reset_less
=True)
57 t_b1zero
= Signal(reset_less
=True)
58 t_abz
= Signal(reset_less
=True)
59 t_abnan
= Signal(reset_less
=True)
60 bexp128s
= Signal(reset_less
=True)
61 t_special
= Signal(reset_less
=True)
63 comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
64 comb
+= m_match
.eq(a1
.m
== b1
.m
)
65 comb
+= e_match
.eq(a1
.e
== b1
.e
)
67 # logic-chain (matches comments, below) gives an if-elif-elif-elif...
68 comb
+= t_abnan
.eq(a1
.is_nan | b1
.is_nan
)
69 comb
+= t_a1inf
.eq(a1
.is_inf
)
70 comb
+= t_b1inf
.eq(b1
.is_inf
)
71 comb
+= t_abz
.eq(a1
.is_zero
& b1
.is_zero
)
72 comb
+= t_a1zero
.eq(a1
.is_zero
)
73 comb
+= t_b1zero
.eq(b1
.is_zero
)
74 comb
+= t_aeqmb
.eq(s_nomatch
& m_match
& e_match
)
75 comb
+= t_special
.eq(Cat(t_aeqmb
, t_b1zero
, t_a1zero
, t_abz
,
76 t_b1inf
, t_a1inf
, t_abnan
).bool())
78 comb
+= absa
.eq(a1
.s
& b1
.s
)
79 comb
+= bexp128s
.eq(b1
.exp_128
& s_nomatch
)
81 # prepare inf/zero/nans
82 z_zero
= FPNumBaseRecord(width
, False, name
="z_zero")
83 z_nan
= FPNumBaseRecord(width
, False, name
="z_nan")
84 z_infa
= FPNumBaseRecord(width
, False, name
="z_infa")
85 z_infb
= FPNumBaseRecord(width
, False, name
="z_infb")
86 comb
+= z_zero
.zero(0)
88 comb
+= z_infa
.inf(a1
.s
)
89 comb
+= z_infb
.inf(b1
.s
)
91 # any special-cases it's a "special".
92 comb
+= self
.o
.out_do_z
.eq(t_special
)
94 # this is the logic-decision-making for special-cases:
95 # if a is NaN or b is NaN return NaN
96 # elif a is inf return inf (or NaN)
97 # if a is inf and signs don't match return NaN
99 # elif b is inf return inf(b)
100 # elif a is zero and b zero return signed-a/b
101 # elif a is zero return b
102 # elif b is zero return a
103 # elif a equal to -b return zero (+ve zero)
105 # XXX *sigh* there are better ways to do this...
106 # one of them: use a priority-picker!
107 # in reverse-order, accumulate Muxing
110 oz
= Mux(t_aeqmb
, z_zero
.v
, oz
)
111 oz
= Mux(t_b1zero
, a1
.v
, oz
)
112 oz
= Mux(t_a1zero
, b1
.v
, oz
)
113 oz
= Mux(t_abz
, Cat(self
.i
.b
[:-1], absa
), oz
)
114 oz
= Mux(t_b1inf
, z_infb
.v
, oz
)
115 oz
= Mux(t_a1inf
, Mux(bexp128s
, z_nan
.v
, z_infa
.v
), oz
)
116 oz
= Mux(t_abnan
, z_nan
.v
, oz
)
118 comb
+= self
.o
.oz
.eq(oz
)
120 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
125 class FPAddSpecialCasesDeNorm(PipeModBaseChain
):
126 """ special cases chain
130 """ links module to inputs and outputs
132 smod
= FPAddSpecialCasesMod(self
.pspec
)
133 dmod
= FPAddDeNormMod(self
.pspec
, True)