Addition of MUX2x1 PDK support and optimization of hierarchical Verilog code generation when using PDK modules (the gates and wires associated with native ArithsGen implementation are not generated).

This commit is contained in:
honzastor 2023-03-22 17:57:51 +01:00
parent bb4c6d35a7
commit b88c502343
4 changed files with 88 additions and 18 deletions

View File

@ -86,19 +86,24 @@ class GeneralCircuit():
else:
return sum(isinstance(c, cls) for c in self.components)
def get_circuit_gates(self):
def get_circuit_gates(self, verilog_output: bool = False):
"""Gets a list of all the logic gates in circuit that should be generated.
Args:
verilog_output (bool): Specifies whether the call has been invoked by a verilog output generation method.
Returns:
list: List of composite logic gates.
"""
gates = []
for c in self.components:
if isinstance(c, TwoInputLogicGate):
if c.disable_generation is False:
if c.disable_generation is False and (verilog_output is False or (hasattr(self, "use_verilog_instance") and self.use_verilog_instance is False)) or hasattr(self, "use_verilog_instance") is False:
gates.append(c)
else:
gates.extend((c.get_circuit_gates()))
# Check whether it is necessary to use gates for the Verilog component
# description (ArithsGen internally defined comp) or not (technology specific instance)
if verilog_output is False or (hasattr(c, "use_verilog_instance") and c.use_verilog_instance is False) or hasattr(c, "use_verilog_instance") is False:
gates.extend((c.get_circuit_gates(verilog_output)))
return gates
def get_one_bit_components(self):
@ -150,15 +155,17 @@ class GeneralCircuit():
else:
return list({type(c): c for c in components}.values())
def get_component_types(self):
def get_component_types(self, verilog_output: bool = False):
"""Retrieves a list of all the unique types of subcomponents composing the circuit.
Returning list consists of only the unique types of logic gates, one bit circuits and multi bit circuits.
Args:
verilog_output (bool): Specifies whether the call has been invoked by a verilog output generation method.
Returns:
list: List of unique component types describing the circuit.
"""
gate_comps = self.get_unique_types(components=self.get_circuit_gates())
gate_comps = self.get_unique_types(components=self.get_circuit_gates(verilog_output))
one_bit_comps = self.get_unique_types(
components=self.get_one_bit_components())
multi_bit_comps = self.get_unique_types(
@ -371,7 +378,6 @@ class GeneralCircuit():
# Obtain proper circuit name with its bit width
circuit_prefix = self.__class__(
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
print(self._parent_kwargs)
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
N=self.N, prefix="b"), name=circuit_prefix, **self._parent_kwargs)
return f"{circuit_block.get_circuit_c()}\n\n"
@ -509,7 +515,7 @@ class GeneralCircuit():
str: Hierarchical Verilog code of all subcomponents function blocks description.
"""
# Retrieve all unique component types composing this circuit and add them kwargs from the parent circuit to allow propagatation of config settings for subcomponents
self.component_types = self.get_component_types()
self.component_types = self.get_component_types(verilog_output=True)
for c in self.component_types:
c._parent_kwargs = self.kwargs
return "".join([c.get_function_block_v() for c in self.component_types])

View File

@ -76,13 +76,12 @@ class FullAdder(ThreeInputOneBitCircuit):
return " " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.prefix,
"wireb": self.b.prefix,
"wirec": self.c.prefix,
"wirea": f"1'b{self.a.value}" if self.a.is_const() else self.a.name,
"wireb": f"1'b{self.b.value}" if self.b.is_const() else self.b.name,
"wirec": f"1'b{self.c.value}" if self.c.is_const() else self.c.name,
"wireys": self.get_sum_wire().prefix,
"wireyc": self.get_carry_wire().prefix,
}
) + ";\n"
}) + ";\n"
def get_self_init_v_hier(self):
""" support of custom PDK """
@ -93,7 +92,8 @@ class FullAdder(ThreeInputOneBitCircuit):
for o in self.out.bus:
unique_out_wires.append(o.name+"_outid"+str(self.out.bus.index(o))) if o.is_const() or o.name in [self.a.name, self.b.name] else unique_out_wires.append(o.name)
return " " + self.use_verilog_instance.format(**{
return " " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.name,
"wireb": self.b.name,
@ -102,6 +102,15 @@ class FullAdder(ThreeInputOneBitCircuit):
"wireyc": unique_out_wires[1],
}) + ";\n"
def get_circuit_v(self):
""" support of custom PDK """
if not self.use_verilog_instance:
return super().get_circuit_v()
return f"{self.get_prototype_v_hier()}" + \
f"{self.get_self_init_v_hier()}" + \
f"endmodule"
class FullAdderP(FullAdder, ThreeInputOneBitCircuit):
"""Class representing three input one bit full adder with additional output wire for P signal.
@ -264,6 +273,8 @@ class TwoOneMultiplexer(ThreeInputOneBitCircuit):
c (Wire, optional): Select signal. Defaults to Wire(name="sel").
prefix (str, optional): Prefix name of two to one multiplexer. Defaults to "mux2to1".
"""
use_verilog_instance = False
def __init__(self, a: Wire = Wire(name="d0"), b: Wire = Wire(name="d1"), c: Wire = Wire(name="sel"), prefix: str = "mux2to1"):
super().__init__(a, b, c, prefix)
# Represents select signal (self.c naming for proper unified generation)
@ -295,6 +306,49 @@ class TwoOneMultiplexer(ThreeInputOneBitCircuit):
"""
return self.out.get_wire(0)
def get_init_v_flat(self):
""" support of custom PDK """
if not self.use_verilog_instance:
return super().get_init_v_flat()
neg_out_w_name = f"neg_{self.out.get_wire(0).name}"
return f" wire {neg_out_w_name};\n " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.name,
"wireb": self.b.name,
"wires": self.c.name,
"wirey": neg_out_w_name,
}) + ";\n" + f" assign {self.out.get_wire(0).name} = ~{neg_out_w_name};\n"
def get_self_init_v_hier(self):
""" support of custom PDK """
if not self.use_verilog_instance:
return super().get_self_init_v_hier()
unique_out_wires = []
for o in self.out.bus:
unique_out_wires.append(o.name+"_outid"+str(self.out.bus.index(o))) if o.is_const() or o.name in [self.a.name, self.b.name] else unique_out_wires.append(o.name)
neg_out_w_name = f"neg_{unique_out_wires[0]}"
return f" wire {neg_out_w_name};\n " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.name,
"wireb": self.b.name,
"wires": self.c.name,
"wirey": neg_out_w_name
}) + ";\n" + f" assign {unique_out_wires[0]} = ~{neg_out_w_name};\n"
def get_circuit_v(self):
""" support of custom PDK """
if not self.use_verilog_instance:
return super().get_circuit_v()
return f"{self.get_prototype_v_hier()}" + \
f"{self.get_self_init_v_hier()}" + \
f"endmodule"
class FullSubtractor(ThreeInputOneBitCircuit):
"""Class representing three input one bit full subtractor.

View File

@ -64,12 +64,11 @@ class HalfAdder(TwoInputOneBitCircuit):
return " " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.prefix,
"wireb": self.b.prefix,
"wirea": f"1'b{self.a.value}" if self.a.is_const() else self.a.name,
"wireb": f"1'b{self.b.value}" if self.b.is_const() else self.b.name,
"wireys": self.get_sum_wire().prefix,
"wireyc": self.get_carry_wire().prefix,
}
) + ";\n"
}) + ";\n"
def get_self_init_v_hier(self):
""" support of custom PDK """
@ -80,7 +79,8 @@ class HalfAdder(TwoInputOneBitCircuit):
for o in self.out.bus:
unique_out_wires.append(o.name+"_outid"+str(self.out.bus.index(o))) if o.is_const() or o.name in [self.a.name, self.b.name] else unique_out_wires.append(o.name)
return " " + self.use_verilog_instance.format(**{
return " " + self.use_verilog_instance.format(
**{
"unit": self.prefix,
"wirea": self.a.name,
"wireb": self.b.name,
@ -88,6 +88,15 @@ class HalfAdder(TwoInputOneBitCircuit):
"wireyc": unique_out_wires[1],
}) + ";\n"
def get_circuit_v(self):
""" support of custom PDK """
if not self.use_verilog_instance:
return super().get_circuit_v()
return f"{self.get_prototype_v_hier()}" + \
f"{self.get_self_init_v_hier()}" + \
f"endmodule"
class PGLogicBlock(TwoInputOneBitCircuit):
"""Class representing two input one bit propagate/generate logic block.

View File

@ -18,3 +18,4 @@ from .one_bit_circuits import (
def set_pdk45_library():
one_bit_components.FullAdder.use_verilog_instance = "FAX1 {unit} (.A({wirea}), .B({wireb}), .C({wirec}), .YS({wireys}), .YC({wireyc}))"
one_bit_components.HalfAdder.use_verilog_instance = "HAX1 {unit} (.A({wirea}), .B({wireb}), .YS({wireys}), .YC({wireyc}))"
one_bit_components.TwoOneMultiplexer.use_verilog_instance = "MUX2X1 {unit} (.A({wirea}), .B({wireb}), .S({wires}), .Y({wirey}))"