diff --git a/ariths_gen/core/arithmetic_circuits/general_circuit.py b/ariths_gen/core/arithmetic_circuits/general_circuit.py index 95d3f31..ffa0f90 100644 --- a/ariths_gen/core/arithmetic_circuits/general_circuit.py +++ b/ariths_gen/core/arithmetic_circuits/general_circuit.py @@ -1,6 +1,5 @@ from ariths_gen.core.logic_gate_circuits.logic_gate_circuit import ( - OneInputLogicGate, - TwoInputLogicGate + ThreeInputLogicGate ) from ariths_gen.wire_components import ( Wire, @@ -124,7 +123,7 @@ class GeneralCircuit(): """ # TODO should be refactored in ArithsGen rework # We should probably check also wire names for especially hierarchical generation - if isinstance(component, TwoInputLogicGate): + if isinstance(component, ThreeInputLogicGate): if component.disable_generation is False: self.circuit_gates.append(component) else: @@ -158,7 +157,7 @@ class GeneralCircuit(): Returns: int: Number of instances of the same class type. """ - if issubclass(cls, TwoInputLogicGate) and count_disabled_gates is False: + if issubclass(cls, ThreeInputLogicGate) and count_disabled_gates is False: return sum(isinstance(c, cls) for c in self.components if isinstance(c, cls) and c.disable_generation is False) else: return sum(isinstance(c, cls) for c in self.components) @@ -173,7 +172,7 @@ class GeneralCircuit(): """ gates = [] for c in self.components: - if isinstance(c, TwoInputLogicGate): + if isinstance(c, ThreeInputLogicGate): if (c.disable_generation is False) and (verilog_output is False or getattr(c, "use_verilog_instance", False) is False): gates.append(c) else: @@ -191,7 +190,7 @@ class GeneralCircuit(): """ one_bit_comps = [] for c in self.components: - if isinstance(c, TwoInputLogicGate): + if isinstance(c, ThreeInputLogicGate): continue elif all(isinstance(i, Wire) for i in self.inputs): one_bit_comps.append(c) @@ -208,7 +207,7 @@ class GeneralCircuit(): """ multi_bit_comps = [] for c in self.components: - if isinstance(c, TwoInputLogicGate): + if isinstance(c, ThreeInputLogicGate): continue elif all(isinstance(i, Wire) for i in self.inputs): continue @@ -340,7 +339,7 @@ class GeneralCircuit(): Returns: str: Flat Python code initialization of arithmetic circuit wires. """ - return "".join([c.get_assign_python_flat() if isinstance(c, TwoInputLogicGate) else c.get_init_python_flat() for c in self.components]) + return "".join([c.get_assign_python_flat() if isinstance(c, ThreeInputLogicGate) else c.get_init_python_flat() for c in self.components]) def get_function_out_python_flat(self): """Generates flat Python code assignment of corresponding arithmetic circuit's output bus wires. @@ -398,7 +397,7 @@ class GeneralCircuit(): Returns: str: Flat C code initialization of arithmetic circuit wires. """ - return "".join([c.get_assign_c_flat() if isinstance(c, TwoInputLogicGate) else c.get_init_c_flat() for c in self.components]) + return "".join([c.get_assign_c_flat() if isinstance(c, ThreeInputLogicGate) else c.get_init_c_flat() for c in self.components]) def get_function_out_c_flat(self): """Generates flat C code assignment of corresponding arithmetic circuit's output bus wires. @@ -469,7 +468,7 @@ class GeneralCircuit(): Returns: str: Hierarchical C code initialization of arithmetic circuit wires. """ - return "".join([c.get_gate_invocation_c() if isinstance(c, TwoInputLogicGate) else c.get_out_invocation_c() for c in self.components]) + return "".join([c.get_gate_invocation_c() if isinstance(c, ThreeInputLogicGate) else c.get_out_invocation_c() for c in self.components]) def get_out_invocation_c(self): """Generates hierarchical C code invocation of corresponding arithmetic circuit's generated function block. @@ -546,7 +545,7 @@ class GeneralCircuit(): Returns: str: Flat Verilog code initialization of arithmetic circuit wires. """ - return "".join([c.get_assign_v_flat() if isinstance(c, TwoInputLogicGate) else c.get_init_v_flat() for c in self.components]) + return "".join([c.get_assign_v_flat() if isinstance(c, ThreeInputLogicGate) else c.get_init_v_flat() for c in self.components]) def get_function_out_v_flat(self): """Generates flat Verilog code assignment of corresponding arithmetic circuit's output bus wires. @@ -614,7 +613,7 @@ class GeneralCircuit(): Returns: str: Hierarchical Verilog code initialization of arithmetic circuit wires. """ - return "".join([c.get_gate_invocation_v() if isinstance(c, TwoInputLogicGate) else c.get_out_invocation_v() for c in self.components]) + return "".join([c.get_gate_invocation_v() if isinstance(c, ThreeInputLogicGate) else c.get_out_invocation_v() for c in self.components]) def get_out_invocation_v(self): """Generates hierarchical Verilog code invocation of corresponding arithmetic circuit's generated function block. diff --git a/ariths_gen/core/logic_gate_circuits/__init__.py b/ariths_gen/core/logic_gate_circuits/__init__.py index 1612dae..052aa19 100644 --- a/ariths_gen/core/logic_gate_circuits/__init__.py +++ b/ariths_gen/core/logic_gate_circuits/__init__.py @@ -1,6 +1,4 @@ from .logic_gate_circuit import ( MultipleInputLogicGate, - TwoInputLogicGate, - TwoInputInvertedLogicGate, - OneInputLogicGate + ThreeInputLogicGate ) 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 76c122d..9b65120 100644 --- a/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py +++ b/ariths_gen/core/logic_gate_circuits/logic_gate_circuit.py @@ -53,15 +53,14 @@ class MultipleInputLogicGate(): a = Bus(prefix=a.prefix, N=N, wires_list=out_wires) self.out = a.get_wire(0) - # Two-input # -class TwoInputLogicGate(): - """Class representing two input logic gates. +class ThreeInputLogicGate(): + """Class representing tree input logic gates. ``` ┌──────┐ ──►│ FUNC │ - │ ├─► + ──►│ ├─► ──►│ │ └──────┘ ``` @@ -71,11 +70,12 @@ class TwoInputLogicGate(): Args: a (Wire): First input wire. b (Wire): Second input wire. + c (Wire): Third input wire. prefix (str, optional): Prefix name of logic gate. Defaults to "gate". outid (int, optional): Index of output wire. Defaults to 0. parent_component (object, optional) Object of upper component of which logic gate is a subcomponent. Defaults to None. """ - def __init__(self, a: Wire, b: Wire, prefix: str = "gate", outid: int = 0, parent_component: object = None): + def __init__(self, a: Wire, b: Wire, c: Wire, prefix: str = "gate", outid: int = 0, parent_component: object = None): self.a = a self.b = b self.prefix = prefix @@ -104,7 +104,7 @@ class TwoInputLogicGate(): Returns: str: Function's name and parameters in flat C code. """ - return f"uint8_t {self.prefix}(uint8_t {self.a.name}, uint8_t {self.b.name})" + "{" + "\n" + return f"uint8_t {self.prefix}(uint8_t {self.a.name}, uint8_t {self.b.name}, uint8_t {self.c.name})" + "{" + "\n" def get_function_c(self): """Generates C code representing corresponding two input logic gate's Boolean function using bitwise operators between its bitwise shifted inputs. @@ -114,7 +114,8 @@ class TwoInputLogicGate(): """ 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()}" + + return self.function.replace("A", self.a.get_wire_value_c_flat()).replace("B", self.b.get_wire_value_c_flat()).replace("C", self.c.get_wire_value_c_flat()) def get_declaration_c_flat(self): """Generates C code declaration of output wire for flat representation. @@ -154,51 +155,6 @@ class TwoInputLogicGate(): file_object.write(self.get_prototype_c_flat()) file_object.write(" return "+(self.get_function_c())+";\n}") - # HIERARCHICAL C # - def get_prototype_c_hier(self): - """Generates hierarchical C code function header to describe corresponding two input logic gate's interface in hierarchical C code. - - Returns: - str: Function's name and parameters in hierarchical C code. - """ - return f"uint8_t {self.gate_type}(uint8_t {self.a.name}, uint8_t {self.b.name})" + "{" + "\n" - - def get_function_block_c(self): - """Generates C code representation of corresponding logic gate used as a function block in hierarchical circuit description. - - Returns: - str: C code of logic gate's function block description. - """ - gate_block = type(self)(a=Wire(name="a"), b=Wire(name="b")) - return f"{gate_block.get_prototype_c_hier()}" + \ - f" return "+(gate_block.get_function_c())+";\n}\n\n" - - def get_declaration_c_hier(self): - """Generates C code declaration of output wire for hierarchical representation. - - Returns: - str: C code logic gate's output wire declaration. - """ - # No gate output wire 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 "" - else: - return f"{self.out.get_declaration_c()}" - - def get_gate_invocation_c(self): - """Generates C code invocation of corresponding logic gate's generated function block. - - Returns: - str: C code of logic gate's function block invocation. - """ - # No function block 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 "" - else: - return f" {self.out.name} = {self.gate_type}({self.a.get_wire_value_c_hier()}, {self.b.get_wire_value_c_hier()});\n" - """ PYTHON CODE GENERATION """ # FLAT PYTHON # def get_assign_python_flat(self): @@ -211,7 +167,6 @@ class TwoInputLogicGate(): # 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" @@ -254,7 +209,7 @@ class TwoInputLogicGate(): Returns: str: Verilog description of logic gate's Boolean function. """ - return f"{self.a.get_wire_value_v_flat()} {self.operator} {self.b.get_wire_value_v_flat()}" + return self.function.replace("A", self.a.get_wire_value_c_flat()).replace("B", self.b.get_wire_value_c_flat()).replace("C", self.c.get_wire_value_c_flat()) def get_assign_v_flat(self): """Generates Verilog code for invocation of logical functions and subsequently provides assignment to their output. @@ -281,53 +236,6 @@ class TwoInputLogicGate(): file_object.write(self.get_output_v_flat()) file_object.write(f"endmodule") - # HIERARCHICAL VERILOG # - def get_prototype_v_hier(self): - """Generates hierarchical Verilog module header to describe corresponding two input logic gate's interface in hierarchical Verilog. - - Returns: - str: Module's name and parameters in hierarchical Verilog. - """ - return f"module {self.gate_type}(input {self.a.name}, input {self.b.name}, output {self.out.name});\n" - - def get_function_block_v(self): - """Generates Verilog code representation of corresponding logic gate used as function block in hierarchical circuit description. - - Returns: - str: Verilog logic gate's function block description. - """ - gate_block = type(self)(a=Wire(name="a"), b=Wire(name="b"), prefix="out") - return f"{gate_block.get_prototype_v_hier()}" + \ - f" assign {gate_block.out.name} = {gate_block.get_function_v()};\n" + \ - f"endmodule\n\n" - - def get_declaration_v_hier(self): - """Generates Verilog code declaration of output wire for hierarchical representation. - - Returns: - str: Verilog code logic gate's output wire declaration. - """ - # No gate output wire 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 "" - else: - return f"{self.out.get_declaration_v_hier()}" - - def get_gate_invocation_v(self): - """Generates Verilog code invocation of corresponding logic gate's generated function block. - - Returns: - str: Verilog code logic gate's function block invocation. - """ - # No function block 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 "" - else: - gate_block = self.__class__(a=Wire(name="a"), b=Wire(name="b"), prefix="out") - return f" {self.gate_type} {self.gate_type}_{self.out.prefix}(.{gate_block.a.prefix}({self.a.get_wire_value_v_hier()}), .{gate_block.b.prefix}({self.b.get_wire_value_v_hier()}), .{gate_block.out.prefix}({self.out.prefix}));\n" - """ BLIF CODE GENERATION """ # FLAT BLIF # def get_prototype_blif_flat(self): @@ -381,394 +289,4 @@ class TwoInputLogicGate(): file_object.write(self.get_prototype_blif_flat()) file_object.write(self.get_declaration_blif()) file_object.write(self.get_function_blif_flat(top_modul=True)) - file_object.write(f".end\n") - - # HIERARCHICAL BLIF # - def get_prototype_blif_hier(self): - """Generates hierarchical Blif model header to describe corresponding logic gate's interface in hierarchical Blif. - - Returns: - str: Model's name in hierarchical Blif. - """ - return f".model {self.gate_type}\n" - - def get_function_block_blif(self): - """Generates Blif code representation of corresponding two input logic gate used as subcomponent in hierarchical circuit description. - - Returns: - str: Blif logic gate subcomponent description. - """ - gate_block = type(self)(a=Wire(name="a"), b=Wire(name="b"), prefix="out") - return f"{gate_block.get_prototype_blif_hier()}" + \ - f"{gate_block.get_declaration_blif()}" + \ - f"{gate_block.get_function_blif()}" + \ - f".end\n" - - def get_invocation_blif_hier(self, top_modul: bool = False, *args, **kwargs): - """Generates Blif code invocation of corresponding two input logic gate's generated subcomponent. - - Args: - top_modul (bool, optional): Specifies whether the described circuit has logic gate as its top modul component (used for self logic gate generation). Defaults to False. - - Returns: - str: Blif logic gate subcomponent invocation. - """ - # No function block 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 and top_modul is False: - return "" - else: - return f".subckt {self.gate_type} a={self.a.get_wire_value_blif()} b={self.b.get_wire_value_blif()} out={self.out.get_wire_value_blif()}\n" - - """ CGP CODE GENERATION """ - # FLAT CGP # - @staticmethod - def get_parameters_cgp(): - """Generates CGP chromosome parameters of corresponding logic gate. - - In total seven parameters represent: total inputs, total outputs, number of rows, number of columns (gates), - number of each gate's inputs, number of each gate's outputs, quality constant value. - - Returns: - str: CGP chromosome parameters of described logic gate. - """ - return "{2,1,1,1,2,1,0}" - - def get_triplet_cgp(self, a_id: int, b_id: int, out_id: int): - """Generates logic gate triplet (first input wire, second input wire, logic gate function) using wires unique position indexes within the described circuit. - - Each triplet represents unique logic gate within the described circuit. Besides the contained input wires indexes and gate's inner logic function, an output wire - with incremented index position is also created and remembered to be appropriately driven as an input to another logic gate or as the circuit's output. - - Constant wire with value 0 has constant index of 0. - Constant wire with value 1 has constant index of 1. - Other wires indexes start counting from 2 and up. - - Args: - a_id (int): First input wire index position. - b_id (int): Second input wire index position. - out_id (int): The output wire index position - - Returns: - str: Triplet describing function of corresponding two input logic gate. - """ - return f"([{out_id}]{a_id},{b_id},{self.cgp_function})" - - @staticmethod - def get_output_cgp(out_id: int): - """Generates list of output wires indexes of described two input logic gate from MSB to LSB. - - Args: - out_id (int): Output wire index position. - - Returns: - str: List containing logic gate's output wire indexes (one in this case). - """ - return f"({out_id})" - - def get_gate_triplet_cgp(self): - """Generates flat CGP triplet and output representation of corresponding logic gate itself. - - Returns: - str: Triplet and output lists describing function of corresponding two input logic gate. - """ - if self.a.is_const() and self.b.is_const(): - a_id = self.a.cgp_const - b_id = self.b.cgp_const - elif self.a.is_const(): - a_id = self.a.cgp_const - b_id = 2 - elif self.b.is_const(): - a_id = 2 - b_id = self.b.cgp_const - else: - a_id = 2 - b_id = 3 - - if self.out.is_const(): - out_id = self.out.cgp_const - else: - out_id = a_id+1 if a_id > b_id else b_id+1 - return self.get_triplet_cgp(a_id=a_id, b_id=b_id, out_id=out_id) + self.get_output_cgp(out_id=out_id) - - def get_cgp_code(self, file_object): - """Generates flat CGP chromosome representation of corresponding logic gate itself. - - Args: - file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. - """ - file_object.write(self.get_parameters_cgp()) - file_object.write(self.get_gate_triplet_cgp()) - - -class TwoInputInvertedLogicGate(TwoInputLogicGate): - """Class representing two input inverted logic gates. - - ``` - ┌──────┐ - ──►│ FUNC │ - │ │O──► - ──►│ │ - └──────┘ - ``` - - Description of the __init__ method. - - Args: - a (Wire): First input wire. - b (Wire): Second input wire. - prefix (str, optional): Prefix name of logic gate. Defaults to "gate". - outid (int, optional): Index of output wire. Defaults to 0. - parent_component (object, optional) Object of upper component of which logic gate is a subcomponent. Defaults to None. - """ - def __init__(self, a: Wire, b: Wire, prefix: str = "gate", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - - """ C CODE GENERATION """ - # FLAT C # - def get_function_c(self): - """Generates C code representing corresponding negated two input logic gate's Boolean function using bitwise operators between its bitwise shifted inputs. - - Returns: - str: C code description of negated logic gate's Boolean function (with bitwise shifted inputs). - """ - return "~("+(super().get_function_c()) + ") & 0x01" - - """ VERILOG CODE GENERATION """ - # FLAT VERILOG # - def get_function_v(self): - """Generates Verilog code representing corresponding negated two input logic gate's Boolean function using bitwise operators between its inputs. - - Returns: - str: Verilog description of negated logic gate's Boolean function. - """ - return "~("+(super().get_function_v())+")" - - -# One-input # -class OneInputLogicGate(TwoInputLogicGate): - """Class representing one input logic gates. - - ``` - ┌──────┐ - │ FUNC │ - ──►│ │───► - │ │ - └──────┘ - ``` - - Description of the __init__ method. - - Args: - a (Wire): First input wire. - prefix (str, optional): Prefix name of logic gate. Defaults to "gate". - outid (int, optional): Index of output wire. Defaults to 0. - parent_component (object, optional) Object of upper component of which logic gate is a subcomponent. Defaults to None. - """ - def __init__(self, a: Wire, prefix: str = "gate", outid: int = 0, parent_component: object = None): - self.a = a - self.prefix = prefix - self.outid = outid - # To toggle whether logic gate function ought to be generated or to be replaced - # by a constant wire for the sake of more optimized circuit generation - self.disable_generation = False - # Obtaining the caller object to gain access into its `components` list Used for adding NOT gates as a replacement for two input logic gates with constant input (optimalization) - # Also used to obtain caller object's `prefix` name for proper wire names generation of flat/hier representations - self.parent_component = parent_component - - """ C CODE GENERATION """ - # FLAT C # - def get_prototype_c_flat(self): - """Generates flat C code function header to describe corresponding one input logic gate's interface in flat C code. - - Returns: - str: Function's name and parameter in flat C code. - """ - return f"uint8_t {self.prefix}(uint8_t {self.a.name})" + "{" + "\n" - - def get_function_c(self): - """Generates C code representing corresponding one input logic gate's Boolean function using bitwise operators between its bitwise shifted input. - - Returns: - str: C code description of logic gate's Boolean function (with bitwise shifted input). - """ - return f"{self.operator}({self.a.get_wire_value_c_flat()}) & 0x01" - - # HIERARCHICAL C # - def get_prototype_c_hier(self): - """Generates hierarchical C code function header to describe corresponding one input logic gate's interface in hierarchical C code. - - Returns: - str: Function's name and parameters in hierarchical C code. - """ - return f"uint8_t {self.gate_type}(uint8_t {self.a.name})" + "{" + "\n" - - def get_function_block_c(self): - """Generates C code representation of corresponding logic gate used as a function block in hierarchical circuit description. - - Returns: - str: C code of logic gate's function block description. - """ - gate_block = type(self)(a=Wire(name="a")) - return f"{gate_block.get_prototype_c_hier()}" + \ - f" return "+(gate_block.get_function_c())+";\n}\n\n" - - def get_gate_invocation_c(self): - """Generates C code invocation of corresponding logic gate's generated function block. - - Returns: - str: C code of logic gate's function block invocation. - """ - # No function block 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 "" - else: - return f" {self.out.name} = {self.gate_type}({self.a.get_wire_value_c_hier()});\n" - - """ VERILOG CODE GENERATION """ - # FLAT VERILOG # - def get_prototype_v_flat(self): - """Generates flat Verilog module header to describe corresponding one input logic gate's interface in flat Verilog. - - Returns: - str: Module's name and parameter in flat Verilog. - """ - return f"module {self.prefix}(input {self.a.name}" + \ - "".join([f", output {self.out.name});\n" if self.disable_generation is False else f", output {self.out.name}_out);\n" for _ in range(1)]) - - def get_function_v(self): - """Generates Verilog code representing corresponding one input logic gate's Boolean function using bitwise operators between its input. - - Returns: - str: Verilog description of logic gate's Boolean function. - """ - return f"{self.operator}{self.a.get_wire_value_v_flat()}" - - # HIERARCHICAL VERILOG # - def get_prototype_v_hier(self): - """Generates hierarchical Verilog module header to describe corresponding one input logic gate's interface in hierarchical Verilog. - - Returns: - str: Module's name and parameter in hierarchical Verilog. - """ - return f"module {self.gate_type}(input {self.a.name}, output {self.out.name});\n" - - def get_function_block_v(self): - """Generates Verilog code representation of corresponding logic gate used as a function block in hierarchical circuit description. - - Returns: - str: Verilog code of logic gate's function block description. - """ - gate_block = type(self)(a=Wire(name="a"), prefix="out") - return f"{gate_block.get_prototype_v_hier()}" + \ - f" assign {gate_block.out.name} = {gate_block.get_function_v()};\n" + \ - f"endmodule\n\n" - - def get_gate_invocation_v(self): - """Generates Verilog code invocation of corresponding logic gate's generated function block. - - Returns: - str: Verilog code logic gate's function block invocation. - """ - # No function block 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 "" - else: - gate_block = self.__class__(a=Wire(name="a"), prefix="out") - return f" {self.gate_type} {self.gate_type}_{self.out.prefix}(.{gate_block.a.prefix}({self.a.get_wire_value_v_hier()}), .{gate_block.out.prefix}({self.out.prefix}));\n" - - """ BLIF CODE GENERATION """ - # FLAT BLIF # - def get_declaration_blif(self): - """Generates Blif code declaration of one input logic gate's wires. - - Returns: - str: Blif logic gate's wires declaration. - """ - return f".inputs {self.a.get_wire_declaration_blif()}\n" + \ - f".outputs" + \ - "".join([f" {self.out.name}\n" if self.disable_generation is False else f" {self.out.name}_out\n" for _ in range(1)]) + \ - f".names vdd\n1\n" + \ - f".names gnd\n0\n" - - # HIERARCHICAL BLIF # - def get_function_block_blif(self): - """Generates Blif code representation of corresponding one input logic gate used as subcomponent in hierarchical circuit description. - - Returns: - str: Blif logic gate subcomponent description. - """ - gate_block = type(self)(a=Wire(name="a"), prefix="out") - return f"{gate_block.get_prototype_blif_hier()}" + \ - f"{gate_block.get_declaration_blif()}" + \ - f"{gate_block.get_function_blif()}" + \ - f".end\n" - - def get_invocation_blif_hier(self, top_modul: bool = False, *args, **kwargs): - """Generates Blif code invocation of corresponding one input logic gate's generated subcomponent. - - Args: - top_modul (bool, optional): Specifies whether the described circuit has logic gate as its top modul component (used for self logic gate generation). Defaults to False. - - Returns: - str: Blif logic gate subcomponent invocation. - """ - # No function block 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 and top_modul is False: - return "" - else: - return f".subckt {self.gate_type} a={self.a.get_wire_value_blif()} out={self.out.get_wire_value_blif()}\n" - - """ CGP CODE GENERATION """ - # FLAT CGP # - def get_triplet_cgp(self, a_id: int, out_id: int): - """Generates logic gate triplet (first input wire, second input wire, logic gate function) using wires unique position indexes within the described circuit. - - Each triplet represents unique logic gate within the described circuit. In this case of one input logic gate, the same input wire index is driven to both inputs. - Besides the contained input wires indexes and gate's inner logic function, an output wire with incremented index position is also created and remembered to be - appropriately driven as an input to another logic gate or as the circuit's output. - - Constant wire with value 0 has constant index of 0. - Constant wire with value 1 has constant index of 1. - Other wires indexes start counting from 2 and up. - - Args: - a_id (int): First (used also as the second) input wire index position. - out_id (int): Outpu wire index position - - Returns: - str: Triplet describing function of corresponding one input logic gate. - """ - return f"([{out_id}]{a_id},{a_id},{self.cgp_function})" - - @staticmethod - def get_output_cgp(out_id: int): - """Generates list of output wires indexes of described one input logic gate from MSB to LSB. - - Args: - out_id (int): Output wire index position. - - Returns: - str: List containing logic gate's output wire indexes (one in this case). - """ - return f"({out_id})" - - def get_gate_triplet_cgp(self): - """Generates flat CGP triplet and output representation of corresponding logic gate itself. - - Returns: - str: Triplet and output lists describing function of corresponding one input logic gate. - """ - if self.a.is_const(): - a_id = self.a.cgp_const - else: - a_id = 2 - - if self.out.is_const(): - out_id = self.out.cgp_const - else: - out_id = a_id+1 if a_id == 2 else 2 - return self.get_triplet_cgp(a_id=a_id, out_id=out_id) + self.get_output_cgp(out_id=out_id) + file_object.write(f".end\n") \ No newline at end of file diff --git a/ariths_gen/multi_bit_circuits/approximate_multipliers/broken_carry_save_multiplier.py b/ariths_gen/multi_bit_circuits/approximate_multipliers/broken_carry_save_multiplier.py index 910bc9c..2f9e94d 100644 --- a/ariths_gen/multi_bit_circuits/approximate_multipliers/broken_carry_save_multiplier.py +++ b/ariths_gen/multi_bit_circuits/approximate_multipliers/broken_carry_save_multiplier.py @@ -5,9 +5,6 @@ from ariths_gen.wire_components import ( from ariths_gen.core.arithmetic_circuits import ( MultiplierCircuit, ) -from ariths_gen.core.logic_gate_circuits import ( - TwoInputLogicGate -) from ariths_gen.one_bit_circuits.one_bit_components import ( HalfAdder, FullAdder diff --git a/ariths_gen/one_bit_circuits/__init__.py b/ariths_gen/one_bit_circuits/__init__.py index e69de29..92c7026 100644 --- a/ariths_gen/one_bit_circuits/__init__.py +++ b/ariths_gen/one_bit_circuits/__init__.py @@ -0,0 +1 @@ +from .maji import Maji \ No newline at end of file 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 822b850..b3d3ce6 100644 --- a/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py +++ b/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py @@ -1,9 +1,9 @@ -from ariths_gen.core.logic_gate_circuits import TwoInputLogicGate, TwoInputInvertedLogicGate, OneInputLogicGate -from ariths_gen.wire_components import Wire, ConstantWireValue0, ConstantWireValue1 +from ariths_gen.one_bit_circuits import Maji +from ariths_gen.wire_components import Wire, ConstantWireValue0, ConstantWireValue1 # Two-input # -class AndGate(TwoInputLogicGate): +class AndGate(Maji): """Class representing two input AND gate. ``` @@ -24,45 +24,10 @@ class AndGate(TwoInputLogicGate): parent_component (object, optional) Object of upper component of which AND gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "and_gate" - self.cgp_function = 2 - self.operator = "&" - - # Logic gate output wire generation based on input values - # 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: - self.out = b - self.disable_generation = True - elif a.is_const() and a.value == 0: - self.out = ConstantWireValue0() - self.disable_generation = True - elif b.is_const() and b.value == 1: - self.out = a - self.disable_generation = True - elif b.is_const() and b.value == 0: - self.out = ConstantWireValue0() - self.disable_generation = True - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing AND gate Boolean function using its truth table. - - Returns: - str: Blif description of AND gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"11 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"11 1\n" + super().__init__(a, b, ConstantWireValue0(), prefix=prefix, outid=outid, parent_component=parent_component) -class NandGate(TwoInputInvertedLogicGate): +class NandGate(Maji): """Class representing two input NAND gate. ``` @@ -83,51 +48,9 @@ class NandGate(TwoInputInvertedLogicGate): parent_component (object, optional) Object of upper component of which NAND gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "nand_gate" - self.cgp_function = 5 - self.operator = "&" + super().__init__(a, b, ConstantWireValue1(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component) - # Logic gate output wire generation based on input values - # 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: - 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 - elif a.is_const() and a.value == 0: - self.out = ConstantWireValue1() - self.disable_generation = True - elif b.is_const() and b.value == 1: - 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 - elif b.is_const() and b.value == 0: - self.out = ConstantWireValue1() - self.disable_generation = True - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing NAND gate Boolean function using its truth table. - - Returns: - str: Blif description of NAND gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"0- 1\n-0 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"0- 1\n-0 1\n" - - -class OrGate(TwoInputLogicGate): +class OrGate(Maji): """Class representing two input OR gate. ``` @@ -148,45 +71,10 @@ class OrGate(TwoInputLogicGate): parent_component (object, optional) Object of upper component of which OR gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "or_gate" - self.cgp_function = 3 - self.operator = "|" - - # Logic gate output wire generation based on input values - # 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: - self.out = ConstantWireValue1() - self.disable_generation = True - elif a.is_const() and a.value == 0: - self.out = b - self.disable_generation = True - elif b.is_const() and b.value == 1: - self.out = ConstantWireValue1() - self.disable_generation = True - elif b.is_const() and b.value == 0: - self.out = a - self.disable_generation = True - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing OR gate Boolean function using its truth table. - - Returns: - str: Blif description of OR gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"1- 1\n-1 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"1- 1\n-1 1\n" + super().__init__(a, b, ConstantWireValue1(), prefix=prefix, outid=outid, parent_component=parent_component) -class NorGate(TwoInputInvertedLogicGate): +class NorGate(Maji): """Class representing two input NOR gate. ``` @@ -207,51 +95,9 @@ class NorGate(TwoInputInvertedLogicGate): parent_component (object, optional) Object of upper component of which NOR gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "nor_gate" - self.cgp_function = 6 - self.operator = "|" + super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component) - # Logic gate output wire generation based on input values - # 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: - self.out = ConstantWireValue0() - self.disable_generation = True - elif a.is_const() and a.value == 0: - 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 - elif b.is_const() and b.value == 1: - self.out = ConstantWireValue0() - self.disable_generation = True - elif b.is_const() and b.value == 0: - 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 - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing NOR gate Boolean function using its truth table. - - Returns: - str: Blif description of NOR gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"00 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"00 1\n" - - -class XorGate(TwoInputLogicGate): +class XorGate(Maji): """Class representing two input XOR gate. ``` @@ -272,51 +118,17 @@ class XorGate(TwoInputLogicGate): parent_component (object, optional) Object of upper component of which XOR gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "xor_gate" - self.cgp_function = 4 - self.operator = "^" - # Logic gate output wire generation based on input values - # 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: - 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 - elif a.is_const() and a.value == 0: - self.out = b - self.disable_generation = True - elif b.is_const() and b.value == 1: - 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 - elif b.is_const() and b.value == 0: - self.out = a - self.disable_generation = True - else: - self.out = Wire(name=prefix) + super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component) + """super().__init__(a, b, prefix=prefix, outid=outid, parent_component=parent_component) - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing XOR gate Boolean function using its truth table. - - Returns: - str: Blif description of XOR gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"01 1\n10 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"01 1\n10 1\n" + self.and1 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, False, False], parent_component = parent_component) + self.and2 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[False, True, False], parent_component = parent_component) + self.orOut = Maji(self.and1.out, self.and2.out, ConstantWireValue1(), prefix=prefix, parent_component = parent_component) + self.out = self.orOut.out""" -class XnorGate(TwoInputInvertedLogicGate): +class XnorGate(Maji): """Class representing two input XNOR gate. ``` @@ -337,52 +149,17 @@ class XnorGate(TwoInputInvertedLogicGate): parent_component (object, optional) Object of upper component of which XNOR gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, b, prefix, outid, parent_component) - self.gate_type = "xnor_gate" - self.cgp_function = 7 - self.operator = "^" + """super().__init__(a, b, prefix=prefix, outid=outid, parent_component=parent_component) - # Logic gate output wire generation based on input values - # 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: - self.out = b - self.disable_generation = True - elif a.is_const() and a.value == 0: - 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 - elif b.is_const() and b.value == 1: - self.out = a - self.disable_generation = True - elif b.is_const() and b.value == 0: - 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 - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing XNOR gate Boolean function using its truth table. - - Returns: - str: Blif description of XNOR gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"00 1\n11 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"00 1\n11 1\n" + self.and1 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, False, False], parent_component = parent_component) + self.and2 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[False, True, False], parent_component = parent_component) + self.orOut = Maji(self.and1.out, self.and2.out, ConstantWireValue1(), prefix=prefix, parent_component = parent_component) + self.out = self.orOut.out""" + super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component) # Single-input # -class NotGate(OneInputLogicGate): +class NotGate(Maji): """Class representing one input NOT gate. ``` @@ -402,33 +179,4 @@ class NotGate(OneInputLogicGate): parent_component (object, optional) Object of upper component of which NOT gate is a subcomponent. Defaults to None. """ def __init__(self, a: Wire, prefix: str = "", outid: int = 0, parent_component: object = None): - super().__init__(a, prefix, outid, parent_component) - self.gate_type = "not_gate" - self.cgp_function = 1 - self.operator = "~" - - # Logic gate output wire generation based on input values - # 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: - self.out = ConstantWireValue0() - self.disable_generation = True - elif a.is_const() and a.value == 0: - self.out = ConstantWireValue1() - self.disable_generation = True - else: - self.out = Wire(name=prefix) - - """ BLIF CODE GENERATION """ - def get_function_blif(self): - """Generates Blif code representing NOT gate Boolean function using its truth table. - - Returns: - str: Blif description of NOT gate's Boolean function. - """ - if self.disable_generation: - return f".names {self.a.get_wire_value_blif()} {self.out.name}_out\n" + \ - f"0 1\n" - else: - return f".names {self.a.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ - f"0 1\n" + super().__init__(a, a, a, prefix=prefix, inverts=[True, True, True], outid=outid, parent_component=parent_component) diff --git a/ariths_gen/one_bit_circuits/maji.py b/ariths_gen/one_bit_circuits/maji.py new file mode 100644 index 0000000..9b99095 --- /dev/null +++ b/ariths_gen/one_bit_circuits/maji.py @@ -0,0 +1,78 @@ +from ariths_gen.wire_components import ( + Wire +) + +from ariths_gen.core.logic_gate_circuits import ( + ThreeInputLogicGate +) + +from typing import List + +class Maji(ThreeInputLogicGate): + """ + Args: + a (Wire): First input wire. + b (Wire): Second input wire. + c (Wire): Second input wire. + inverts: inversion of input edges [A, B, C], defaults is [False, False, False] + prefix (str, optional): Prefix name of unsigned bka. Defaults to "". + name (str, optional): Name of unsigned bka. Defaults to "u_maji". + """ + def __init__(self, a: Wire, b: Wire, c: Wire, inverts: List[bool] = [False, False, False], prefix: str = "", **kwargs): + super().__init__(a, b, c, prefix=prefix, **kwargs) + + self.inverts = inverts + self.gate_type = "maji_gate" + self.cgp_function = 0 + self.disable_generation = False + + self.a = a + self.b = b + self.c = c + + aIn = '~A' if inverts[0] else 'A' + bIn = '~B' if inverts[1] else 'B' + cIn = '~C' if inverts[2] else 'C' + + self.function = f"({aIn} & {bIn}) | ({bIn} & {cIn}) | ({aIn} & {cIn})" + + # @todo optimalize by const inputs + + self.out = Wire(name="out_" + prefix) + + """ BLIF CODE GENERATION """ + def get_function_blif(self): + """Generates Blif code representing AND gate Boolean function using its truth table. + + Returns: + str: Blif description of MAJI gate's Boolean function. + """ + + tt = "" + + for varinat in range(2**3): ## for all input varinats + inputs = [ + (varinat & 0b001) > 0, + (varinat & 0b010) > 0, + (varinat & 0b100) > 0 + ] + + iinputs = inputs[:] # inverted inputs by self.inverts + + # invert input edge if set + for i in range(len(iinputs)): + if self.inverts[i]: + iinputs[i] = not(iinputs[i]) + + # compute output + out = iinputs[0] and iinputs[1] or iinputs[1] and iinputs[2] or iinputs[0] and iinputs[2] + + if out: + inputs[0] = '1' if inputs[0] else '-1' + inputs[1] = '1' if inputs[1] else '-1' + inputs[2] = '1' if inputs[2] else '-1' + + tt += f"{input[0]}{input[1]}{input[2]} 1\n" + + return f".names {self.a.get_wire_value_blif()} {self.b.get_wire_value_blif()} {self.c.get_wire_value_blif()} {self.out.get_wire_value_blif()}\n" + \ + out \ No newline at end of file diff --git a/tests/test_maji.py b/tests/test_maji.py new file mode 100644 index 0000000..b3008f3 --- /dev/null +++ b/tests/test_maji.py @@ -0,0 +1,57 @@ +import os, sys + +DIR_PATH = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(DIR_PATH, '..')) + +import numpy as np +from ariths_gen.core.arithmetic_circuits.general_circuit import GeneralCircuit +from ariths_gen.wire_components import Bus +from ariths_gen.one_bit_circuits import Maji + +from ariths_gen.pdk import * + +class MultiMaji(GeneralCircuit): + def __init__(self, a: Bus, b: Bus, c: Bus, prefix: str = "", name: str = "maji", **kwargs): + super().__init__(prefix=prefix, name=name, out_N=a.N, inputs=[a, b, c], **kwargs) + + self.out = Bus("out", a.N * 4) + + assert a.N == b.N + assert b.N == c.N + + for i in range(a.N): + self.maji = self.add_component(Maji(a.get_wire(i), b.get_wire(i), c.get_wire(i), parent_component=self, prefix="ABC")) + self.maji1 = self.add_component(Maji(a.get_wire(i), b.get_wire(i), c.get_wire(i), inverts=[True, False, False], parent_component=self, prefix="NABC")) + self.maji2 = self.add_component(Maji(a.get_wire(i), b.get_wire(i), c.get_wire(i), inverts=[False, True, False], parent_component=self, prefix="ANBC")) + self.maji3 = self.add_component(Maji(a.get_wire(i), b.get_wire(i), c.get_wire(i), inverts=[False, False, True], parent_component=self, prefix="ABNC")) + + self.out.connect(i, self.maji.out) + self.out.connect(a.N + i, self.maji1.out) + self.out.connect(a.N * 2 + i, self.maji2.out) + self.out.connect(a.N * 3 + i, self.maji3.out) + +# usage +if __name__ == "__main__": + maji = MultiMaji(Bus("a", 1), Bus("b", 1), Bus("c", 1)) + + # try to test maji + for varinat in range(16): + a = varinat & 0b001 + b = (varinat & 0b010) >> 1 + c = (varinat & 0b100) >> 2 + + testOut = maji(a, b, c) + + #compute mayority + expected = np.bincount([a, b, c]).argmax() + expected1 = np.bincount([~a & 0b1, b, c]).argmax() + expected2 = np.bincount([a, ~b & 0b1, c]).argmax() + expected3 = np.bincount([a, b, ~c & 0b01]).argmax() + + expectedBus = expected | expected1 << 1 | expected2 << 2 | expected3 << 3 + + if (expectedBus != testOut): + print(f"expexted {expectedBus} have {testOut}") + exit(1) + + print("Test maji OK") diff --git a/tests/test_maji_gates.py b/tests/test_maji_gates.py new file mode 100644 index 0000000..d2b01b6 --- /dev/null +++ b/tests/test_maji_gates.py @@ -0,0 +1,52 @@ + +import os, sys + +DIR_PATH = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(DIR_PATH, '..')) + +from ariths_gen.core.arithmetic_circuits import GeneralCircuit +from ariths_gen.one_bit_circuits.logic_gates import AndGate, NandGate, NorGate, NotGate, OrGate +from ariths_gen.wire_components import Bus + +from ariths_gen.pdk import * +import os + +class MultiMaji(GeneralCircuit): + def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "maji", **kwargs): + super().__init__(prefix=prefix, name=name, out_N=a.N, inputs=[a, b], **kwargs) + + self.out = Bus("out", a.N * 5) + + assert a.N == b.N + + for i in range(a.N): + self.orGate = self.add_component( OrGate(a.get_wire(i), b.get_wire(i), parent_component=self, prefix="or")) + self.andGate = self.add_component( AndGate(a.get_wire(i), b.get_wire(i), parent_component=self, prefix="and")) + self.norGate = self.add_component( NorGate(a.get_wire(i), b.get_wire(i), parent_component=self, prefix="nor")) + self.nandGate = self.add_component(NandGate(a.get_wire(i), b.get_wire(i), parent_component=self, prefix="nand")) + self.notGate = self.add_component( NotGate(a.get_wire(i), parent_component=self, prefix="not")) + + self.out.connect(i , self.orGate.out) + self.out.connect(a.N + i, self.andGate.out) + self.out.connect(a.N * 2 + i, self.norGate.out) + self.out.connect(a.N * 3 + i, self.nandGate.out) + self.out.connect(a.N * 4 + i, self.notGate.out) + +# usage +if __name__ == "__main__": + maji = MultiMaji(Bus("a", 1), Bus("b", 1)) + + # try to test maji + for varinat in range(4): + a = varinat & 0b01 + b = (varinat & 0b10) >> 1 + + testOut = maji(a, b) + + expectedBus = (a | b) | (a & b) << 1 | (~(a | b) & 0b1) << 2 | (~(a & b) & 0b1) << 3 | (~a & 0b1) << 4 + + if (expectedBus != testOut): + print(f"expexted {expectedBus} have {testOut}") + exit(1) + + print("Test maji as logic gates OK")