From 309241d6fa8ca6fcbce8535426848183a4ec794b Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:11:09 +0530 Subject: [PATCH 01/10] added FVF Pcell files, Analog Vibes, Chipathon 2024 1. drc and lvs reports are also attached 2. sample picture of gds is attached 3. README file and annotations in fvf.py are added --- .../glayout/flow/blocks/elementary/FVF/LVS | 41 +++++ .../flow/blocks/elementary/FVF/README.md | 35 ++++ .../glayout/flow/blocks/elementary/FVF/drc | 31 ++++ .../glayout/flow/blocks/elementary/FVF/fvf.py | 167 ++++++++++++++++++ .../flow/blocks/elementary/FVF/fvfgds.png | Bin 0 -> 13575 bytes 5 files changed, 274 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/LVS create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/drc create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvfgds.png diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/LVS b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/LVS new file mode 100644 index 000000000..515a0a769 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/LVS @@ -0,0 +1,41 @@ + +Circuit 1 cell sky130_fd_pr__nfet_01v8 and Circuit 2 cell sky130_fd_pr__nfet_01v8 are black boxes. +Warning: Equate pins: cell sky130_fd_pr__nfet_01v8 is a placeholder, treated as a black box. +Warning: Equate pins: cell sky130_fd_pr__nfet_01v8 is a placeholder, treated as a black box. + +Subcircuit pins: +Circuit 1: sky130_fd_pr__nfet_01v8 |Circuit 2: sky130_fd_pr__nfet_01v8 +-------------------------------------------|------------------------------------------- +1 |1 +2 |2 +3 |3 +4 |4 +--------------------------------------------------------------------------------------- +Cell pin lists are equivalent. +Device classes sky130_fd_pr__nfet_01v8 and sky130_fd_pr__nfet_01v8 are equivalent. +Flattening unmatched subcell NMOS in circuit fvf (1)(2 instances) + +Class fvf (0): Merged 3 parallel devices. +Class fvf (1): Merged 3 parallel devices. +Subcircuit summary: +Circuit 1: fvf |Circuit 2: fvf +-------------------------------------------|------------------------------------------- +sky130_fd_pr__nfet_01v8 (6->3) |sky130_fd_pr__nfet_01v8 (6->3) +Number of devices: 3 |Number of devices: 3 +Number of nets: 4 |Number of nets: 4 +--------------------------------------------------------------------------------------- +Netlists match uniquely. + +Subcircuit pins: +Circuit 1: fvf |Circuit 2: fvf +-------------------------------------------|------------------------------------------- +VIN |VIN +Ib |Ib +VOUT |VOUT +VBULK |VBULK +--------------------------------------------------------------------------------------- +Cell pin lists are equivalent. +Device classes fvf and fvf are equivalent. + +Final result: Circuits match uniquely. +. diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md new file mode 100644 index 000000000..8f5bca85f --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md @@ -0,0 +1,35 @@ +##FLIPPED VOLTAGE FOLLOWER CELL +def flipped_voltage_follower( + pdk: MappedPDK, + device_type: str = "nmos", + placement: str = "horizontal", + width: tuple[float,float] = (3,3), + length: tuple[float,float] = (None,None), + fingers: tuple[int,int] = (1,1), + multipliers: tuple[int,int] = (1,1), + dummy_1: tuple[bool,bool] = (True,True), + dummy_2: tuple[bool,bool] = (True,True), + tie_layers1: tuple[str,str] = ("met2","met1"), + tie_layers2: tuple[str,str] = ("met2","met1"), + sd_rmult: int=1, + **kwargs + ) -> Component: + """ + creates a Flipped Voltage Follower + pdk: pdk to use + device_type: either "nmos" or "pmos" + placement: either "horizontal" or "vertical" + width: (input fet, feedback fet) + length: (input fet, feedback fet) + fingers: (input fet, feedback fet) + multipliers: (input fet, feedback fet) + dummy_1: dummy for input fet + dummy_2: dummy for feedback fet + dnwell: adds Deep N-well + sb_short: shorts the source and bulk of input fet if True + tie_layers1: tie layers for input fet + tie_layers2: tie layers for feedback fet + sd_rmult: sd_rmult for both fets + **kwargs: any kwarg that is supported by nmos and pmos + NB:- currently LVS is passed only for nmos without sd_short and pmos with sd_short + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/drc b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/drc new file mode 100644 index 000000000..d622202f2 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/drc @@ -0,0 +1,31 @@ +using default pdk_root: /usr/bin/miniconda3/share/pdk/ +Defaulting to stale magic_commands.tcl + +Magic 8.3 revision 464 - Compiled on Sat Mar 9 23:18:29 UTC 2024. +Starting magic under Tcl interpreter +Using the terminal as the console. +Using NULL graphics device. +Processing system .magicrc file +Sourcing design .magicrc for technology sky130A ... +2 Magic internal units = 1 Lambda +Input style sky130(): scaleFactor=2, multiplier=2 +The following types are not handled by extraction and will be treated as non-electrical types: + ubm +Scaled tech values by 2 / 1 to match internal grid scaling +Loading sky130A Device Generator Menu ... +Loading "/tmp/tmp0t0g30yo/magic_commands.tcl" from command line. +Warning: Calma reading is not undoable! I hope that's OK. +Library written using GDS-II Release 6.0 +Library name: library +Reading "fvf". +[INFO]: Loading fvf + +Loading DRC CIF style. +No errors found. +[INFO]: DONE with /tmp/tmp0t0g30yo/fvf.rpt + +Using technology "sky130A", version 1.0.471-0-g97d0844 + +Soft errors: +Error while reading cell "fvf" (byte position 118): Unknown layer/datatype in boundary, layer=64 type=44 + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py new file mode 100644 index 000000000..7186f9918 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -0,0 +1,167 @@ +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from gdsfactory.cell import cell +from gdsfactory.component import Component +from gdsfactory import Component +from glayout.flow.primitives.fet import nmos, pmos, multiplier +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_center, prec_ref_center, align_comp_to_port +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid +from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation +from glayout.flow.routing.straight_route import straight_route +from glayout.flow.routing.c_route import c_route +from glayout.flow.routing.L_route import L_route +from glayout.flow.primitives.guardring import tapring +from glayout.flow.pdk.util.port_utils import add_ports_perimeter +from glayout.flow.spice.netlist import Netlist +from glayout.flow.primitives.via_gen import via_stack +from gdsfactory.components import text_freetype, rectangle + +def fvf_netlist(fet_1: Component, fet_2: Component) -> Netlist: + + netlist = Netlist(circuit_name='FLIPPED_VOLTAGE_FOLLOWER', nodes=['VIN', 'VBULK', 'VOUT', 'Ib']) + + netlist.connect_netlist(fet_1.info['netlist'], [('D', 'Ib'), ('G', 'VIN'), ('S', 'VOUT'), ('B', 'VBULK')]) + netlist.connect_netlist(fet_2.info['netlist'], [('D', 'VOUT'), ('G', 'Ib'), ('S', 'VBULK'), ('B', 'VBULK')]) + + return netlist + +def sky130_add_fvf_labels(fvf_in: Component) -> Component: + + fvf_in.unlock() + # define layers` + met1_pin = (68,16) + met1_label = (68,5) + met2_pin = (69,16) + met2_label = (69,5) + # list that will contain all port/comp info + move_info = list() + # create labels and append to info list + # gnd + gnd2label = rectangle(layer=met1_pin,size=(0.5,0.5),centered=True).copy() + gnd2label.add_label(text="VBULK",layer=met1_label) + move_info.append((gnd2label,fvf_in.ports["B_tie_N_top_met_N"],None)) + + #currentbias + ibiaslabel = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + ibiaslabel.add_label(text="Ib",layer=met2_label) + move_info.append((ibiaslabel,fvf_in.ports["A_drain_bottom_met_N"],None)) + + # output (3rd stage) + outputlabel = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + outputlabel.add_label(text="VOUT",layer=met2_label) + move_info.append((outputlabel,fvf_in.ports["A_source_bottom_met_N"],None)) + + # input + inputlabel = rectangle(layer=met1_pin,size=(0.5,0.5),centered=True).copy() + inputlabel.add_label(text="VIN",layer=met1_label) + move_info.append((inputlabel,fvf_in.ports["A_multiplier_0_gate_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) + fvf_in.add(compref) + return fvf_in.flatten() + +@cell +def flipped_voltage_follower( + pdk: MappedPDK, + device_type: str = "nmos", + placement: str = "horizontal", + width: tuple[float,float] = (3,3), + length: tuple[float,float] = (None,None), + fingers: tuple[int,int] = (1,1), + multipliers: tuple[int,int] = (1,1), + dummy_1: tuple[bool,bool] = (True,True), + dummy_2: tuple[bool,bool] = (True,True), + tie_layers1: tuple[str,str] = ("met2","met1"), + tie_layers2: tuple[str,str] = ("met2","met1"), + sd_rmult: int=1, + **kwargs + ) -> Component: + """ + creates a Flipped Voltage Follower + pdk: pdk to use + device_type: either "nmos" or "pmos" + placement: either "horizontal" or "vertical" + width: (input fet, feedback fet) + length: (input fet, feedback fet) + fingers: (input fet, feedback fet) + multipliers: (input fet, feedback fet) + dummy_1: dummy for input fet + dummy_2: dummy for feedback fet + dnwell: adds Deep N-well + sb_short: shorts the source and bulk of input fet if True + tie_layers1: tie layers for input fet + tie_layers2: tie layers for feedback fet + sd_rmult: sd_rmult for both fets + **kwargs: any kwarg that is supported by nmos and pmos + NB:- currently LVS is passed only for nmos without sd_short and pmos with sd_short + """ + + #top level component + top_level = Component(name="flipped_voltage_follower") + + #two fets + if device_type == "nmos": + fet_1 = nmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=dummy_1, with_dnwell=False, with_substrate_tap=False, length=length[0], tie_layers=tie_layers1, sd_rmult=sd_rmult, **kwargs) + fet_2 = nmos(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=dummy_2, with_dnwell=False, with_substrate_tap=False, length=length[1], tie_layers=tie_layers2, sd_rmult=sd_rmult, **kwargs) + well = "pwell" + elif device_type == "pmos": + fet_1 = pmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=dummy_1, with_substrate_tap=False, length=length[0], tie_layers=tie_layers1, sd_rmult=sd_rmult, **kwargs) + fet_2 = pmos(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=dummy_2, with_substrate_tap=False, length=length[1], tie_layers=tie_layers2, sd_rmult=sd_rmult, **kwargs) + well = "nwell" + fet_1_ref = top_level << fet_1 + fet_2_ref = top_level << fet_2 + + #Relative move + ref_dimensions = evaluate_bbox(fet_2) + if placement == "horizontal": + fet_2_ref.movex(fet_1_ref.xmax + ref_dimensions[0]/2 + pdk.util_max_metal_seperation()+1) + if placement == "vertical": + fet_2_ref.movey(fet_1_ref.ymin - ref_dimensions[1]/2 - pdk.util_max_metal_seperation()-1) + + #Routing + viam2m3 = via_stack(pdk, "met2", "met3", centered=True) + drain_1_via = top_level << viam2m3 + source_1_via = top_level << viam2m3 + drain_2_via = top_level << viam2m3 + gate_2_via = top_level << viam2m3 + drain_1_via.move(fet_1_ref.ports["multiplier_0_drain_W"].center).movex(-0.5*evaluate_bbox(fet_1)[1]) + source_1_via.move(fet_1_ref.ports["multiplier_0_source_E"].center).movex(1.5) + drain_2_via.move(fet_2_ref.ports["multiplier_0_drain_W"].center).movex(-1.5) + gate_2_via.move(fet_2_ref.ports["multiplier_0_gate_E"].center).movex(1) + + top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_source_E"], source_1_via.ports["bottom_met_W"]) + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_drain_W"], drain_2_via.ports["bottom_met_E"]) + top_level << c_route(pdk, source_1_via.ports["top_met_N"], drain_2_via.ports["top_met_N"], extension=1.2*width[1], width1=0.32, width2=0.32, cwidth=0.32, e1glayer="met3", e2glayer="met3", cglayer="met2") + top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_drain_W"], drain_1_via.ports["bottom_met_E"]) + top_level << c_route(pdk, drain_1_via.ports["top_met_S"], gate_2_via.ports["top_met_S"], extension=1.2*width[1], cglayer="met2") + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_gate_E"], gate_2_via.ports["bottom_met_W"]) + + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_source_W"], fet_2_ref.ports["tie_W_top_met_W"], glayer1=tie_layers2[1], width=0.2*sd_rmult, fullbottom=True) + + #Renaming Ports + top_level.add_ports(fet_1_ref.get_ports_list(), prefix="A_") + top_level.add_ports(fet_2_ref.get_ports_list(), prefix="B_") + top_level.add_ports(drain_1_via.get_ports_list(), prefix="A_drain_") + top_level.add_ports(source_1_via.get_ports_list(), prefix="A_source_") + top_level.add_ports(drain_2_via.get_ports_list(), prefix="B_drain_") + top_level.add_ports(gate_2_via.get_ports_list(), prefix="B_gate_") + #add dnwell + if well == "nwell": + top_level.add_padding(layers=(pdk.get_glayer("nwell"),),default= 1 ) + + + comp = Component() + compref = comp << top_level + correctionxy = prec_center(compref) + compref.movex(correctionxy[0]).movey(correctionxy[1]) + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + + component.info['netlist'] = fvf_netlist(fet_1, fet_2) + + return component + + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvfgds.png b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvfgds.png new file mode 100644 index 0000000000000000000000000000000000000000..5bc7422aafc51d3f3af20fe4940bb36ce6f3c142 GIT binary patch literal 13575 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 Date: Sun, 24 Nov 2024 17:20:27 +0530 Subject: [PATCH 02/10] Updated README.md --- .../glayout/flow/blocks/elementary/FVF/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md index 8f5bca85f..1cef36bea 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/README.md @@ -1,4 +1,6 @@ -##FLIPPED VOLTAGE FOLLOWER CELL +## FLIPPED VOLTAGE FOLLOWER CELL + +``` def flipped_voltage_follower( pdk: MappedPDK, device_type: str = "nmos", @@ -25,11 +27,11 @@ def flipped_voltage_follower( multipliers: (input fet, feedback fet) dummy_1: dummy for input fet dummy_2: dummy for feedback fet - dnwell: adds Deep N-well - sb_short: shorts the source and bulk of input fet if True tie_layers1: tie layers for input fet tie_layers2: tie layers for feedback fet sd_rmult: sd_rmult for both fets **kwargs: any kwarg that is supported by nmos and pmos - NB:- currently LVS is passed only for nmos without sd_short and pmos with sd_short +``` +### GDS generated +![gds generated](./fvfgds.png) From 51bb49388030d69eed750d6cc5c5f6781502fb82 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:22:07 +0530 Subject: [PATCH 03/10] Updated comments --- .../glayout/glayout/flow/blocks/elementary/FVF/fvf.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index 7186f9918..988227fb6 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -90,13 +90,10 @@ def flipped_voltage_follower( multipliers: (input fet, feedback fet) dummy_1: dummy for input fet dummy_2: dummy for feedback fet - dnwell: adds Deep N-well - sb_short: shorts the source and bulk of input fet if True tie_layers1: tie layers for input fet tie_layers2: tie layers for feedback fet sd_rmult: sd_rmult for both fets **kwargs: any kwarg that is supported by nmos and pmos - NB:- currently LVS is passed only for nmos without sd_short and pmos with sd_short """ #top level component From aa3eb80c8293c9259702a415dbede321d96fb5f5 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:35:16 +0530 Subject: [PATCH 04/10] removed code duplication --- .../glayout/flow/blocks/elementary/FVF/fvf.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index 988227fb6..81c7b524d 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -100,14 +100,16 @@ def flipped_voltage_follower( top_level = Component(name="flipped_voltage_follower") #two fets - if device_type == "nmos": - fet_1 = nmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=dummy_1, with_dnwell=False, with_substrate_tap=False, length=length[0], tie_layers=tie_layers1, sd_rmult=sd_rmult, **kwargs) - fet_2 = nmos(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=dummy_2, with_dnwell=False, with_substrate_tap=False, length=length[1], tie_layers=tie_layers2, sd_rmult=sd_rmult, **kwargs) - well = "pwell" - elif device_type == "pmos": - fet_1 = pmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=dummy_1, with_substrate_tap=False, length=length[0], tie_layers=tie_layers1, sd_rmult=sd_rmult, **kwargs) - fet_2 = pmos(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=dummy_2, with_substrate_tap=False, length=length[1], tie_layers=tie_layers2, sd_rmult=sd_rmult, **kwargs) - well = "nwell" + device_map = { + "nmos": nmos, + "pmos":pmos, + } + device = device_map.get(device_type) + + fet_1 = device(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=dummy_1, with_substrate_tap=False, length=length[0], tie_layers=tie_layers1, sd_rmult=sd_rmult, **kwargs) + fet_2 = device(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=dummy_2, with_substrate_tap=False, length=length[1], tie_layers=tie_layers2, sd_rmult=sd_rmult, **kwargs) + well = "pwell" if device == nmos else "nwell" + fet_1_ref = top_level << fet_1 fet_2_ref = top_level << fet_2 @@ -145,7 +147,7 @@ def flipped_voltage_follower( top_level.add_ports(source_1_via.get_ports_list(), prefix="A_source_") top_level.add_ports(drain_2_via.get_ports_list(), prefix="B_drain_") top_level.add_ports(gate_2_via.get_ports_list(), prefix="B_gate_") - #add dnwell + #add nwell if well == "nwell": top_level.add_padding(layers=(pdk.get_glayer("nwell"),),default= 1 ) From 85facbc9b0fa82a60310688e825bc776b8869e3a Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:37:14 +0530 Subject: [PATCH 05/10] updated for proper routing to pass all drc --- .../glayout/glayout/flow/blocks/elementary/FVF/fvf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index 81c7b524d..d7aa1d161 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -133,9 +133,9 @@ def flipped_voltage_follower( top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_source_E"], source_1_via.ports["bottom_met_W"]) top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_drain_W"], drain_2_via.ports["bottom_met_E"]) - top_level << c_route(pdk, source_1_via.ports["top_met_N"], drain_2_via.ports["top_met_N"], extension=1.2*width[1], width1=0.32, width2=0.32, cwidth=0.32, e1glayer="met3", e2glayer="met3", cglayer="met2") + top_level << c_route(pdk, source_1_via.ports["top_met_N"], drain_2_via.ports["top_met_N"], extension=1.2*max(width[0],width[1]), width1=0.32, width2=0.32, cwidth=0.32, e1glayer="met3", e2glayer="met3", cglayer="met2") top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_drain_W"], drain_1_via.ports["bottom_met_E"]) - top_level << c_route(pdk, drain_1_via.ports["top_met_S"], gate_2_via.ports["top_met_S"], extension=1.2*width[1], cglayer="met2") + top_level << c_route(pdk, drain_1_via.ports["top_met_S"], gate_2_via.ports["top_met_S"], extension=1.2*max(width[0],width[1]), cglayer="met2") top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_gate_E"], gate_2_via.ports["bottom_met_W"]) top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_source_W"], fet_2_ref.ports["tie_W_top_met_W"], glayer1=tie_layers2[1], width=0.2*sd_rmult, fullbottom=True) From dfe0499c465d8bff0cbcc7da99cf497e7899a796 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:50:04 +0530 Subject: [PATCH 06/10] removed unnecessary lines --- .../glayout/glayout/flow/blocks/elementary/FVF/fvf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index d7aa1d161..0bf6c63ae 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -150,12 +150,6 @@ def flipped_voltage_follower( #add nwell if well == "nwell": top_level.add_padding(layers=(pdk.get_glayer("nwell"),),default= 1 ) - - - comp = Component() - compref = comp << top_level - correctionxy = prec_center(compref) - compref.movex(correctionxy[0]).movey(correctionxy[1]) component = component_snap_to_grid(rename_ports_by_orientation(top_level)) From 507e10ccb404999737c375b210724d4cc0bad2fa Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:39:20 +0530 Subject: [PATCH 07/10] adding more flexibility for without tie option --- .../glayout/glayout/flow/blocks/elementary/FVF/fvf.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index 0bf6c63ae..ce1b83c0d 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -137,9 +137,10 @@ def flipped_voltage_follower( top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_drain_W"], drain_1_via.ports["bottom_met_E"]) top_level << c_route(pdk, drain_1_via.ports["top_met_S"], gate_2_via.ports["top_met_S"], extension=1.2*max(width[0],width[1]), cglayer="met2") top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_gate_E"], gate_2_via.ports["bottom_met_W"]) - - top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_source_W"], fet_2_ref.ports["tie_W_top_met_W"], glayer1=tie_layers2[1], width=0.2*sd_rmult, fullbottom=True) - + try: + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_source_W"], fet_2_ref.ports["tie_W_top_met_W"], glayer1=tie_layers2[1], width=0.2*sd_rmult, fullbottom=True) + except: + pass #Renaming Ports top_level.add_ports(fet_1_ref.get_ports_list(), prefix="A_") top_level.add_ports(fet_2_ref.get_ports_list(), prefix="B_") From 3b59e93cc0dd17ddcdc6a28d955aca6c83c7fd01 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:56:32 +0530 Subject: [PATCH 08/10] updated comments --- .../glayout/glayout/flow/blocks/elementary/FVF/fvf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py index ce1b83c0d..d0fd3b866 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/FVF/fvf.py @@ -94,6 +94,8 @@ def flipped_voltage_follower( tie_layers2: tie layers for feedback fet sd_rmult: sd_rmult for both fets **kwargs: any kwarg that is supported by nmos and pmos + + Note- While using nmos, use with_dnwell=False """ #top level component From f373d989a4b387db19b766d29a016558e69ede8a Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:06:03 +0530 Subject: [PATCH 09/10] added code to add more vias at intermedate ports --- .../glayout/glayout/flow/routing/c_route.py | 440 ++++++++++-------- 1 file changed, 235 insertions(+), 205 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/routing/c_route.py b/openfasoc/generators/glayout/glayout/flow/routing/c_route.py index 7f7bcf18b..da3c5b467 100644 --- a/openfasoc/generators/glayout/glayout/flow/routing/c_route.py +++ b/openfasoc/generators/glayout/glayout/flow/routing/c_route.py @@ -4,10 +4,10 @@ from glayout.flow.pdk.mappedpdk import MappedPDK from typing import Optional, Union from math import isclose -from glayout.flow.primitives.via_gen import via_stack +from glayout.flow.primitives.via_gen import via_stack, via_array from glayout.flow.routing.straight_route import straight_route from gdsfactory.components.rectangle import rectangle -from glayout.flow.pdk.util.comp_utils import evaluate_bbox, get_primitive_rectangle +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, get_primitive_rectangle, to_float, prec_ref_center from glayout.flow.pdk.util.port_utils import add_ports_perimeter, rename_ports_by_orientation, rename_ports_by_list, print_ports, set_port_width, set_port_orientation, get_orientation from pydantic import validate_arguments from gdsfactory.snap import snap_to_grid @@ -15,211 +15,241 @@ @validate_arguments def __fill_empty_viastack__macro(pdk: MappedPDK, glayer: str, size: Optional[tuple[float,float]]=None) -> Component: - """returns a rectangle with ports that pretend to be viastack ports - by default creates a rectangle with size double the min width of the glayer""" - if size is None: - size = pdk.snap_to_2xgrid([2*pdk.get_grule(glayer)["min_width"],2*pdk.get_grule(glayer)["min_width"]]) - comp = rectangle(size=size,layer=pdk.get_glayer(glayer),centered=True) - return rename_ports_by_orientation(rename_ports_by_list(comp,replace_list=[("e","top_met_")])).flatten() + """returns a rectangle with ports that pretend to be viastack ports + by default creates a rectangle with size double the min width of the glayer""" + if size is None: + size = pdk.snap_to_2xgrid([2*pdk.get_grule(glayer)["min_width"],2*pdk.get_grule(glayer)["min_width"]]) + comp = rectangle(size=size,layer=pdk.get_glayer(glayer),centered=True) + return rename_ports_by_orientation(rename_ports_by_list(comp,replace_list=[("e","top_met_")])).flatten() @cell def c_route( - pdk: MappedPDK, - edge1: Port, - edge2: Port, - extension: Optional[float]=0.5, - width1: Optional[float] = None, - width2: Optional[float] = None, - cwidth: Optional[float] = None, - e1glayer: Optional[str] = None, - e2glayer: Optional[str] = None, - cglayer: Optional[str] = None, - viaoffset: Optional[Union[bool,tuple[Optional[bool],Optional[bool]]]]=(True,True), - fullbottom: Optional[bool] = False, - debug=False + pdk: MappedPDK, + edge1: Port, + edge2: Port, + extension: Optional[float]=0.5, + width1: Optional[float] = None, + width2: Optional[float] = None, + cwidth: Optional[float] = None, + e1glayer: Optional[str] = None, + e2glayer: Optional[str] = None, + cglayer: Optional[str] = None, + viaoffset: Optional[Union[bool,tuple[Optional[bool],Optional[bool]]]]=(True,True), + fullbottom: Optional[bool] = False, + debug=False ) -> Component: - """creates a C shaped route between two Ports. - - edge1--| - | - edge2--| - - REQUIRES: ports be parralel vertical or horizontal edges - ****NOTE: does no drc error checking (creates a dumb route) - args: - pdk = pdk to use - edge1 = first port - edge2 = second port - width1 = optional will default to edge1 width if None - width2 = optional will default to edge2 width if None - e1glayer = glayer for the parts connecting to the edge1. Default to layer of edge1 - e2glayer = glayer for the parts connecting to the edge2. Default to layer of edge2 - cglayer = glayer for the connection part (part that goes through a via) defaults to e1glayer met+1 - viaoffset = offsets the via so that it is flush with the cglayer (may be needed for drc) i.e. -| vs _| - - True offsets via towards the other via - - False offsets via away from the other via - - None means center (no offset) - ****NOTE: viaoffset pushes both vias towards each other slightly - """ - if debug: - pass - #import pdb; pdb.set_trace() - # error checking and figure out args - if round(edge1.orientation) % 90 or round(edge2.orientation) % 90: - raise ValueError("Ports must be vertical or horizontal") - if not isclose(edge1.orientation,edge2.orientation): - raise ValueError("Ports must be parralel and have same orientation") - width1 = width1 if width1 else edge1.width - width2 = width2 if width2 else edge1.width - e1glayer = e1glayer if e1glayer else pdk.layer_to_glayer(edge1.layer) - e2glayer = e2glayer if e2glayer else pdk.layer_to_glayer(edge2.layer) - eglayer_plusone = "met" + str(int(e1glayer[-1])+1) - cglayer = cglayer if cglayer else eglayer_plusone - if not "met" in e1glayer or not "met" in e2glayer or not "met" in cglayer: - raise ValueError("given layers must be metals") - viaoffset = (None, None) if viaoffset is None else viaoffset - if isinstance(viaoffset,bool): - viaoffset = (True,True) if viaoffset else (False,False) - pdk.has_required_glayers([e1glayer,e2glayer,cglayer]) - pdk.activate() - extension = snap_to_grid(extension) - # create route - croute = Component() - viastack1 = via_stack(pdk,e1glayer,cglayer,fullbottom=fullbottom,assume_bottom_via=True) - viastack2 = via_stack(pdk,e2glayer,cglayer,fullbottom=fullbottom,assume_bottom_via=True) - if e1glayer==cglayer and e2glayer==cglayer: - viastack1 = __fill_empty_viastack__macro(pdk,e1glayer) - viastack2 = __fill_empty_viastack__macro(pdk,e2glayer) - elif e1glayer == cglayer: - viastack1 = __fill_empty_viastack__macro(pdk,e1glayer,size=evaluate_bbox(viastack2)) - elif e2glayer == cglayer: - viastack2 = __fill_empty_viastack__macro(pdk,e2glayer,size=evaluate_bbox(viastack1)) - # find extension - e1_length = snap_to_grid(extension + evaluate_bbox(viastack1)[0]) - e2_length = snap_to_grid(extension + evaluate_bbox(viastack2)[0]) - xdiff = snap_to_grid(abs(edge1.center[0] - edge2.center[0])) - ydiff = snap_to_grid(abs(edge1.center[1] - edge2.center[1])) - if not isclose(edge1.center[0],edge2.center[0]): - if round(edge1.orientation) == 0:# facing east - if edge1.center[0] > edge2.center[0]: - e2_length += xdiff - else: - e1_length += xdiff - elif round(edge1.orientation) == 180:# facing west - if edge1.center[0] < edge2.center[0]: - e2_length += xdiff - else: - e1_length += xdiff - if not isclose(edge1.center[1],edge2.center[1]): - if round(edge1.orientation) == 270:# facing south - if edge1.center[1] < edge2.center[1]: - e2_length += ydiff - else: - e1_length += ydiff - elif round(edge1.orientation) == 90:#facing north - if edge1.center[1] > edge2.center[1]: - e2_length += ydiff - else: - e1_length += ydiff - # move into position - e1_extension_comp = Component("edge1 extension") - e2_extension_comp = Component("edge2 extension") - box_dims = [(e1_length, width1),(e2_length, width2)] - if round(edge1.orientation) == 90 or round(edge1.orientation) == 270: - box_dims = [(width1, e1_length),(width2, e2_length)] - rect_c1 = get_primitive_rectangle(size=box_dims[0], layer=pdk.get_glayer(e1glayer)) - rect_c2 = get_primitive_rectangle(size=box_dims[1], layer=pdk.get_glayer(e2glayer)) - rect_c1 = rename_ports_by_orientation(rename_ports_by_list(rect_c1,[("e","e_")])) - rect_c2 = rename_ports_by_orientation(rename_ports_by_list(rect_c2,[("e","e_")])) - # TODO: make sure ports match bbox - e1_extension = e1_extension_comp << rect_c1 - e2_extension = e2_extension_comp << rect_c2 - e1_extension.move(destination=edge1.center) - e2_extension.move(destination=edge2.center) - if round(edge1.orientation) == 0:# facing east - e1_extension.movey(0-evaluate_bbox(e1_extension)[1]/2) - e2_extension.movey(0-evaluate_bbox(e2_extension)[1]/2) - elif round(edge1.orientation) == 180:# facing west - e1_extension.movex(0-evaluate_bbox(e1_extension)[0]) - e2_extension.movex(0-evaluate_bbox(e2_extension)[0]) - e1_extension.movey(0-evaluate_bbox(e1_extension)[1]/2) - e2_extension.movey(0-evaluate_bbox(e2_extension)[1]/2) - elif round(edge1.orientation) == 270:# facing south - e1_extension.movex(0-evaluate_bbox(e1_extension)[0]/2) - e2_extension.movex(0-evaluate_bbox(e2_extension)[0]/2) - e1_extension.movey(0-evaluate_bbox(e1_extension)[1]) - e2_extension.movey(0-evaluate_bbox(e2_extension)[1]) - else:#facing north - e1_extension.movex(0-evaluate_bbox(e1_extension)[0]/2) - e2_extension.movex(0-evaluate_bbox(e2_extension)[0]/2) - # place viastacks - e1_extension_comp.add_ports(e1_extension.get_ports_list()) - e2_extension_comp.add_ports(e2_extension.get_ports_list()) - me1 = e1_extension_comp << viastack1 - me2 = e2_extension_comp << viastack2 - route_ports = [None,None] - via_flush = snap_to_grid(abs((width1 - evaluate_bbox(viastack1)[0])/2) if viaoffset else 0) - via_flush1 = via_flush if viaoffset[0] else 0-via_flush - via_flush1 = 0 if viaoffset[0] is None else via_flush1 - via_flush2 = via_flush if viaoffset[1] else 0-via_flush - via_flush2 = 0 if viaoffset[1] is None else via_flush2 - if round(edge1.orientation) == 0:# facing east - me1.move(destination=e1_extension.ports["e_E"].center) - me2.move(destination=e2_extension.ports["e_E"].center) - via_flush *= 1 if me1.ymax > me2.ymax else -1 - me1.movex(0-viastack1.xmax).movey(0-via_flush1) - me2.movex(0-viastack2.xmax).movey(via_flush2) - me1, me2 = (me1, me2) if (me1.origin[1] > me2.origin[1]) else (me2, me1) - route_ports = [me1.ports["top_met_N"],me2.ports["top_met_S"]] - fix_connection_direction = "E" - fix_ports = [me1.ports["top_met_E"],me2.ports["top_met_E"]] - elif round(edge1.orientation) == 180:# facing west - me1.move(destination=e1_extension.ports["e_W"].center) - me2.move(destination=e2_extension.ports["e_W"].center) - via_flush *= 1 if me1.ymax > me2.ymax else -1 - me1.movex(viastack1.xmax).movey(0-via_flush1) - me2.movex(viastack2.xmax).movey(via_flush2) - me1, me2 = (me1, me2) if (me1.origin[1] > me2.origin[1]) else (me2, me1) - route_ports = [me1.ports["top_met_N"],me2.ports["top_met_S"]] - fix_connection_direction = "E" - fix_ports = [me1.ports["top_met_E"],me2.ports["top_met_E"]] - elif round(edge1.orientation) == 270:# facing south - me1.move(destination=e1_extension.ports["e_S"].center) - me2.move(destination=e2_extension.ports["e_S"].center) - via_flush *= 1 if me1.xmax > me2.xmax else -1 - me1.movey(viastack1.xmax).movex(0-via_flush1) - me2.movey(viastack2.xmax).movex(via_flush2) - me1, me2 = (me1, me2) if (me1.origin[0] > me2.origin[0]) else (me2, me1) - route_ports = [me1.ports["top_met_E"],me2.ports["top_met_W"]] - fix_connection_direction = "N" - fix_ports = [me1.ports["top_met_N"],me2.ports["top_met_N"]] - else:#facing north - me1.move(destination=e1_extension.ports["e_N"].center) - me2.move(destination=e2_extension.ports["e_N"].center) - via_flush *= 1 if me1.xmax > me2.xmax else -1 - me1.movey(0-viastack1.xmax).movex(0-via_flush1) - me2.movey(0-viastack2.xmax).movex(via_flush2) - me1, me2 = (me1, me2) if (me1.origin[0] > me2.origin[0]) else (me2, me1) - route_ports = [me1.ports["top_met_E"],me2.ports["top_met_W"]] - fix_connection_direction = "N" - fix_ports = [me1.ports["top_met_N"],me2.ports["top_met_N"]] - # connect extensions, add ports, return - croute << e1_extension_comp - croute << e2_extension_comp - if cwidth: - route_ports = [set_port_width(port_,cwidth) for port_ in route_ports] - route_ports[0].width = route_ports[1].width = max(route_ports[0].width, route_ports[1].width) - route_port0 = route_ports[0].copy() - route_port1 = route_ports[1].copy() - route_port0.layer = route_port1.layer = pdk.get_glayer(cglayer) - cconnection = croute << straight_route(pdk, route_port0,route_port1,glayer1=cglayer,glayer2=cglayer) - for _port in fix_ports: - port2 = cconnection.ports["route_"+fix_connection_direction] - port2.layer = _port.layer = pdk.get_glayer(cglayer) - croute << straight_route(pdk, _port, port2, glayer1=cglayer,glayer2=cglayer) - for i,port_to_add in enumerate(route_ports): - orta = get_orientation(port_to_add.orientation) - route_ports[i] = set_port_orientation(port_to_add, orta) - croute.add_ports(route_ports,prefix="con_") - return rename_ports_by_orientation(rename_ports_by_list(croute.flatten(), [("con_","con_")])) + """creates a C shaped route between two Ports. + + edge1--| + | + edge2--| + + REQUIRES: ports be parralel vertical or horizontal edges + ****NOTE: does no drc error checking (creates a dumb route) + args: + pdk = pdk to use + edge1 = first port + edge2 = second port + width1 = optional will default to edge1 width if None + width2 = optional will default to edge2 width if None + e1glayer = glayer for the parts connecting to the edge1. Default to layer of edge1 + e2glayer = glayer for the parts connecting to the edge2. Default to layer of edge2 + cglayer = glayer for the connection part (part that goes through a via) defaults to e1glayer met+1 + viaoffset = offsets the via so that it is flush with the cglayer (may be needed for drc) i.e. -| vs _| + - True offsets via towards the other via + - False offsets via away from the other via + - None means center (no offset) + ****NOTE: viaoffset pushes both vias towards each other slightly + """ + if debug: + pass + #import pdb; pdb.set_trace() + # error checking and figure out args + if round(edge1.orientation) % 90 or round(edge2.orientation) % 90: + raise ValueError("Ports must be vertical or horizontal") + if not isclose(edge1.orientation,edge2.orientation): + raise ValueError("Ports must be parralel and have same orientation") + width1 = width1 if width1 else edge1.width + width2 = width2 if width2 else edge1.width + cwidth = cwidth if cwidth else max(width1,width2) + e1glayer = e1glayer if e1glayer else pdk.layer_to_glayer(edge1.layer) + e2glayer = e2glayer if e2glayer else pdk.layer_to_glayer(edge2.layer) + eglayer_plusone = "met" + str(int(e1glayer[-1])+1) + cglayer = cglayer if cglayer else eglayer_plusone + if not "met" in e1glayer or not "met" in e2glayer or not "met" in cglayer: + raise ValueError("given layers must be metals") + viaoffset = (None, None) if viaoffset is None else viaoffset + if isinstance(viaoffset,bool): + viaoffset = (True,True) if viaoffset else (False,False) + pdk.has_required_glayers([e1glayer,e2glayer,cglayer]) + pdk.activate() + extension = snap_to_grid(extension) + # create route + croute = Component() + viastack1 = via_stack(pdk,e1glayer,cglayer,fullbottom=fullbottom,assume_bottom_via=True,fulltop=True) + viastack2 = via_stack(pdk,e2glayer,cglayer,fullbottom=fullbottom,assume_bottom_via=True,fulltop=True) + + viastack1_dims = evaluate_bbox(viastack1,True) + if round(edge1.orientation) == 0 or round(edge1.orientation) == 180: + use_arr1 = viastack1_dims[0] < cwidth or viastack1_dims[1] < width1 + if round(edge1.orientation) == 90 or round(edge1.orientation) == 270: + use_arr1 = viastack1_dims[0] < width1 or viastack1_dims[1] < cwidth + if use_arr1: + if round(edge1.orientation) == 0 or round(edge1.orientation) == 180: + viastack1 = via_array(pdk, e1glayer, cglayer, size=(cwidth,width1), fullbottom=fullbottom, no_exception=True) + if round(edge1.orientation) == 90 or round(edge1.orientation) == 270: + viastack1 = via_array(pdk, e1glayer, cglayer, size=(width1,cwidth), fullbottom=fullbottom, no_exception=True) + + + viastack2_dims = evaluate_bbox(viastack2,True) + if round(edge2.orientation) == 0 or round(edge2.orientation) == 180: + use_arr2 = viastack2_dims[0] < cwidth or viastack2_dims[1] < width2 + if round(edge2.orientation) == 90 or round(edge2.orientation) == 270: + use_arr2 = viastack2_dims[0] < width2 or viastack2_dims[1] < cwidth + if use_arr2: + if round(edge1.orientation) == 0 or round(edge1.orientation) == 180: + viastack2 = via_array(pdk, e2glayer, cglayer, size=(cwidth,width2), fullbottom=fullbottom, no_exception=True) + if round(edge1.orientation) == 90 or round(edge1.orientation) == 270: + viastack2 = via_array(pdk, e2glayer, cglayer, size=(width2,cwidth), fullbottom=fullbottom, no_exception=True) + + if e1glayer==cglayer and e2glayer==cglayer: + viastack1 = __fill_empty_viastack__macro(pdk,e1glayer) + viastack2 = __fill_empty_viastack__macro(pdk,e2glayer) + elif e1glayer == cglayer: + viastack1 = __fill_empty_viastack__macro(pdk,e1glayer,size=evaluate_bbox(viastack2)) + elif e2glayer == cglayer: + viastack2 = __fill_empty_viastack__macro(pdk,e2glayer,size=evaluate_bbox(viastack1)) + # find extension + e1_length = snap_to_grid(extension + evaluate_bbox(viastack1)[0]) + e2_length = snap_to_grid(extension + evaluate_bbox(viastack2)[0]) + xdiff = snap_to_grid(abs(edge1.center[0] - edge2.center[0])) + ydiff = snap_to_grid(abs(edge1.center[1] - edge2.center[1])) + if not isclose(edge1.center[0],edge2.center[0]): + if round(edge1.orientation) == 0:# facing east + if edge1.center[0] > edge2.center[0]: + e2_length += xdiff + else: + e1_length += xdiff + elif round(edge1.orientation) == 180:# facing west + if edge1.center[0] < edge2.center[0]: + e2_length += xdiff + else: + e1_length += xdiff + if not isclose(edge1.center[1],edge2.center[1]): + if round(edge1.orientation) == 270:# facing south + if edge1.center[1] < edge2.center[1]: + e2_length += ydiff + else: + e1_length += ydiff + elif round(edge1.orientation) == 90:#facing north + if edge1.center[1] > edge2.center[1]: + e2_length += ydiff + else: + e1_length += ydiff + # move into position + e1_extension_comp = Component("edge1 extension") + e2_extension_comp = Component("edge2 extension") + box_dims = [(e1_length, width1),(e2_length, width2)] + if round(edge1.orientation) == 90 or round(edge1.orientation) == 270: + box_dims = [(width1, e1_length),(width2, e2_length)] + rect_c1 = get_primitive_rectangle(size=box_dims[0], layer=pdk.get_glayer(e1glayer)) + rect_c2 = get_primitive_rectangle(size=box_dims[1], layer=pdk.get_glayer(e2glayer)) + rect_c1 = rename_ports_by_orientation(rename_ports_by_list(rect_c1,[("e","e_")])) + rect_c2 = rename_ports_by_orientation(rename_ports_by_list(rect_c2,[("e","e_")])) + # TODO: make sure ports match bbox + e1_extension = e1_extension_comp << rect_c1 + e2_extension = e2_extension_comp << rect_c2 + e1_extension.move(destination=edge1.center) + e2_extension.move(destination=edge2.center) + if round(edge1.orientation) == 0:# facing east + e1_extension.movey(0-evaluate_bbox(e1_extension)[1]/2) + e2_extension.movey(0-evaluate_bbox(e2_extension)[1]/2) + elif round(edge1.orientation) == 180:# facing west + e1_extension.movex(0-evaluate_bbox(e1_extension)[0]) + e2_extension.movex(0-evaluate_bbox(e2_extension)[0]) + e1_extension.movey(0-evaluate_bbox(e1_extension)[1]/2) + e2_extension.movey(0-evaluate_bbox(e2_extension)[1]/2) + elif round(edge1.orientation) == 270:# facing south + e1_extension.movex(0-evaluate_bbox(e1_extension)[0]/2) + e2_extension.movex(0-evaluate_bbox(e2_extension)[0]/2) + e1_extension.movey(0-evaluate_bbox(e1_extension)[1]) + e2_extension.movey(0-evaluate_bbox(e2_extension)[1]) + else:#facing north + e1_extension.movex(0-evaluate_bbox(e1_extension)[0]/2) + e2_extension.movex(0-evaluate_bbox(e2_extension)[0]/2) + # place viastacks + e1_extension_comp.add_ports(e1_extension.get_ports_list()) + e2_extension_comp.add_ports(e2_extension.get_ports_list()) + me1 = prec_ref_center(viastack1) + e1_extension_comp.add(me1) + me2 = prec_ref_center(viastack2) + e2_extension_comp.add(me2) + route_ports = [None,None] + if round(edge2.orientation) == 0 or round(edge2.orientation) == 180: + via_flush = snap_to_grid(abs((width1 - evaluate_bbox(viastack1)[1])/2) if viaoffset else 0) + if round(edge2.orientation) == 90 or round(edge2.orientation) == 270: + via_flush = snap_to_grid(abs((width1 - evaluate_bbox(viastack1)[0])/2) if viaoffset else 0) + via_flush1 = via_flush if viaoffset[0] else 0-via_flush + via_flush1 = 0 if viaoffset[0] is None else via_flush1 + via_flush2 = via_flush if viaoffset[1] else 0-via_flush + via_flush2 = 0 if viaoffset[1] is None else via_flush2 + if round(edge1.orientation) == 0:# facing east + me1.move(destination=e1_extension.ports["e_E"].center) + me2.move(destination=e2_extension.ports["e_E"].center) + via_flush *= 1 if me1.ymax > me2.ymax else -1 + me1.movex(0-viastack1.xmax).movey(0-via_flush1) + me2.movex(0-viastack2.xmax).movey(via_flush2) + me1, me2 = (me1, me2) if (me1.origin[1] > me2.origin[1]) else (me2, me1) + route_ports = [me1.ports["top_met_N"],me2.ports["top_met_S"]] + fix_connection_direction = "E" + fix_ports = [me1.ports["top_met_E"],me2.ports["top_met_E"]] + elif round(edge1.orientation) == 180:# facing west + me1.move(destination=e1_extension.ports["e_W"].center) + me2.move(destination=e2_extension.ports["e_W"].center) + via_flush *= 1 if me1.ymax > me2.ymax else -1 + me1.movex(viastack1.xmax).movey(0-via_flush1) + me2.movex(viastack2.xmax).movey(via_flush2) + me1, me2 = (me1, me2) if (me1.origin[1] > me2.origin[1]) else (me2, me1) + route_ports = [me1.ports["top_met_N"],me2.ports["top_met_S"]] + fix_connection_direction = "E" + fix_ports = [me1.ports["top_met_E"],me2.ports["top_met_E"]] + elif round(edge1.orientation) == 270:# facing south + me1.move(destination=e1_extension.ports["e_S"].center) + me2.move(destination=e2_extension.ports["e_S"].center) + via_flush *= 1 if me1.xmax > me2.xmax else -1 + me1.movey(viastack1.xmax).movex(0-via_flush1) + me2.movey(viastack2.xmax).movex(via_flush2) + me1, me2 = (me1, me2) if (me1.origin[0] > me2.origin[0]) else (me2, me1) + route_ports = [me1.ports["top_met_E"],me2.ports["top_met_W"]] + fix_connection_direction = "N" + fix_ports = [me1.ports["top_met_N"],me2.ports["top_met_N"]] + else:#facing north + me1.move(destination=e1_extension.ports["e_N"].center) + me2.move(destination=e2_extension.ports["e_N"].center) + via_flush *= 1 if me1.xmax > me2.xmax else -1 + me1.movey(0-viastack1.xmax).movex(0-via_flush1) + me2.movey(0-viastack2.xmax).movex(via_flush2) + me1, me2 = (me1, me2) if (me1.origin[0] > me2.origin[0]) else (me2, me1) + route_ports = [me1.ports["top_met_E"],me2.ports["top_met_W"]] + fix_connection_direction = "N" + fix_ports = [me1.ports["top_met_N"],me2.ports["top_met_N"]] + # connect extensions, add ports, return + croute << e1_extension_comp + croute << e2_extension_comp + if cwidth: + route_ports = [set_port_width(port_,cwidth) for port_ in route_ports] + route_ports[0].width = route_ports[1].width = max(route_ports[0].width, route_ports[1].width) + route_port0 = route_ports[0].copy() + route_port1 = route_ports[1].copy() + route_port0.layer = route_port1.layer = pdk.get_glayer(cglayer) + cconnection = croute << straight_route(pdk, route_port0,route_port1,glayer1=cglayer,glayer2=cglayer) + for _port in fix_ports: + port2 = cconnection.ports["route_"+fix_connection_direction] + port2.layer = _port.layer = pdk.get_glayer(cglayer) + croute << straight_route(pdk, _port, port2, glayer1=cglayer,glayer2=cglayer) + for i,port_to_add in enumerate(route_ports): + orta = get_orientation(port_to_add.orientation) + route_ports[i] = set_port_orientation(port_to_add, orta) + croute.add_ports(route_ports,prefix="con_") + return rename_ports_by_orientation(rename_ports_by_list(croute.flatten(), [("con_","con_")])) From 48b41b6f30d3302b18b0588eda4e2f9a2cddaf3c Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:09:59 +0530 Subject: [PATCH 10/10] moved add ports for substrate tap inside the if block --- .../glayout/flow/placement/four_transistor_interdigitized.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/placement/four_transistor_interdigitized.py b/openfasoc/generators/glayout/glayout/flow/placement/four_transistor_interdigitized.py index 7df38d6e9..e74737ef7 100644 --- a/openfasoc/generators/glayout/glayout/flow/placement/four_transistor_interdigitized.py +++ b/openfasoc/generators/glayout/glayout/flow/placement/four_transistor_interdigitized.py @@ -39,8 +39,8 @@ def generic_4T_interdigitzed( 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(substrate_tap_ref.get_ports_list(),prefix="substratetap_") toplvl.add_ports(toprow.get_ports_list(),prefix="top_") toplvl.add_ports(bottomrow.get_ports_list(),prefix="bottom_") # flag for smart route