Merge branch 'popcount' into devel

This commit is contained in:
Vojta Mrazek 2024-04-05 09:19:04 +02:00 committed by GitHub
commit 1219d7bec5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 790 additions and 77 deletions

View File

@ -91,8 +91,8 @@ class GeneralCircuit():
Args:
component: Subcomponent to be added into list of components composing described circuit.
"""
prefixes = [c.prefix for c in self.components] # TODO ?
#assert component.prefix not in prefixes, f"Component with prefix {component.prefix} already exists in the circuit."
prefixes = [c.prefix for c in self.components]
assert component.prefix not in prefixes, f"Component with prefix {component.prefix} already exists in the circuit."
self.components.append(component)
return component
@ -236,28 +236,16 @@ class GeneralCircuit():
"""
self.circuit_wires = []
circuit_wires_names = []
if isinstance(self.a, Bus):
[self.circuit_wires.append(
(w, f"{w.name}", self.save_wire_id(wire=w))) for w in self.a.bus]
[self.circuit_wires.append(
(w, f"{w.name}", self.save_wire_id(wire=w))) for w in self.b.bus]
[circuit_wires_names.append(w.name) for w in self.a.bus]
[circuit_wires_names.append(w.name) for w in self.b.bus]
if hasattr(self, 'c'):
for input in self.inputs:
if isinstance(input, Bus):
[self.circuit_wires.append(
(w, f"{w.name}", self.save_wire_id(wire=w))) for w in self.c.bus]
[circuit_wires_names.append(w.name) for w in self.c.bus]
else:
self.circuit_wires.append(
(self.a, f"{self.a.name}", self.save_wire_id(wire=self.a)))
self.circuit_wires.append(
(self.b, f"{self.b.name}", self.save_wire_id(wire=self.b)))
circuit_wires_names.append(self.a.name)
circuit_wires_names.append(self.b.name)
if hasattr(self, 'c'):
(w, f"{w.name}", self.save_wire_id(wire=w))) for w in input.bus]
[circuit_wires_names.append(w.name) for w in input.bus]
else:
self.circuit_wires.append(
(self.c, f"{self.c.name}", self.save_wire_id(wire=self.c)))
circuit_wires_names.append(self.c.name)
(input, f"{input.name}", self.save_wire_id(wire=input)))
circuit_wires_names.append(input.name)
for gate in self.circuit_gates:
if gate.a.name not in circuit_wires_names:

View File

@ -123,7 +123,13 @@ class UnsignedCGPCircuit(GeneralCircuit):
return ConstantWireValue0()
if i == 1:
return ConstantWireValue1()
return self.vals[i]
try:
return self.vals[i]
except KeyError:
raise KeyError(f"Key {i} not found in " + ", ".join(
[f"{i}: {v}" for i, v in self.vals.items()]
))
class SignedCGPCircuit(UnsignedCGPCircuit):

View File

@ -33,14 +33,16 @@ class MultipleInputLogicGate():
prefix (str, optional): Prefix used to name inner composite logic gates. Defaults to "".
"""
def __init__(self, a: Bus, two_input_gate_cls, parent_component: object, prefix: str = ""):
i = 0
while a.N != 1:
N = math.floor(a.N/2)
out_wires = []
# Creation of composite two input logic gates from bus `a`'s bit pairs and addition of generated blocks outputs for next iteration
for bus_index in range(0, N):
gate = two_input_gate_cls(a=a.get_wire(bus_index), b=a.get_wire(bus_index+N), prefix=prefix+str(parent_component.get_instance_num(cls=two_input_gate_cls, count_disabled_gates=False)), parent_component=parent_component)
gate = two_input_gate_cls(a=a.get_wire(bus_index), b=a.get_wire(bus_index+N), prefix=prefix+ "_" + str(i) + "_" + str(parent_component.get_instance_num(cls=two_input_gate_cls, count_disabled_gates=False)), parent_component=parent_component)
parent_component.add_component(gate)
out_wires.append(gate.out)
i += 1
# In case bus `a` has odd number of wires
if a.N % 2 != 0:
@ -110,6 +112,8 @@ class TwoInputLogicGate():
Returns:
str: C code description of logic gate's Boolean function (with bitwise shifted inputs).
"""
if self.out.is_const():
return self.out.get_wire_value_c_flat()
return f"{self.a.get_wire_value_c_flat()} {self.operator} {self.b.get_wire_value_c_flat()}"
def get_declaration_c_flat(self):
@ -206,6 +210,8 @@ class TwoInputLogicGate():
# No gate logic is generated if one of the inputs is a wire with constant value.
# I.e. either the constant or the second input wire is propagated to the output for the corresponding logic gate's logic function.
if self.disable_generation:
#return f" {self.out.prefix} = {self.get_function_c()} # DD {self.prefix} \n"
return ""
else:
return f" {self.out.prefix} = {self.get_function_c()}\n"

View File

@ -109,14 +109,14 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
# For each pg pair values algorithmically combine two input AND gates to replace multiple input gates (resolves fan-in issue)
pg_wires = Bus(wires_list=composite_wires)
multi_bit_and_gate = MultipleInputLogicGate(a=pg_wires, two_input_gate_cls=AndGate, prefix=self.prefix+"_and", parent_component=self)
multi_bit_and_gate = MultipleInputLogicGate(a=pg_wires, two_input_gate_cls=AndGate, prefix=self.prefix+f"_and{block_n}_{i}_{g_index}", parent_component=self)
composite_or_gates_inputs.append(multi_bit_and_gate.out)
# Final OR gates cascade using generated AND gates output wires
composite_or_wires = Bus(wires_list=composite_or_gates_inputs)
multi_bit_or_gate = MultipleInputLogicGate(a=composite_or_wires, two_input_gate_cls=OrGate, prefix=self.prefix+"_or", parent_component=self)
multi_bit_or_gate = MultipleInputLogicGate(a=composite_or_wires, two_input_gate_cls=OrGate, prefix=self.prefix+f"_orred{block_n}_{i}_{g_index}_", parent_component=self)
# Carry bit generation
obj_cout_or = OrGate(pg_block.get_generate_wire(), multi_bit_or_gate.out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=OrGate, count_disabled_gates=False)), parent_component=self)
obj_cout_or = OrGate(pg_block.get_generate_wire(), multi_bit_or_gate.out, prefix=self.prefix+f"_or{block_n}_{i}_{g_index}_"+str(self.get_instance_num(cls=OrGate, count_disabled_gates=False)), parent_component=self)
self.add_component(obj_cout_or)
# Updating cin for the the next cla block/sum XOR
cin = obj_cout_or.out

View File

@ -8,5 +8,7 @@ from ariths_gen.multi_bit_circuits.others.bit_reduce import (
)
from ariths_gen.multi_bit_circuits.others.compare import (
UnsignedCompareLT
)
UnsignedCompareLT, UnsignedCompareLTE, UnsignedCompareGT, UnsignedCompareGTE
)
from ariths_gen.multi_bit_circuits.others.popcount_compare import PopCountCompare

View File

@ -68,8 +68,8 @@ class BitReduce(GeneralCircuit):
for i, j in enumerate(range(half, a.N)):
c_in[i] = a[j]
b = create_tree(b_in, depth=depth + 1, branch = "A")
c = create_tree(c_in, depth= depth + 1, branch = "B")
b = create_tree(b_in, depth=depth + 1, branch = branch + "A")
c = create_tree(c_in, depth= depth + 1, branch = branch + "B")
d = gate(a=b, b=c, prefix = f"{self.prefix}_red_{branch}_{depth}")
self.add_component(d)
return d.out

View File

@ -44,7 +44,6 @@ class UnsignedCompareLT(GeneralCircuit):
Returns true if a < b
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lt", **kwargs):
@ -52,32 +51,144 @@ class UnsignedCompareLT(GeneralCircuit):
self.b = b
self.N = max(a.N, b.N)
#print("outc", outc)
super().__init__(name=name, prefix=prefix,
inputs = [self.a, self.b], out_N=1)
self.a.bus_extend(self.N, prefix=a.prefix)
self.b.bus_extend(self.N, prefix=b.prefix)
# create wires
psum = ConstantWireValue1()
res = Bus(N = self.N, prefix=self.prefix + "res")
for i in reversed(range(self.N)):
i1 = self.add_component(NotGate(self.a[i], f"{self.prefix}_i1_{i}")).out
i2 = self.b[i]
iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = self.add_component(NotGate(iA, f"{self.prefix}_i1_{i}")).out
i2 = iB
and1 = self.add_component(AndGate(i1, i2, f"{self.prefix}_and1_{i}")).out
res[i] = self.add_component(AndGate(and1, psum, f"{self.prefix}_and2_{i}")).out
pi = self.add_component(XnorGate(self.a[i], self.b[i], f"{self.prefix}_pi_{i}")).out
pi = self.add_component(XnorGate(iA, iB, f"{self.prefix}_pi_{i}", parent_component=self)).out
psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}")).out
self.out = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred")).out
#self.out.connect_bus(sumbus )
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True))
self.out.connect_bus(red.out)
class UnsignedCompareLTE(GeneralCircuit):
"""Class representing unsigned compare
Returns true if a <= b
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lt", **kwargs):
self.a = a
self.b = b
self.N = max(a.N, b.N)
super().__init__(name=name, prefix=prefix,
inputs = [self.a, self.b], out_N=1)
# create wires
psum = ConstantWireValue1()
res = Bus(N = self.N + 1, prefix=self.prefix + "res")
for i in reversed(range(self.N)):
iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = self.add_component(NotGate(iA, f"{self.prefix}_i1_{i}")).out
i2 = iB
and1 = self.add_component(AndGate(i1, i2, f"{self.prefix}_and1_{i}")).out
res[i] = self.add_component(AndGate(and1, psum, f"{self.prefix}_and2_{i}")).out
pi = self.add_component(XnorGate(iA, iB, f"{self.prefix}_pi_{i}", parent_component=self)).out
psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}")).out
res[self.N] = psum # or all equal (xor)
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True))
self.out.connect_bus(red.out)
class UnsignedCompareGT(GeneralCircuit):
"""Class representing unsigned compare
Returns true if a < b
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_gt", **kwargs):
self.a = a
self.b = b
self.N = max(a.N, b.N)
super().__init__(name=name, prefix=prefix,
inputs = [self.a, self.b], out_N=1)
# create wires
psum = ConstantWireValue1()
res = Bus(N = self.N, prefix=self.prefix + "res")
for i in reversed(range(self.N)):
iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = iA
i2 = self.add_component(NotGate(iB, f"{self.prefix}_i2_{i}")).out
and1 = self.add_component(AndGate(i1, i2, f"{self.prefix}_and1_{i}")).out
res[i] = self.add_component(AndGate(and1, psum, f"{self.prefix}_and2_{i}")).out
pi = self.add_component(XnorGate(iA, iB, f"{self.prefix}_pi_{i}", parent_component=self)).out
psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}")).out
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True))
self.out.connect_bus(red.out)
class UnsignedCompareGTE(GeneralCircuit):
"""Class representing unsigned compare
Returns true if a <= b
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_gte", **kwargs):
self.a = a
self.b = b
self.N = max(a.N, b.N)
super().__init__(name=name, prefix=prefix,
inputs = [self.a, self.b], out_N=1)
# create wires
psum = ConstantWireValue1()
res = Bus(N = self.N + 1, prefix=self.prefix + "res")
for i in reversed(range(self.N)):
iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = iA
i2 = self.add_component(NotGate(iB, f"{self.prefix}_i1_{i}", parent_component=self)).out
and1 = self.add_component(AndGate(i1, i2, f"{self.prefix}_and1_{i}", parent_component=self)).out
res[i] = self.add_component(AndGate(and1, psum, f"{self.prefix}_and2_{i}", parent_component=self)).out
pi = self.add_component(XnorGate(iA, iB, f"{self.prefix}_pi_{i}", parent_component=self)).out
psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}", parent_component=self)).out
res[self.N] = psum # or all equal (xor)
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True))
self.out.connect_bus(red.out)

View File

@ -79,8 +79,8 @@ class UnsignedPopCount(GeneralCircuit):
for i, j in enumerate(range(half, a.N)):
c_in[i] = a[j]
b = create_tree(b_in, depth=depth + 1, branch = "A")
c = create_tree(c_in, depth= depth + 1, branch = "B")
b = create_tree(b_in, depth=depth + 1, branch = branch + "A")
c = create_tree(c_in, depth= depth + 1, branch = branch + "B")
d = self.adder(a=b, b=c, prefix = f"{self.prefix}_add{branch}_{depth}")
self.add_component(d)
return d.out

View File

@ -0,0 +1,81 @@
"""
"""
from ariths_gen.multi_bit_circuits.others import UnsignedPopCount
from ariths_gen.multi_bit_circuits.others.compare import UnsignedCompareGTE
from ariths_gen.wire_components import (
Wire,
ConstantWireValue0,
ConstantWireValue1,
Bus,
wires
)
from ariths_gen.core.arithmetic_circuits import (
ArithmeticCircuit,
GeneralCircuit,
MultiplierCircuit
)
from ariths_gen.core.logic_gate_circuits import (
MultipleInputLogicGate
)
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
FullAdder,
FullAdderP,
TwoOneMultiplexer
)
from ariths_gen.one_bit_circuits.logic_gates import (
AndGate,
NandGate,
OrGate,
NorGate,
XorGate,
XnorGate,
NotGate
)
from ariths_gen.multi_bit_circuits.others import OrReduce
from math import log2, ceil
class PopCountCompare(GeneralCircuit):
"""Class representing a circiut
if number of ones in a is larger or equal than number of ones in b
popcnt popcnt
<=
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lt", **kwargs):
self.a = a
self.b = b
super().__init__(name=name, prefix=prefix,
inputs = [self.a, self.b], out_N=1)
p1 = self.add_component(UnsignedPopCount(self.a,
prefix=f"{prefix}_popcount1",
inner_component=True)).out
p2 = self.add_component(UnsignedPopCount(self.b,
prefix=f"{prefix}_popcount2",
inner_component=True)).out
N = max(p1.N, p2.N)
p1.bus_extend(N)
p2.bus_extend(N)
red = self.add_component(UnsignedCompareGTE(p1, p2, prefix=f"{prefix}_cmp", inner_component = True))
self.out.connect_bus(red.out)

View File

@ -92,7 +92,8 @@ class NandGate(TwoInputInvertedLogicGate):
# If constant input is present, logic gate is not generated and corresponding
# input value is propagated to the output to connect to other components
if a.is_const() and a.value == 1:
output = NotGate(a=b, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=b, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -100,7 +101,8 @@ class NandGate(TwoInputInvertedLogicGate):
self.out = ConstantWireValue1()
self.disable_generation = True
elif b.is_const() and b.value == 1:
output = NotGate(a=a, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=a, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -217,7 +219,8 @@ class NorGate(TwoInputInvertedLogicGate):
self.out = ConstantWireValue0()
self.disable_generation = True
elif a.is_const() and a.value == 0:
output = NotGate(a=b, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=b, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -225,7 +228,8 @@ class NorGate(TwoInputInvertedLogicGate):
self.out = ConstantWireValue0()
self.disable_generation = True
elif b.is_const() and b.value == 0:
output = NotGate(a=a, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=a, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -277,7 +281,8 @@ class XorGate(TwoInputLogicGate):
# If constant input is present, logic gate is not generated and corresponding
# input value is propagated to the output to connect to other components
if a.is_const() and a.value == 1:
output = NotGate(a=b, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=b, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -285,7 +290,8 @@ class XorGate(TwoInputLogicGate):
self.out = b
self.disable_generation = True
elif b.is_const() and b.value == 1:
output = NotGate(a=a, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=a, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -343,7 +349,8 @@ class XnorGate(TwoInputInvertedLogicGate):
self.out = b
self.disable_generation = True
elif a.is_const() and a.value == 0:
output = NotGate(a=b, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=b, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True
@ -351,7 +358,8 @@ class XnorGate(TwoInputInvertedLogicGate):
self.out = a
self.disable_generation = True
elif b.is_const() and b.value == 0:
output = NotGate(a=a, prefix=prefix, outid=outid, parent_component=parent_component)
assert self.parent_component, "Parent component for gate {self} is not defined"
output = NotGate(a=a, prefix=prefix + "_not", outid=outid, parent_component=parent_component)
self.parent_component.add_component(output) if parent_component is not None else None
self.out = output.out
self.disable_generation = True

View File

@ -17,6 +17,9 @@ class Wire():
self.prefix = name if prefix == "" else prefix
self.parent_bus = parent_bus
def __str__(self):
return f"wire{self.name}{self.value}{self.index}"
@staticmethod
def is_const():
"""Information whether wire carries constant value.

View File

@ -370,8 +370,8 @@ def test_wire_as_bus():
def __init__(self, a: Wire, b: Wire, c: Bus, prefix="test_circuit", **kwargs):
super().__init__(prefix=prefix, name="test_circuit", inputs=[a, b, c], out_N=1, **kwargs)
g = self.add_component(AndGate(a, b, prefix="g2"))
g2 = self.add_component(AndGate(g.out, c[0], prefix="g2"))
g3 = self.add_component(AndGate(g2.out, c[1], prefix="g2"))
g2 = self.add_component(AndGate(g.out, c[0], prefix="g3"))
g3 = self.add_component(AndGate(g2.out, c[1], prefix="g4"))
self.out[0] = g3.out
circ = test_circuit(Wire("a"), Wire("b"), Bus("c", 2), "c1")

View File

@ -18,11 +18,18 @@ from ariths_gen.wire_components import (
from ariths_gen.core.arithmetic_circuits import GeneralCircuit
from ariths_gen.multi_bit_circuits.others import (
UnsignedCompareLT
UnsignedCompareLT, UnsignedCompareLTE, UnsignedCompareGT, UnsignedCompareGTE
)
from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit, SignedCGPCircuit
def test_compare():
import numpy as np
import math
from io import StringIO
def test_compare_lt_same():
""" Test unsigned comparator """
N = 8
@ -33,9 +40,39 @@ def test_compare():
cmp = UnsignedCompareLT(a=a, b=b)
o = StringIO()
cmp.get_v_code_hier(open("tmp.verilog", "w"))
print(o.getvalue())
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av < bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_lt_small():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N//2, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**(N //2)).reshape(-1, 1)
cmp = UnsignedCompareLT(a=a, b=b)
#o = StringIO()
cmp.get_python_code_flat(open("tmp.py", "w"))
cmp.get_c_code_flat(open("tmp.c", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
@ -53,6 +90,290 @@ def test_compare():
np.testing.assert_array_equal(v, expected)
if __name__ == "__main__":
test_compare()
print("Python compare tests were successful!")
def test_compare_lte_same():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**N).reshape(-1, 1)
cmp = UnsignedCompareLTE(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av <= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_lte_small():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N//2, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**(N //2)).reshape(-1, 1)
cmp = UnsignedCompareLTE(a=a, b=b)
#o = StringIO()
cmp.get_python_code_flat(open("tmp.py", "w"))
cmp.get_c_code_flat(open("tmp.c", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av <= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_lte_small2():
""" Test unsigned comparator """
N = 8
a = Bus(N=N//2, prefix="a")
b = Bus(N=N, prefix="b")
av = np.arange(2**(N // 2)).reshape(1, -1)
bv = np.arange(2**(N)).reshape(-1, 1)
cmp = UnsignedCompareLTE(a=a, b=b)
#o = StringIO()
cmp.get_python_code_flat(open("tmp.py", "w"))
cmp.get_c_code_flat(open("tmp.c", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av <= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gt_same():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**N).reshape(-1, 1)
cmp = UnsignedCompareGT(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av > bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gt_small():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N//2, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**(N //2)).reshape(-1, 1)
cmp = UnsignedCompareGT(a=a, b=b)
#o = StringIO()
cmp.get_python_code_flat(open("tmp.py", "w"))
cmp.get_c_code_flat(open("tmp.c", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av > bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gte_same():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**N).reshape(-1, 1)
cmp = UnsignedCompareGTE(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av >= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gte_small():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N//2, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**(N //2)).reshape(-1, 1)
cmp = UnsignedCompareGTE(a=a, b=b)
#o = StringIO()
cmp.get_python_code_flat(open("tmp.py", "w"))
cmp.get_c_code_flat(open("tmp.c", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(av >= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gte_cgp_same():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**N).reshape(-1, 1)
cmp = UnsignedCompareGTE(a=a, b=b)
o = StringIO()
cmp.get_v_code_hier(open("tmp.verilog", "w"))
cmp.get_cgp_code_flat(o)
cgp = UnsignedCGPCircuit(o.getvalue(), [N, N])
v = cgp(av, bv)
print("ret = ", v)
expected = np.array(av >= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_compare_gte_cgp_small():
""" Test unsigned comparator """
N = 8
a = Bus(N=N, prefix="a")
b = Bus(N=N//2, prefix="b")
av = np.arange(2**N).reshape(1, -1)
bv = np.arange(2**(N //2)).reshape(-1, 1)
cmp = UnsignedCompareGTE(a=a, b=b)
o = StringIO()
cmp.get_v_code_flat(open("tmp.verilog", "w"))
cmp.get_cgp_code_flat(o)
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
cgp = UnsignedCGPCircuit(o.getvalue(), [N, N // 2])
v = cgp(av, bv)
#cmp.get_v_code_hier(open("tmp.verilog", "w"))
#print(o.getvalue())
# av = 0
# bv = 5
print("ret = ", v)
expected = np.array(av >= bv).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)

View File

@ -1,13 +1,4 @@
import os
import sys
# Add the parent directory to the system path
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(DIR_PATH, '..'))
import numpy as np
import math
from io import StringIO
from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit
from ariths_gen.wire_components import (
Wire,
ConstantWireValue0,
@ -52,7 +43,34 @@ def test_popcount():
np.testing.assert_array_equal(popcnt(av), expected)
def test_popcount_cgp():
""" Test unsigned adders """
N = 7
for N in [3, 7, 8, 9, 16]:
a = Bus(N=N, prefix="a")
av = np.arange(2**N)
popcnt = UnsignedPopCount(a=a)
o = StringIO()
popcnt.get_cgp_code_flat(o)
cgp = UnsignedCGPCircuit(o.getvalue(), [N])
v = cgp(av)
print(popcnt(av))
# conv to binary
r = []
a_s = av.copy()
for i in range(N):
r.append(a_s % 2)
a_s = a_s // 2
r = np.dstack(r).reshape(-1, N)
print("r = ", r)
expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
if __name__ == "__main__":
test_popcount()
print("Python popcnt tests were successful!")

View File

@ -0,0 +1,169 @@
from ariths_gen.wire_components import (
Wire,
ConstantWireValue0,
ConstantWireValue1,
Bus
)
from ariths_gen.core.arithmetic_circuits import GeneralCircuit
from ariths_gen.multi_bit_circuits.others import (
PopCountCompare
)
from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit, SignedCGPCircuit
import numpy as np
import math
from io import StringIO
from itertools import product
def test_popcountcompare_same():
N = 10
a = Bus(N=N, prefix="a")
b = Bus(N=N, prefix="b")
test_cases = list(product(list(range(2**N)), repeat=2))
all = np.array(test_cases)
print(all)
av = all[:, 0]
bv = all[:, 1]
def popcnt(x):
mask = x & (2**np.arange(N)).reshape(-1, 1)
return np.sum(mask > 0, axis=0)
cnta = (popcnt(av))
cntb = (popcnt(bv))
print(cnta)
print(cntb)
cmp = PopCountCompare(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(cnta >= cntb).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_popcountcompare_small():
N = 10
a = Bus(N=N, prefix="a")
b = Bus(N=N // 2, prefix="b")
test_cases = list(product(range(2**N), range(2**(N//2))))
all = np.array(test_cases)
print(all)
av = all[:, 0]
bv = all[:, 1]
def popcnt(x):
mask = x & (2**np.arange(N)).reshape(-1, 1)
return np.sum(mask > 0, axis=0)
cnta = (popcnt(av))
cntb = (popcnt(bv))
cmp = PopCountCompare(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(cnta >= cntb).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_popcountcompare_small2():
N = 10
a = Bus(N=N // 2, prefix="a")
b = Bus(N=N, prefix="b")
test_cases = list(product( range(2**(N//2)), range(2**N)))
all = np.array(test_cases)
print(all)
av = all[:, 0]
bv = all[:, 1]
def popcnt(x):
mask = x & (2**np.arange(N)).reshape(-1, 1)
return np.sum(mask > 0, axis=0)
cnta = (popcnt(av))
cntb = (popcnt(bv))
cmp = PopCountCompare(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
v = cmp(av, bv)
print("ret = ", v)
expected = np.array(cnta >= cntb).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)
def test_popcountcompare_small2_cgp():
N = 10
a = Bus(N=N // 2, prefix="a")
b = Bus(N=N, prefix="b")
test_cases = list(product( range(2**(N//2)), range(2**N)))
all = np.array(test_cases)
print(all)
av = all[:, 0]
bv = all[:, 1]
def popcnt(x):
mask = x & (2**np.arange(N)).reshape(-1, 1)
return np.sum(mask > 0, axis=0)
cnta = (popcnt(av))
cntb = (popcnt(bv))
cmp = PopCountCompare(a=a, b=b)
cmp.get_v_code_hier(open("tmp.verilog", "w"))
cmp.get_cgp_code_flat(open("tmp.cgp", "w"))
o = StringIO()
cmp.get_cgp_code_flat(o)
cgp = UnsignedCGPCircuit(o.getvalue(), [N//2, N])
v = cgp(av, bv)
print("ret = ", v)
expected = np.array(cnta >= cntb).astype(int)
print("expected = ", expected)
#expected = np.sum(r, axis=1)
np.testing.assert_array_equal(v, expected)