Added documentation of classes methods.

This commit is contained in:
honzastor 2021-04-06 01:39:11 +02:00
parent a328e91996
commit 068def0226
10 changed files with 986 additions and 67 deletions

View File

@ -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
```

View File

@ -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 <stdio.h>\n#include <stdint.h>\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())

View File

@ -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)

View File

@ -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}}"

View File

@ -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}}"

View File

@ -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

View File

@ -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

View File

@ -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 <stdio.h>\n#include <stdint.h>\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})"

View File

@ -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)

View File

@ -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)