diff --git a/README.md b/README.md index aeae52c..fc5ae25 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ python3 ariths_gen.py ## Documentation Code documentation is provided using **pdoc** documentation generator tool. Source: https://pdoc3.github.io/pdoc/. -### Instalation +### Installation ```bash pip3 install pdoc3 ``` diff --git a/ariths_gen/core/arithmetic_circuit.py b/ariths_gen/core/arithmetic_circuit.py index 64a810b..1dab7d0 100644 --- a/ariths_gen/core/arithmetic_circuit.py +++ b/ariths_gen/core/arithmetic_circuit.py @@ -27,15 +27,41 @@ class ArithmeticCircuit(): self.N = 1 def add_component(self, component): + """Adds component into a list of circuit's inner subcomponents. + + Args: + component: Subcomponent to be added into list of components composing described circuit. + """ self.components.append(component) def get_previous_component(self, number: int = 1): + """Retrieves previously added composite subcomponent from circuit's list of components. + + Args: + number (int, optional): Offset indicating which lastly added component will be retrieved. Defaults to 1. + + Returns: + component: Desired previously added composite component. + """ return self.components[-number] def get_instance_num(self, cls): + """Informs how many instances of the same type are already present inside circuit's components list. + + Args: + cls (type): Class type of which to search for instances. + + Returns: + int: Number of instances of the same class type. + """ return sum(isinstance(c, cls) for c in self.components) - def get_unique_one_bit_components(self): + def get_one_bit_components(self): + """Retrieves list of all one bit circuits (besides logic gates) present as subcomponents inside the circuit. + + Returns: + list: List of composite one bit circuits. + """ one_bit_comps = [] for c in self.components: if isinstance(c, LogicGate): @@ -43,11 +69,16 @@ class ArithmeticCircuit(): elif type(getattr(c, 'a')) == Wire: one_bit_comps.append(c) else: - one_bit_comps.extend(c.get_unique_one_bit_components()) + one_bit_comps.extend(c.get_one_bit_components()) return one_bit_comps - def get_unique_multi_bit_components(self): + def get_multi_bit_components(self): + """Retrieves list of all multi bit circuits present as subcomponents inside the circuit. + + Returns: + list: List of composite multi bit circuits. + """ multi_bit_comps = [] for c in self.components: if isinstance(c, LogicGate): @@ -60,23 +91,51 @@ class ArithmeticCircuit(): @staticmethod def get_unique_types(components: list): + """Retrieves just the unique representatives of class types present inside the provided components list. + + Args: + components (list): List of components to be filtered. + + Returns: + list: List of unique composite class types. + """ return list({type(c): c for c in components}.values()) def get_component_types(self): + """Retrieves list of all unique types of subcomponents composing the circuit. + + Returning list consists of unique types of logic gates, one bit circuits and multi bit circuits. + + Returns: + list: List of unique component types describing the circuit. + """ gate_comps = self.get_unique_types(components=self.get_circuit_gates()) - one_bit_comps = self.get_unique_types(components=self.get_unique_one_bit_components()) - multi_bit_comps = self.get_unique_types(components=self.get_unique_multi_bit_components()) + one_bit_comps = self.get_unique_types(components=self.get_one_bit_components()) + multi_bit_comps = self.get_unique_types(components=self.get_multi_bit_components()) all_components = gate_comps + one_bit_comps + multi_bit_comps return all_components def get_sum_wire(self): + """Get output wire carrying sum value. + + Returns: + Wire: Return sum wire. + """ return self.out.get_wire(0) def get_carry_wire(self): + """Get output wire carrying carry out value. + + Returns: + Wire: Return carry out wire. + """ return self.out.get_wire(1) def get_circuit_wires(self): + """Retrieves all the unique wires used for interconnecting subcomponents inside the circuit and stores them inside `self.circuit_wires` list. + Additionally stores all unique names of just the inner input wires inside `self.inputs` list. + """ self.circuit_wires = [] for component in self.components: if not [item for item in self.circuit_wires if item[1] == component.a.name]: @@ -91,14 +150,25 @@ class ArithmeticCircuit(): # Get unique names of all inner input circuits (mainly used in one bit circuits) self.inputs = [i[0] for i in self.circuit_wires if i[0] not in [o.out for o in self.components]] - # Search for circuit's wire unique index for cgp chromosome generation def get_circuit_wire_index(self, wire: Wire): + """Searches for circuit's wire unique index position within the circuit. Used for cgp chromosome generation. + + Args: + wire (Wire): Wire to retrieve index position of. + + Returns: + int: Wire's index position number within the circuit. + """ for w in self.circuit_wires: if wire.name.endswith(w[1]): return w[2] - # Get list of all gates present in circuit def get_circuit_gates(self): + """Gets list of all logic gates present in circuit. + + Returns: + list: List of composite logic gates. + """ gates = [] for c in self.components: if isinstance(c, LogicGate): @@ -107,8 +177,9 @@ class ArithmeticCircuit(): gates.extend((c.get_circuit_gates())) return gates - # Get list of all wires in circuit along with their index position for cgp chromosome generation def get_cgp_wires(self): + """Gets list of all wires in circuit along with their index position for cgp chromosome generation and stores them inside `self.circuit_wires` list. + """ self.circuit_wires = [] if isinstance(self.a, Bus): [self.circuit_wires.append((w, f"_{w.name}", len(self.circuit_wires))) for w in self.a.bus] @@ -133,34 +204,74 @@ class ArithmeticCircuit(): # FLAT C # @staticmethod def get_includes_c(): + """Generates necessary C library includes for output representation. + + Returns: + str: C code library includes. + """ return f"#include \n#include \n\n" def get_prototype_c(self): + """Generates C code function header to describe corresponding arithmetic circuit's interface in C code. + + Returns: + str: Function's name and parameters in C code. + """ return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + "\n" def get_declarations_c_flat(self): + """Generates flat C code declaration of input/output buses wires. + + Returns: + str: Flattened C code arithmetic circuit's wires declaration. + """ return f"{self.a.get_wire_declaration_c()}" + \ f"{self.b.get_wire_declaration_c()}" + \ f"".join([c.get_declaration_c_flat() for c in self.components]) # For multi-bit circuit wires declaration def get_declaration_c_flat(self): + """Generates flat C code declaration of input/output buses wires of multi-bit arithmetic circuit present as subcomponent in the circuit. + + Returns: + str: Flattened C code multi-bit arithmetic circuit subcomponent wires declaration. + """ return f"".join([c.get_declaration_c_flat() for c in self.components]) def get_inits_c_flat(self): + """Generates flat C code initialization and assignment of corresponding arithmetic circuit's input/output buses wires. + + Returns: + str: Flattened C code initialization of arithmetic circuit wires. + """ return f"{self.a.get_wire_assign_c()}" + \ f"{self.b.get_wire_assign_c()}" + \ "".join([c.get_assign_c_flat() if isinstance(c, LogicGate) else c.get_init_c_flat() for c in self.components]) # For multi-bit circuit wires initialization def get_init_c_flat(self): + """Generates flat C code initialization and assignment of input/output buses wires of multi-bit arithmetic circuit present as subcomponent in the circuit. + + Returns: + str: Flattened C code multi-bit arithmetic circuit subcomponent wires initialization. + """ return "".join([c.get_assign_c_flat() if isinstance(c, LogicGate) 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. + + Returns: + str: Flattened C code containing output bus wires assignment. + """ return "".join([f" {self.out.prefix} |= {o.return_wire_value_c(offset=self.out.bus.index(o))};\n" for o in self.out.bus]) # Generating flat C code representation of circuit def get_c_code_flat(self, file_object): + """Generates flat C code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_includes_c()) file_object.write(self.get_prototype_c()) file_object.write(self.out.get_declaration_c()) @@ -172,33 +283,71 @@ class ArithmeticCircuit(): # HIERARCHICAL C # def get_function_blocks_c(self): + """Generates hierarchical C code representation of all subcomponents function blocks present in corresponding arithmetic circuit. + + Returns: + str: Hierarchical C code of all subcomponents function blocks description. + """ # Add unique component types composing this circuit self.component_types = self.get_component_types() return "".join([c.get_function_block_c() for c in self.component_types]) def get_function_block_c(self): + """Generates hierarchical C code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical C code of multi-bit arithmetic circuit's function block description. + """ # Obtain proper adder name with its bit width adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N) adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix) return f"{adder_block.get_circuit_c()}\n\n" def get_declaration_c_hier(self): + """Generates hierarchical C code declaration of input/output buses wires. + + Returns: + str: Hierarchical C code containing unique declaration of arithmetic circuit wires. + """ return "".join(self.a.get_wire_declaration_c()) + \ "".join(self.b.get_wire_declaration_c()) + \ "".join([c.out.get_declaration_c() if isinstance(c, LogicGate) else c.get_wire_declaration_c_hier() for c in self.components]) def get_wire_declaration_c_hier(self): + """Generates hierarchical C code declaration of corresponding subcomponent input/output buses wires inside the upper component. + + Generates wires used to connect input/output values to/from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchical C code of subcomponent arithmetic circuit's wires declaration. + """ return f" {self.c_data_type} {self.prefix}_{self.a.prefix} = 0;\n" + \ f" {self.c_data_type} {self.prefix}_{self.b.prefix} = 0;\n" + \ f" {self.c_data_type} {self.prefix}_{self.out.prefix} = 0;\n" + \ f"{self.out.get_wire_declaration_c()}" def get_init_c_hier(self): + """Generates hierarchical C code initialization and assignment of corresponding arithmetic circuit's input/output buses wires. + + Returns: + str: Hierarchical C code initialization of arithmetic circuit wires. + """ return f"{self.a.get_wire_assign_c()}" + \ f"{self.b.get_wire_assign_c()}" + \ "".join([f" {c.out.name} = {c.get_gate_invocation_c()}" if isinstance(c, LogicGate) else c.get_out_invocation_c(circuit_prefix=self.prefix) for c in self.components]) def get_out_invocation_c(self, circuit_prefix: str): + """Generates hierarchical C code invocation of corresponding arithmetic circuit's generated function block. + + Assigns input values from other subcomponents into multi-bit input buses used as inputs for function block invocation. + Assigns output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Args: + circuit_prefix (str): Prefix name of the upper component from which function block is being invoked. + + Returns: + str: Hierarchical C code of subcomponent's C function invocation and output assignment. + """ # Getting name of circuit type and insitu copying out bus for proper C code generation without affecting actual generated composition circuit_type = self.prefix.replace(circuit_prefix+"_", "") out = Bus(prefix=self.prefix+"_"+self.out.prefix, wires_list=self.out.bus) @@ -208,9 +357,19 @@ class ArithmeticCircuit(): f"{out.get_wire_assign_c()}" def get_function_out_c_hier(self): + """Generates hierarchical C code assignment of corresponding arithmetic circuit's output bus wires. + + Returns: + str: Hierarchical C code containing output bus wires assignment. + """ return "".join([f" {self.out.prefix} |= {o.return_wire_value_c(offset=self.out.bus.index(o))};\n" for o in self.out.bus]) def get_circuit_c(self): + """Generates hierarchical C code subcomponent's function block. + + Returns: + str: Hierarchical C code of subcomponent's function block. + """ return f"{self.get_prototype_c()}" + \ f"{self.out.get_declaration_c()}" + \ f"{self.get_declaration_c_hier()}\n" + \ @@ -220,6 +379,11 @@ class ArithmeticCircuit(): # Generating hierarchical C code representation of circuit def get_c_code_hier(self, file_object): + """Generates hierarchical C code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_includes_c()) file_object.write(self.get_function_blocks_c()) file_object.write(self.get_circuit_c()) @@ -228,29 +392,66 @@ class ArithmeticCircuit(): """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_prototype_v(self): + """Generates Verilog code module header to describe corresponding arithmetic circuit's interface in Verilog code. + + Returns: + str: Module's name and parameters in Verilog code. + """ return f"module {self.prefix}(input [{self.N-1}:0] {self.a.prefix}, input [{self.N-1}:0] {self.b.prefix}, output [{self.out.N-1}:0] {self.out.prefix});\n" def get_declarations_v_flat(self): + """Generates flat Verilog code declaration of input/output buses wires. + + Returns: + str: Flattened Verilog code arithmetic circuit's wires declaration. + """ return f"{self.a.get_wire_declaration_v()}" + \ f"{self.b.get_wire_declaration_v()}" + \ f"".join([c.get_declaration_v_flat() for c in self.components]) + # For multi-bit circuit wires declaration def get_declaration_v_flat(self): + """Generates flat Verilog code declaration of input/output buses wires of multi-bit arithmetic circuit present as subcomponent in the circuit. + + Returns: + str: Flattened Verilog code multi-bit arithmetic circuit subcomponent wires declaration. + """ return f"".join([c.get_declaration_v_flat() for c in self.components]) def get_inits_v_flat(self): + """Generates flat Verilog code initialization and assignment of corresponding arithmetic circuit's input/output buses wires. + + Returns: + str: Flattened Verilog code initialization of arithmetic circuit wires. + """ return f"{self.a.get_wire_assign_v()}" + \ f"{self.b.get_wire_assign_v()}" + \ "".join([c.get_assign_v_flat() if isinstance(c, LogicGate) else c.get_init_v_flat() for c in self.components]) + # For multi-bit circuit wires initialization def get_init_v_flat(self): + """Generates flat Verilog code initialization and assignment of input/output buses wires of multi-bit arithmetic circuit present as subcomponent in the circuit. + + Returns: + str: Flattened Verilog code multi-bit arithmetic circuit subcomponent wires initialization. + """ return "".join([c.get_assign_v_flat() if isinstance(c, LogicGate) 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. + + Returns: + str: Flattened Verilog code containing output bus wires assignment. + """ return "".join([f" assign {self.out.prefix}[{self.out.bus.index(o)}] = {o.prefix};\n" for o in self.out.bus]) # Generating flat Verilog code representation of circuit def get_v_code_flat(self, file_object): + """Generates flat Verilog code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_prototype_v()) file_object.write(self.get_declarations_v_flat()+"\n") file_object.write(self.get_inits_v_flat() + "\n") @@ -260,33 +461,71 @@ class ArithmeticCircuit(): # HIERARCHICAL VERILOG # def get_function_blocks_v(self): + """Generates hierarchical Verilog code representation of all subcomponents function blocks present in corresponding arithmetic circuit. + + Returns: + str: Hierarchical Verilog code of all subcomponents function blocks description. + """ # Add unique component types composing this circuit self.component_types = self.get_component_types() return "".join([c.get_function_block_v() for c in self.component_types]) def get_function_block_v(self): + """Generates hierarchical Verilog code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical Verilog code of multi-bit arithmetic circuit's function block description. + """ # Obtain proper adder name with its bit width adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N) adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix) return f"{adder_block.get_circuit_v()}\n\n" def get_declaration_v_hier(self): + """Generates hierarchical Verilog code declaration of input/output buses wires. + + Returns: + str: Hierarchical Verilog code containing unique declaration of arithmetic circuit wires. + """ return "".join(self.a.get_wire_declaration_v()) + \ "".join(self.b.get_wire_declaration_v()) + \ "".join([c.out.get_declaration_v() if isinstance(c, LogicGate) else c.get_wire_declaration_v_hier() for c in self.components]) def get_wire_declaration_v_hier(self): + """Generates hierarchical Verilog code declaration of corresponding subcomponent input/output buses wires inside the upper component. + + Generates wires used to connect input/output values to/from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchical Verilog code of subcomponent arithmetic circuit's wires declaration. + """ return f" wire [{self.a.N-1}:0] {self.prefix}_{self.a.prefix};\n" + \ f" wire [{self.b.N-1}:0] {self.prefix}_{self.b.prefix};\n" + \ f" wire [{self.out.N-1}:0] {self.prefix}_{self.out.prefix};\n" + \ f"{self.out.get_wire_declaration_v()}" def get_init_v_hier(self): + """Generates hierarchical Verilog code initialization and assignment of corresponding arithmetic circuit's input/output buses wires. + + Returns: + str: Hierarchical Verilog code initialization of arithmetic circuit wires. + """ return f"{self.a.get_wire_assign_v()}" + \ f"{self.b.get_wire_assign_v()}" + \ "".join([c.get_gate_invocation_v() if isinstance(c, LogicGate) else c.get_invocation_v(circuit_prefix=self.prefix) for c in self.components]) def get_invocation_v(self, circuit_prefix: str): + """Generates hierarchical Verilog code invocation of corresponding arithmetic circuit's generated function block. + + Assigns input values from other subcomponents into multi-bit input buses used as inputs for function block invocation. + Assigns output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Args: + circuit_prefix (str): Prefix name of the upper component from which function block is being invoked. + + Returns: + str: Hierarchical Verilog code of subcomponent's module invocation and output assignment. + """ # Getting name of circuit type and insitu copying out bus for proper Verilog code generation without affecting actual generated composition circuit_type = self.prefix.replace(circuit_prefix+"_", "") out = Bus(prefix=self.prefix+"_"+self.out.prefix, wires_list=self.out.bus) @@ -296,9 +535,19 @@ class ArithmeticCircuit(): f"{out.get_wire_assign_v()}" def get_function_out_v_hier(self): + """Generates hierarchical Verilog code assignment of corresponding arithmetic circuit's output bus wires. + + Returns: + str: Hierarchical Verilog code containing output bus wires assignment. + """ return "".join([f" assign {self.out.prefix}[{self.out.bus.index(o)}] = {o.name};\n" for o in self.out.bus]) def get_circuit_v(self): + """Generates hierarchical Verilog code subcomponent's function block. + + Returns: + str: Hierarchical Verilog code of subcomponent's function block. + """ return f"{self.get_prototype_v()}" + \ f"{self.get_declaration_v_hier()}\n" + \ f"{self.get_init_v_hier()}\n" + \ @@ -307,6 +556,11 @@ class ArithmeticCircuit(): # Generating hierarchical Verilog code representation of circuit def get_v_code_hier(self, file_object): + """Generates hierarchical Verilog code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_function_blocks_v()) file_object.write(self.get_circuit_v()) file_object.close() @@ -314,9 +568,19 @@ class ArithmeticCircuit(): """ BLIF CODE GENERATION """ # FLAT BLIF # def get_prototype_blif(self): + """Generates Blif code model name of described arithmetic circuit. + + Returns: + str: Model's name in Blif code. + """ return f".model {self.prefix}\n" def get_declaration_blif(self): + """Generates flat Blif code declaration of arithmetic circuit's input/output buses wires. + + Returns: + str: Flattened Blif code containing declaration of circuit's interface wires. + """ if self.N == 1: return f".inputs {self.a.prefix} {self.b.prefix}\n" + \ f".outputs{self.out.get_wire_declaration_blif()}\n" + \ @@ -329,13 +593,28 @@ class ArithmeticCircuit(): f"{self.b.get_wire_assign_blif()}" def get_function_blif_flat(self): + """Generates flat Blif code with unique input wire mapping and invocation of subcomponents functions via their corresponding truth tables. + + Returns: + str: Flattened Blif code containing input wires mapping and inner subcomponents Boolean functions invocation. + """ return "".join(c.get_init_function_blif_flat() if isinstance(c, LogicGate) else c.get_function_blif_flat() for c in self.components) def get_function_out_blif(self): + """Generates flat Blif code mapping of corresponding arithmetic circuit's output bus wires. + + Returns: + str: Flattened Blif code containing output bus wires assignment mapping. + """ return f"{self.out.get_wire_assign_blif(output=True)}" # Generating flat BLIF code representation of circuit def get_blif_code_flat(self, file_object): + """Generates flat Blif code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_prototype_blif()) file_object.write(self.get_declaration_blif()) file_object.write(self.get_function_blif_flat()) @@ -345,9 +624,25 @@ class ArithmeticCircuit(): # HIERARCHICAL BLIF # def get_function_blif_hier(self): + """Generates hierarchical Blif code with unique input wire mapping and invocation of subcomponents function blocks. + + Returns: + str: Hierarchical Blif code containing input wires mapping and inner subcomponents function blocks invocation. + """ return "".join(c.get_invocation_blif_hier(init=True) if isinstance(c, LogicGate) else c.get_invocation_blif_hier(circuit_prefix=self.prefix) for c in self.components) def get_invocation_blif_hier(self, circuit_prefix: str): + """Generates hierarchical Blif code invocation of corresponding arithmetic circuit's generated function block. + + Assigns input values from other subcomponents into multi-bit input buses used as inputs for function block invocation. + Assigns output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Args: + circuit_prefix (str): Prefix name of the upper component from which function block is being invoked. + + Returns: + str: Hierarchical Blif code of subcomponent's model invocation and output assignment. + """ # Getting name of circuit type for proper Blif code generation without affecting actual generated composition circuit_type = self.prefix.replace(circuit_prefix+"_", "") return "".join([w.get_assign_blif(name=self.prefix+'_'+self.a.prefix+f'[{self.a.bus.index(w)}]', output=True)for w in self.a.bus]) + \ @@ -358,6 +653,11 @@ class ArithmeticCircuit(): "".join([f" out[{self.out.bus.index(o)}]={o.name}" for o in self.out.bus]) + "\n" def get_circuit_blif(self): + """Generates hierarchical Blif code subcomponent's function block. + + Returns: + str: Hierarchical Blif code of subcomponent's function block. + """ return f"{self.get_prototype_blif()}" + \ f"{self.get_declaration_blif()}" + \ f"{self.get_function_blif_hier()}" + \ @@ -365,11 +665,21 @@ class ArithmeticCircuit(): f".end\n" def get_function_blocks_blif(self): + """Generates hierarchical Blif code representation of all subcomponents function blocks present in corresponding arithmetic circuit. + + Returns: + str: Hierarchical Blif code of all subcomponents function blocks description. + """ # Add unique component types composing this circuit self.component_types = self.get_component_types() return "\n".join([c.get_function_block_blif() for c in self.component_types[::-1]]) def get_function_block_blif(self): + """Generates hierarchical Blif code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical Blif code of multi-bit arithmetic circuit's function block description. + """ # Obtain proper adder name with its bit width adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N) adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix) @@ -377,6 +687,11 @@ class ArithmeticCircuit(): # Generating hierarchical BLIF code representation of circuit def get_blif_code_hier(self, file_object): + """Generates hierarchical Blif code representation of corresponding arithmetic circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_circuit_blif()+"\n") file_object.write(self.get_function_blocks_blif()) file_object.close() @@ -384,18 +699,42 @@ class ArithmeticCircuit(): """ CGP CODE GENERATION """ # FLAT CGP # def get_parameters_cgp(self): + """Generates CGP chromosome parameters of corresponding arithmetic circuit. + 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 arithmetic circuit. + """ self.circuit_gates = self.get_circuit_gates() return f"{{{self.a.N+self.a.N},{self.out.N},1,{len(self.circuit_gates)},2,1,0}}" def get_triplet_cgp(self): + """Generates list of logic gate triplets (2 input wires, logic gate function) using wires unique position indexes within the described circuit. + Each triplet represents unique logic gate within the described arithmetic 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. + + Returns: + str: List of triplets each describing logic function of corresponding two input logic gate and as a whole describe the arithmetic circuit. + """ self.get_cgp_wires() return "".join([g.get_triplet_cgp(a_index=self.get_circuit_wire_index(g.a), b_index=self.get_circuit_wire_index(g.b)) for g in self.circuit_gates]) def get_output_cgp(self): + """Generates list of output wires indexes of described arithmetic circuit from MSB to LSB. + + Returns: + str: List of arithmetic circuit's output wire indexes. + """ return "(" + ",".join([str(self.get_circuit_wire_index(o)) for o in self.out.bus[::-1]]) + ")" # Generating flat CGP chromosome representation of circuit def get_cgp_code_flat(self, file_object): + """Generates flat CGP chromosome representation of corresponding arithmetic circuit. + + 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_triplet_cgp()) file_object.write(self.get_output_cgp()) diff --git a/ariths_gen/core/multiplier_circuit.py b/ariths_gen/core/multiplier_circuit.py index 62c8a3a..d8c77cb 100644 --- a/ariths_gen/core/multiplier_circuit.py +++ b/ariths_gen/core/multiplier_circuit.py @@ -29,9 +29,17 @@ class MultiplierCircuit(ArithmeticCircuit): super().__init__() """ Array multipliers """ - # Used in array multipliers to get previous row's component output wires - # for further connection to another component's input def get_previous_partial_product(self, a_index: int, b_index: int, offset: int = 0): + """Used in array multipliers to get previous row's component output wires for further connection to another component's input. + + Args: + a_index (int): First input wire index. + b_index (int): Second input wire index. + offset (int, optional): Offset to properly retrieve previous partial product. Defaults to 0. + + Returns: + Wire: Previous row's component wire of corresponding pp. + """ # To get the index of previous row's connecting adder and its generated pp index = ((b_index-2) * (self.N*2)) + ((self.N-1)+2*(a_index+2)) + offset @@ -44,9 +52,21 @@ class MultiplierCircuit(ArithmeticCircuit): return self.components[index].get_sum_wire() """ Dadda multiplier """ - # Used in dadda multipliers to get multiplier's maximum height @staticmethod def get_maximum_height(initial_value: int): + """Used in dadda multipliers to get multiplier's maximum height. + + Maximum height sequence as defined here: https://en.wikipedia.org/wiki/Dadda_multiplier + d(j=1) = 2; d(j+1) = floor(1.5*d) + + `j` stands for initial stage value + `d` stands for maximum height for current initial stage value + Args: + initial_value (int): Initial algorithms stage value. + + Returns: + int, int: Current algorithms stage and maximum bits (height) allowed in a column for current stage. + """ stage = 0 d = 2 while True: @@ -58,12 +78,26 @@ class MultiplierCircuit(ArithmeticCircuit): if d >= initial_value: return stage, max_height - def init_column_heights(self, signed=False): + def init_column_heights(self): + """Creates appropriate number of partial product columns along with filling them with corresponding number of bit pairs. + + Returns: + list: List of partial product columns with their bit pairs. + """ columns = [[num] if num <= self.N else [num - (num - self.N)*2] for num in range(1, self.out.N)] columns = [self.add_column_wires(column=col, column_index=columns.index(col)) for col in columns] return columns def add_column_wires(self, column: list, column_index: int): + """Fills circuit's partial product column with corresponding bit pairs. + + Args: + column (list): List representing column of partial product bits. + column_index (int): Index of partial products column. + + Returns: + list: Updated column list containing corresponding number of input bit pairs to form proper pp column. + """ [column.append([]) for _ in range(column[0])] if column_index <= self.N-1: [column[column[0]-index].append(self.a.get_wire(index)) for index in range(0, column[0])] @@ -72,7 +106,6 @@ class MultiplierCircuit(ArithmeticCircuit): [column[self.a.N-index].append(self.a.get_wire(index)) for index in range(self.a.N-1, self.a.N-column[0]-1, -1)] [column[index-(self.a.N-1-column[0])].append(self.b.get_wire(index)) for index in range(self.a.N-column[0], self.a.N)] - # TODO check and refactor # Filling unsigned pp matrix with AND gates if self.__class__.__name__ == "unsigned_dadda_multiplier" or self.__class__.__name__ == "unsigned_wallace_multiplier": column[1:] = [AndGate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(1, len(column))] @@ -91,14 +124,45 @@ class MultiplierCircuit(ArithmeticCircuit): return column def get_column_height(self, column_num: int): + """Retrieves the current height of desired partial products column. + + Args: + column_num (int): Index of pp column. + + Returns: + int: Height of the current bit column. + """ return self.columns[column_num][0] def update_column_heights(self, curr_column: int, curr_height_change: int, next_column: int = 0, next_height_change: int = 0): + """Updates height of desired column and optionally also its subsequent column. + + Used within dadda and wallace multipliers to perform gradual reduction of partial product columns through the stages. + Allows to choose the height change to take effect on the chosen column index and optionally also the same for the following + column if it should also be affected. + + Args: + curr_column (int): Current pp column index. + curr_height_change (int): Height change for the chosen current pp column. + next_column (int, optional): Subsequent pp column index. Defaults to 0. + next_height_change (int, optional): Height change for the chosen subsequent pp column. Defaults to 0. + """ self.columns[curr_column][0] = self.get_column_height(curr_column)+curr_height_change if next_column-1 == curr_column: self.columns[next_column][0] = self.get_column_height(next_column)+next_height_change def get_column_wire(self, column: int, bit: int): + """Retrieves wire from desired partial product column bit position. + + If bit pair is present at the desired position, it is reduced to one wire with AND/NAND gate accordingly. + + Args: + column (int): Partial product column index. + bit (int): Bit position within the chosen column. + + Returns: + Wire: Return Wire present at specified position. + """ if isinstance(self.columns[column][bit], AndGate) or isinstance(self.columns[column][bit], NandGate): self.add_component(self.columns[column][bit]) return self.get_previous_component(1).out @@ -106,6 +170,16 @@ class MultiplierCircuit(ArithmeticCircuit): return self.columns[column][bit] def update_column_wires(self, curr_column: int, adder: ArithmeticCircuit, next_column: int = 0): + """Provides bit height reduction of the chosen column. + + Inserts chosen column's top bits into an `adder` circuit to reduce its bit height. + Generated sum is stored to the bottom of the column and generated carry bit is stored to the top of the next column. + + Args: + curr_column (int): Current pp column index. + adder (ArithmeticCircuit): Two/three input one bit adder. + next_column (int, optional): Subsequent pp column index. Defaults to 0. + """ if hasattr(adder, "c"): self.columns[curr_column].pop(1) self.columns[curr_column].pop(1) diff --git a/ariths_gen/core/three_input_one_bit_circuit.py b/ariths_gen/core/three_input_one_bit_circuit.py index fc5952b..b3b7c26 100644 --- a/ariths_gen/core/three_input_one_bit_circuit.py +++ b/ariths_gen/core/three_input_one_bit_circuit.py @@ -13,11 +13,23 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit): # FLAT C # # Function prototype with three inputs def get_prototype_c(self): + """Generates C code function header to describe corresponding three input one bit circuit's interface in C code. + + Returns: + str: Function's name and parameters in C code. + """ return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix}, {self.c_data_type} {self.c.prefix})" + "{" + "\n" # HIERARCHICAL C # - # Subcomponent generation (3 inputs) + # Subcomponent generation (three inputs) def get_out_invocation_c(self, **kwargs): + """Generates hierarchical C code invocation of corresponding three input one bit circuit's generated function block. + + Assigns output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchiacal C code subcomponent's C function invocation and output assignment. + """ circuit_class = self.__class__() return "".join([f' {o.name} = ({circuit_class.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> {self.out.bus.index(o)}) & 0x01;\n' for o in self.out.bus]) @@ -25,11 +37,21 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit): # FLAT VERILOG # # Module prototype with three inputs def get_prototype_v(self): + """Generates Verilog module header to describe corresponding three input one bit circuit's interface in Verilog. + + Returns: + str: Module's name and parameters in Verilog. + """ return f"module {self.prefix}(input {self.a.name}, input {self.b.name}, input {self.c.name}{''.join([f', output {o.name}' for o in self.out.bus])});\n" # HIERARCHICAL VERILOG # - # Subcomponent generation (3 inputs) + # Subcomponent generation (three inputs) def get_invocation_v(self, **kwargs): + """Generates hierarchical Verilog code invocation of corresponding three input one bit circuit's generated function block. + + Returns: + str: Hierarchiacal Verilog code subcomponent's module invocation. + """ circuit_class = self.__class__() return f" {circuit_class.prefix} {circuit_class.prefix}_{self.out.get_wire().name}({self.a.name}, {self.b.name}, {self.c.name}{''.join([f', {o.name}' for o in self.out.bus])});\n" @@ -37,12 +59,22 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit): # FLAT BLIF # # Model prototype with three inputs def get_declaration_blif(self): + """Generates flat Blif code declaration of three input one bit circuit's input/output wires. + + Returns: + str: Flattened Blif code containing declaration of circuit's interface wires. + """ return f".inputs {self.a.name} {self.b.name} {self.c.name}\n" + \ f".outputs{self.out.get_wire_declaration_blif(array=False)}\n" # HIERARCHICAL BLIF # # Subcomponent generation (3 inputs) def get_invocation_blif_hier(self, **kwargs): + """Generates hierarchical Blif code invocation of corresponding three input one bit circuit's generated function block. + + Returns: + str: Hierarchiacal Blif code subcomponent's model invocation. + """ circuit_class = self.__class__() return f"{self.get_wire_mapping_blif()}" + \ f".subckt {circuit_class.prefix} a={self.inputs[0].name} b={self.inputs[1].name} cin={self.inputs[2].name}{''.join([f' {o.name}={self.out.get_wire(circuit_class.out.bus.index(o)).name}' for o in circuit_class.out.bus])}\n" @@ -51,5 +83,12 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit): # FLAT CGP # # Chromosome prototype with three inputs def get_parameters_cgp(self): + """Generates CGP chromosome parameters of corresponding three input one bit circuit. + 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 circuit. + """ self.circuit_gates = self.get_circuit_gates() return f"{{3,2,1,{len(self.circuit_gates)},2,1,0}}" diff --git a/ariths_gen/core/two_input_one_bit_circuit.py b/ariths_gen/core/two_input_one_bit_circuit.py index 3d9ba72..e76ccbf 100644 --- a/ariths_gen/core/two_input_one_bit_circuit.py +++ b/ariths_gen/core/two_input_one_bit_circuit.py @@ -14,17 +14,32 @@ class TwoInputOneBitCircuit(ArithmeticCircuit): # Obtaining list of all the unique circuit wires from all contained logic gates # to ensure non-recurring declaration of same wires def get_declaration_c_flat(self): + """Generates flat C code declaration of input/output wires. + + Returns: + str: Flattened C code containing unique declaration of circuit wires. + """ self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) # Wires values initialization and assignment def get_init_c_flat(self): + """Generates flat C code initialization and assignment of corresponding two input one bit circuit's input/output wires. + + Returns: + str: Flattened C code initialization of two input one bit circuit wires. + """ return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_", ""))) for i in self.inputs]) + \ "".join([f" {c.out.name} = {c.get_init_c_flat()};\n" for c in self.components]) # Generating flat C code representation of circuit def get_c_code_flat(self, file_object): + """Generates flat C code representation of corresponding two input one bit circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_includes_c()) file_object.write(self.get_prototype_c()) file_object.write(self.out.get_declaration_c()) @@ -37,46 +52,100 @@ class TwoInputOneBitCircuit(ArithmeticCircuit): # HIERARCHICAL C # # Subcomponent generation def get_function_block_c(self): + """Generates hierarchical C code representation of corresponding two input one bit circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical C code of two input one bit circuit's function block description. + """ adder_block = self.__class__() return f"{adder_block.get_circuit_c()}\n\n" def get_wire_declaration_c_hier(self): + """Generates hierarchical C code declaration of corresponding subcomponent output wires inside the upper component. + + Generates wires used to connect output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchical C code of two input one bit circuit's output wires declaration. + """ return f"{self.out.get_wire_declaration_c()}" def get_out_invocation_c(self, **kwargs): + """Generates hierarchical C code invocation of corresponding two input one bit circuit's generated function block. + + Assigns output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchical C code subcomponent's C function invocation and output assignment. + """ circuit_class = self.__class__() return "".join([f' {o.name} = ({circuit_class.prefix}({self.a.name}, {self.b.name}) >> {self.out.bus.index(o)}) & 0x01;\n' for o in self.out.bus]) # Self circuit hierarchical generation def get_declaration_c_hier(self): + """Generates hierarchical C code declaration of input/output wires. + + Returns: + str: Hierarchical C code containing unique declaration of circuit wires. + """ self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) def get_init_c_hier(self): + """Generates hierarchical C code initialization and assignment of corresponding two input one bit circuit's input/output wires. + + Returns: + str: Hierarchical C code initialization of two input one bit circuit wires. + """ return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_", ""))) for i in self.inputs]) + \ "".join([f" {c.out.name} = {c.get_gate_invocation_c(remove_prefix=False)}" for c in self.components]) def get_function_out_c_hier(self): + """Generates hierarchical C code assignment of corresponding two input one bit circuit's output wires. + + Returns: + str: Hierarchical C code containing output bus wires assignment. + """ return "".join([f" {self.out.prefix} |= {o.return_wire_value_c(offset=self.out.bus.index(o))};\n" for o in self.out.bus]) """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_prototype_v(self): + """Generates Verilog module header to describe corresponding two input one bit circuit's interface in Verilog. + + Returns: + str: Module's name and parameters in Verilog. + """ return f"module {self.prefix}(input {self.a.name}, input {self.b.name}{''.join([f', output {o.name}' for o in self.out.bus])});\n" def get_declaration_v_flat(self): + """Generates flat Verilog code declaration of input/output wires. + + Returns: + str: Flattened Verilog code containing unique declaration of circuit wires. + """ self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_v() for c in self.circuit_wires]) # Wires values initialization and assignment def get_init_v_flat(self): + """Generates flat Verilog code initialization and assignment of corresponding two input one bit circuit's input/output wires. + + Returns: + str: Flattened Verilog code initialization of two input one bit circuit wires. + """ return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs]) + \ "".join([f" assign {c.out.name} = {c.get_init_v_flat()};\n" for c in self.components]) # Generating flat Verilog code representation of circuit def get_v_code_flat(self, file_object): + """Generates flat Verilog code representation of corresponding two input one bit circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ file_object.write(self.get_prototype_v()) file_object.write(self.get_declaration_v_flat()+"\n") file_object.write(self.get_init_v_flat()) @@ -86,62 +155,141 @@ class TwoInputOneBitCircuit(ArithmeticCircuit): # HIERARCHICAL VERILOG # # Subcomponent generation def get_function_block_v(self): + """Generates hierarchical Verilog code representation of corresponding two input one bit circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical Verilog code of two input one bit circuit's function block description. + """ adder_block = self.__class__() return f"{adder_block.get_circuit_v()}\n\n" def get_wire_declaration_v_hier(self): + """Generates hierarchical Verilog code declaration of corresponding subcomponent output wires inside the upper component. + + Generates wires used to connect output values from invocation of the correspoding function block into inner wires present inside the upper component from which function block has been invoked. + + Returns: + str: Hierarchical Verilog code of two input one bit circuit's output wires declaration. + """ return f"{self.out.get_wire_declaration_v()}" def get_invocation_v(self, **kwargs): + """Generates hierarchical Verilog code invocation of corresponding two input one bit circuit's generated function block. + + Returns: + str: Hierarchical Verilog code subcomponent's module invocation. + """ circuit_class = self.__class__() return f" {circuit_class.prefix} {circuit_class.prefix}_{self.out.get_wire().name}({self.a.name}, {self.b.name}{''.join([f', {o.name}' for o in self.out.bus])});\n" # Self circuit hierarchical generation def get_declaration_v_hier(self): + """Generates hierarchical Verilog code declaration of input/output wires. + + Returns: + str: Hierarchical Verilog code containing unique declaration of circuit wires. + """ self.get_circuit_wires() # Unique declaration of all circuit's interconnections return "".join([c[0].get_declaration_v() for c in self.circuit_wires if c[0] not in self.out.bus]) def get_init_v_hier(self): + """Generates hierarchical Verilog code initialization and assignment of corresponding two input one bit circuit's input/output wires. + + Returns: + str: Hierarchical Verilog code initialization of two input one bit circuit wires. + """ return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs]) def get_function_out_v_hier(self): + """Generates hierarchical Verilog code invocation of corresponding two input one bit circuit's inner subcomponents to map their output values into circuit's output wires. + + Returns: + str: Hierarchical Verilog code of inner subcomponents invocations and their inner assignment of output wires values. + """ return "".join([f"{c.get_gate_invocation_v(remove_prefix=False)}" for c in self.components]) """ BLIF CODE GENERATION """ # FLAT BLIF # def get_declaration_blif(self): + """Generates flat Blif code declaration of two input one bit circuit's input/output wires. + + Returns: + str: Flattened Blif code containing declaration of circuit's interface wires. + """ return f".inputs {self.a.name} {self.b.name}\n" + \ f".outputs{self.out.get_wire_declaration_blif(array=False)}\n" def get_wire_mapping_blif(self): + """Generates flat Blif code used to map the input wires into other inner wires to obtain proper wire names used for interconnections inside the circuit. + + Returns: + str: Flattened Blif code containing unique mapping of all circuit's input interconnections. + """ # For unique mapping of all circuit's input interconnections self.get_circuit_wires() return "".join([i.get_assign_blif(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs]) def get_function_blif_flat(self): + """Generates flat Blif code with unique input wire mapping and invocation of subcomponents Boolean functions via their corresponding truth tables. + + Returns: + str: Flattened Blif code containing input wires mapping and inner subcomponents Boolean functions invocation. + """ return f"{self.get_wire_mapping_blif()}"+"".join([c.get_function_blif_flat() for c in self.components]) - def get_function_out_blif(self): - return f"" + # Generating flat BLIF code representation of circuit + def get_blif_code_flat(self, file_object): + """Generates flat Blif code representation of corresponding two input one bit circuit. + + Args: + file_object (TextIOWrapper): Destination file object where circuit's representation will be written to. + """ + file_object.write(self.get_prototype_blif()) + file_object.write(self.get_declaration_blif()) + file_object.write(self.get_function_blif_flat()) + file_object.write(f".end\n") + file_object.close() # HIERARCHICAL BLIF # # Subcomponent generation def get_function_block_blif(self): + """Generates hierarchical Blif code representation of corresponding two input one bit circuit used as function block in hierarchical circuit description. + + Returns: + str: Hierarchical Blif code of two input one bit circuit's function block description. + """ adder_block = self.__class__() return f"{adder_block.get_circuit_blif()}" def get_invocation_blif_hier(self, **kwargs): + """Generates hierarchical Blif code invocation of corresponding two input one bit circuit's generated function block. + + Returns: + str: Hierarchical Blif code subcomponent's model invocation. + """ circuit_class = self.__class__() return f"{self.get_wire_mapping_blif()}" + \ f".subckt {circuit_class.prefix} a={self.inputs[0].name} b={self.inputs[1].name}{''.join([f' {o.name}={self.out.get_wire(circuit_class.out.bus.index(o)).name}' for o in circuit_class.out.bus])}\n" # Self circuit hierarchical generation def get_function_blif_hier(self): + """Generates hierarchical Blif code with unique input wire mapping and invocation of subcomponents function blocks. + + Returns: + str: Hierarchical Blif code containing input wires mapping and inner subcomponents function blocks invocation. + """ return f"{self.get_wire_mapping_blif()}"+"".join(c.get_invocation_blif_hier(init=False) for c in self.components) """ CGP CODE GENERATION """ # FLAT CGP # def get_parameters_cgp(self): + """Generates CGP chromosome parameters of corresponding two input one bit circuit. + 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 circuit. + """ self.circuit_gates = self.get_circuit_gates() return f"{{2,2,1,{len(self.circuit_gates)},2,1,0}}" 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 5a61394..90ab8e0 100644 --- a/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py +++ b/ariths_gen/multi_bit_circuits/adders/carry_lookahead_adder.py @@ -40,9 +40,9 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit): │ PG │ │ PG │ │ PG │ │ PG │ │ block│ │ block│ │ block│ │ block│ │ │ │ │ │ │ │ │ - └─┬──┬─┘ └─┬──┬─┘ └─┬──┬─┘ └─┬──┬─┘ - │ │ G3P3 │ │ G2P2 │ │ G1P1 │ │ G0P0 - ┌─▼──▼───────▼──▼───────▼──▼───────▼──▼─┐ + └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ + │││G3P3S3 │││G2P2S2 │││G1P1S1 │││G0P0S0 + ┌─▼▼▼────────▼▼▼────────▼▼▼────────▼▼▼──┐ │ Carry Lookahead logic │ │ │ └┬────┬───────┬──────────┬──────────┬───┘ @@ -162,9 +162,9 @@ class SignedCarryLookaheadAdder(UnsignedCarryLookaheadAdder, ArithmeticCircuit): │ PG │ │ PG │ │ PG │ │ PG │ │ block│ │ block│ │ block│ │ block│ │ │ │ │ │ │ │ │ - └─┬──┬─┘ └─┬──┬─┘ └─┬──┬─┘ └─┬──┬─┘ - │ │ G3P3 │ │ G2P2 │ │ G1P1 │ │ G0P0 - ┌─▼──▼───────▼──▼───────▼──▼───────▼──▼─┐ + └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ + │││G3P3S3 │││G2P2S2 │││G1P1S1 │││G0P0S0 + ┌─▼▼▼────────▼▼▼────────▼▼▼────────▼▼▼──┐ │ Carry Lookahead logic │ │ with sign extension │ └┬────┬───────┬──────────┬──────────┬───┘ diff --git a/ariths_gen/multi_bit_circuits/adders/pg_ripple_carry_adder.py b/ariths_gen/multi_bit_circuits/adders/pg_ripple_carry_adder.py index a418371..a31d996 100644 --- a/ariths_gen/multi_bit_circuits/adders/pg_ripple_carry_adder.py +++ b/ariths_gen/multi_bit_circuits/adders/pg_ripple_carry_adder.py @@ -33,23 +33,23 @@ class UnsignedPGRippleCarryAdder(ArithmeticCircuit): of N-bit unsigned adder which is composed of N one bit full adders with P/G logic. ``` - B3 A3 B2 A2 B1 A1 B0 A0 - │ │ │ │ │ │ │ │ - ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ - │ PG │ │ PG │ │ PG │ │ PG │ - │ FA │ │ FA │ │ FA │ │ FA │ - │ │ │ │ │ │ │ │ - └─┬──┬┬┘ └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ - │ ││G3P3S3 │││G2P2S2 │││G1P1S1 │││ G0P0S0 - │ ┌▼▼───────▼▼▼─────────▼▼▼─────────▼▼▼──┐ - │ │ Group PG logic │ - │ │ │ - │ └─┬───────┬──────────┬──────────┬──────┘ + B3 A3 B2 A2 B1 A1 B0 A0 + │ │ │ │ │ │ │ │ + ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ + │ PG │ C3 │ PG │ C2 │ PG │ C1 │ PG │ + │ FA │◄────┐│ FA │◄──┐│ FA │◄──┐│ FA │◄──0 + │ │ ││ │ ││ │ ││ │ + └─┬──┬┬┘ │└─┬┬┬──┘ │└─┬┬┬──┘ │└─┬┬┬──┘ + │ ││G3P3S3│ │││G2P2S2│ │││G1P1S1│ │││G0P0S0 + │ ┌▼▼──────┴──▼▼▼──────┴──▼▼▼──────┴──▼▼▼──┐ + │ │ Group PG logic │ + │ │ │ + │ └─┬───────┬──────────┬──────────┬────────┘ │ │ │ │ │ - ┌─▼───▼───────▼──────────▼──────────▼──────┐ - │ Sum logic │ - │ │ - └┬────┬───────┬──────────┬──────────┬──────┘ + ┌─▼───▼───────▼──────────▼──────────▼────────┐ + │ Sum logic │ + │ │ + └┬────┬───────┬──────────┬──────────┬────────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ Cout S3 S1 S0 S0 @@ -107,23 +107,23 @@ class SignedPGRippleCarryAdder(UnsignedPGRippleCarryAdder, ArithmeticCircuit): At last XOR gates are used to ensure proper sign extension. ``` - B3 A3 B2 A2 B1 A1 B0 A0 - │ │ │ │ │ │ │ │ - ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ - │ PG │ │ PG │ │ PG │ │ PG │ - │ FA │ │ FA │ │ FA │ │ FA │ - │ │ │ │ │ │ │ │ - └─┬──┬┬┘ └─┬┬┬──┘ └─┬┬┬──┘ └─┬┬┬──┘ - │ ││G3P3S3 │││G2P2S2 │││G1P1S1 │││ G0P0S0 - │ ┌▼▼───────▼▼▼─────────▼▼▼─────────▼▼▼──┐ - │ │ Group PG logic │ - │ │ │ - │ └─┬───────┬──────────┬──────────┬──────┘ + B3 A3 B2 A2 B1 A1 B0 A0 + │ │ │ │ │ │ │ │ + ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ ┌─▼──▼─┐ + │ PG │ C3 │ PG │ C2 │ PG │ C1 │ PG │ + │ FA │◄────┐│ FA │◄──┐│ FA │◄──┐│ FA │◄──0 + │ │ ││ │ ││ │ ││ │ + └─┬──┬┬┘ │└─┬┬┬──┘ │└─┬┬┬──┘ │└─┬┬┬──┘ + │ ││G3P3S3│ │││G2P2S2│ │││G1P1S1│ │││G0P0S0 + │ ┌▼▼──────┴──▼▼▼──────┴──▼▼▼──────┴──▼▼▼──┐ + │ │ Group PG logic │ + │ │ │ + │ └─┬───────┬──────────┬──────────┬────────┘ │ │ │ │ │ - ┌─▼───▼───────▼──────────▼──────────▼──────┐ - │ Sum logic │ - │ with sign extension │ - └┬────┬───────┬──────────┬──────────┬──────┘ + ┌─▼───▼───────▼──────────▼──────────▼────────┐ + │ Sum logic │ + │ with sign extension │ + └┬────┬───────┬──────────┬──────────┬────────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ Cout S3 S1 S0 S0 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 567ec1a..162fe87 100644 --- a/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py +++ b/ariths_gen/one_bit_circuits/logic_gates/logic_gates.py @@ -25,28 +25,55 @@ class LogicGate(): self.b = Wire(name=prefix+"_"+b.name.replace(prefix+"_", ""), value=b.value) self.prefix = prefix - def get_component_types(self): - return list([self]) - """ C CODE GENERATION """ # FLAT C # @staticmethod def get_includes_c(): + """Generates necessary C library includes for output representation. + + Returns: + str: C code library includes. + """ return f"#include \n#include \n\n" def get_prototype_c(self): + """Generates C code function header to describe corresponding two input logic gate's interface in C code. + + Returns: + str: Function's name and parameters in C code. + """ return f"uint8_t {self.gate_type}(uint8_t {self.a.name}, uint8_t {self.b.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. + + Returns: + str: C code description of logic gate's Boolean function (with bitwise shifted inputs). + """ return f"{self.a.get_wire_value_c()} {self.operator} {self.b.get_wire_value_c()}" def get_declaration_c_flat(self): + """Generates C code declaration of input/output wires. + + Returns: + str: C code logic gate's wires declaration. + """ return f"{self.a.get_declaration_c()}{self.b.get_declaration_c()}{self.out.get_declaration_c()}" def get_init_c_flat(self): + """Generates C code representing corresponding two input logic gate's Boolean function using bitwise operators between its inputs. + + Returns: + str: C code description of logic gate's Boolean function. + """ return f"{self.a.name} {self.operator} {self.b.name}" def get_assign_c_flat(self): + """Generates C code for assigning initial values into logic gate's wires. + + Returns: + str: C code initialization of wires values. + """ return f"{self.a.get_assign_c(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f"{self.b.get_assign_c(name=self.b.name.replace(self.prefix+'_', ''))}" + \ f" {self.out.prefix} = {self.get_init_c_flat()};\n" @@ -54,6 +81,11 @@ class LogicGate(): # Generating flat C code representation of the logic gate itself # (i.e. not as a component of bigger circuit) def get_c_code(self, file_object): + """Generates flat C code 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_includes_c()) file_object.write(self.get_prototype_c()) file_object.write(" return "+(self.get_function_c())+";\n}") @@ -61,30 +93,60 @@ class LogicGate(): # HIERARCHICAL C # def get_function_block_c(self): + """Generates C code representation of corresponding logic gate used as function block in hierarchical circuit description. + + Returns: + str: C code logic gate's function block description. + """ gate_block = NotGate(a=Wire(name="a")) if isinstance(self, NotGate) else type(self)(a=Wire(name="a"), b=Wire(name="b")) return f"{gate_block.get_prototype_c()}" + \ f" return "+(gate_block.get_function_c())+";\n}\n\n" def get_gate_invocation_c(self, remove_prefix: bool = True): + """Generates C code invocation of corresponding logic gate's generated function block. + + Args: + remove_prefix (bool, optional): Specifies whether function block's input parameter names should contain also its prefix (parent circuit name) or not. Defaults to True. + + Returns: + str: C code logic gate's function block invocation. + """ a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name b_name = self.b.name.replace(self.prefix+"_", "") if remove_prefix is True else self.b.name return f"{self.gate_type}({a_name}, {b_name});\n" - def get_gate_output_c(self, a: Wire, b: Wire, offset: int = 0): - return f"({self.gate_type}({a.name}, {b.name}) & 0x01) << {offset}" - """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_prototype_v(self): + """Generates Verilog module header to describe corresponding two input logic gate's interface in Verilog. + + Returns: + str: Module's name and parameters in Verilog. + """ return f"module {self.gate_type}(input {self.a.name}, input {self.b.name}, output {self.out.name});\n" def get_declaration_v_flat(self): + """Generates Verilog code declaration of input/output wires. + + Returns: + str: Verilog code logic gate's wires declaration. + """ return f"{self.a.get_declaration_v()}{self.b.get_declaration_v()}{self.out.get_declaration_v()}" def get_init_v_flat(self): + """Generates Verilog code representing corresponding two input logic gate's Boolean function using bitwise operators between its inputs. + + Returns: + str: Verilog description of logic gate's Boolean function. + """ return f"{self.a.name} {self.operator} {self.b.name}" def get_assign_v_flat(self): + """Generates Verilog code for assigning initial values into logic gate's wires. + + Returns: + str: Verilog code initialization of wires values. + """ return f"{self.a.get_assign_v(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f"{self.b.get_assign_v(name=self.b.name.replace(self.prefix+'_', ''))}" + \ f" assign {self.out.prefix} = {self.get_init_v_flat()};\n" @@ -92,6 +154,11 @@ class LogicGate(): # Generating flat Verilog code representation of the logic gate itself # (i.e. not as a component of bigger circuit) def get_v_code(self, file_object): + """Generates flat Verilog code 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_prototype_v()) file_object.write(f" assign {self.out.name} = {self.get_init_v_flat()};\n") file_object.write(f"endmodule") @@ -99,12 +166,25 @@ class LogicGate(): # HIERARCHICAL VERILOG # 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 = NotGate(a=Wire(name="a")) if isinstance(self, NotGate) else type(self)(a=Wire(name="a"), b=Wire(name="b")) return f"{gate_block.get_prototype_v()}" + \ f" assign {gate_block.out.name} = {gate_block.get_init_v_flat()};\n" + \ f"endmodule\n\n" def get_gate_invocation_v(self, remove_prefix: bool = True): + """Generates Verilog code invocation of corresponding logic gate's generated function block. + + Args: + remove_prefix (bool, optional): Specifies whether function block's input parameter names contain also its prefix (parent circuit name) or not. Defaults to True. + + Returns: + str: Verilog code logic gate's function block invocation. + """ a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name b_name = self.b.name.replace(self.prefix+"_", "") if remove_prefix is True else self.b.name return f" {self.gate_type} {self.gate_type}_{self.out.name}({a_name}, {b_name}, {self.out.name});\n" @@ -112,13 +192,28 @@ class LogicGate(): """ BLIF CODE GENERATION """ # FLAT BLIF # def get_prototype_blif(self): + """Generates Blif model header to describe corresponding logic gate's interface in Blif. + + Returns: + str: Model's name and parameters in Blif. + """ return f".model {self.gate_type}\n" def get_declaration_blif(self): + """Generates Blif code declaration of input/output wires. + + Returns: + str: Blif logic gate's wires declaration. + """ return f".inputs {self.a.name} {self.b.name}\n" + \ f".outputs {self.out.name}\n" def get_init_function_blif_flat(self): + """Generates Blif code representing corresponding two input logic gate's Boolean function between its inputs. + + Returns: + str: Blif description of logic gate's Boolean function. + """ return f"{self.a.get_assign_blif(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f"{self.b.get_assign_blif(name=self.b.name.replace(self.prefix+'_', ''))}" + \ f"{self.get_function_blif_flat()}" @@ -126,6 +221,11 @@ class LogicGate(): # Generating flat BLIF code representation of the logic gate itself # (i.e. not as a component of bigger circuit) def get_blif_code(self, file_object): + """Generates flat Blif code 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_prototype_blif()) file_object.write(self.get_declaration_blif()) file_object.write(self.get_function_blif_flat()) @@ -134,6 +234,11 @@ class LogicGate(): # HIERARCHICAL BLIF # def get_function_block_blif(self): + """Generates Blif code representation of corresponding logic gate used as subcomponent in hierarchical circuit description. + + Returns: + str: Blif logic gate subcomponent description. + """ gate_block = NotGate(a=Wire(name="a")) if isinstance(self, NotGate) else type(self)(a=Wire(name="a"), b=Wire(name="b")) return f"{gate_block.get_prototype_blif()}" + \ f"{gate_block.get_declaration_blif()}" + \ @@ -141,6 +246,14 @@ class LogicGate(): f".end\n" def get_invocation_blif_hier(self, init: bool = False): + """Generates Blif code invocation of corresponding logic gate's generated subcomponent. + + Args: + init (bool, optional): Specifies whether subcomponent's input wires initializiation is neccessary before its invocation. Defaults to False. + + Returns: + str: Blif logic gate subcomponent invocation. + """ if init is True: return f"{self.a.get_assign_blif(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f"{self.b.get_assign_blif(name=self.b.name.replace(self.prefix+'_', ''))}" + \ @@ -152,16 +265,47 @@ class LogicGate(): # 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_index: int = 0, b_index: int = 1): + """Generates logic gate triplet (2 input wires, 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. + + Args: + a_index (int, optional): First input wire index position. Defaults to 0. + b_index (int, optional): Second input wire index position. Defaults to 1. + + Returns: + str: Triplet describing function of corresponding two input logic gate. + """ return f"({a_index},{b_index},{self.cgp_function})" @staticmethod def get_output_cgp(out_index: int = 2): + """Generates list of output wires indexes of described two input logic gate from MSB to LSB. + + Args: + out_index (int, optional): Output wire index. Defaults to 2. + + Returns: + str: List of logic gate's output wire indexes. + """ return f"({out_index})" 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_triplet_cgp()) file_object.write(self.get_output_cgp()) @@ -192,14 +336,29 @@ class InvertedLogicGate(LogicGate): """ 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 << 0" def get_init_c_flat(self): + """Generates C code representing corresponding negated two input logic gate's Boolean function using bitwise operators between its inputs. + + Returns: + str: C code description of negated logic gate's Boolean function. + """ return "~("+(super().get_init_c_flat())+")" """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_init_v_flat(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_init_v_flat())+")" @@ -231,6 +390,11 @@ class AndGate(LogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing AND gate Boolean function using its truth table. + + Returns: + str: Blif description of AND gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"11 1\n" @@ -263,6 +427,11 @@ class NandGate(InvertedLogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing NAND gate Boolean function using its truth table. + + Returns: + str: Blif description of NAND gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"0- 1\n-0 1\n" @@ -295,6 +464,11 @@ class OrGate(LogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing OR gate Boolean function using its truth table. + + Returns: + str: Blif description of OR gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"1- 1\n-1 1\n" @@ -327,6 +501,11 @@ class NorGate(InvertedLogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing NOR gate Boolean function using its truth table. + + Returns: + str: Blif description of NOR gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"00 1\n" @@ -359,6 +538,11 @@ class XorGate(LogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing XOR gate Boolean function using its truth table. + + Returns: + str: Blif description of XOR gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"01 1\n10 1\n" @@ -391,6 +575,11 @@ class XnorGate(InvertedLogicGate): """ BLIF CODE GENERATION """ def get_function_blif_flat(self): + """Generates Blif code representing XNOR gate Boolean function using its truth table. + + Returns: + str: Blif description of XNOR gate's Boolean function. + """ return f".names {self.a.name} {self.b.name} {self.out.name}\n" + \ f"00 1\n11 1\n" @@ -425,65 +614,146 @@ class NotGate(InvertedLogicGate): """ C CODE GENERATION """ # FLAT C # def get_prototype_c(self): + """Generates C code function header to describe corresponding one input logic gate's interface in C code. + + Returns: + str: Function's name and parameter in C code. + """ return f"uint8_t {self.gate_type}(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()} & 0x01 << 0" def get_declaration_c_flat(self): + """Generates C code declaration of input/output wires. + + Returns: + str: C code logic gate's wires declaration. + """ return f"{self.a.get_declaration_c()}{self.out.get_declaration_c()}" def get_init_c_flat(self): + """Generates C code representing corresponding one input logic gate's Boolean function using bitwise operators between its input. + + Returns: + str: C code description of logic gate's Boolean function. + """ return f"{self.operator}{self.a.name}" def get_assign_c_flat(self): + """Generates C code for assigning initial values into logic gate's wires. + + Returns: + str: C code initialization of wires values. + """ return f"{self.a.get_assign_c(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f" {self.out.prefix} = {self.get_init_c_flat()};\n" # HIERARCHICAL C # def get_gate_invocation_c(self, remove_prefix: bool = True): + """Generates C code invocation of corresponding logic gate's generated function block. + + Args: + remove_prefix (bool, optional): Specifies whether function block's input parameter name should contain also its prefix (parent circuit name) or not. Defaults to True. + + Returns: + str: C code logic gate's function block invocation. + """ a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name return f"{self.gate_type}({a_name});" - def get_gate_output_c(self, a: Wire, offset: int = 0): - return f"({self.gate_type}({a.name}) & 0x01) << {offset}" - """ VERILOG CODE GENERATION """ # FLAT VERILOG # def get_prototype_v(self): + """Generates Verilog module header to describe corresponding one input logic gate's interface in Verilog. + + Returns: + str: Module's name and parameter in Verilog. + """ return f"module {self.gate_type}(input {self.a.name}, output {self.out.name});\n" def get_declaration_v_flat(self): + """Generates Verilog code declaration of input/output wires. + + Returns: + str: Verilog code logic gate's wires declaration. + """ return f"{self.a.get_declaration_v()}{self.out.get_declaration_v()}" def get_init_v_flat(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.name}" def get_assign_v_flat(self): + """Generates Verilog code for assigning initial values into logic gate's wires. + + Returns: + str: Verilog code initialization of wires values. + """ return f"{self.a.get_assign_v(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f" assign {self.out.prefix} = {self.get_init_v_flat()};\n" # HIERARCHICAL VERILOG # def get_gate_invocation_v(self, remove_prefix: bool = True): + """Generates Verilog code invocation of corresponding logic gate's generated function block. + + Args: + remove_prefix (bool, optional): Specifies whether function block's input parameter name should contain also its prefix (parent circuit name) or not. Defaults to True. + + Returns: + str: Verilog code logic gate's function block invocation. + """ a_name = self.a.name.replace(self.prefix+"_", "") if remove_prefix is True else self.a.name return f" {self.gate_type} {self.gate_type}_{self.out.name}({a_name}, {self.out.name});\n" """ BLIF CODE GENERATION """ # FLAT BLIF # def get_declaration_blif(self): + """Generates Blif model header to describe corresponding logic gate's interface in Blif. + + Returns: + str: Model's name and parameter in Blif. + """ return f".inputs {self.a.name}\n" + \ f".outputs {self.out.name}\n" def get_function_blif_flat(self): + """Generates Blif code representing NOT gate Boolean function using its truth table. + + Returns: + str: Blif description of NOT gate's Boolean function. + """ return f".names {self.a.name} {self.out.name}\n" + \ f"0 1\n" def get_init_function_blif_flat(self): + """Generates Blif code representing corresponding one input logic gate's Boolean function between its input. + + Returns: + str: Blif description of logic gate's Boolean function. + """ return f"{self.a.get_assign_blif(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f"{self.get_function_blif_flat()}" # HIERARCHICAL BLIF # def get_invocation_blif_hier(self, init: bool = False): + """Generates Blif code invocation of corresponding logic gate's generated subcomponent. + + Args: + init (bool, optional): Specifies whether subcomponent's input wire initializiation is neccessary before its invocation. Defaults to False. + + Returns: + str: Blif logic gate subcomponent invocation. + """ if init is True: return f"{self.a.get_assign_blif(name=self.a.name.replace(self.prefix+'_', ''))}" + \ f".subckt {self.gate_type} _a={self.a.name} _y0={self.out.name}\n" @@ -493,8 +763,27 @@ class NotGate(InvertedLogicGate): """ CGP CODE GENERATION """ # FLAT CGP # def get_triplet_cgp(self, a_index: int = 0): + """Generates logic gate triplet (2 input wires, 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. + + Args: + a_index (int, optional): First (used also as the second) input wire index position. Defaults to 0. + + Returns: + str: Triplet describing function of corresponding one input logic gate. + """ return f"({a_index},{a_index},{self.cgp_function})" @staticmethod def get_output_cgp(out_index: int = 1): + """Generates list of output wires indexes of described one input logic gate from MSB to LSB. + + Args: + out_index (int, optional): Output wire index. Defaults to 1. + + Returns: + str: List of logic gate's output wire indexes. + """ return f"({out_index})" diff --git a/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py b/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py index e706e86..a297397 100644 --- a/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py +++ b/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py @@ -99,10 +99,25 @@ class FullAdderPG(ThreeInputOneBitCircuit): self.out.connect(2, sum_xor.out) def get_propagate_wire(self): + """Get output wire carrying propagate signal value. + + Returns: + Wire: Return propagate wire. + """ return self.out.get_wire(0) def get_generate_wire(self): + """Get output wire carrying generate signal value. + + Returns: + Wire: Return generate wire. + """ return self.out.get_wire(1) def get_sum_wire(self): + """Get output wire carrying sum value. + + Returns: + Wire: Return sum wire. + """ return self.out.get_wire(2) diff --git a/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py b/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py index db4faf4..dddd627 100644 --- a/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py +++ b/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py @@ -49,8 +49,8 @@ class PGLogicBlock(TwoInputOneBitCircuit): ``` ┌──────┐ ──►│ ├─► P - │ │ - ──►│ ├─► G + │ ├─► G + ──►│ ├─► S └──────┘ ``` @@ -83,12 +83,27 @@ class PGLogicBlock(TwoInputOneBitCircuit): self.out.connect(2, sum_xor.out) def get_propagate_wire(self): + """Get output wire carrying propagate signal value. + + Returns: + Wire: Return propagate wire. + """ return self.out.get_wire(0) def get_generate_wire(self): + """Get output wire carrying generate signal value. + + Returns: + Wire: Return generate wire. + """ return self.out.get_wire(1) def get_sum_wire(self): + """Get output wire carrying sum value. + + Returns: + Wire: Return sum wire. + """ return self.out.get_wire(2)