diff --git a/ariths_gen/core/arithmetic_circuits/general_circuit.py b/ariths_gen/core/arithmetic_circuits/general_circuit.py index 20b380d..c6571a1 100644 --- a/ariths_gen/core/arithmetic_circuits/general_circuit.py +++ b/ariths_gen/core/arithmetic_circuits/general_circuit.py @@ -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: diff --git a/ariths_gen/core/cgp_circuit.py b/ariths_gen/core/cgp_circuit.py index cbb5fbc..be1a6cb 100644 --- a/ariths_gen/core/cgp_circuit.py +++ b/ariths_gen/core/cgp_circuit.py @@ -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): diff --git a/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py b/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py index eac7a40..c24c2c2 100644 --- a/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py +++ b/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py @@ -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" diff --git a/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py b/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py index 4665b50..439286c 100644 --- a/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py +++ b/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py @@ -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 diff --git a/ariths_gen/multi_bit_circuits/others/__init__.py b/ariths_gen/multi_bit_circuits/others/__init__.py index 44ed65b..de090f3 100644 --- a/ariths_gen/multi_bit_circuits/others/__init__.py +++ b/ariths_gen/multi_bit_circuits/others/__init__.py @@ -8,5 +8,7 @@ from ariths_gen.multi_bit_circuits.others.bit_reduce import ( ) from ariths_gen.multi_bit_circuits.others.compare import ( - UnsignedCompareLT -) \ No newline at end of file + UnsignedCompareLT, UnsignedCompareLTE, UnsignedCompareGT, UnsignedCompareGTE +) + +from ariths_gen.multi_bit_circuits.others.popcount_compare import PopCountCompare \ No newline at end of file diff --git a/ariths_gen/multi_bit_circuits/others/bit_reduce.py b/ariths_gen/multi_bit_circuits/others/bit_reduce.py index 45da4d7..bd0cd8b 100644 --- a/ariths_gen/multi_bit_circuits/others/bit_reduce.py +++ b/ariths_gen/multi_bit_circuits/others/bit_reduce.py @@ -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 diff --git a/ariths_gen/multi_bit_circuits/others/compare.py b/ariths_gen/multi_bit_circuits/others/compare.py index 6c62970..6e92ce1 100644 --- a/ariths_gen/multi_bit_circuits/others/compare.py +++ b/ariths_gen/multi_bit_circuits/others/compare.py @@ -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 ) \ No newline at end of file + 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) \ No newline at end of file diff --git a/ariths_gen/multi_bit_circuits/others/popcount.py b/ariths_gen/multi_bit_circuits/others/popcount.py index 00e5d79..04fcda3 100644 --- a/ariths_gen/multi_bit_circuits/others/popcount.py +++ b/ariths_gen/multi_bit_circuits/others/popcount.py @@ -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 diff --git a/ariths_gen/multi_bit_circuits/others/popcount_compare.py b/ariths_gen/multi_bit_circuits/others/popcount_compare.py new file mode 100644 index 0000000..1f2095c --- /dev/null +++ b/ariths_gen/multi_bit_circuits/others/popcount_compare.py @@ -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) diff --git a/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py b/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py index f0c74db..822b850 100644 --- a/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py +++ b/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py @@ -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 diff --git a/ariths_gen/wire_components/wires.py b/ariths_gen/wire_components/wires.py index 8a68d1e..6c8f993 100644 --- a/ariths_gen/wire_components/wires.py +++ b/ariths_gen/wire_components/wires.py @@ -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. diff --git a/tests/test_all.py b/tests/test_all.py index d194669..bcd9342 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -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") diff --git a/tests/test_compare.py b/tests/test_compare.py index 9375887..f0f5bd7 100644 --- a/tests/test_compare.py +++ b/tests/test_compare.py @@ -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!") \ No newline at end of file + + +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) diff --git a/tests/test_popcnt.py b/tests/test_popcnt.py index 85bf55c..52de63f 100644 --- a/tests/test_popcnt.py +++ b/tests/test_popcnt.py @@ -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!") diff --git a/tests/test_popcount_compare.py b/tests/test_popcount_compare.py new file mode 100644 index 0000000..3f02ede --- /dev/null +++ b/tests/test_popcount_compare.py @@ -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)