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