6c9e2cb6d9df763fdc61efba517b2c82e08f4fa1
[ieee754fpu.git] / src / ieee754 / part_bits / bool.py
1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
3
4 """
5 Copyright (C) 2020,2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6
7 dynamically-partitionable "bool" class, directly equivalent
8 to Signal.bool() except SIMD-partitionable
9
10 See:
11
12 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/logicops
13 * http://bugs.libre-riscv.org/show_bug.cgi?id=176
14 """
15
16 from nmigen import Signal, Module, Elaboratable, Cat, C
17 from nmigen.back.pysim import Simulator, Settle
18 from nmigen.cli import rtlil
19 from nmutil.ripple import RippleLSB
20
21 from ieee754.part_mul_add.partpoints import PartitionPoints
22 from ieee754.part_cmp.experiments.eq_combiner import EQCombiner
23
24
25 class PartitionedBool(Elaboratable):
26
27 def __init__(self, width, partition_points):
28 """Create a ``PartitionedBool`` operator
29 """
30 self.width = width
31 self.a = Signal(width, reset_less=True)
32 self.partition_points = PartitionPoints(partition_points)
33 self.mwidth = len(self.partition_points)+1
34 self.output = Signal(self.mwidth, reset_less=True)
35 if not self.partition_points.fits_in_width(width):
36 raise ValueError("partition_points doesn't fit in width")
37
38 def elaborate(self, platform):
39 m = Module()
40 comb = m.d.comb
41 m.submodules.boolc = boolc = EQCombiner(self.mwidth)
42
43 # make a series of "bool", splitting a and b into partition chunks
44 bools = Signal(self.mwidth, reset_less=True)
45 booll = []
46 keys = list(self.partition_points.keys()) + [self.width]
47 start = 0
48 for i in range(len(keys)):
49 end = keys[i]
50 booll.append(self.a[start:end].bool())
51 start = end # for next time round loop
52 comb += bools.eq(Cat(*booll))
53
54 # put the partial results through the combiner
55 comb += boolc.gates.eq(self.partition_points.as_sig())
56 comb += boolc.neqs.eq(bools)
57
58 m.submodules.ripple = ripple = RippleLSB(self.mwidth)
59 comb += ripple.results_in.eq(boolc.outputs)
60 comb += ripple.gates.eq(self.partition_points.as_sig())
61 comb += self.output.eq(~ripple.output)
62
63 return m
64
65 def ports(self):
66 return [self.a, self.output]
67
68
69 if __name__ == "__main__":
70
71 from ieee754.part_mul_add.partpoints import make_partition
72 m = Module()
73 mask = Signal(4)
74 m.submodules.mbool = mbool = PartitionedBool(16, make_partition(mask, 16))
75
76 vl = rtlil.convert(mbool, ports=mbool.ports())
77 with open("part_bool.il", "w") as f:
78 f.write(vl)
79
80 sim = Simulator(m)
81
82 def process():
83 yield mask.eq(0b010)
84 yield mbool.a.eq(0x80c4)
85 yield Settle()
86 out = yield mbool.output
87 m = yield mask
88 a = yield mbool.a
89 print("in", hex(a), "out", bin(out), "mask", bin(m))
90
91 yield mask.eq(0b111)
92 yield Settle()
93 out = yield mbool.output
94 m = yield mask
95 a = yield mbool.a
96 print("in", hex(a), "out", bin(out), "mask", bin(m))
97
98 yield mask.eq(0b010)
99 yield Settle()
100 out = yield mbool.output
101 m = yield mask
102 a = yield mbool.a
103 print("in", hex(a), "out", bin(out), "mask", bin(m))
104
105 yield mask.eq(0b000)
106 yield mbool.a.eq(0x0300)
107 yield Settle()
108 out = yield mbool.output
109 m = yield mask
110 a = yield mbool.a
111 print("in", hex(a), "out", bin(out), "mask", bin(m))
112
113 yield mask.eq(0b010)
114 yield Settle()
115 out = yield mbool.output
116 m = yield mask
117 a = yield mbool.a
118 print("in", hex(a), "out", bin(out), "mask", bin(m))
119
120 yield mask.eq(0b111)
121 yield Settle()
122 out = yield mbool.output
123 m = yield mask
124 a = yield mbool.a
125 print("in", hex(a), "out", bin(out), "mask", bin(m))
126
127 yield mask.eq(0b010)
128 yield Settle()
129 out = yield mbool.output
130 m = yield mask
131 a = yield mbool.a
132 print("in", hex(a), "out", bin(out), "mask", bin(m))
133
134 sim.add_process(process)
135 with sim.write_vcd("part_bool.vcd", "part_bool.gtkw", traces=mbool.ports()):
136 sim.run()
137