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