c9dfcb5216e608194ab4a835fc6ae407d2c32b1c
[ieee754fpu.git] / src / ieee754 / part / test / test_partsig.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # See Notices.txt for copyright information
4
5 from nmigen import Signal, Module, Elaboratable
6 from nmigen.back.pysim import Simulator, Delay, Tick, Passive
7 from nmigen.cli import verilog, rtlil
8
9 from ieee754.part.partsig import PartitionedSignal
10 from ieee754.part_mux.part_mux import PMux
11
12 import unittest
13
14 def create_ilang(dut, traces, test_name):
15 vl = rtlil.convert(dut, ports=traces)
16 with open("%s.il" % test_name, "w") as f:
17 f.write(vl)
18
19
20 def create_simulator(module, traces, test_name):
21 create_ilang(module, traces, test_name)
22 return Simulator(module,
23 vcd_file=open(test_name + ".vcd", "w"),
24 gtkw_file=open(test_name + ".gtkw", "w"),
25 traces=traces)
26
27 class TestAddMod(Elaboratable):
28 def __init__(self, width, partpoints):
29 self.partpoints = partpoints
30 self.a = PartitionedSignal(partpoints, width)
31 self.b = PartitionedSignal(partpoints, width)
32 self.add_output = Signal(width)
33 self.eq_output = Signal(len(partpoints)+1)
34 self.gt_output = Signal(len(partpoints)+1)
35 self.ge_output = Signal(len(partpoints)+1)
36 self.ne_output = Signal(len(partpoints)+1)
37 self.lt_output = Signal(len(partpoints)+1)
38 self.le_output = Signal(len(partpoints)+1)
39 self.mux_sel = Signal(len(partpoints)+1)
40 self.mux_out = Signal(width)
41
42 def elaborate(self, platform):
43 m = Module()
44 self.a.set_module(m)
45 self.b.set_module(m)
46 m.d.comb += self.lt_output.eq(self.a < self.b)
47 m.d.comb += self.ne_output.eq(self.a != self.b)
48 m.d.comb += self.le_output.eq(self.a <= self.b)
49 m.d.comb += self.gt_output.eq(self.a > self.b)
50 m.d.comb += self.eq_output.eq(self.a == self.b)
51 m.d.comb += self.ge_output.eq(self.a >= self.b)
52 m.d.comb += self.add_output.eq(self.a + self.b)
53 ppts = self.partpoints
54 m.d.comb += self.mux_out.eq(PMux(m, ppts, self.mux_sel, self.a, self.b))
55
56 return m
57
58
59 class TestPartitionPoints(unittest.TestCase):
60 def test(self):
61 width = 16
62 part_mask = Signal(4) # divide into 4-bits
63 module = TestAddMod(width, part_mask)
64
65 sim = create_simulator(module,
66 [part_mask,
67 module.a.sig,
68 module.b.sig,
69 module.add_output,
70 module.eq_output],
71 "part_sig_add")
72 def async_process():
73 def test_add(msg_prefix, *mask_list):
74 for a, b in [(0x0000, 0x0000),
75 (0x1234, 0x1234),
76 (0xABCD, 0xABCD),
77 (0xFFFF, 0x0000),
78 (0x0000, 0x0000),
79 (0xFFFF, 0xFFFF),
80 (0x0000, 0xFFFF)]:
81 yield module.a.eq(a)
82 yield module.b.eq(b)
83 yield Delay(0.1e-6)
84 y = 0
85 for mask in mask_list:
86 y |= mask & ((a & mask) + (b & mask))
87 outval = (yield module.add_output)
88 msg = f"{msg_prefix}: 0x{a:X} + 0x{b:X}" + \
89 f" => 0x{y:X} != 0x{outval:X}"
90 self.assertEqual(y, outval, msg)
91 yield part_mask.eq(0)
92 yield from test_add("16-bit", 0xFFFF)
93 yield part_mask.eq(0b10)
94 yield from test_add("8-bit", 0xFF00, 0x00FF)
95 yield part_mask.eq(0b1111)
96 yield from test_add("4-bit", 0xF000, 0x0F00, 0x00F0, 0x000F)
97
98 def test_ne_fn(a, b, mask):
99 return (a & mask) != (b & mask)
100
101 def test_lt_fn(a, b, mask):
102 return (a & mask) < (b & mask)
103
104 def test_le_fn(a, b, mask):
105 return (a & mask) <= (b & mask)
106
107 def test_eq_fn(a, b, mask):
108 return (a & mask) == (b & mask)
109
110 def test_gt_fn(a, b, mask):
111 return (a & mask) > (b & mask)
112
113 def test_ge_fn(a, b, mask):
114 return (a & mask) >= (b & mask)
115
116 def test_binop(msg_prefix, test_fn, mod_attr, *maskbit_list):
117 for a, b in [(0x0000, 0x0000),
118 (0x1234, 0x1234),
119 (0xABCD, 0xABCD),
120 (0xFFFF, 0x0000),
121 (0x0000, 0x0000),
122 (0xFFFF, 0xFFFF),
123 (0x0000, 0xFFFF),
124 (0xABCD, 0xABCE),
125 (0x8000, 0x0000),
126 (0xBEEF, 0xFEED)]:
127 yield module.a.eq(a)
128 yield module.b.eq(b)
129 yield Delay(0.1e-6)
130 # convert to mask_list
131 mask_list = []
132 for mb in maskbit_list:
133 v = 0
134 for i in range(4):
135 if mb & (1<<i):
136 v |= 0xf << (i*4)
137 mask_list.append(v)
138 y = 0
139 # do the partitioned tests
140 for i, mask in enumerate(mask_list):
141 if test_fn(a, b, mask):
142 # OR y with the lowest set bit in the mask
143 y |= maskbit_list[i]
144 # check the result
145 outval = (yield getattr(module, "%s_output" % mod_attr))
146 msg = f"{msg_prefix}: {mod_attr} 0x{a:X} == 0x{b:X}" + \
147 f" => 0x{y:X} != 0x{outval:X}, masklist %s"
148 print ((msg % str(maskbit_list)).format(locals()))
149 self.assertEqual(y, outval, msg % str(maskbit_list))
150
151 for (test_fn, mod_attr) in ((test_eq_fn, "eq"),
152 (test_gt_fn, "gt"),
153 (test_ge_fn, "ge"),
154 (test_lt_fn, "lt"),
155 (test_le_fn, "le"),
156 (test_ne_fn, "ne"),
157 ):
158 yield part_mask.eq(0)
159 yield from test_binop("16-bit", test_fn, mod_attr, 0b1111)
160 yield part_mask.eq(0b10)
161 yield from test_binop("8-bit", test_fn, mod_attr,
162 0b1100, 0b0011)
163 yield part_mask.eq(0b1111)
164 yield from test_binop("4-bit", test_fn, mod_attr,
165 0b1000, 0b0100, 0b0010, 0b0001)
166
167 def test_muxop(msg_prefix, *maskbit_list):
168 for a, b, sel in [(0x0000, 0x0000, 0b0110),
169 (0x1234, 0x1234, 0b1010),
170 (0xABCD, 0xABCD, 0b1100),
171 (0xFFFF, 0x0000, 0b0011),
172 (0x0000, 0x0000, 0b1001),
173 (0xFFFF, 0xFFFF, 0b1101),
174 (0x0000, 0xFFFF, 0b1100)]:
175 yield module.a.eq(a)
176 yield module.b.eq(b)
177 yield module.mux_sel.eq(sel)
178 yield Delay(0.1e-6)
179 # convert to mask_list
180 mask_list = []
181 for mb in maskbit_list:
182 v = 0
183 for i in range(4):
184 if mb & (1<<i):
185 v |= 0xf << (i*4)
186 mask_list.append(v)
187 y = 0
188 # do the partitioned tests
189 for i, mask in enumerate(mask_list):
190 if (sel & mask):
191 y |= (a & mask)
192 else:
193 y |= (b & mask)
194 # check the result
195 outval = (yield module.mux_out)
196 msg = f"{msg_prefix}: mux 0x{a:X} == 0x{b:X}" + \
197 f" => 0x{y:X} != 0x{outval:X}, masklist %s"
198 #print ((msg % str(maskbit_list)).format(locals()))
199 self.assertEqual(y, outval, msg % str(maskbit_list))
200
201 yield part_mask.eq(0)
202 yield from test_muxop("16-bit", 0b1111)
203 yield part_mask.eq(0b10)
204 yield from test_muxop("8-bit", 0b1100, 0b0011)
205 yield part_mask.eq(0b1111)
206 yield from test_muxop("4-bit", 0b1000, 0b0100, 0b0010, 0b0001)
207
208 sim.add_process(async_process)
209 sim.run()
210
211 if __name__ == '__main__':
212 unittest.main()
213