diff --git a/ariths_gen/core/arithmetic_circuits/general_circuit.py b/ariths_gen/core/arithmetic_circuits/general_circuit.py index 232774c..4e12819 100644 --- a/ariths_gen/core/arithmetic_circuits/general_circuit.py +++ b/ariths_gen/core/arithmetic_circuits/general_circuit.py @@ -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]) diff --git a/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py b/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py index 3e93b21..069d38b 100644 --- a/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py +++ b/ariths_gen/one_bit_circuits/one_bit_components/three_input_one_bit_components.py @@ -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. diff --git a/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py b/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py index 835b545..d6bb318 100644 --- a/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py +++ b/ariths_gen/one_bit_circuits/one_bit_components/two_input_one_bit_components.py @@ -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. diff --git a/ariths_gen/pdk.py b/ariths_gen/pdk.py index fab62ed..41d3a12 100644 --- a/ariths_gen/pdk.py +++ b/ariths_gen/pdk.py @@ -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}))"