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 (
|
from ariths_gen.core.logic_gate_circuits.logic_gate_circuit import (
|
||||||
OneInputLogicGate,
|
ThreeInputLogicGate
|
||||||
TwoInputLogicGate
|
|
||||||
)
|
)
|
||||||
from ariths_gen.wire_components import (
|
from ariths_gen.wire_components import (
|
||||||
Wire,
|
Wire,
|
||||||
@ -124,7 +123,7 @@ class GeneralCircuit():
|
|||||||
"""
|
"""
|
||||||
# TODO should be refactored in ArithsGen rework
|
# TODO should be refactored in ArithsGen rework
|
||||||
# We should probably check also wire names for especially hierarchical generation
|
# 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:
|
if component.disable_generation is False:
|
||||||
self.circuit_gates.append(component)
|
self.circuit_gates.append(component)
|
||||||
else:
|
else:
|
||||||
@ -158,7 +157,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
int: Number of instances of the same class type.
|
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)
|
return sum(isinstance(c, cls) for c in self.components if isinstance(c, cls) and c.disable_generation is False)
|
||||||
else:
|
else:
|
||||||
return sum(isinstance(c, cls) for c in self.components)
|
return sum(isinstance(c, cls) for c in self.components)
|
||||||
@ -173,7 +172,7 @@ class GeneralCircuit():
|
|||||||
"""
|
"""
|
||||||
gates = []
|
gates = []
|
||||||
for c in self.components:
|
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):
|
if (c.disable_generation is False) and (verilog_output is False or getattr(c, "use_verilog_instance", False) is False):
|
||||||
gates.append(c)
|
gates.append(c)
|
||||||
else:
|
else:
|
||||||
@ -191,7 +190,7 @@ class GeneralCircuit():
|
|||||||
"""
|
"""
|
||||||
one_bit_comps = []
|
one_bit_comps = []
|
||||||
for c in self.components:
|
for c in self.components:
|
||||||
if isinstance(c, TwoInputLogicGate):
|
if isinstance(c, ThreeInputLogicGate):
|
||||||
continue
|
continue
|
||||||
elif all(isinstance(i, Wire) for i in self.inputs):
|
elif all(isinstance(i, Wire) for i in self.inputs):
|
||||||
one_bit_comps.append(c)
|
one_bit_comps.append(c)
|
||||||
@ -208,7 +207,7 @@ class GeneralCircuit():
|
|||||||
"""
|
"""
|
||||||
multi_bit_comps = []
|
multi_bit_comps = []
|
||||||
for c in self.components:
|
for c in self.components:
|
||||||
if isinstance(c, TwoInputLogicGate):
|
if isinstance(c, ThreeInputLogicGate):
|
||||||
continue
|
continue
|
||||||
elif all(isinstance(i, Wire) for i in self.inputs):
|
elif all(isinstance(i, Wire) for i in self.inputs):
|
||||||
continue
|
continue
|
||||||
@ -340,7 +339,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Flat Python code initialization of arithmetic circuit wires.
|
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):
|
def get_function_out_python_flat(self):
|
||||||
"""Generates flat Python code assignment of corresponding arithmetic circuit's output bus wires.
|
"""Generates flat Python code assignment of corresponding arithmetic circuit's output bus wires.
|
||||||
@ -398,7 +397,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Flat C code initialization of arithmetic circuit wires.
|
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):
|
def get_function_out_c_flat(self):
|
||||||
"""Generates flat C code assignment of corresponding arithmetic circuit's output bus wires.
|
"""Generates flat C code assignment of corresponding arithmetic circuit's output bus wires.
|
||||||
@ -469,7 +468,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Hierarchical C code initialization of arithmetic circuit wires.
|
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):
|
def get_out_invocation_c(self):
|
||||||
"""Generates hierarchical C code invocation of corresponding arithmetic circuit's generated function block.
|
"""Generates hierarchical C code invocation of corresponding arithmetic circuit's generated function block.
|
||||||
@ -546,7 +545,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Flat Verilog code initialization of arithmetic circuit wires.
|
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):
|
def get_function_out_v_flat(self):
|
||||||
"""Generates flat Verilog code assignment of corresponding arithmetic circuit's output bus wires.
|
"""Generates flat Verilog code assignment of corresponding arithmetic circuit's output bus wires.
|
||||||
@ -614,7 +613,7 @@ class GeneralCircuit():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Hierarchical Verilog code initialization of arithmetic circuit wires.
|
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):
|
def get_out_invocation_v(self):
|
||||||
"""Generates hierarchical Verilog code invocation of corresponding arithmetic circuit's generated function block.
|
"""Generates hierarchical Verilog code invocation of corresponding arithmetic circuit's generated function block.
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
from .logic_gate_circuit import (
|
from .logic_gate_circuit import (
|
||||||
MultipleInputLogicGate,
|
MultipleInputLogicGate,
|
||||||
TwoInputLogicGate,
|
ThreeInputLogicGate
|
||||||
TwoInputInvertedLogicGate,
|
|
||||||
OneInputLogicGate
|
|
||||||
)
|
)
|
||||||
|
@ -53,15 +53,14 @@ class MultipleInputLogicGate():
|
|||||||
a = Bus(prefix=a.prefix, N=N, wires_list=out_wires)
|
a = Bus(prefix=a.prefix, N=N, wires_list=out_wires)
|
||||||
self.out = a.get_wire(0)
|
self.out = a.get_wire(0)
|
||||||
|
|
||||||
|
|
||||||
# Two-input #
|
# Two-input #
|
||||||
class TwoInputLogicGate():
|
class ThreeInputLogicGate():
|
||||||
"""Class representing two input logic gates.
|
"""Class representing tree input logic gates.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────┐
|
┌──────┐
|
||||||
──►│ FUNC │
|
──►│ FUNC │
|
||||||
│ ├─►
|
──►│ ├─►
|
||||||
──►│ │
|
──►│ │
|
||||||
└──────┘
|
└──────┘
|
||||||
```
|
```
|
||||||
@ -71,11 +70,12 @@ class TwoInputLogicGate():
|
|||||||
Args:
|
Args:
|
||||||
a (Wire): First input wire.
|
a (Wire): First input wire.
|
||||||
b (Wire): Second input wire.
|
b (Wire): Second input wire.
|
||||||
|
c (Wire): Third input wire.
|
||||||
prefix (str, optional): Prefix name of logic gate. Defaults to "gate".
|
prefix (str, optional): Prefix name of logic gate. Defaults to "gate".
|
||||||
outid (int, optional): Index of output wire. Defaults to 0.
|
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.
|
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.a = a
|
||||||
self.b = b
|
self.b = b
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
@ -104,7 +104,7 @@ class TwoInputLogicGate():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Function's name and parameters in flat C code.
|
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):
|
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.
|
"""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():
|
if self.out.is_const():
|
||||||
return self.out.get_wire_value_c_flat()
|
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):
|
def get_declaration_c_flat(self):
|
||||||
"""Generates C code declaration of output wire for flat representation.
|
"""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(self.get_prototype_c_flat())
|
||||||
file_object.write(" return "+(self.get_function_c())+";\n}")
|
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 """
|
""" PYTHON CODE GENERATION """
|
||||||
# FLAT PYTHON #
|
# FLAT PYTHON #
|
||||||
def get_assign_python_flat(self):
|
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.
|
# 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:
|
if self.disable_generation:
|
||||||
#return f" {self.out.prefix} = {self.get_function_c()} # DD {self.prefix} \n"
|
#return f" {self.out.prefix} = {self.get_function_c()} # DD {self.prefix} \n"
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
else:
|
else:
|
||||||
return f" {self.out.prefix} = {self.get_function_c()}\n"
|
return f" {self.out.prefix} = {self.get_function_c()}\n"
|
||||||
@ -254,7 +209,7 @@ class TwoInputLogicGate():
|
|||||||
Returns:
|
Returns:
|
||||||
str: Verilog description of logic gate's Boolean function.
|
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):
|
def get_assign_v_flat(self):
|
||||||
"""Generates Verilog code for invocation of logical functions and subsequently provides assignment to their output.
|
"""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(self.get_output_v_flat())
|
||||||
file_object.write(f"endmodule")
|
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 """
|
""" BLIF CODE GENERATION """
|
||||||
# FLAT BLIF #
|
# FLAT BLIF #
|
||||||
def get_prototype_blif_flat(self):
|
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_prototype_blif_flat())
|
||||||
file_object.write(self.get_declaration_blif())
|
file_object.write(self.get_declaration_blif())
|
||||||
file_object.write(self.get_function_blif_flat(top_modul=True))
|
file_object.write(self.get_function_blif_flat(top_modul=True))
|
||||||
file_object.write(f".end\n")
|
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)
|
|
@ -5,9 +5,6 @@ from ariths_gen.wire_components import (
|
|||||||
from ariths_gen.core.arithmetic_circuits import (
|
from ariths_gen.core.arithmetic_circuits import (
|
||||||
MultiplierCircuit,
|
MultiplierCircuit,
|
||||||
)
|
)
|
||||||
from ariths_gen.core.logic_gate_circuits import (
|
|
||||||
TwoInputLogicGate
|
|
||||||
)
|
|
||||||
from ariths_gen.one_bit_circuits.one_bit_components import (
|
from ariths_gen.one_bit_circuits.one_bit_components import (
|
||||||
HalfAdder,
|
HalfAdder,
|
||||||
FullAdder
|
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.one_bit_circuits import Maji
|
||||||
from ariths_gen.wire_components import Wire, ConstantWireValue0, ConstantWireValue1
|
from ariths_gen.wire_components import Wire, ConstantWireValue0, ConstantWireValue1
|
||||||
|
|
||||||
|
|
||||||
# Two-input #
|
# Two-input #
|
||||||
class AndGate(TwoInputLogicGate):
|
class AndGate(Maji):
|
||||||
"""Class representing two input AND gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, b, prefix, outid, parent_component)
|
super().__init__(a, b, ConstantWireValue0(), prefix=prefix, outid=outid, parent_component=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"
|
|
||||||
|
|
||||||
|
|
||||||
class NandGate(TwoInputInvertedLogicGate):
|
class NandGate(Maji):
|
||||||
"""Class representing two input NAND gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, b, prefix, outid, parent_component)
|
super().__init__(a, b, ConstantWireValue1(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component)
|
||||||
self.gate_type = "nand_gate"
|
|
||||||
self.cgp_function = 5
|
|
||||||
self.operator = "&"
|
|
||||||
|
|
||||||
# Logic gate output wire generation based on input values
|
class OrGate(Maji):
|
||||||
# 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 representing two input OR gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, b, prefix, outid, parent_component)
|
super().__init__(a, b, ConstantWireValue1(), prefix=prefix, outid=outid, parent_component=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"
|
|
||||||
|
|
||||||
|
|
||||||
class NorGate(TwoInputInvertedLogicGate):
|
class NorGate(Maji):
|
||||||
"""Class representing two input NOR gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, b, prefix, outid, parent_component)
|
super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component)
|
||||||
self.gate_type = "nor_gate"
|
|
||||||
self.cgp_function = 6
|
|
||||||
self.operator = "|"
|
|
||||||
|
|
||||||
# Logic gate output wire generation based on input values
|
class XorGate(Maji):
|
||||||
# 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 representing two input XOR gate.
|
"""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.
|
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):
|
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
|
super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component)
|
||||||
# If constant input is present, logic gate is not generated and corresponding
|
"""super().__init__(a, b, prefix=prefix, outid=outid, parent_component=parent_component)
|
||||||
# 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)
|
|
||||||
|
|
||||||
""" BLIF CODE GENERATION """
|
self.and1 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, False, False], parent_component = parent_component)
|
||||||
def get_function_blif(self):
|
self.and2 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[False, True, False], parent_component = parent_component)
|
||||||
"""Generates Blif code representing XOR gate Boolean function using its truth table.
|
self.orOut = Maji(self.and1.out, self.and2.out, ConstantWireValue1(), prefix=prefix, parent_component = parent_component)
|
||||||
|
self.out = self.orOut.out"""
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
class XnorGate(TwoInputInvertedLogicGate):
|
class XnorGate(Maji):
|
||||||
"""Class representing two input XNOR gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, b, prefix, outid, parent_component)
|
"""super().__init__(a, b, prefix=prefix, outid=outid, parent_component=parent_component)
|
||||||
self.gate_type = "xnor_gate"
|
|
||||||
self.cgp_function = 7
|
|
||||||
self.operator = "^"
|
|
||||||
|
|
||||||
# Logic gate output wire generation based on input values
|
self.and1 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, False, False], parent_component = parent_component)
|
||||||
# If constant input is present, logic gate is not generated and corresponding
|
self.and2 = Maji(a, b, ConstantWireValue0(), prefix=prefix, inverts=[False, True, False], parent_component = parent_component)
|
||||||
# input value is propagated to the output to connect to other components
|
self.orOut = Maji(self.and1.out, self.and2.out, ConstantWireValue1(), prefix=prefix, parent_component = parent_component)
|
||||||
if a.is_const() and a.value == 1:
|
self.out = self.orOut.out"""
|
||||||
self.out = b
|
super().__init__(a, b, ConstantWireValue0(), prefix=prefix, inverts=[True, True, False], outid=outid, parent_component=parent_component)
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
# Single-input #
|
# Single-input #
|
||||||
class NotGate(OneInputLogicGate):
|
class NotGate(Maji):
|
||||||
"""Class representing one input NOT gate.
|
"""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.
|
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):
|
def __init__(self, a: Wire, prefix: str = "", outid: int = 0, parent_component: object = None):
|
||||||
super().__init__(a, prefix, outid, parent_component)
|
super().__init__(a, a, a, prefix=prefix, inverts=[True, True, True], outid=outid, parent_component=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"
|
|
||||||
|
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