diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/cross_coupled_load.py b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/cross_coupled_load.py new file mode 100644 index 000000000..0e96a488d --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/cross_coupled_load.py @@ -0,0 +1,108 @@ +from gdsfactory.components import rectangle +from gdsfactory import Component +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.primitives.fet import nmos, pmos +from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized +from four_transistor_interdigitized import generic_4T_interdigitzed +from glayout.flow.pdk.util.comp_utils import prec_ref_center +from glayout.flow.routing.smart_route import smart_route, c_route, straight_route, L_route +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from glayout.flow.spice import Netlist +from glayout.flow.primitives.guardring import tapring +from glayout.flow.primitives.via_gen import via_stack, via_array + +def x_coupled_netlist(nfetA: Component, nfetB: Component, pfetA: Component, pfetB: Component, nfetdum: Component, pfetdum: Component): + x_coupled_netlist = Netlist(circuit_name ='cross_cpoupled_load', nodes=['VSN1', 'VSN2', 'VSP1', 'VSP2', 'VO1', 'VO2', 'VBULKN', 'VBULKP']) + x_coupled_netlist.connect_netlist( + nfetA.info['netlist'], + [('G','VO1'), ('D','VO2'), ('S','VSN1'), ('B','VBULKN')] + ) + x_coupled_netlist.connect_netlist( + nfetdum.info['netlist'], + [('G','VBULKN'), ('D','VBULKN'), ('S','VBULKN'), ('B','VBULKN')] + ) + x_coupled_netlist.connect_netlist( + pfetdum.info['netlist'], + [('G','VBULKP'), ('D','VBULKP'), ('S','VBULKP'), ('B','VBULKP')] + ) + x_coupled_netlist.connect_netlist( + nfetB.info['netlist'], + [('G','VO2'), ('D','VO1'), ('S','VSN2'), ('B','VBULKN')] + ) + x_coupled_netlist.connect_netlist( + pfetA.info['netlist'], + [('G','VO1'), ('D','VO2'), ('S','VSP1'), ('B','VBULKP')] + ) + x_coupled_netlist.connect_netlist( + pfetB.info['netlist'], + [('G','VO2'), ('D','VO1'), ('S','VSP2'), ('B','VBULKP')] + ) + return x_coupled_netlist + +def cross_coupled_load(pdk: MappedPDK, ccinv_col): + cross_coupled_load=Component(name="cross_coupled_load") + cross_couple = generic_4T_interdigitzed(pdk, numcols=ccinv_col, top_row_device="pfet", bottom_row_device="nfet", length=0.4, with_substrate_tap = False) + cross_couple_ref = prec_ref_center(cross_couple) + cross_coupled_load.add(cross_couple_ref) + cross_coupled_load.add_ports(cross_couple_ref.get_ports_list(), prefix="cross_couple_") + cross_coupled_load << smart_route(pdk,cross_coupled_load.ports["cross_couple_top_A_source_E"],cross_coupled_load.ports["cross_couple_top_B_source_E"],cross_couple_ref,cross_coupled_load) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_top_A_drain_E"],cross_coupled_load.ports["cross_couple_top_B_gate_E"]) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_bottom_A_drain_E"],cross_coupled_load.ports["cross_couple_bottom_B_gate_E"]) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_top_B_drain_W"],cross_coupled_load.ports["cross_couple_top_A_gate_W"]) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_bottom_B_drain_W"],cross_coupled_load.ports["cross_couple_bottom_A_gate_W"]) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_top_B_gate_E"],cross_coupled_load.ports["cross_couple_bottom_A_drain_E"]) + cross_coupled_load << c_route(pdk,cross_coupled_load.ports["cross_couple_top_A_gate_W"],cross_coupled_load.ports["cross_couple_bottom_B_drain_W"]) + + nfetA = nmos(pdk, width=3*ccinv_col, length=0.4, with_dummy=(False, False)) + nfetB = nmos(pdk, width=3*ccinv_col, length=0.4, with_dummy=(False, False)) + pfetA = pmos(pdk, width=3*ccinv_col, length=0.4, with_dummy=(False, False)) + pfetB = pmos(pdk, width=3*ccinv_col, length=0.4, with_dummy=(False, False)) + nfetdum = nmos(pdk, width=3*2, length=0.4, with_dummy=(False, False)) + pfetdum = pmos(pdk, width=3*2, length=0.4, with_dummy=(False, False)) + cross_coupled_load.info['netlist'] = x_coupled_netlist(nfetA, nfetB, pfetA, pfetB, nfetdum, pfetdum) + return cross_coupled_load + + +def add_x_coupled_labels(x_coupled: Component): + x_coupled.unlock() + met1_label = (68, 5) + met1_pin = (68, 16) + move_info = list() + #vo1 label + vo1label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vo1label.add_label(text="VO1",layer=met1_label) + move_info.append((vo1label,x_coupled.ports["cross_couple_top_B_drain_N"],None)) + #vo2 label + vo2label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vo2label.add_label(text="VO2",layer=met1_label) + move_info.append((vo2label,x_coupled.ports["cross_couple_top_A_drain_N"],None)) + #vsn1 label + vsn1label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vsn1label.add_label(text="VSN1",layer=met1_label) + move_info.append((vsn1label,x_coupled.ports["cross_couple_bottom_A_source_N"],None)) + #vsn2 label + vsn2label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vsn2label.add_label(text="VSN2",layer=met1_label) + move_info.append((vsn2label,x_coupled.ports["cross_couple_bottom_B_source_N"],None)) + #vsp1 label + vsp1label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vsp1label.add_label(text="VSP1",layer=met1_label) + move_info.append((vsp1label,x_coupled.ports["cross_couple_top_A_source_N"],None)) + #vsp2 label + vsp2label = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vsp2label.add_label(text="VSP2",layer=met1_label) + move_info.append((vsp2label,x_coupled.ports["cross_couple_top_B_source_N"],None)) + #vbulk label + vbulknlabel = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vbulknlabel.add_label(text="VBULKN",layer=met1_label) + move_info.append((vbulknlabel,x_coupled.ports["cross_couple_bottom_welltie_N_top_met_N"],None)) + #vbulk label + vbulkplabel = rectangle(layer=met1_pin, size=(0.05,0.05), centered=True).copy() + vbulkplabel.add_label(text="VBULKP",layer=met1_label) + move_info.append((vbulkplabel,x_coupled.ports["cross_couple_top_welltie_N_top_met_N"],None)) + #move everything to position + for comp, prt, alignment in move_info: + alignment = ('c','b') if alignment is None else alignment + compref = align_comp_to_port(comp, prt, alignment=alignment) + x_coupled.add(compref) + return x_coupled.flatten() diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/diff_pair.py b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/diff_pair.py new file mode 100644 index 000000000..fcbd1df33 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/diff_pair.py @@ -0,0 +1,195 @@ +from typing import Optional, Union + +from gdsfactory.cell import cell +from gdsfactory.component import Component, copy +from gdsfactory.components.rectangle import rectangle +from gdsfactory.routing.route_quad import route_quad +from gdsfactory.routing.route_sharp import route_sharp +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.util.comp_utils import align_comp_to_port, evaluate_bbox, movex, movey +from glayout.flow.pdk.util.port_utils import ( + add_ports_perimeter, + get_orientation, + print_ports, + rename_ports_by_list, + rename_ports_by_orientation, + set_port_orientation, +) +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid +from glayout.flow.placement.common_centroid_ab_ba import common_centroid_ab_ba +from glayout.flow.primitives.fet import nmos, pmos +from glayout.flow.primitives.guardring import tapring +from glayout.flow.primitives.via_gen import via_stack +from glayout.flow.routing.c_route import c_route +from glayout.flow.routing.smart_route import smart_route +from glayout.flow.routing.straight_route import straight_route +from glayout.flow.spice import Netlist + + +def diff_pair_netlist(fetL: Component, fetR: Component) -> Netlist: + diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B']) + diff_pair_netlist.connect_netlist( + fetL.info['netlist'], + [('D', 'VDD1'), ('G', 'VP'), ('S', 'VTAIL'), ('B', 'B')] + ) + diff_pair_netlist.connect_netlist( + fetR.info['netlist'], + [('D', 'VDD2'), ('G', 'VN'), ('S', 'VTAIL'), ('B', 'B')] + ) + return diff_pair_netlist + +@cell +def diff_pair( + pdk: MappedPDK, + width: float = 3, + fingers: int = 4, + length: Optional[float] = None, + n_or_p_fet: bool = True, + plus_minus_seperation: float = 0, + rmult: int = 1, + dummy: Union[bool, tuple[bool, bool]] = True, + substrate_tap: bool=True +) -> Component: + """create a diffpair with 2 transistors placed in two rows with common centroid place. Sources are shorted + width = width of the transistors + fingers = number of fingers in the transistors (must be 2 or more) + length = length of the transistors, None or 0 means use min length + short_source = if true connects source of both transistors + n_or_p_fet = if true the diffpair is made of nfets else it is made of pfets + substrate_tap: if true place a tapring around the diffpair (connects on met1) + """ + # TODO: error checking + pdk.activate() + diffpair = Component() + # create transistors + well = None + if isinstance(dummy, bool): + dummy = (dummy, dummy) + if n_or_p_fet: + fetL = nmos(pdk, width=width, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(dummy[0], False),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + fetR = nmos(pdk, width=width, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(False,dummy[1]),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + fetL2 = nmos(pdk, width=width*2, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(dummy[0], False),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + fetR2 = nmos(pdk, width=width*2, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(False,dummy[1]),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + + min_spacing_x = pdk.get_grule("n+s/d")["min_separation"] - 2*(fetL.xmax - fetL.ports["multiplier_0_plusdoped_E"].center[0]) + well = "pwell" + else: + fetL = pmos(pdk, width=width, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(dummy[0], False),dnwell=False,with_substrate_tap=False,rmult=rmult) + fetR = pmos(pdk, width=width, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(False,dummy[1]),dnwell=False,with_substrate_tap=False,rmult=rmult) + fetL2 = pmos(pdk, width=width*2, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(dummy[0], False),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + fetR2 = pmos(pdk, width=width*2, fingers=fingers,length=length,multipliers=1,with_tie=False,with_dummy=(False,dummy[1]),with_dnwell=False,with_substrate_tap=False,rmult=rmult) + + min_spacing_x = pdk.get_grule("p+s/d")["min_separation"] - 2*(fetL.xmax - fetL.ports["multiplier_0_plusdoped_E"].center[0]) + well = "nwell" + # place transistors + viam2m3 = via_stack(pdk,"met2","met3",centered=True) + metal_min_dim = max(pdk.get_grule("met2")["min_width"],pdk.get_grule("met3")["min_width"]) + metal_space = max(pdk.get_grule("met2")["min_separation"],pdk.get_grule("met3")["min_separation"],metal_min_dim) + gate_route_os = evaluate_bbox(viam2m3)[0] - fetL.ports["multiplier_0_gate_W"].width + metal_space + min_spacing_y = metal_space + 2*gate_route_os + min_spacing_y = min_spacing_y - 2*abs(fetL.ports["well_S"].center[1] - fetL.ports["multiplier_0_gate_S"].center[1]) + # TODO: fix spacing where you see +-0.5 + a_topl = (diffpair << fetL).movey(fetL.ymax+min_spacing_y/2+0.5).movex(0-fetL.xmax-min_spacing_x/2) + b_topr = (diffpair << fetR).movey(fetR.ymax+min_spacing_y/2+0.5).movex(fetL.xmax+min_spacing_x/2) + a_botr = (diffpair << fetR) + a_botr.mirror_y().movey(0-0.5-fetL.ymax-min_spacing_y/2).movex(fetL.xmax+min_spacing_x/2) + b_botl = (diffpair << fetL) + b_botl.mirror_y().movey(0-0.5-fetR.ymax-min_spacing_y/2).movex(0-fetL.xmax-min_spacing_x/2) + # if substrate tap place substrate tap + if substrate_tap: + tapref = diffpair << tapring(pdk,evaluate_bbox(diffpair,padding=1),horizontal_glayer="met1") + diffpair.add_ports(tapref.get_ports_list(),prefix="tap_") + try: + diffpair< Component: + diffpair = common_centroid_ab_ba(pdk,width,fingers,length,n_or_p_fet,rmult,dummy,substrate_tap) + diffpair << smart_route(pdk,diffpair.ports["A_source_E"],diffpair.ports["B_source_E"],diffpair, diffpair) + return diffpair diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/four_transistor_interdigitized.py b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/four_transistor_interdigitized.py new file mode 100644 index 000000000..8d9b587a0 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/four_transistor_interdigitized.py @@ -0,0 +1,50 @@ +# 4 transistor placed in two rows (each row is an interdigitized pair of transistors) +# the 4 transistors are labeled top or bottom and transistor A or B +# top_A_, bottom_A, top_B_, bottom_B_ + +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized, two_pfet_interdigitized +from typing import Literal, Optional +from gdsfactory import Component +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, movey +from glayout.flow.primitives.guardring import tapring + +def generic_4T_interdigitzed( + pdk: MappedPDK, + top_row_device: Literal["nfet", "pfet"], + bottom_row_device: Literal["nfet", "pfet"], + numcols: int, + length: float=None, + with_substrate_tap: bool = True, + top_kwargs: Optional[dict]=None, + bottom_kwargs: Optional[dict]=None +): + if top_kwargs is None: + top_kwargs = dict() + if bottom_kwargs is None: + bottom_kwargs = dict() + # place + toplvl = Component() + if top_row_device=="nfet": + toprow = toplvl << two_nfet_interdigitized(pdk,numcols,with_substrate_tap=False,length=length,**top_kwargs) + else: + toprow = toplvl << two_pfet_interdigitized(pdk,numcols,with_substrate_tap=False,length=length,**top_kwargs) + if bottom_row_device=="nfet": + bottomrow = toplvl << two_nfet_interdigitized(pdk,numcols,with_substrate_tap=False,length=length,**bottom_kwargs) + else: + bottomrow = toplvl << two_pfet_interdigitized(pdk,numcols,with_substrate_tap=False,length=length,**bottom_kwargs) + # move + toprow.movey(pdk.snap_to_2xgrid((evaluate_bbox(bottomrow)[1]/2 + evaluate_bbox(toprow)[1]/2 + pdk.util_max_metal_seperation()))) + # add substrate tap + if with_substrate_tap: + substrate_tap = tapring(pdk, enclosed_rectangle=pdk.snap_to_2xgrid(evaluate_bbox(toplvl.flatten(),padding=pdk.util_max_metal_seperation()))) + substrate_tap_ref = toplvl << movey(substrate_tap,destination=pdk.snap_to_2xgrid(toplvl.flatten().center[1],snap4=True)) + toplvl.add_ports(substrate_tap_ref.get_ports_list(),prefix="substratetap_") + + # add ports + + toplvl.add_ports(toprow.get_ports_list(),prefix="top_") + toplvl.add_ports(bottomrow.get_ports_list(),prefix="bottom_") + # flag for smart route + toplvl.info["route_genid"] = "four_transistor_interdigitized" + return toplvl diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/strongARM_v2.py b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/strongARM_v2.py new file mode 100644 index 000000000..0028efaaa --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/strongARM_US/strongARM_v2.py @@ -0,0 +1,221 @@ +from gdsfactory.components import rectangle +from gdsfactory import Component +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.primitives.fet import nmos, pmos +from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized +from glayout.flow.placement.four_transistor_interdigitized import generic_4T_interdigitzed +from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized +from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, movex, align_comp_to_port +from glayout.flow.routing.smart_route import smart_route, c_route, straight_route, L_route +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from glayout.flow.spice import Netlist +from glayout.flow.primitives.guardring import tapring +from glayout.flow.primitives.via_gen import via_stack, via_array +#from glayout.flow.blocks.diff_pair import * +from diff_pair import * +from cross_coupled_load import * + +import os + +def mystrongARM_netlist(diffpair: Component, cross_couple: Component, nfet_clk: Component, nfet_clk_dum: Component, pfetA: Component, pfetB: Component, pfetC: Component, pfetD: Component): + mystrongARM_netlist = Netlist(circuit_name ='strongARM', nodes=['VIP', 'VIM', 'VOP', 'VOM', 'VCLK', 'VDD', 'VSS', 'VP', 'VQ', 'VS']) + mystrongARM_netlist.connect_netlist( + diffpair.info['netlist'], + [('VP','VIP'), ('VN','VIM'), ('VDD1','VP'), ('VDD2','VQ'), ('VTAIL','VS'), ('B','VSS')] + ) + mystrongARM_netlist.connect_netlist( + cross_couple.info['netlist'], + [('VSN1','VP'), ('VSN2','VQ'), ('VSP1','VDD'), ('VSP2','VDD'), ('VO1','VOP'), ('VO2','VOM'), ('VBULKN','VSS'), ('VBULKP','VDD')] + ) + #mystrongARM_netlist.connect_netlist( + # clk_nmos.info['netlist'], + # [('G','VCLK'), ('S','VSS'), ('D','VS'), ('B','VSS')] + #) + mystrongARM_netlist.connect_netlist( + nfet_clk.info['netlist'], + [('G','VCLK'), ('S','VSS'), ('D','VS'), ('B','VSS')] + ) + mystrongARM_netlist.connect_netlist( + nfet_clk_dum.info['netlist'], + [('G','VSS'), ('S','VSS'), ('D','VSS'), ('B','VSS')] + ) + mystrongARM_netlist.connect_netlist( + pfetA.info['netlist'], + [('G','VCLK'), ('S','VDD'), ('D','VOP'), ('B','VDD')] + ) + mystrongARM_netlist.connect_netlist( + pfetB.info['netlist'], + [('G','VCLK'), ('S','VDD'), ('D','VOM'), ('B','VDD')] + ) + mystrongARM_netlist.connect_netlist( + pfetC.info['netlist'], + [('G','VCLK'), ('S','VDD'), ('D','VP'), ('B','VDD')] + ) + mystrongARM_netlist.connect_netlist( + pfetD.info['netlist'], + [('G','VCLK'), ('S','VDD'), ('D','VQ'), ('B','VDD')] + ) + return mystrongARM_netlist +def mystrongARM(pdk: MappedPDK, diffp_w, diffp_l, ccinv_col, clk_fing, reset_w, reset_l): + mystrongARM=Component(name="mystrongARM") + diffp = diff_pair(pdk, diffp_w, 2, diffp_l) + diffp_ref = prec_ref_center(diffp) + mystrongARM.add(diffp_ref) + + + cross_couple = cross_coupled_load(pdk, ccinv_col) + cross_couple_ref = prec_ref_center(cross_couple) + mystrongARM.add(cross_couple_ref) + + + clk_nmos = nmos(pdk, width=4, fingers=clk_fing,rmult=1, with_substrate_tap=False, with_dnwell=False) + clk_nmos_ref = prec_ref_center(clk_nmos) + mystrongARM.add(clk_nmos_ref) + + reset_pmos_right = two_pfet_interdigitized(pdk, numcols=2, dummy=False, with_substrate_tap=False, with_tie=True, width=reset_w, length=reset_l, rmult=1) + reset_pmos_ref1 = prec_ref_center(reset_pmos_right) + mystrongARM.add(reset_pmos_ref1) + offsety_reset_pmos=evaluate_bbox(cross_couple)[1]/4 + + reset_pmos_left = two_pfet_interdigitized(pdk, numcols=2, dummy=False, with_substrate_tap=False, with_tie=True, width=reset_w, length=reset_l, rmult=1) + reset_pmos_ref2 = prec_ref_center(reset_pmos_left) + mystrongARM.add(reset_pmos_ref2) + offsetx_cross = (evaluate_bbox(cross_couple)[0]-evaluate_bbox(reset_pmos_left)[0])/2 + + offsety_diffp = (evaluate_bbox(diffp)[1]-evaluate_bbox(clk_nmos)[1])/2 + offsety_cross = (evaluate_bbox(cross_couple)[1]-evaluate_bbox(diffp)[1])/2 + + movey(reset_pmos_ref2, evaluate_bbox(clk_nmos_ref)[1]+pdk.util_max_metal_seperation() + offsety_diffp + evaluate_bbox(diffp)[1]+pdk.util_max_metal_seperation() + offsety_cross+offsety_reset_pmos) + movex(cross_couple_ref, evaluate_bbox(reset_pmos_left)[0]+pdk.util_max_metal_seperation()+offsetx_cross) + movex(diffp_ref, evaluate_bbox(reset_pmos_left)[0]+pdk.util_max_metal_seperation()+offsetx_cross) + movex(clk_nmos_ref, evaluate_bbox(reset_pmos_left)[0]+pdk.util_max_metal_seperation()+offsetx_cross) + movey(cross_couple_ref, evaluate_bbox(clk_nmos_ref)[1]+pdk.util_max_metal_seperation() + offsety_diffp + evaluate_bbox(diffp)[1]+pdk.util_max_metal_seperation() + offsety_cross) + movey(diffp_ref, evaluate_bbox(clk_nmos_ref)[1]+pdk.util_max_metal_seperation()+offsety_diffp) + movey(reset_pmos_ref1, evaluate_bbox(clk_nmos_ref)[1]+pdk.util_max_metal_seperation() + offsety_diffp + evaluate_bbox(diffp)[1]+pdk.util_max_metal_seperation() + offsety_cross + offsety_reset_pmos) + movex(reset_pmos_ref1, evaluate_bbox(reset_pmos_left)[0]+pdk.util_max_metal_seperation() + evaluate_bbox(cross_couple)[0]+pdk.util_max_metal_seperation()) + #print("bbox",evaluate_bbox(clk_nmos_ref)[1]) + #print(diffp_ref.get_ports_list()) + mystrongARM.add_ports(diffp_ref.get_ports_list(), prefix="strongARM_diffp_") + mystrongARM.add_ports(cross_couple_ref.get_ports_list(), prefix="strongARM_") + mystrongARM.add_ports(clk_nmos_ref.get_ports_list(), prefix="strongARM_clk_nmos_") + mystrongARM.add_ports(reset_pmos_ref1.get_ports_list(), prefix="strongARM_clk_reset_pmos_r_") + mystrongARM.add_ports(reset_pmos_ref2.get_ports_list(), prefix="strongARM_clk_reset_pmos_l_") + + mystrongARM << c_route(pdk, mystrongARM.ports["strongARM_diffp_tl_drain_W"], mystrongARM.ports["strongARM_cross_couple_bottom_A_source_W"], extension = 2) + mystrongARM << c_route(pdk, mystrongARM.ports["strongARM_diffp_tr_drain_E"], mystrongARM.ports["strongARM_cross_couple_bottom_B_source_E"], extension = 2) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_diffp_bl_source_W"], mystrongARM.ports["strongARM_clk_nmos_drain_W"], clk_nmos_ref, mystrongARM) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_diffp_br_source_E"], mystrongARM.ports["strongARM_clk_nmos_drain_E"], clk_nmos_ref, mystrongARM) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_A_source_E"], mystrongARM.ports["strongARM_clk_reset_pmos_r_B_source_E"],reset_pmos_ref1,mystrongARM) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_A_source_E"], mystrongARM.ports["strongARM_clk_reset_pmos_l_B_source_E"],reset_pmos_ref2,mystrongARM) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_A_drain_E"], mystrongARM.ports["strongARM_cross_couple_bottom_A_gate_E"]) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_B_drain_E"], mystrongARM.ports["strongARM_cross_couple_bottom_B_source_E"], extension = 1.25) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_A_drain_W"], mystrongARM.ports["strongARM_cross_couple_bottom_B_gate_W"]) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_B_drain_W"], mystrongARM.ports["strongARM_cross_couple_bottom_A_source_W"], extension = 1.25) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_A_gate_W"], mystrongARM.ports["strongARM_clk_reset_pmos_r_B_gate_W"],reset_pmos_ref1,mystrongARM) + mystrongARM << smart_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_A_gate_E"], mystrongARM.ports["strongARM_clk_reset_pmos_l_B_gate_E"],reset_pmos_ref2,mystrongARM) + + mystrongARM << c_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_A_gate_E"], mystrongARM.ports["strongARM_clk_nmos_gate_E"], extension = 3) + mystrongARM << c_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_A_gate_W"], mystrongARM.ports["strongARM_clk_nmos_gate_W"], extension = 3) + + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_l_A_source_N"], mystrongARM.ports["strongARM_clk_reset_pmos_l_welltie_N_top_met_S"], width = 1,glayer1="met3",fullbottom=True) + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_clk_reset_pmos_r_A_source_N"], mystrongARM.ports["strongARM_clk_reset_pmos_r_welltie_N_top_met_S"], width = 1,glayer1="met3",fullbottom=True) + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_cross_couple_top_A_source_N"], mystrongARM.ports["strongARM_cross_couple_top_welltie_N_top_met_S"], width = 1,glayer1="met3",fullbottom=True) + + #Gnd tap connections + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_clk_nmos_source_N"], mystrongARM.ports["strongARM_clk_nmos_tie_N_top_met_S"] ,width=0.5,glayer1="met3",fullbottom=True) + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_diffp_tap_S_top_met_S"], mystrongARM.ports["strongARM_clk_nmos_tie_N_top_met_S"] ,width=1,glayer1="met1",fullbottom=True) + mystrongARM << straight_route(pdk, mystrongARM.ports["strongARM_cross_couple_bottom_welltie_S_top_met_S"], mystrongARM.ports["strongARM_diffp_tap_N_top_met_N"] ,width=1,glayer1="met1",fullbottom=True) + + + + pfetA = pmos(pdk, width=reset_w, length=reset_l, fingers=2, with_dummy=(False, False)) + pfetB = pmos(pdk, width=reset_w, length=reset_l, fingers=2, with_dummy=(False, False)) + pfetC = pmos(pdk, width=reset_w, length=reset_l, fingers=2, with_dummy=(False, False)) + pfetD = pmos(pdk, width=reset_w, length=reset_l, fingers=2, with_dummy=(False, False)) + + nfet_clk = nmos(pdk, width=4*clk_fing, length=0.15, fingers=1, with_dummy=(False, False)) + nfet_clk_dum = nmos(pdk, width=4*2, length=0.15, fingers=1, with_dummy=(False, False)) + mystrongARM.info['netlist'] = mystrongARM_netlist(diffp, cross_couple, nfet_clk, nfet_clk_dum, pfetA, pfetB, pfetC, pfetD) + + return mystrongARM + +def add_strongARM_labels(pdk: MappedPDK, mystrongARM: Component): + mystrongARM.unlock() + met1_label = (68, 5) + met1_pin = (68, 16) + met2_label = (69, 5) + met2_pin = (69, 16) + move_info = list() + + vddpin = mystrongARM << rectangle(size=(5,1),layer=pdk.get_glayer("met3"),centered=True) + vddpin.movey(mystrongARM.ymax + 2) + vddpin.movex((mystrongARM.xmax)/2 - 4) + #Vdd connections + mystrongARM << straight_route(pdk, vddpin.ports["e4"] ,mystrongARM.ports["strongARM_cross_couple_top_welltie_N_top_met_N"], width=6,glayer1="met3",fullbottom=True) + mystrongARM << L_route(pdk, vddpin.ports["e1"] ,mystrongARM.ports["strongARM_clk_reset_pmos_l_welltie_N_top_met_N"], vwidth=1,vglayer="met2",fullbottom=True) + mystrongARM << L_route(pdk, vddpin.ports["e3"] ,mystrongARM.ports["strongARM_clk_reset_pmos_r_welltie_N_top_met_N"], vwidth=1,vglayer="met2",fullbottom=True) + + #vdd label + vddlabel = rectangle(layer=met2_pin, size=(0.1,0.1), centered=True).copy() + vddlabel.add_label(text="VDD",layer=met2_label) + move_info.append((vddlabel,vddpin.ports["e1"],None)) + #inp label + vinplabel = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vinplabel.add_label(text="VIP",layer=met1_label) + move_info.append((vinplabel,mystrongARM.ports["strongARM_diffp_tl_gate_N"],None)) + #inm label + vinmlabel = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vinmlabel.add_label(text="VIM",layer=met1_label) + move_info.append((vinmlabel,mystrongARM.ports["strongARM_diffp_tr_gate_N"],None)) + #vtail label + vtaillabel = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vtaillabel.add_label(text="VS",layer=met1_label) + move_info.append((vtaillabel,mystrongARM.ports["strongARM_diffp_bl_source_E"],None)) + #vd1 label + vd1label = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vd1label.add_label(text="VP",layer=met1_label) + move_info.append((vd1label,mystrongARM.ports["strongARM_diffp_tl_drain_N"],None)) + #vd2 label + vd2label = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vd2label.add_label(text="VQ",layer=met1_label) + move_info.append((vd2label,mystrongARM.ports["strongARM_diffp_tr_drain_N"],None)) + #vclk label + vclklabel = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vclklabel.add_label(text="VCLK",layer=met1_label) + move_info.append((vclklabel,mystrongARM.ports["strongARM_clk_nmos_gate_N"],None)) + #gnd label + vgndlabel = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vgndlabel.add_label(text="VSS",layer=met1_label) + move_info.append((vgndlabel,mystrongARM.ports["strongARM_clk_nmos_tie_N_top_met_S"],None)) + #vo1 label + vo1label = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vo1label.add_label(text="VOP",layer=met1_label) + move_info.append((vo1label,mystrongARM.ports["strongARM_cross_couple_top_B_drain_N"],None)) + #vo2 label + vo2label = rectangle(layer=met1_pin, size=(0.1,0.1), centered=True).copy() + vo2label.add_label(text="VOM",layer=met1_label) + move_info.append((vo2label,mystrongARM.ports["strongARM_cross_couple_top_A_drain_N"],None)) + #move everything to position + for comp, prt, alignment in move_info: + alignment = ('c','b') if alignment is None else alignment + compref = align_comp_to_port(comp, prt, alignment=alignment) + mystrongARM.add(compref) + return mystrongARM.flatten() + +strong = add_strongARM_labels(sky130_mapped_pdk,mystrongARM(sky130_mapped_pdk, 8, 0.4, 2, 4, 3, 0.4)) +strong.write_gds("./mystrongARM.gds") +strong.show() + +#magic_drc_result = sky130_mapped_pdk.drc_magic(strong, strong.name) +#lvs_result = sky130_mapped_pdk.lvs_netgen(strong,strong.name,copy_intermediate_files=True) + +#fname = f"{strong.name}_lvsmag.spice" +#os.rename(fname, "mystrongARM_lvsmag.spice") + +#with open("mystrongARM_lvsmag.spice","r") as file: +# file_content = file.read() + +#new_content = file_content.replace(strong.name,"mystrongARM") + +#with open("mystrongARM_lvsmag.spice","w") as file: +# file.write(new_content)