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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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 90826ea3538ebe0201e8dec4cde9f856fec71cda Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:12:42 +0530 Subject: [PATCH 09/24] Create README.md --- .../glayout/flow/blocks/composite/FVF based OTA/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md new file mode 100644 index 000000000..660951111 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md @@ -0,0 +1 @@ +FVF based super class AB OTA From 57f525dc38cf7afe509df3516d7eeebceefc420a Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:13:44 +0530 Subject: [PATCH 10/24] Delete openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA directory --- .../glayout/flow/blocks/composite/FVF based OTA/README.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md deleted file mode 100644 index 660951111..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/FVF based OTA/README.md +++ /dev/null @@ -1 +0,0 @@ -FVF based super class AB OTA From cfc5dbf878332571b94622db0c50b197d271be50 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:14:52 +0530 Subject: [PATCH 11/24] Create README.md --- .../glayout/flow/blocks/composite/fvf_based_ota/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md new file mode 100644 index 000000000..660951111 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md @@ -0,0 +1 @@ +FVF based super class AB OTA From e29620a0c1b0802ad9be0988afd5fd8086863349 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:22:00 +0530 Subject: [PATCH 12/24] Files for FVF based OTA --- .../fvf_based_ota/extract.bash.template | 56 ++ .../blocks/composite/fvf_based_ota/n_block.py | 155 ++++ .../blocks/composite/fvf_based_ota/ota.py | 292 ++++++ .../composite/fvf_based_ota/ota_perf_eval.sp | 124 +++ .../blocks/composite/fvf_based_ota/p_block.py | 103 +++ .../sky130A/cryo_models/nshort.spice | 420 +++++++++ .../sky130A/cryo_models/nshortlvth.spice | 420 +++++++++ .../sky130A/cryo_models/pmos.spice | 419 +++++++++ .../fvf_based_ota/sky130A/sky130A.magicrc | 86 ++ .../fvf_based_ota/sky130A/sky130A_setup.tcl | 419 +++++++++ .../fvf_based_ota/sky130_ota_tapeout.py | 848 ++++++++++++++++++ 11 files changed, 3342 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/extract.bash.template create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota_perf_eval.sp create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshort.spice create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshortlvth.spice create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/pmos.spice create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A.magicrc create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A_setup.tcl create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/extract.bash.template b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/extract.bash.template new file mode 100644 index 000000000..1a2bcb111 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/extract.bash.template @@ -0,0 +1,56 @@ +#!/bin/bash + +# Actual +export PDK_ROOT=@@PDK_ROOT + +# args: +# first arg = gds file to read +# second arg = name of top cell in gds file to read +# third arg (optional) = noparasitics (basically an LVS extraction) + +paropt="@@@PAROPT" + +if [ "$paropt" = "noparasitics" ]; then + +magic -rcfile ./sky130A/sky130A.magicrc -noconsole -dnull << EOF +gds read $1 +flatten $2 +load $2 +select top cell +extract do local +extract all +ext2sim labels on +ext2sim +ext2spice lvs +ext2spice cthresh 0 +ext2spice -o $2_pex.spice +exit +EOF + +else + +magic -rcfile ./sky130A/sky130A.magicrc -noconsole -dnull << EOF +gds read $1 +flatten $2 +load $2 +select top cell +extract do local +extract all +ext2sim labels on +ext2sim +extresist tolerance 10 +extresist +ext2spice lvs +ext2spice cthresh 0 +ext2spice extresist on +ext2spice -o $2_pex.spice +exit +EOF + +fi + +rm -f $2.nodes +rm -f $2.ext +rm -f $2.res.ext +rm -f $2.sim + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py new file mode 100644 index 000000000..a8d0556d5 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py @@ -0,0 +1,155 @@ +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from gdsfactory import Component +from gdsfactory.cell import cell +from gdsfactory.component_reference import ComponentReference + +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_ref_center, prec_center, align_comp_to_port +from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid +from gdsfactory.components import text_freetype, rectangle + +from glayout.flow.spice.netlist import Netlist +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 fvf import fvf_netlist, flipped_voltage_follower +from cm import current_mirror, current_mirror_netlist +from glayout.flow.primitives.via_gen import via_stack, via_array +from glayout.flow.primitives.fet import nmos, pmos, multiplier +from cm2 import low_voltage_cmirror, low_voltage_cmirr_netlist + +def n_block_netlist(fet_inA_ref: ComponentReference, fet_inB_ref: ComponentReference, fvf_1_ref: ComponentReference, fvf_2_ref: ComponentReference, cmirror: Component, global_c_bias: Component) -> Netlist: + + netlist = Netlist(circuit_name='N_block', nodes=['IBIAS1', 'IBIAS2', 'GND', 'ILCM1', 'ILCM2', 'IFVF1','IFVF2', 'INP', 'INM', 'Min1_D', 'Min2_D', 'OUT_N_1', 'OUT_N_2']) + netlist.connect_netlist(global_c_bias.info['netlist'], [('IBIAS1','IBIAS1'),('GND','GND'),('IBIAS2','IBIAS2'),('IOUT1','ILCM1'),('IOUT2','ILCM2')]) + netlist.connect_netlist(cmirror.info['netlist'], [('VREF','OUT_N_1'),('VCOPY','OUT_N_2'),('VSS', 'GND'),('VB','GND')]) + netlist.connect_netlist(fet_inA_ref.info['netlist'], [('D', 'Min1_D'),('G','INM'),('B','GND')]) + netlist.connect_netlist(fet_inB_ref.info['netlist'], [('D', 'Min2_D'),('G','INP'),('B','GND')]) + netlist.connect_netlist(fvf_1_ref.info['netlist'], [('VIN','INM'),('VOUT', 'INP'),('VBULK','GND'),('Ib','IFVF1')]) + netlist.connect_netlist(fvf_2_ref.info['netlist'], [('VIN','INP'),('VOUT', 'INM'),('VBULK','GND'),('Ib','IFVF2')]) + + return netlist + + +@cell +def n_block( + pdk: MappedPDK, + input_pair_params: tuple[float,float]=(4,2), + fvf_shunt_params: tuple[float,float]=(2.75,1), + current_mirror_params: tuple[float,float]=(2.25,1), + ratio: int=1, + global_current_bias_params: tuple[float,float,float]=(8.3,1.42,2) + ) -> Component: + """ + creates a super class AB OTA using flipped voltage follower at biasing stage and local common mode feedback to give dynamic current and gain boost much less dependent on biasing current + NB:- This block can only support device dimensions which achieve our design goal. In future steps will be taken to make it more flexible. + pdk: pdk to use + input_pair_params: differential input pair(N-type) - (width,length), input nmoses of the fvf get the same dimensions + fvf_shunt_params: feedback fet of fvf - (width,length) + current_mirror_params: output stage N-type currrent mirrors - (width, length) + global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - ((W,W'),L) + """ + # Create a top level component + top_level = Component("n_block") + + #input differential pair + fet_in = nmos(pdk, width=input_pair_params[0], length=input_pair_params[1], fingers=1, with_dnwell=False, with_tie=True, with_substrate_tap=False, sd_rmult=3) + fet_inA_ref = prec_ref_center(fet_in) + fet_inB_ref = prec_ref_center(fet_in) + fet_inA_ref.movex(-evaluate_bbox(fet_in)[0]/2 - pdk.util_max_metal_seperation()) + fet_inB_ref.movex(evaluate_bbox(fet_in)[0]/2 + pdk.util_max_metal_seperation()) + + top_level.add(fet_inA_ref) + top_level.add(fet_inB_ref) + + #creating VinP and VinM ports + viam2m3 = via_stack(pdk, "met2", "met3", centered=True) + viam3m4 = via_stack(pdk, "met3", "met4", centered=True) + gate_inA_via = top_level << viam3m4 + gate_inB_via = top_level << viam3m4 + source_inA_via = top_level << viam2m3 + source_inB_via = top_level << viam2m3 + gate_inA_via.move(fet_inA_ref.ports["multiplier_0_gate_W"].center).movex(-evaluate_bbox(fet_in)[0]/4).movey(-evaluate_bbox(fet_in)[1]/2) + gate_inB_via.move(fet_inB_ref.ports["multiplier_0_gate_E"].center).movex(evaluate_bbox(fet_in)[0]/4).movey(-evaluate_bbox(fet_in)[1]/2) + + source_inA_via.move(fet_inA_ref.ports["multiplier_0_source_W"].center).movex(-evaluate_bbox(fet_in)[0]/4) + source_inB_via.move(fet_inB_ref.ports["multiplier_0_source_E"].center).movex(evaluate_bbox(fet_in)[0]/4) + + + top_level << L_route(pdk, fet_inA_ref.ports["multiplier_0_gate_W"], gate_inA_via.ports["bottom_met_N"], hglayer="met2", vglayer="met3") + top_level << L_route(pdk, fet_inB_ref.ports["multiplier_0_gate_E"], gate_inB_via.ports["bottom_met_N"], hglayer="met2", vglayer="met3") + top_level << straight_route(pdk, fet_inA_ref.ports["multiplier_0_source_W"], source_inA_via.ports["bottom_met_E"], width=0.29*2) + top_level << straight_route(pdk, fet_inB_ref.ports["multiplier_0_source_E"], source_inB_via.ports["bottom_met_W"], width=0.29*2) + + top_level.add_ports(fet_inA_ref.get_ports_list(), prefix="Min_1_") + top_level.add_ports(fet_inB_ref.get_ports_list(), prefix="Min_2_") + top_level.add_ports(gate_inA_via.get_ports_list(), prefix="gate_inA_") + top_level.add_ports(gate_inB_via.get_ports_list(), prefix="gate_inB_") + + #FVF cells + fvf = flipped_voltage_follower(pdk, width=(input_pair_params[0],fvf_shunt_params[0]), length=(input_pair_params[1],fvf_shunt_params[1]), fingers=(1,1), sd_rmult=3, with_dnwell=False) + fvf_1_ref = prec_ref_center(fvf) + fvf_2_ref = prec_ref_center(fvf) + fvf_1_ref.movex(fet_inB_ref.xmax + evaluate_bbox(fvf)[0]/2 + pdk.util_max_metal_seperation()) + fvf_2_ref.movex(fet_inB_ref.xmax + evaluate_bbox(fvf)[0]/2 + pdk.util_max_metal_seperation()) + fvf_1_ref = rename_ports_by_orientation(fvf_1_ref.mirror((0,-100),(0,100))) + top_level.add(fvf_1_ref) + top_level.add(fvf_2_ref) + + #creating ports for conncetion + gate_fvf_1A_via = top_level << viam2m3 + gate_fvf_2A_via = top_level << viam2m3 + gate_fvf_1A_via.move(fvf_1_ref.ports["A_multiplier_0_gate_S"].center).movex(-evaluate_bbox(fet_in)[0]/4).movey(-evaluate_bbox(fet_in)[1]/1.5) + gate_fvf_2A_via.move(fvf_2_ref.ports["A_multiplier_0_gate_S"].center).movex(evaluate_bbox(fet_in)[0]/4).movey(-evaluate_bbox(fet_in)[1]/1.5) + + + top_level << L_route(pdk, fvf_1_ref.ports["A_multiplier_0_gate_E"], gate_fvf_1A_via.ports["top_met_N"], hglayer="met2", vglayer="met3") + top_level << L_route(pdk, fvf_2_ref.ports["A_multiplier_0_gate_E"], gate_fvf_2A_via.ports["top_met_N"], hglayer="met2", vglayer="met3") + + + #connecting input pair with fvfs + top_level << L_route(pdk, gate_inA_via.ports["bottom_met_S"], gate_fvf_1A_via.ports["top_met_E"], hglayer="met2", vglayer="met3") + top_level << L_route(pdk, gate_inB_via.ports["bottom_met_S"], gate_fvf_2A_via.ports["top_met_W"], hglayer="met2", vglayer="met3") + top_level << c_route(pdk, source_inA_via.ports["top_met_N"], fvf_2_ref.ports["A_source_top_met_N"], extension=0.8*evaluate_bbox(fet_in)[1], width1=0.4, width2=0.4, cwidth=0.5, e1glayer="met3", e2glayer="met3", cglayer="met2") + top_level << c_route(pdk, source_inB_via.ports["top_met_N"], fvf_1_ref.ports["A_source_top_met_N"], extension=1.1*evaluate_bbox(fet_in)[1], width1=0.4, width2=0.4, cwidth=0.5, e1glayer="met3", e2glayer="met3", cglayer="met2") + + top_level.add_ports(fvf_1_ref.get_ports_list(), prefix="fvf_1_") + top_level.add_ports(fvf_2_ref.get_ports_list(), prefix="fvf_2_") + + cmirror = current_mirror(pdk, numcols=2, with_substrate_tap=False, width=current_mirror_params[0], length=current_mirror_params[1], fingers=ratio, sd_rmult=3) + cmirr_ref = prec_ref_center(cmirror) + cmirr_ref.movey(fvf_1_ref.ymin - (evaluate_bbox(cmirror)[1] + evaluate_bbox(fvf)[1])/2) + top_level.add(cmirr_ref) + + top_level << straight_route(pdk, cmirr_ref.ports["fet_A_source_W"], cmirr_ref.ports["welltie_W_top_met_W"], glayer1='met1', width=0.6) + top_level << straight_route(pdk, cmirr_ref.ports["fet_A_0_dummy_L_gsdcon_top_met_W"],cmirr_ref.ports["welltie_W_top_met_W"],glayer1="met1", width=0.5) + top_level << straight_route(pdk, cmirr_ref.ports["fet_B_1_dummy_R_gsdcon_top_met_E"],cmirr_ref.ports["welltie_E_top_met_E"],glayer1="met1", width=0.5) + + + top_level.add_ports(cmirr_ref.get_ports_list(), prefix="op_cmirr_") + + global_c_bias = low_voltage_cmirror(pdk, width=(global_current_bias_params[0]/2,global_current_bias_params[1]), length=global_current_bias_params[2], fingers=(2,1)) + global_c_bias_ref = prec_ref_center(global_c_bias) + global_c_bias_ref.movey(cmirr_ref.ymin - evaluate_bbox(global_c_bias)[1]/2 - 8*pdk.util_max_metal_seperation()) + top_level.add(global_c_bias_ref) + top_level.add_ports(global_c_bias_ref.get_ports_list(), prefix="cbias_") + + + fet_1 = nmos(pdk, width=input_pair_params[0], length=input_pair_params[1], fingers=1, with_dnwell=False, with_tie=True, with_substrate_tap=False, sd_rmult=3) + fet_2 = nmos(pdk, width=input_pair_params[0], length=input_pair_params[1], fingers=1, with_dnwell=False, with_tie=True, with_substrate_tap=False, sd_rmult=3) + fvf_1 = flipped_voltage_follower(pdk, width=(input_pair_params[0],fvf_shunt_params[0]), length=(input_pair_params[1],fvf_shunt_params[1]), fingers=(1,1), sd_rmult=3, with_dnwell=False) + fvf_2 = flipped_voltage_follower(pdk, width=(input_pair_params[0],fvf_shunt_params[0]), length=(input_pair_params[1],fvf_shunt_params[1]), fingers=(1,1), sd_rmult=3, with_dnwell=False) + + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = n_block_netlist(fet_inA_ref, fet_inB_ref, fvf_1_ref, fvf_2_ref, cmirror, global_c_bias) + #print(component.info['netlist'].generate_netlist(only_subcircuits=True)) + + return component + +#nb = n_block(sky130_mapped_pdk) +#nb.show() +#nb.name = "n_block" +#magic_drc_result = sky130_mapped_pdk.drc_magic(nb, nb.name) + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py new file mode 100644 index 000000000..ee6d090c8 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py @@ -0,0 +1,292 @@ +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from gdsfactory import Component +from gdsfactory.cell import cell +from gdsfactory.component_reference import ComponentReference + +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_ref_center, prec_center, align_comp_to_port +from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid +from gdsfactory.components import text_freetype, rectangle +from glayout.flow.spice.netlist import Netlist + + +from glayout.flow.routing.straight_route import straight_route +from c_route import c_route +from glayout.flow.routing.L_route import L_route +from fvf import fvf_netlist, flipped_voltage_follower +from cm import current_mirror, current_mirror_netlist +from glayout.flow.primitives.via_gen import via_stack, via_array +from glayout.flow.primitives.fet import nmos, pmos, multiplier +from transmission_gate import transmission_gate,tg_netlist +from p_block import p_block,p_block_netlist +from n_block import n_block,n_block_netlist +#from lvt_cmirror import low_voltage_cmirror + +def super_class_AB_OTA_netlist(local_c_bias_1_ref: ComponentReference, local_c_bias_2_ref: ComponentReference, res_1_ref: ComponentReference, res_2_ref: ComponentReference, nb: Component, pblock: Component) -> Netlist: + + netlist = Netlist(circuit_name='OTA', nodes=['AVDD', 'INP', 'INM', 'VOUT', 'NBC_10U', 'NB_10U', 'AVSS']) + pblock_ref = netlist.connect_netlist(pblock.info['netlist'], [('VDD','AVDD'),('MB_2_D','VOUT')]) + nblock_ref = netlist.connect_netlist(nb.info['netlist'], [('IBIAS1','NBC_10U'),('IBIAS2','NB_10U'),('GND', 'AVSS'),('INP','INP'),('INM','INM'),('OUT_N_2','VOUT')]) + cmirr_1_ref = netlist.connect_netlist(local_c_bias_1_ref.info['netlist'], [('VSS','AVDD'),('VB','AVDD')]) + cmirr_2_ref = netlist.connect_netlist(local_c_bias_2_ref.info['netlist'], [('VSS', 'AVDD'),('VB','AVDD')]) + res_1_ref = netlist.connect_netlist(res_1_ref.info['netlist'], [('VSS','AVSS'),('VCC','AVDD')]) + res_2_ref = netlist.connect_netlist(res_2_ref.info['netlist'], [('VSS','AVSS'),('VCC','AVDD')]) + + netlist.connect_subnets( + pblock_ref, + nblock_ref, + [('MA_1_D', 'Min1_D'),('MA_2_D','Min2_D'),('MB_1_D','OUT_N_1')] + ) + netlist.connect_subnets( + pblock_ref, + res_1_ref, + [('MA_1_D', 'VIN'),('MA_G','VOUT')] + ) + netlist.connect_subnets( + pblock_ref, + res_2_ref, + [('MA_2_D', 'VIN'),('MA_G','VOUT')] + ) + netlist.connect_subnets( + nblock_ref, + res_1_ref, + [('Min1_D', 'VIN')] + ) + netlist.connect_subnets( + nblock_ref, + res_2_ref, + [('Min2_D', 'VIN')] + ) + netlist.connect_subnets( + nblock_ref, + cmirr_1_ref, + [('ILCM1', 'VREF'),('IFVF1','VCOPY')] + ) + netlist.connect_subnets( + nblock_ref, + cmirr_2_ref, + [('ILCM2', 'VREF'),('IFVF2','VCOPY')] + ) + + return netlist + + +@cell +def super_class_AB_OTA( + pdk: MappedPDK, + input_pair_params: tuple[float,float]=(4,2), + fvf_shunt_params: tuple[float,float]=(2.75,1), + local_current_bias_params: tuple[float,float]=(3.76,3.0), + diff_pair_load_params: tuple[float,float]=(9,1), + ratio: int=1, + current_mirror_params: tuple[float,float]=(2.25,1), + resistor_params: tuple[float,float,float,float]=(0.5,3,4,4), + global_current_bias_params: tuple[float,float,float]=(8.3,1.42,2) + ) -> Component: + """ + creates a super class AB OTA using flipped voltage follower at biasing stage and local common mode feedback to give dynamic current and gain boost much less dependent on biasing current + NB:- This block can only support device dimensions which achieve our design goal. In future steps will be taken to make it more flexible. + pdk: pdk to use + input_pair_params: differential input pair(N-type) - (width,length), input nmoses of the fvf get the same dimensions + fvf_shunt_params: feedback fet of fvf - (width,length) + local_current_bias_params: local currrent mirror which directly biases each fvf - (width,length) + diff_pair_load_params: creates a p_block consisting of both input stage pmos loads and output stage pmoses - (width,length) + ratio: current mirroring ratio from input stage to output stage, currently suports only identical mirroring + current_mirror_params: output stage N-type currrent mirrors - (width, length) + resistor_params: passgates are used as resistors for LCMFB - ((width of nmos, width of pmos),(length of nmos, length of pmos)) + global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - ((W,W'),L) + """ + # Create a top level component + top_level = Component("Super_class_AB_OTA") + + #input differential pair + nb = n_block(pdk, input_pair_params=input_pair_params, fvf_shunt_params=fvf_shunt_params, ratio=ratio, current_mirror_params=current_mirror_params, global_current_bias_params=global_current_bias_params) + n_block_ref = prec_ref_center(nb) + top_level.add(n_block_ref) + top_level.add_ports(n_block_ref.get_ports_list()) + + #local current mirrors + local_c_bias = current_mirror(pdk, numcols=2, device='pfet', width=local_current_bias_params[0]/2, length=local_current_bias_params[1], fingers=1) + local_c_bias_2_ref = prec_ref_center(local_c_bias) + local_c_bias_1_ref = prec_ref_center(local_c_bias) + local_c_bias_1_ref.movex(n_block_ref.xmax + evaluate_bbox(local_c_bias)[0]/2 + 10).movey(n_block_ref.ymax+evaluate_bbox(local_c_bias)[1]/2 + 2) + local_c_bias_2_ref.movex(n_block_ref.xmax + evaluate_bbox(local_c_bias)[0]/2 + 10).movey(n_block_ref.ymax+evaluate_bbox(local_c_bias)[1]/2 + 2) + local_c_bias_1_ref = rename_ports_by_orientation(local_c_bias_1_ref.mirror((0,100),(0,-100))) + + top_level.add(local_c_bias_1_ref) + top_level.add(local_c_bias_2_ref) + + #adding lvt layer + + + + #biasing fvfs + top_level << c_route(pdk, n_block_ref.ports["fvf_1_B_gate_bottom_met_E"], local_c_bias_1_ref.ports["fet_B_drain_E"], extension=5,width1=0.29, width2=0.29, cwidth=0.29, cglayer="met3") + top_level << c_route(pdk, n_block_ref.ports["fvf_2_B_gate_bottom_met_E"], local_c_bias_2_ref.ports["fet_B_drain_E"], extension=5,width1=0.29, width2=0.29, cwidth=0.29, cglayer="met3") + + top_level << straight_route(pdk, local_c_bias_1_ref.ports["fet_A_source_W"], local_c_bias_1_ref.ports["welltie_W_top_met_W"],glayer1='met1', width=0.22) + top_level << straight_route(pdk, local_c_bias_1_ref.ports["fet_A_0_dummy_L_gsdcon_top_met_W"], local_c_bias_1_ref.ports["welltie_W_top_met_W"],glayer1="met1") + top_level << straight_route(pdk, local_c_bias_1_ref.ports["fet_B_1_dummy_R_gsdcon_top_met_E"], local_c_bias_1_ref.ports["welltie_E_top_met_E"],glayer1="met1") + + top_level << straight_route(pdk, local_c_bias_2_ref.ports["fet_A_source_W"], local_c_bias_2_ref.ports["welltie_W_top_met_W"], glayer1='met1', width=0.22) + top_level << straight_route(pdk, local_c_bias_2_ref.ports["fet_A_0_dummy_L_gsdcon_top_met_W"], local_c_bias_2_ref.ports["welltie_W_top_met_W"],glayer1="met1", width=0.2) + top_level << straight_route(pdk, local_c_bias_2_ref.ports["fet_B_1_dummy_R_gsdcon_top_met_E"], local_c_bias_2_ref.ports["welltie_E_top_met_E"],glayer1="met1", width=0.2) + + top_level << c_route(pdk, local_c_bias_1_ref.ports["fet_A_drain_E"], n_block_ref.ports["cbias_M_3_A_multiplier_0_drain_W"], viaoffset=False) + top_level << c_route(pdk, local_c_bias_2_ref.ports["fet_A_drain_E"], n_block_ref.ports["cbias_M_4_A_multiplier_0_drain_E"], viaoffset=False) + + + top_level.add_ports(local_c_bias_1_ref.get_ports_list(), prefix="cmirr_1_") + top_level.add_ports(local_c_bias_2_ref.get_ports_list(), prefix="cmirr_2_") + + #LCMFB resistors + resistor = transmission_gate(pdk, width=(resistor_params[0],resistor_params[1]), length=(resistor_params[2],resistor_params[3]), sd_rmult=3) + res_1_ref = prec_ref_center(resistor) + res_2_ref = prec_ref_center(resistor) + res_1_ref.movey(n_block_ref.ymax + evaluate_bbox(resistor)[1]/2 + 1).movex(-evaluate_bbox(resistor)[0]/2 - 5) + res_2_ref.movey(n_block_ref.ymax + evaluate_bbox(resistor)[1]/2 + 1).movex(-evaluate_bbox(resistor)[0]/2 - 5) + res_2_ref = rename_ports_by_orientation(res_2_ref.mirror((0,-100),(0,100))) + + top_level.add(res_1_ref) + top_level.add(res_2_ref) + + top_level << c_route(pdk, n_block_ref.ports["Min_1_multiplier_0_drain_E"], res_1_ref.ports["N_multiplier_0_source_E"], cwidth=0.6) + top_level << c_route(pdk, n_block_ref.ports["Min_2_multiplier_0_drain_W"], res_2_ref.ports["N_multiplier_0_source_E"], cwidth=0.6) + + + top_level.add_ports(res_1_ref.get_ports_list(), prefix="res_1_") + top_level.add_ports(res_2_ref.get_ports_list(), prefix="res_2_") + + + #output stage N-type current mirrors + + + #adding the p_block + pblock = p_block(pdk, width=diff_pair_load_params[0]/2, length=diff_pair_load_params[1], fingers=1, ratio=ratio) + p_block_ref = prec_ref_center(pblock) + p_block_ref.movey(res_1_ref.ymax + evaluate_bbox(pblock)[1]/2 + 8) + top_level.add(p_block_ref) + + top_level << c_route(pdk, res_1_ref.ports["P_multiplier_0_drain_E"], p_block_ref.ports["bottom_A_0_gate_E"], e1glayer='met2', width2=0.29*2) + top_level << c_route(pdk, res_2_ref.ports["P_multiplier_0_drain_E"], p_block_ref.ports["bottom_B_1_gate_W"], e1glayer='met2', width2=0.29*2) + + top_level << c_route(pdk, p_block_ref.ports["top_A_0_drain_W"], n_block_ref.ports["op_cmirr_fet_A_drain_W"], extension=-local_c_bias_1_ref.xmax-8-2*ratio*diff_pair_load_params[1] , cwidth=3, viaoffset=(True,True)) + top_level << c_route(pdk, p_block_ref.ports["top_B_1_drain_E"], n_block_ref.ports["op_cmirr_fet_B_drain_E"], extension=local_c_bias_2_ref.xmin-8-2*ratio*diff_pair_load_params[1] , cwidth=3, viaoffset=(True,True)) + + top_level << c_route(pdk, p_block_ref.ports["bottom_A_0_drain_W"], res_1_ref.ports["P_multiplier_0_source_W"], cwidth=0.9, width2=0.29*3) + top_level << c_route(pdk, p_block_ref.ports["bottom_B_1_drain_E"], res_2_ref.ports["P_multiplier_0_source_W"], cwidth=0.9, width2=0.29*3) + + top_level.add_ports(p_block_ref.get_ports_list(), prefix="pblock_") + """ + #adding lvt layer + lvt_layer=(125,44) + dimensions = (evaluate_bbox(top_level)[0], (p_block_ref.ymax - res_1_ref.ymin)) + + lvt_rectangle = rectangle(layer=lvt_layer, size=(dimensions[0], dimensions[1])) + lvt_rectangle_ref = prec_ref_center(lvt_rectangle) + lvt_rectangle_ref.movey(n_block_ref.ymax + dimensions[1]/2) + top_level.add(lvt_rectangle_ref) + + #adding a pwell + pwell_rectangle = rectangle(layer=(pdk.get_glayer("pwell")), size=(85,30.25)) + pwell_rectangle_ref = prec_ref_center(pwell_rectangle,(0,-8.825)) + top_level.add(pwell_rectangle_ref) + """ + #adding output pin + viam2m3 = via_stack(pdk, "met2", "met3", centered=True, fulltop=True) + viam3m4 = via_stack(pdk, "met3", "met4", centered=True, fulltop=True) + op_int_via = top_level << viam2m3 + op_via = prec_ref_center(viam3m4) + op_via.movex(min(n_block_ref.xmin,local_c_bias_1_ref.xmax)-8).movey(n_block_ref.ymin) + top_level.add(op_via) + op_int_via.move(n_block_ref.ports["op_cmirr_fet_B_drain_W"].center).movex(-1.5) + top_level << straight_route(pdk, op_int_via.ports["bottom_met_E"], n_block_ref.ports["op_cmirr_fet_B_drain_W"], glayer1='met2', width=0.58) + top_level << c_route(pdk, op_int_via.ports["top_met_N"], op_via.ports["bottom_met_N"], e1glayer='met3', e2glayer='met3', cglayer='met4', width1=0.6, width2=2, cwidth=2, extension=1.5, fullbottom=True) + top_level.add_ports(op_via.get_ports_list(), prefix="DIFFOUT_") + + + #adding IBIAS pins + IBIAS1_via = prec_ref_center(viam3m4) + IBIAS1_via.move(n_block_ref.ports["cbias_M_2_A_drain_bottom_met_W"].center).movex(-4).movey(-evaluate_bbox(nb)[1]/2) + top_level.add(IBIAS1_via) + top_level << L_route(pdk, n_block_ref.ports["cbias_M_1_A_drain_bottom_met_W"], IBIAS1_via.ports["bottom_met_N"], hwidth=2, vwidth=0.8) + top_level.add_ports(IBIAS1_via.get_ports_list(), prefix="IBIAS1_") + + + IBIAS2_via = prec_ref_center(viam3m4) + IBIAS2_via.movex(n_block_ref.xmax+5).movey(n_block_ref.ymin) + top_level.add(IBIAS2_via) + top_level << c_route(pdk, n_block_ref.ports["cbias_M_2_A_drain_top_met_N"], IBIAS2_via.ports["bottom_met_N"], e1glayer='met3', e2glayer='met3', cglayer='met4', width1=0.4, width2=1, cwidth=0.6, extension=1.5, fullbottom=True) + top_level.add_ports(IBIAS2_via.get_ports_list(), prefix="IBIAS2_") + + #adding differential input pins + MINUS_via = top_level << viam3m4 + MINUS_via.move(n_block_ref.ports["gate_inA_top_met_W"].center).movex(local_c_bias_1_ref.xmin+3*input_pair_params[1]) + top_level << straight_route(pdk, n_block_ref.ports["gate_inA_top_met_W"], MINUS_via.ports["top_met_E"], width=0.6, glayer1='met4') + top_level.add_ports(MINUS_via.get_ports_list(), prefix="MINUS_") + + PLUS_via = top_level << viam3m4 + PLUS_via.move(n_block_ref.ports["gate_inB_top_met_E"].center).movex(local_c_bias_2_ref.xmax-3*input_pair_params[1]) + top_level << straight_route(pdk, n_block_ref.ports["gate_inB_top_met_E"], PLUS_via.ports["top_met_W"], width=0.6, glayer1='met4') + top_level.add_ports(PLUS_via.get_ports_list(), prefix="PLUS_") + + #adding VCC pin + arrm2m3_1 = via_array( + pdk, + "met2", + "met3", + size=(6,0.6), + fullbottom=True + ) + VCC_via = prec_ref_center(arrm2m3_1) + VCC_via.movey(p_block_ref.ymax+5) + top_level.add(VCC_via) + top_level << straight_route(pdk, p_block_ref.ports["top_welltie_N_top_met_N"], VCC_via.ports["bottom_lay_S"], glayer1='met2', width=6, fullbottom=True) + top_level.add_ports(VCC_via.get_ports_list(), prefix="VCC_") + + arrm2m3_2 = via_array( + pdk, + "met2", + "met3", + num_vias=(2,2), + fullbottom=True + ) + VCC_int_via = prec_ref_center(arrm2m3_2) + VCC_int_via.movey(p_block_ref.ymin-4) + top_level.add(VCC_int_via) + top_level << straight_route(pdk, p_block_ref.ports["bottom_welltie_S_top_met_S"], VCC_int_via.ports["top_met_N"], glayer1='met3', width=0.5) + top_level << L_route(pdk, VCC_int_via.ports["bottom_lay_W"], res_1_ref.ports["P_tie_S_top_met_S"], hglayer='met2', vglayer='met2', hwidth=2, vwidth=2, fullbottom=True) + top_level << L_route(pdk, VCC_int_via.ports["bottom_lay_E"], res_2_ref.ports["P_tie_S_top_met_S"], hglayer='met2', vglayer='met2', hwidth=2, vwidth=2, fullbottom=True) + top_level << L_route(pdk, VCC_int_via.ports["bottom_lay_W"], local_c_bias_1_ref.ports["welltie_N_top_met_N"], hglayer='met2', vglayer='met2', hwidth=2, vwidth=2, fullbottom=True) + top_level << L_route(pdk, VCC_int_via.ports["bottom_lay_E"], local_c_bias_2_ref.ports["welltie_N_top_met_N"], hglayer='met2', vglayer='met2', hwidth=2, vwidth=2, fullbottom=True) + top_level << L_route(pdk, res_1_ref.ports["N_multiplier_0_gate_E"], VCC_int_via.ports["top_met_S"], hglayer='met2', vglayer='met3', hwidth=0.5, vwidth=0.3, fullbottom=True) + top_level << L_route(pdk, res_2_ref.ports["N_multiplier_0_gate_W"], VCC_int_via.ports["top_met_S"], hglayer='met2', vglayer='met3', hwidth=0.5, vwidth=0.3, fullbottom=True) + + #adding GND pin + top_level << L_route(pdk, res_1_ref.ports["N_tie_W_top_met_W"], n_block_ref.ports["fvf_1_B_tie_N_top_met_N"], hglayer='met1', vglayer='met2', vwidth=4, hwidth=0.8, fullbottom=True) + top_level << L_route(pdk, res_2_ref.ports["N_tie_W_top_met_W"], n_block_ref.ports["fvf_2_B_tie_N_top_met_N"], hglayer='met1', vglayer='met2', vwidth=4, hwidth=0.8, fullbottom=True) + top_level << L_route(pdk, res_1_ref.ports["P_multiplier_0_gate_W"], n_block_ref.ports["fvf_1_B_tie_N_top_met_N"], hglayer='met2', vglayer='met2', vwidth=0.3, hwidth=1.2, fullbottom=True) + top_level << L_route(pdk, res_2_ref.ports["P_multiplier_0_gate_E"], n_block_ref.ports["fvf_2_B_tie_N_top_met_N"], hglayer='met2', vglayer='met2', vwidth=0.3, hwidth=1.2, fullbottom=True) + + top_level << L_route(pdk, n_block_ref.ports["op_cmirr_welltie_N_top_met_N"], n_block_ref.ports["Min_1_tie_E_top_met_E"], hwidth=0.6, vwidth=1, hglayer='met1') + top_level << L_route(pdk, n_block_ref.ports["op_cmirr_welltie_N_top_met_N"], n_block_ref.ports["Min_2_tie_W_top_met_W"], hwidth=0.6, vwidth=1, hglayer='met1') + + GND_via = top_level << arrm2m3_2 + GND_via.move(n_block_ref.ports["op_cmirr_welltie_S_top_met_S"].center).movey(-2).movex(local_c_bias_2_ref.xmax) + top_level << L_route(pdk, n_block_ref.ports["op_cmirr_welltie_S_top_met_S"], GND_via.ports["bottom_lay_W"], vglayer='met2', hglayer='met2', vwidth=1.5, hwidth=1.5) + top_level.add_ports(GND_via.get_ports_list(), prefix="VSS_") + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = super_class_AB_OTA_netlist(local_c_bias_1_ref, local_c_bias_2_ref, res_1_ref, res_2_ref, nb, pblock) + print(component.info['netlist'].generate_netlist()) + + return component +""" +OTA = sky130_add_ota_labels(super_class_AB_OTA(sky130_mapped_pdk)) +OTA.show() +OTA.name = "ota" +OTA.write_gds("./ota.gds") +magic_drc_result = sky130_mapped_pdk.drc_magic(OTA, OTA.name) +netgen_lvs_result = sky130_mapped_pdk.lvs_netgen(OTA, design_name="ota", netlist="ota.spice") +""" diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota_perf_eval.sp b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota_perf_eval.sp new file mode 100644 index 000000000..359bcb045 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota_perf_eval.sp @@ -0,0 +1,124 @@ +* ota_perf_eval.sp +** OpenFASOC Team, Ryan Wans 2023 +.param mc_mm_switch=0 + +** IMPORTANT: Temperature setting is added automatically in the reading +** of this file on line 6 as 25. DO NOT OVERRIDE. +.temp {@@TEMP} + +*.save all +** Define global parameters for altering +.param b1 = 10u +.param b2 = 10u + +** Define netlist +Vsupply VDD GND 1.8 +**V0 AVSS GND 0 +Vindc net1 GND 0.9 +V2_ac net2 net1 DC 0 AC -0.5 +V3_ac net3 net1 DC 0 AC 0.5 +V2_tran net4 net1 pulse(0.9 -0.9 50us 100ns 100ns 50us 100us) +V3_tran net5 net1 pulse(-0.9 0.9 50us 100ns 100ns 50us 100us) + +R_ac1 vin net2 10M +R_ac2 vip net3 10M +R_tran1 vin net4 10M +R_tran2 vip net5 10M + +* bias currents +Ibias1 VDD bias1 {b1} +Ibias2 VDD bias2 {b2} + +** Import SKY130 libs (this should be replaced with a path relative to some env variable) +* the ones with double * will not be used. The one with only 1 * will be used + +** example not used +**@@stp .include /home/rw/work/open_pdks/sky130/sky130A/libs.ref/sky130_fd_sc_hvl/spice/sky130_fd_sc_hvl.spice + +** GCP machine +.lib @@PDK_ROOT/sky130A/libs.tech/ngspice/sky130.lib.spice tt +*@@stp .include @@PDK_ROOT/sky130A/libs.ref/sky130_fd_sc_hvl/spice/sky130_fd_sc_hvl.spice + + +** Import cryo libs (these are stored in the sky130A folder) +*@@cryo .include ./sky130A/cryo_models/nshort.spice +*@@cryo .include ./sky130A/cryo_models/nshortlvth.spice +*@@cryo .include ./sky130A/cryo_models/pmos.spice + +** Import ota subcircuit +.include ota_pex.spice +XDUT GND vin vip vo VDD bias1 bias2 ota +* parameter sweep +** Run initial analysis +*.save all +*.options savecurrents +*.ac dec 10 10 10G +.control +** Set initial values +set filetype = ascii + + +** Sweep bias voltages +reset +alter R_tran1 = 10M +alter R_tran2 = 10M +alter R_ac1 = 1000G +alter R_ac2 = 1000G + +tran 25n 150u +** Find slew rate +let rise_slew = maximum(deriv(v(vo))) * 1e-6 +let fall_slew = abs(minimum(deriv(v(vo)))) * 1e-6 +echo "rise_slew: $&rise_slew" +echo "fall_slew: $&fall_slew" + +alter R_ac1 = 10M +alter R_ac2 = 10M + +** Export global maxima +wrdata result_slew.txt rise_slew fall_slew + +** Export power usage of correctly biased ota + +reset +alter R_tran1 = 1000G +alter R_tran2 = 1000G +save vo +ac dec 10 10 1G +** Find unity-gain bw point +meas ac ugb_f when vdb(vo)=0 +** Measure phase margin +let phase_margin = 180+(180/PI)*vp(vo) +meas ac pm find phase_margin when vdb(vo)=0 +** Measure DC(ish) gain +meas ac dcg find vdb(vo) at=10 +** Measure 3db BW +let threedbabsgain = dcg - 3 +meas ac threedb when vdb(vo)=threedbabsgain FALL=1 +let b1 = 10u +let b2 = 10u +wrdata result_ac.txt ugb_f b1 b2 pm dcg threedb + +reset +alter R_tran1 = 1000G +alter R_tran2 = 1000G +op +let ptotal_exact = -i(vsupply)*1.8 +wrdata result_power.txt ptotal_exact + +** Run noise analysis on ota w/ best gain +reset +alter R_tran1 = 1000G +alter R_tran2 = 1000G +noise V(vo) V2_ac dec 100 1k 1G +setplot previous +let integ = integ(onoise_spectrum) +let totalNoise = sqrt(integ[length(integ)-1]) +wrdata result_noise.txt totalNoise + +quit +.endc +.GLOBAL GND +.GLOBAL VDD +.end + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py new file mode 100644 index 000000000..3ad01fcef --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py @@ -0,0 +1,103 @@ +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.component_reference import ComponentReference +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 +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 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, rename_ports_by_list +from glayout.flow.spice.netlist import Netlist +from glayout.flow.primitives.via_gen import via_stack +from gdsfactory.components import text_freetype, rectangle +from four_transistor_interdigitized import generic_4T_interdigitzed + +def p_block_netlist(pdk: MappedPDK, pblock: tuple[float, float, int]) -> Netlist: + return Netlist( + circuit_name="p_block", + nodes=['MA_1_D', 'MA_2_D', 'MA_G', 'MB_1_D', 'MB_2_D', 'VDD'], + source_netlist=""".subckt {circuit_name} {nodes} """ + f'l={pblock[1]} wb={pblock[0]} wt={pblock[0] * pblock[2]} ' + """ +XTOP1 MB_1_D MA_1_D VDD VDD {model} l={{l}} w={{wt}} +XTOP2 MB_2_D MA_2_D VDD VDD {model} l={{l}} w={{wt}} +XBOT1 MA_1_D MA_G VDD VDD {model} l={{l}} w={{wb}} +XBOT2 MA_2_D MA_G VDD VDD {model} l={{l}} w={{wb}} +.ends {circuit_name}""", + instance_format="X{name} {nodes} {circuit_name} l={length} wt={width_top} wb={width_bot}", + parameters={ + 'model': pdk.models['pfet'], + 'width_top': pblock[0] * pblock[2], + 'width_bot': pblock[0], + 'length': pblock[1], + } + ) + + +@cell +def p_block( + pdk: MappedPDK, + width: float = 4.5, + length: float = 1, + fingers: int = 1, + ratio: int = 1, + ) -> Component: + """ + p_block for super class AB OTA + + """ + #top level component + top_level = Component(name="p_block") + top_kwargs = { + "fingers": ratio*fingers, + "width": width, + "with_tie": True, + "sd_rmult":3 + } + bottom_kwargs = { + "fingers": fingers, + "width": width, + "with_tie": True, + "sd_rmult":3 + } + + p_block = generic_4T_interdigitzed(pdk, top_row_device = "pfet", bottom_row_device = "pfet", numcols = 2, length = length, with_substrate_tap = False, top_kwargs = top_kwargs, bottom_kwargs = bottom_kwargs) + p_block_ref = top_level << p_block + + top_level << c_route(pdk, p_block.ports["top_A_0_gate_W"], p_block.ports["bottom_A_0_drain_W"]) + top_level << c_route(pdk, p_block.ports["top_B_1_gate_E"], p_block.ports["bottom_B_1_drain_E"]) + top_level << c_route(pdk, p_block.ports["bottom_A_0_gate_W"], p_block.ports["bottom_B_0_gate_W"], width1=0.29, width2=0.29, cwidth=0.29) + + top_level << c_route(pdk, p_block.ports["top_A_0_source_W"], p_block.ports["top_B_0_source_W"]) + top_level << straight_route(pdk, p_block.ports["top_A_0_source_W"], p_block.ports["top_welltie_W_top_met_W"], glayer1='met1', width=0.6) + top_level << c_route(pdk, p_block.ports["bottom_A_0_source_W"], p_block.ports["bottom_B_0_source_W"], extension=1.2, cwidth=0.29) + top_level << straight_route(pdk, p_block.ports["bottom_A_0_source_W"], p_block.ports["bottom_welltie_W_top_met_W"], glayer1='met1', width=0.6) + + top_level << straight_route(pdk, p_block.ports["top_welltie_S_top_met_S"], p_block.ports["bottom_welltie_N_top_met_N"], glayer1='met2', width=3) + + #adding a nwell + nwell_rectangle = rectangle(layer=(pdk.get_glayer("nwell")), size=evaluate_bbox(top_level)) + nwell_rectangle_ref = prec_ref_center(nwell_rectangle) + nwell_rectangle_ref.move(p_block_ref.center) + top_level.add(nwell_rectangle_ref) + + + #Renaming Ports + top_level.add_ports(p_block.get_ports_list()) + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = p_block_netlist(pdk, pblock=(width,length,ratio)) + #print(component.info['netlist'].generate_netlist()) + + + return component + +#p_block = p_block(sky130_mapped_pdk) +#p_block.show() +#magic_drc_result = sky130_mapped_pdk.drc_magic(p_block, p_block.name) + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshort.spice b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshort.spice new file mode 100644 index 000000000..c9febdad0 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshort.spice @@ -0,0 +1,420 @@ +* +* 4k spice models for n-channel thin oxide mosfets (std VTH). +* +* +* this scaled model was extracted by coolcad electroncis llc, +* akin akturk, akin.akturk@coolcadelectronics.com +* +* measurements used in model extraction correspond to the +* following W (um)/L (um) devices: +*'nshort; w=1.68; l=0.15; m=1'; +*'nshort; w=7.0; l=8.0; m=1'; +*'nshort; w=7.0; l=0.15; m=1'; +*'nshort; w=0.42; l=8.0; m=1'; +*'nshort; w=0.42; l=0.15; m=1'; +* +* to use the models, please set the circuit temperature +* to -269 in celcius. for standard spice, this can be done +* by adding the following line to netlist: .options temp=-269 +* +* +* +* +.MODEL nshort NMOS ++ LEVEL = 54 ++ VERSION = 4.6.5 ++ BINUNIT = 2 ++ PARAMCHK = 1 ++ MOBMOD = 1 ++ MTRLMOD = 0 ++ RDSMOD = 0 ++ IGCMOD = 0 ++ IGBMOD = 0 ++ CVCHARGEMOD = 0 ++ CAPMOD = 2 ++ RGATEMOD = 0 ++ RBODYMOD = 0 ++ TRNQSMOD = 0 ++ ACNQSMOD = 0 ++ FNOIMOD = 1 ++ TNOIMOD = 0 ++ DIOMOD = 1 ++ TEMPMOD = 0 ++ PERMOD = 1 ++ GEOMOD = 0 ++ WPEMOD = 0 ++ EPSROX = 3.9 ++ TOXE = 4.0840E-009 ++ EOT = 4.0840E-009 ++ TOXP = 4.0840E-009 ++ TOXM = 4.0840E-009 ++ DTOX = 0 ++ XJ = 1.5E-007 ++ NDEP = 1.7E+017 ++ NGATE = 1E+022 ++ NSD = 1E+020 ++ XT = 1.55E-007 ++ RSH = 0 ++ RSHG = 0.1 ++ VTH0 = 0.665 ++ WVTH0 = -0.02E-7 ++ LVTH0 = 0.22E-7 ++ PVTH0 = 0.08E-14 ++ VDDEOT = 1.5 ++ LEFFEOT = 1 ++ WEFFEOT = 10 ++ TEMPEOT = 300.1 ++ PHIN = 0 ++ EASUB = 4.05 ++ EPSRSUB = 11.7 ++ NI0SUB = 1.45E+010 ++ BG0SUB = 1.16 ++ TBGASUB = 0.000702 ++ TBGBSUB = 1108 ++ ADOS = 1 ++ BDOS = 1 ++ VFB = -1 ++ K1 = 0.4 ++ K2 = 0.01 ++ LK2 = 0.01E-6 ++ PK2 = 0.008E-13 ++ K3 = 15 ++ K3B = 0 ++ WK1 = -0.0225E-6 ++ LK1 = -0.045E-6 ++ PK1 = -0.5E-15 ++ W0 = 9.222E-007 ++ LPE0 = 1.899E-008 ++ LPEB = 6.702E-008 ++ VBM = -3 ++ DVT0 = 0.001 ++ DVT1 = 0.1135 ++ DVT2 = -2.864 ++ DVTP0 = 5.919E-009 ++ DVTP1 = 2.966 ++ DVT0W = -10.37 ++ DVT1W = 5.3E+006 ++ DVT2W = -0.032 ++ U0 = 0.25 ++ LU0 = -0.036E-6 ++ WU0 = -0.02E-6 ++ PU0 = 0.01E-12 ++ UA = -1.986E-009 ++ LUA = -5E-0117 ++ UB = 0.47E-017 ++ WUB = -2E-025 ++ LUB = -5E-025 ++ PUB = 12E-032 ++ UC = -0.07076 ++ UD = 3.228 ++ UCS = 1.67 ++ UP = 0.3928 ++ LP = 1.39E-005 ++ EU = 1.6 ++ VSAT = 1.8e+004 ++ WVSAT = -1.8E-3 ++ LVSAT = 20E-3 ++ PVSAT = 1.5e-9 ++ A0 = 2.2 ++ AGS = 1.4 ++ B0 = 0 ++ B1 = 0 ++ KETA = -0.02134 ++ A1 = 0 ++ A2 = 0.8779 ++ WINT = -3.6E-008 ++ LINT = -2.4E-008 ++ DWG = 6.974E-009 ++ LDWG = -5E-015 ++ DWB = 0 ++ VOFF = -0.1 ++ VOFFL = 15E-009 ++ MINV = -7 ++ LMINV = -15e-7 ++ NFACTOR = 2 ++ ETA0 = 2.686 ++ ETAB = -1.412 ++ DSUB = 0.6654 ++ CIT = 0 ++ CDSC = 4.441E-016 ++ CDSCB = -6.337E-006 ++ CDSCD = 0 ++ PCLM = 0.5 ++ LPCLM = 0.7E-6 ++ WPCLM = -0.1E-6 ++ PDIBLC1 = 0.001E-10 ++ PDIBLC2 = 1E-006 ++ PDIBLCB = 0 ++ DROUT = 0.56 ++ PSCBE1 = 1.5E+008 ++ PSCBE2 = 0.15E-006 ++ PVAG = 5 ++ DELTA = 0.01 ++ FPROUT = 0 ++ PDITS = 0.01 ++ PDITSL = 1.392E+006 ++ PDITSD = 1 ++ LAMBDA = 0 ++ VTL = 2E+005 ++ LC = 0 ++ XN = 4 ++ PHIG = 4.05 ++ EPSRGATE = 11.7 ++ RDSW = 0.0 ++ RDSWMIN = 5.0 ++ RDW = 100 ++ RDWMIN = 0 ++ RSW = 100 ++ RSWMIN = 0 ++ PRWG = 0.4 ++ PRWB = -0.1169 ++ WR = 8.882E-016 ++ ALPHA0 = 1E-005 ++ ALPHA1 = 0 ++ BETA0 = 15 ++ AGIDL = 1E-015 ++ BGIDL = 2.3E+009 ++ CGIDL = 0.5 ++ EGIDL = 0.8 ++ AGISL = 0 ++ BGISL = 2.3E+009 ++ CGISL = 0.5 ++ EGISL = 0.8 ++ AIGBACC = 0.43 ++ BIGBACC = 0.054 ++ CIGBACC = 0.075 ++ NIGBACC = 1 ++ AIGBINV = 0.35 ++ BIGBINV = 0.03 ++ CIGBINV = 0.006 ++ EIGBINV = 1.1 ++ NIGBINV = 3 ++ AIGC = 0.54 ++ BIGC = 0.054 ++ CIGC = 0.075 ++ AIGSD = 0.43 ++ BIGSD = 0.054 ++ CIGSD = 0.075 ++ DLCIG = 1.051E-008 ++ AIGS = 0.0136 ++ BIGS = 0.00171 ++ CIGS = 0.075 ++ AIGD = 0.0136 ++ BIGD = 0.00171 ++ CIGD = 0.075 ++ DLCIGD = 0 ++ NIGC = 1 ++ POXEDGE = 1 ++ PIGCD = 1 ++ NTOX = 1 ++ TOXREF = 4.0840E-009 ++ VFBSDOFF = 0 ++ XPART = 0 ++ CGSO = 3E-011 ++ CGDO = 3E-011 ++ CGBO = 0 ++ CGSL = 1.343E-010 ++ CGDL = 1.343E-010 ++ CKAPPAS = 0.6 ++ CKAPPAD = 0.6 ++ CF = 2.977E-010 ++ CLC = 1E-007 ++ CLE = 0.6 ++ DLC = 1.051E-008 ++ DWC = 0 ++ VFBCV = -1 ++ NOFF = 2 ++ VOFFCV = 0.051 ++ VOFFCVL = 0 ++ MINVCV = 0 ++ ACDE = 1 ++ MOIN = 15 ++ XRCRG1 = 12 ++ XRCRG2 = 1 ++ RBPB = 50 ++ RBPD = 50 ++ RBPS = 15 ++ RBDB = 50 ++ RBSB = 50 ++ GBMIN = 1E-012 ++ RBPS0 = 50 ++ RBPSL = 0 ++ RBPSW = 0 ++ RBPSNF = 0 ++ RBPD0 = 50 ++ RBPDL = 0 ++ RBPDW = 0 ++ RBPDNF = 0 ++ RBPBX0 = 100 ++ RBPBXL = 0 ++ RBPBXW = 0 ++ RBPBXNF = 0 ++ RBPBY0 = 100 ++ RBPBYL = 0 ++ RBPBYW = 0 ++ RBPBYNF = 0 ++ RBSBX0 = 100 ++ RBSBY0 = 100 ++ RBDBX0 = 100 ++ RBDBY0 = 100 ++ RBSDBXL = 0 ++ RBSDBXW = 0 ++ RBSDBXNF = 0 ++ RBSDBYL = 0 ++ RBSDBYW = 0 ++ RBSDBYNF = 0 ++ NOIA = 6.25E+041 ++ NOIB = 3.125E+026 ++ NOIC = 8.75 ++ EM = 4.1E+007 ++ AF = 1 ++ EF = 1 ++ KF = 0 ++ LINTNOI = 0 ++ NTNOI = 1 ++ TNOIA = 1.5 ++ TNOIB = 3.5 ++ RNOIA = 0.577 ++ RNOIB = 0.5164 ++ DMCG = 0 ++ DMCI = 0 ++ DMDG = 0 ++ DMCGT = 0 ++ DWJ = 0 ++ XGW = 0 ++ XGL = 0 ++ XL = 0 ++ XW = 5E-8 ++ NGCON = 1 ++ IJTHSREV = 0.0044 ++ IJTHSFWD = 0.0044 ++ XJBVS = 1 ++ BVS = 10 ++ JSS = 1.487E-8 ++ JSWS = 1E-18 ++ JSWGS = 0 ++ JTSS = 0 ++ JTSSWS = 0 ++ JTSSWGS = 0 ++ JTWEFF = 0 ++ NJS = 15 ++ NJTS = 20 ++ NJTSSW = 20 ++ NJTSSWG = 20 ++ XTSS = 0.02 ++ XTSSWS = 0.02 ++ XTSSWGS = 0.02 ++ VTSS = 10 ++ VTSSWS = 10 ++ VTSSWGS = 10 ++ TNJTS = 0 ++ TNJTSSW = 0 ++ TNJTSSWG = 0 ++ CJS = 0.001283 ++ MJS = 0.3296 ++ MJSWS = 0.33 ++ CJSWS = 3.5E-011 ++ CJSWGS = 3.5E-011 ++ MJSWGS = 0.33 ++ PBS = 0.9641 ++ PBSWS = 1 ++ PBSWGS = 1 ++ IJTHDREV = 0.0044 ++ IJTHDFWD = 0.0044 ++ XJBVD = 1 ++ BVD = 10 ++ JSD = 1.487E-8 ++ JSWD = 1E-18 ++ JSWGD = 0 ++ JTSD = 0 ++ JTSSWD = 0 ++ JTSSWGD = 0 ++ NJD = 15 ++ NJTSD = 20 ++ NJTSSWD = 20 ++ NJTSSWGD = 20 ++ XTSD = 0.02 ++ XTSSWD = 0.02 ++ XTSSWGD = 0.02 ++ VTSD = 10 ++ VTSSWD = 10 ++ VTSSWGD = 10 ++ TNJTSD = 0 ++ TNJTSSWD = 0 ++ TNJTSSWGD = 0 ++ CJD = 0.001283 ++ MJD = 0.3296 ++ MJSWD = 0.33 ++ CJSWD = 3.5E-011 ++ CJSWGD = 3.5E-011 ++ MJSWGD = 0.33 ++ PBD = 0.9641 ++ PBSWD = 1 ++ PBSWGD = 1 ++ TNOM = -253 ++ UTE = 0 ++ UCSTE = -0.004775 ++ KT1 = 0 ++ KT1L = 0 ++ KT2 = 0 ++ UA1 = 0 ++ UB1 = 0 ++ UC1 = 0 ++ UD1 = 0 ++ AT = 0 ++ PRT = 0 ++ XTIS = 3 ++ XTID = 3 ++ TPB = 0 ++ TPBSW = 0 ++ TPBSWG = 0 ++ TCJ = 0 ++ TCJSW = 0 ++ TCJSWG = 0 ++ TVOFF = 0 ++ TVFBSDOFF = 0 ++ SAREF = 0 ++ SBREF = 0 ++ WLOD = 2E-006 ++ KU0 = 4E-006 ++ KVSAT = 0.0 ++ TKU0 = 0 ++ LKU0 = 1E-006 ++ WKU0 = 1E-006 ++ PKU0 = 0 ++ LLODKU0 = 1.1 ++ WLODKU0 = 1.1 ++ KVTH0 = -2E-008 ++ LKVTH0 = 1.1E-006 ++ WKVTH0 = 1.1E-006 ++ PKVTH0 = 0 ++ LLODVTH = 1 ++ WLODVTH = 1 ++ STK2 = 0 ++ LODK2 = 1 ++ STETA0 = 0 ++ LODETA0 = 1 ++ WEB = 0 ++ WEC = 0 ++ KVTH0WE = 0 ++ K2WE = 0 ++ KU0WE = 0 ++ SCREF = 1E-006 ++ WL = 1E-014 ++ WLN = 1.056 ++ WW = 10.807E-015 ++ WWN = 1.03 ++ WWL = -1.419E-021 ++ LL = -1.609E-015 ++ LLN = 0.9 ++ LW = -7.92E-015 ++ LWN = 1.012 ++ LWL = 6.569E-021 ++ LLC = 0 ++ LWC = 0 ++ LWLC = 0 ++ WLC = 0 ++ WWC = 0 ++ WWLC = 0 +* +* diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshortlvth.spice b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshortlvth.spice new file mode 100644 index 000000000..d201c7890 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/nshortlvth.spice @@ -0,0 +1,420 @@ +* +* 4k spice models for n-channel thin oxide mosfets (low VTH). +* +* +* this scaled model was extracted by coolcad electroncis llc, +* akin akturk, akin.akturk@coolcadelectronics.com +* +* measurements used in model extraction correspond to the +* following W (um)/L (um) devices: +*'nlowvt; w=7.0; l=8.0; m=1'; +*'nlowvt; w=7.0; l=0.15; m=1'; +*'nlowvt; w=0.42; l=1.0; m=1'; +*'nlowvt; w=0.42; l=0.15; m=1'; +*'nlowvt; w=0.84; l=0.15; m=1';* +* to use the models, please set the circuit temperature +* to -269 in celcius. for standard spice, this can be done +* by adding the following line to netlist: .options temp=-269 +* +* +* +* +.MODEL nshortlvth NMOS ++ LEVEL = 54 ++ VERSION = 4.6.5 ++ BINUNIT = 2 ++ PARAMCHK = 1 ++ MOBMOD = 1 ++ MTRLMOD = 0 ++ RDSMOD = 0 ++ IGCMOD = 0 ++ IGBMOD = 0 ++ CVCHARGEMOD = 0 ++ CAPMOD = 2 ++ RGATEMOD = 0 ++ RBODYMOD = 0 ++ TRNQSMOD = 0 ++ ACNQSMOD = 0 ++ FNOIMOD = 1 ++ TNOIMOD = 0 ++ DIOMOD = 1 ++ TEMPMOD = 0 ++ PERMOD = 1 ++ GEOMOD = 0 ++ WPEMOD = 0 ++ EPSROX = 3.9 ++ TOXE = 4.0840E-009 ++ EOT = 4.0840E-009 ++ TOXP = 4.0840E-009 ++ TOXM = 4.0840E-009 ++ DTOX = 0 ++ XJ = 1.5E-007 ++ NDEP = 1.7E+017 ++ NGATE = 1E+022 ++ NSD = 1E+020 ++ XT = 1.55E-007 ++ RSH = 0 ++ RSHG = 0.1 ++ VTH0 = 0.585 ++ WVTH0 = -0.02E-7 ++ LVTH0 = 0.27E-7 ++ PVTH0 = 0.08E-14 ++ VDDEOT = 1.5 ++ LEFFEOT = 1 ++ WEFFEOT = 10 ++ TEMPEOT = 300.1 ++ PHIN = 0 ++ EASUB = 4.05 ++ EPSRSUB = 11.7 ++ NI0SUB = 1.45E+010 ++ BG0SUB = 1.16 ++ TBGASUB = 0.000702 ++ TBGBSUB = 1108 ++ ADOS = 1 ++ BDOS = 1 ++ VFB = -1 ++ K1 = 0.35 ++ K2 = 0.01 ++ LK2 = 0.01E-6 ++ K3 = 15 ++ K3B = 0 ++ WK1 = -0.0225E-6 ++ LK1 = -0.045E-6 ++ PK1 = -0.5E-15 ++ W0 = 9.222E-007 ++ LPE0 = 1.899E-008 ++ LPEB = 6.702E-008 ++ VBM = -3 ++ DVT0 = 0.001 ++ DVT1 = 0.1135 ++ DVT2 = -2.864 ++ DVTP0 = 5.919E-009 ++ DVTP1 = 2.966 ++ DVT0W = -10.37 ++ DVT1W = 5.3E+006 ++ DVT2W = -0.032 ++ U0 = 0.65 ++ LU0 = -0.05E-6 ++ WU0 = -0.02E-6 ++ PU0 = 0.01E-12 ++ UA = -3.5E-009 ++ LUA = -5E-0117 ++ UB = 1.4E-017 ++ WUB = -2E-025 ++ LUB = -5E-025 ++ PUB = 12E-032 ++ UC = -0.07076 ++ UD = 3.228 ++ UCS = 1.67 ++ UP = 0.3928 ++ LP = 2E-005 ++ EU = 1.6 ++ VSAT = 3.2e+004 ++ WVSAT = 8E-3 ++ LVSAT = 20E-3 ++ PVSAT = -1.5e-9 ++ A0 = 2.2 ++ AGS = 1.4 ++ B0 = 0 ++ B1 = 0 ++ KETA = -0.02134 ++ A1 = 0 ++ A2 = 0.8779 ++ WINT = -5E-008 ++ LINT = -2.0E-008 ++ DWG = 6.974E-009 ++ LDWG = -5E-015 ++ DWB = 0 ++ VOFF = -0.05 ++ VOFFL = -11E-009 ++ MINV = -8 ++ LMINV = -15e-7 ++ WMINV = -10e-7 ++ NFACTOR = 5 ++ ETA0 = 2.686 ++ ETAB = -1.412 ++ DSUB = 0.6654 ++ CIT = 0 ++ CDSC = 4.441E-016 ++ CDSCB = -6.337E-006 ++ CDSCD = 0 ++ PCLM = 0.5 ++ LPCLM = 0.3E-6 ++ WPCLM = -0.1E-6 ++ PDIBLC1 = 0.001E-10 ++ PDIBLC2 = 1E-006 ++ PDIBLCB = 0 ++ DROUT = 0.56 ++ PSCBE1 = 1.5E+008 ++ PSCBE2 = 0.05E-006 ++ PVAG = 5 ++ DELTA = 0.002 ++ WDELTA = 2E-8 ++ FPROUT = 0 ++ PDITS = 0.01 ++ PDITSL = 1.392E+006 ++ PDITSD = 1 ++ LAMBDA = 0 ++ VTL = 2E+005 ++ LC = 0 ++ XN = 4 ++ PHIG = 4.05 ++ EPSRGATE = 11.7 ++ RDSW = 0.0 ++ RDSWMIN = 11.0 ++ RDW = 100 ++ RDWMIN = 0 ++ RSW = 100 ++ RSWMIN = 0 ++ PRWG = 0.4 ++ PRWB = -0.1169 ++ WR = 8.882E-016 ++ ALPHA0 = 1E-005 ++ ALPHA1 = 0 ++ BETA0 = 15 ++ AGIDL = 1E-015 ++ BGIDL = 2.3E+009 ++ CGIDL = 0.5 ++ EGIDL = 0.8 ++ AGISL = 0 ++ BGISL = 2.3E+009 ++ CGISL = 0.5 ++ EGISL = 0.8 ++ AIGBACC = 0.43 ++ BIGBACC = 0.054 ++ CIGBACC = 0.075 ++ NIGBACC = 1 ++ AIGBINV = 0.35 ++ BIGBINV = 0.03 ++ CIGBINV = 0.006 ++ EIGBINV = 1.1 ++ NIGBINV = 3 ++ AIGC = 0.54 ++ BIGC = 0.054 ++ CIGC = 0.075 ++ AIGSD = 0.43 ++ BIGSD = 0.054 ++ CIGSD = 0.075 ++ DLCIG = 1.051E-008 ++ AIGS = 0.0136 ++ BIGS = 0.00171 ++ CIGS = 0.075 ++ AIGD = 0.0136 ++ BIGD = 0.00171 ++ CIGD = 0.075 ++ DLCIGD = 0 ++ NIGC = 1 ++ POXEDGE = 1 ++ PIGCD = 1 ++ NTOX = 1 ++ TOXREF = 4.0840E-009 ++ VFBSDOFF = 0 ++ XPART = 0 ++ CGSO = 3E-011 ++ CGDO = 3E-011 ++ CGBO = 0 ++ CGSL = 1.343E-010 ++ CGDL = 1.343E-010 ++ CKAPPAS = 0.6 ++ CKAPPAD = 0.6 ++ CF = 2.977E-010 ++ CLC = 1E-007 ++ CLE = 0.6 ++ DLC = 1.051E-008 ++ DWC = 0 ++ VFBCV = -1 ++ NOFF = 2 ++ VOFFCV = 0.051 ++ VOFFCVL = 0 ++ MINVCV = 0 ++ ACDE = 1 ++ MOIN = 15 ++ XRCRG1 = 12 ++ XRCRG2 = 1 ++ RBPB = 50 ++ RBPD = 50 ++ RBPS = 15 ++ RBDB = 50 ++ RBSB = 50 ++ GBMIN = 1E-012 ++ RBPS0 = 50 ++ RBPSL = 0 ++ RBPSW = 0 ++ RBPSNF = 0 ++ RBPD0 = 50 ++ RBPDL = 0 ++ RBPDW = 0 ++ RBPDNF = 0 ++ RBPBX0 = 100 ++ RBPBXL = 0 ++ RBPBXW = 0 ++ RBPBXNF = 0 ++ RBPBY0 = 100 ++ RBPBYL = 0 ++ RBPBYW = 0 ++ RBPBYNF = 0 ++ RBSBX0 = 100 ++ RBSBY0 = 100 ++ RBDBX0 = 100 ++ RBDBY0 = 100 ++ RBSDBXL = 0 ++ RBSDBXW = 0 ++ RBSDBXNF = 0 ++ RBSDBYL = 0 ++ RBSDBYW = 0 ++ RBSDBYNF = 0 ++ NOIA = 6.25E+041 ++ NOIB = 3.125E+026 ++ NOIC = 8.75 ++ EM = 4.1E+007 ++ AF = 1 ++ EF = 1 ++ KF = 0 ++ LINTNOI = 0 ++ NTNOI = 1 ++ TNOIA = 1.5 ++ TNOIB = 3.5 ++ RNOIA = 0.577 ++ RNOIB = 0.5164 ++ DMCG = 0 ++ DMCI = 0 ++ DMDG = 0 ++ DMCGT = 0 ++ DWJ = 0 ++ XGW = 0 ++ XGL = 0 ++ XL = 0 ++ XW = 5E-8 ++ NGCON = 1 ++ IJTHSREV = 0.0044 ++ IJTHSFWD = 0.0044 ++ XJBVS = 1 ++ BVS = 10 ++ JSS = 1.487E-8 ++ JSWS = 1E-18 ++ JSWGS = 0 ++ JTSS = 0 ++ JTSSWS = 0 ++ JTSSWGS = 0 ++ JTWEFF = 0 ++ NJS = 15 ++ NJTS = 20 ++ NJTSSW = 20 ++ NJTSSWG = 20 ++ XTSS = 0.02 ++ XTSSWS = 0.02 ++ XTSSWGS = 0.02 ++ VTSS = 10 ++ VTSSWS = 10 ++ VTSSWGS = 10 ++ TNJTS = 0 ++ TNJTSSW = 0 ++ TNJTSSWG = 0 ++ CJS = 0.001283 ++ MJS = 0.3296 ++ MJSWS = 0.33 ++ CJSWS = 3.5E-011 ++ CJSWGS = 3.5E-011 ++ MJSWGS = 0.33 ++ PBS = 0.9641 ++ PBSWS = 1 ++ PBSWGS = 1 ++ IJTHDREV = 0.0044 ++ IJTHDFWD = 0.0044 ++ XJBVD = 1 ++ BVD = 10 ++ JSD = 1.487E-8 ++ JSWD = 1E-18 ++ JSWGD = 0 ++ JTSD = 0 ++ JTSSWD = 0 ++ JTSSWGD = 0 ++ NJD = 15 ++ NJTSD = 20 ++ NJTSSWD = 20 ++ NJTSSWGD = 20 ++ XTSD = 0.02 ++ XTSSWD = 0.02 ++ XTSSWGD = 0.02 ++ VTSD = 10 ++ VTSSWD = 10 ++ VTSSWGD = 10 ++ TNJTSD = 0 ++ TNJTSSWD = 0 ++ TNJTSSWGD = 0 ++ CJD = 0.001283 ++ MJD = 0.3296 ++ MJSWD = 0.33 ++ CJSWD = 3.5E-011 ++ CJSWGD = 3.5E-011 ++ MJSWGD = 0.33 ++ PBD = 0.9641 ++ PBSWD = 1 ++ PBSWGD = 1 ++ TNOM = -253 ++ UTE = 0 ++ UCSTE = -0.004775 ++ KT1 = 0 ++ KT1L = 0 ++ KT2 = 0 ++ UA1 = 0 ++ UB1 = 0 ++ UC1 = 0 ++ UD1 = 0 ++ AT = 0 ++ PRT = 0 ++ XTIS = 3 ++ XTID = 3 ++ TPB = 0 ++ TPBSW = 0 ++ TPBSWG = 0 ++ TCJ = 0 ++ TCJSW = 0 ++ TCJSWG = 0 ++ TVOFF = 0 ++ TVFBSDOFF = 0 ++ SAREF = 0 ++ SBREF = 0 ++ WLOD = 2E-006 ++ KU0 = 4E-006 ++ KVSAT = 0.0 ++ TKU0 = 0 ++ LKU0 = 1E-006 ++ WKU0 = 1E-006 ++ PKU0 = 0 ++ LLODKU0 = 1.1 ++ WLODKU0 = 1.1 ++ KVTH0 = -2E-008 ++ LKVTH0 = 1.1E-006 ++ WKVTH0 = 1.1E-006 ++ PKVTH0 = 0 ++ LLODVTH = 1 ++ WLODVTH = 1 ++ STK2 = 0 ++ LODK2 = 1 ++ STETA0 = 0 ++ LODETA0 = 1 ++ WEB = 0 ++ WEC = 0 ++ KVTH0WE = 0 ++ K2WE = 0 ++ KU0WE = 0 ++ SCREF = 1E-006 ++ WL = 1E-014 ++ WLN = 1.056 ++ WW = 10.807E-015 ++ WWN = 1.03 ++ WWL = -1.419E-021 ++ LL = -1.609E-015 ++ LLN = 0.9 ++ LW = -7.92E-015 ++ LWN = 1.012 ++ LWL = 6.569E-021 ++ LLC = 0 ++ LWC = 0 ++ LWLC = 0 ++ WLC = 0 ++ WWC = 0 ++ WWLC = 0 +* +* diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/pmos.spice b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/pmos.spice new file mode 100644 index 000000000..fe1cb7786 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/cryo_models/pmos.spice @@ -0,0 +1,419 @@ +* +* 4k spice models for p-channel thin oxide mosfets (low VTH). +* +* +* this scaled model was extracted by coolcad electroncis llc, +* akin akturk, akin.akturk@coolcadelectronics.com +* +* measurements used in model extraction correspond to the +* following W (um)/L (um) devices: +*'plowvt; w=3.0; l=1.0; m=1'; +*'plowvt; w=7.0; l=8.0; m=1'; +*'plowvt; w=7.0; l=0.35; m=1'; +*'plowvt; w=0.42; l=8.0; m=1'; +*'plowvt; w=0.42; l=0.35; m=1'; +* +* to use the models, please set the circuit temperature +* to -269 in celcius. for standard spice, this can be done +* by adding the following line to netlist: .options temp=-269 +* +* +* +* +.MODEL pshort PMOS ++ LEVEL = 54 ++ VERSION = 4.6.5 ++ BINUNIT = 2 ++ PARAMCHK = 1 ++ MOBMOD = 1 ++ MTRLMOD = 0 ++ RDSMOD = 0 ++ IGCMOD = 0 ++ IGBMOD = 0 ++ CVCHARGEMOD = 0 ++ CAPMOD = 2 ++ RGATEMOD = 0 ++ RBODYMOD = 0 ++ TRNQSMOD = 0 ++ ACNQSMOD = 0 ++ FNOIMOD = 1 ++ TNOIMOD = 0 ++ DIOMOD = 1 ++ TEMPMOD = 0 ++ PERMOD = 1 ++ GEOMOD = 0 ++ WPEMOD = 0 ++ EPSROX = 3.9 ++ TOXE = 4.0349E-009 ++ EOT = 4.0349E-009 ++ TOXP = 4.0349E-009 ++ TOXM = 4.0349E-009 ++ DTOX = 0 ++ XJ = 1.5E-007 ++ NDEP = 4.0E+017 ++ NGATE = 1E+022 ++ NSD = 1E+020 ++ XT = 1.55E-007 ++ RSH = 0 ++ RSHG = 0.1 ++ VTH0 = -1.17 ++ LVTH0 = 0.13e-7 ++ WVTH0 = -0.23e-7 ++ PVTH0 = 20e-16 ++ VDDEOT = -1.5 ++ LEFFEOT = 1 ++ WEFFEOT = 10 ++ TEMPEOT = 300.1 ++ PHIN = 0 ++ EASUB = 4.05 ++ EPSRSUB = 11.7 ++ NI0SUB = 1.45E+010 ++ BG0SUB = 1.16 ++ TBGASUB = 0.000702 ++ TBGBSUB = 1108 ++ ADOS = 1 ++ BDOS = 1 ++ VFB = -1 ++ K1 = 0.618 ++ K2 = 0.039145 ++ K3 = -14.37 ++ K3B = -4.92 ++ WK1 = -4E-8 ++ LK1 = -4E-8 ++ PK1 = 8E-15 ++ W0 = 4.104E-007 ++ LPE0 = 7.535E-016 ++ LPEB = 2.387E-011 ++ VBM = -0.5 ++ DVT0 = 0.007 ++ DVT1 = 0.01 ++ DVT2 = -0.05872 ++ DVTP0 = 0 ++ DVTP1 = 0.001 ++ DVT0W = -100 ++ DVT1W = 5.3E+006 ++ DVT2W = -0.032 ++ U0 = 0.17 ++ LU0 = -6E-9 ++ PU0 = 0E-17 ++ WU0 = 0E-9 ++ UA = -3.272E-010 ++ UB = 2.2E-018 ++ WUB = -3E-026 ++ UC = 0.1 ++ UD = 1.762E+017 ++ UCS = 1 ++ UP = -0.004472 ++ LP = 1E-008 ++ EU = 1.67 ++ VSAT = 25E+004 ++ WVSAT = 3.0 ++ LVSAT = -10E-12 ++ PVSAT = 1E-2 ++ A0 = 0.5 ++ AGS = 0.5529 ++ B0 = 0 ++ B1 = 0 ++ KETA = -0.06744 ++ A1 = 0.07557 ++ A2 = 0.376 ++ WINT = 7E-008 ++ LINT = 1.5E-008 ++ DWG = -1E-008 ++ DWB = -1E-008 ++ VOFF = -0.09 ++ VOFFL = -0.4E-7 ++ MINV = -9 ++ WMINV = 0.39e-6 ++ LMINV = 0.0e-6 ++ PMINV = -0.7e-13 ++ NFACTOR = 4 ++ ETA0 = 12E-005 ++ ETAB = 0.687 ++ DSUB = 0.9 ++ CIT = 0 ++ CDSC = 4.441E-016 ++ CDSCB = -0.001393 ++ CDSCD = 0 ++ PCLM = 0.839 ++ LPCLM = 6E-7 ++ PDIBLC1 = 2 ++ PDIBLC2 = 0.001192 ++ PDIBLCB = 0 ++ DROUT = 0.4 ++ PSCBE1 = 9.24E+008 ++ PSCBE2 = 0.001 ++ PVAG = 1 ++ DELTA = 0.07 ++ PDELTA = -5E-15 ++ FPROUT = 0 ++ PDITS = 0.1 ++ PDITSL = 6.754E+006 ++ PDITSD = 1 ++ LAMBDA = 0 ++ VTL = 3.7E+004 ++ WVTL = 1E-2 ++ LC = 0.2 ++ XN = 10 ++ PHIG = 4.05 ++ EPSRGATE = 11.7 ++ RDSW = 3000 ++ LRDSW = 4e-5 ++ WRDSW = 0e-5 ++ RDSWMIN = 00 ++ RDW = 100 ++ RDWMIN = 0 ++ RSW = 100 ++ RSWMIN = 0 ++ PRWG = 8.421E-005 ++ PRWB = -0.814 ++ WR = 1.21 ++ ALPHA0 = 1E-005 ++ ALPHA1 = 0 ++ BETA0 = 15 ++ AGIDL = 1E-015 ++ BGIDL = 2.3E+009 ++ CGIDL = 0.5 ++ EGIDL = 0.8 ++ AGISL = 0 ++ BGISL = 2.3E+009 ++ CGISL = 0.5 ++ EGISL = 0.8 ++ AIGBACC = 0.43 ++ BIGBACC = 0.054 ++ CIGBACC = 0.075 ++ NIGBACC = 1 ++ AIGBINV = 0.35 ++ BIGBINV = 0.03 ++ CIGBINV = 0.006 ++ EIGBINV = 1.1 ++ NIGBINV = 3 ++ AIGC = 0.54 ++ BIGC = 0.054 ++ CIGC = 0.075 ++ AIGSD = 0.43 ++ BIGSD = 0.054 ++ CIGSD = 0.075 ++ DLCIG = 1.124E-008 ++ AIGS = 0.0136 ++ BIGS = 0.00171 ++ CIGS = 0.075 ++ AIGD = 0.0136 ++ BIGD = 0.00171 ++ CIGD = 0.075 ++ DLCIGD = 0 ++ NIGC = 1 ++ POXEDGE = 1 ++ PIGCD = 1 ++ NTOX = 1 ++ TOXREF = 4.0349E-009 ++ VFBSDOFF = 0 ++ XPART = 0 ++ CGSO = 3.161E-011 ++ CGDO = 3.161E-011 ++ CGBO = 0 ++ CGSL = 1.121E-010 ++ CGDL = 1.121E-010 ++ CKAPPAS = 0.6 ++ CKAPPAD = 0.6 ++ CF = 2.854E-010 ++ CLC = 1E-007 ++ CLE = 0.6 ++ DLC = 1.124E-008 ++ DWC = 0 ++ VFBCV = -1 ++ NOFF = 2 ++ VOFFCV = -0.2538 ++ VOFFCVL = 0 ++ MINVCV = 0 ++ ACDE = 1 ++ MOIN = 15 ++ XRCRG1 = 12 ++ XRCRG2 = 1 ++ RBPB = 50 ++ RBPD = 50 ++ RBPS = 15 ++ RBDB = 50 ++ RBSB = 50 ++ GBMIN = 1E-012 ++ RBPS0 = 50 ++ RBPSL = 0 ++ RBPSW = 0 ++ RBPSNF = 0 ++ RBPD0 = 50 ++ RBPDL = 0 ++ RBPDW = 0 ++ RBPDNF = 0 ++ RBPBX0 = 100 ++ RBPBXL = 0 ++ RBPBXW = 0 ++ RBPBXNF = 0 ++ RBPBY0 = 100 ++ RBPBYL = 0 ++ RBPBYW = 0 ++ RBPBYNF = 0 ++ RBSBX0 = 100 ++ RBSBY0 = 100 ++ RBDBX0 = 100 ++ RBDBY0 = 100 ++ RBSDBXL = 0 ++ RBSDBXW = 0 ++ RBSDBXNF = 0 ++ RBSDBYL = 0 ++ RBSDBYW = 0 ++ RBSDBYNF = 0 ++ NOIA = 6.25E+041 ++ NOIB = 3.125E+026 ++ NOIC = 8.75 ++ EM = 4.1E+007 ++ AF = 1 ++ EF = 1 ++ KF = 0 ++ LINTNOI = 0 ++ NTNOI = 1 ++ TNOIA = 1.5 ++ TNOIB = 3.5 ++ RNOIA = 0.577 ++ RNOIB = 0.5164 ++ DMCG = 0 ++ DMCI = 0 ++ DMDG = 0 ++ DMCGT = 0 ++ DWJ = 0 ++ XGW = 0 ++ XGL = 0 ++ XL = 0 ++ XW = 0 ++ NGCON = 1 ++ IJTHSREV = 0.1 ++ IJTHSFWD = 0.1 ++ XJBVS = 1 ++ BVS = 10 ++ JSS = 0.0001 ++ JSWS = 0 ++ JSWGS = 0 ++ JTSS = 0 ++ JTSSWS = 0 ++ JTSSWGS = 0 ++ JTWEFF = 0 ++ NJS = 15 ++ NJTS = 20 ++ NJTSSW = 20 ++ NJTSSWG = 20 ++ XTSS = 0.02 ++ XTSSWS = 0.02 ++ XTSSWGS = 0.02 ++ VTSS = 10 ++ VTSSWS = 10 ++ VTSSWGS = 10 ++ TNJTS = 0 ++ TNJTSSW = 0 ++ TNJTSSWG = 0 ++ CJS = 0.0005 ++ MJS = 0.5 ++ MJSWS = 0.33 ++ CJSWS = 5E-010 ++ CJSWGS = 5E-010 ++ MJSWGS = 0.33 ++ PBS = 1 ++ PBSWS = 1 ++ PBSWGS = 1 ++ IJTHDREV = 4.878E-003 ++ IJTHDFWD = 4.878E-003 ++ XJBVD = 1 ++ BVD = 10 ++ JSD = 1.004E-014 ++ JSWD = 2.467E-018 ++ JSWGD = 0 ++ JTSD = 0 ++ JTSSWD = 0 ++ JTSSWGD = 0 ++ NJD = 15 ++ NJTSD = 20 ++ NJTSSWD = 20 ++ NJTSSWGD = 20 ++ XTSD = 0.02 ++ XTSSWD = 0.02 ++ XTSSWGD = 0.02 ++ VTSD = 10 ++ VTSSWD = 10 ++ VTSSWGD = 10 ++ TNJTSD = 0 ++ TNJTSSWD = 0 ++ TNJTSSWGD = 0 ++ CJD = 0.0009368 ++ MJD = 0.3545 ++ MJSWD = 0.3141 ++ CJSWD = 7.65E-011 ++ CJSWGD = 5E-010 ++ MJSWGD = 0.33 ++ PBD = 0.9594 ++ PBSWD = 0.9109 ++ PBSWGD = 1 ++ TNOM = -253 ++ UTE = 0 ++ UCSTE = -0.004775 ++ KT1 = -0.11 ++ KT1L = 0 ++ KT2 = 0.022 ++ UA1 = 1E-009 ++ UB1 = -1E-018 ++ UC1 = -0.056 ++ UD1 = 0 ++ AT = 3.3E+004 ++ PRT = 0 ++ XTIS = 3 ++ XTID = 3 ++ TPB = 0 ++ TPBSW = 0 ++ TPBSWG = 0 ++ TCJ = 0 ++ TCJSW = 0 ++ TCJSWG = 0 ++ TVOFF = 0 ++ TVFBSDOFF = 0 ++ SAREF = 0 ++ SBREF = 0 ++ WLOD = 2E-006 ++ KU0 = 4E-006 ++ KVSAT = 0.2 ++ TKU0 = 0 ++ LKU0 = 1E-006 ++ WKU0 = 1E-006 ++ PKU0 = 0 ++ LLODKU0 = 1.1 ++ WLODKU0 = 1.1 ++ KVTH0 = -2E-008 ++ LKVTH0 = 1.1E-006 ++ WKVTH0 = 1.1E-006 ++ PKVTH0 = 0 ++ LLODVTH = 1 ++ WLODVTH = 1 ++ STK2 = 0 ++ LODK2 = 1 ++ STETA0 = 0 ++ LODETA0 = 1 ++ WEB = 0 ++ WEC = 0 ++ KVTH0WE = 0 ++ K2WE = 0 ++ KU0WE = 0 ++ SCREF = 1E-006 ++ WL = 7.641E-015 ++ WLN = 0.9975 ++ WW = -1E-014 ++ WWN = 1.012 ++ WWL = -1.218E-021 ++ LL = -3.165E-015 ++ LLN = 1 ++ LW = -4.827E-015 ++ LWN = 1 ++ LWL = 1.182E-021 ++ LLC = 0 ++ LWC = 0 ++ LWLC = 0 ++ WLC = 0 ++ WWC = 0 ++ WWLC = 0 +* +* diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A.magicrc b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A.magicrc new file mode 100644 index 000000000..9bb1dbd6c --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A.magicrc @@ -0,0 +1,86 @@ +puts stdout "Sourcing design .magicrc for technology sky130A ..." + +# Put grid on 0.005 pitch. This is important, as some commands don't +# rescale the grid automatically (such as lef read?). + +set scalefac [tech lambda] +if {[lindex $scalefac 1] < 2} { + scalegrid 1 2 +} + +# drc off +drc euclidean on +# Change this to a fixed number for repeatable behavior with GDS writes +# e.g., "random seed 12345" +catch {random seed} + +# Turn off the scale option on ext2spice or else it conflicts with the +# scale in the model files. +ext2spice scale off + +# Allow override of PDK path from environment variable PDKPATH +if {[catch {set PDKPATH $env(PDKPATH)}]} { + set PDKPATH $env(PDK_ROOT)/sky130A +} + +# loading technology +tech load $PDKPATH/libs.tech/magic/sky130A.tech + +# load device generator +source $PDKPATH/libs.tech/magic/sky130A.tcl + +# load bind keys (optional) +# source $PDKPATH/libs.tech/magic/sky130A-BindKeys + +# set units to lambda grid +snap lambda + +# set sky130 standard power, ground, and substrate names +set VDD VPWR +set GND VGND +set SUB VSUBS + +# Allow override of type of magic library views used, "mag" or "maglef", +# from environment variable MAGTYPE + +if {[catch {set MAGTYPE $env(MAGTYPE)}]} { + set MAGTYPE mag +} + +# add path to reference cells +if {[file isdir ${PDKPATH}/libs.ref/${MAGTYPE}]} { + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_pr + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_io + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_hd + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_hdll + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_hs + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_hvl + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_lp + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_ls + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_ms + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_osu_sc + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_osu_sc_t18 + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_ml_xx_hd + addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_sram_macros +} else { + addpath ${PDKPATH}/libs.ref/sky130_fd_pr/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_io/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_hd/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_hdll/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_hs/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_hvl/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_lp/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_ls/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_fd_sc_ms/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_osu_sc/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_osu_sc_t18/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_ml_xx_hd/${MAGTYPE} + addpath ${PDKPATH}/libs.ref/sky130_sram_macros/${MAGTYPE} +} + +# add path to GDS cells + +# add path to IP from catalog. This procedure defined in the PDK script. +catch {magic::query_mylib_ip} +# add path to local IP from user design space. Defined in the PDK script. +catch {magic::query_my_projects} diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A_setup.tcl b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A_setup.tcl new file mode 100644 index 000000000..ede844e37 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130A/sky130A_setup.tcl @@ -0,0 +1,419 @@ +#--------------------------------------------------------------- +# Setup file for netgen LVS +# SkyWater sky130A +#--------------------------------------------------------------- +permute default +property default +property parallel none + +# Allow override of default #columns in the output format. +catch {format $env(NETGEN_COLUMNS)} + +#--------------------------------------------------------------- +# For the following, get the cell lists from +# circuit1 and circuit2. +#--------------------------------------------------------------- + +set cells1 [cells list -all -circuit1] +set cells2 [cells list -all -circuit2] + +# NOTE: In accordance with the LVS manager GUI, the schematic is +# always circuit2, so some items like property "par1" only need to +# be specified for circuit2. + +#------------------------------------------- +# Resistors (except metal) +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__res_iso_pw +lappend devices sky130_fd_pr__res_high_po_0p35 +lappend devices sky130_fd_pr__res_high_po_0p69 +lappend devices sky130_fd_pr__res_high_po_1p41 +lappend devices sky130_fd_pr__res_high_po_2p85 +lappend devices sky130_fd_pr__res_high_po_5p73 +lappend devices sky130_fd_pr__res_high_po +lappend devices sky130_fd_pr__res_xhigh_po_0p35 +lappend devices sky130_fd_pr__res_xhigh_po_0p69 +lappend devices sky130_fd_pr__res_xhigh_po_1p41 +lappend devices sky130_fd_pr__res_xhigh_po_2p85 +lappend devices sky130_fd_pr__res_xhigh_po_5p73 +lappend devices sky130_fd_pr__res_xhigh_po +lappend devices sky130_fd_pr__res_generic_nd +lappend devices sky130_fd_pr__res_generic_pd +lappend devices sky130_fd_pr__res_generic_nd__hv +lappend devices sky130_fd_pr__res_generic_pd__hv +lappend devices mrdn_hv mrdp_hv + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + permute "-circuit1 $dev" 1 2 + property "-circuit1 $dev" series enable + property "-circuit1 $dev" series {w critical} + property "-circuit1 $dev" series {l add} + property "-circuit1 $dev" parallel enable + property "-circuit1 $dev" parallel {l critical} + property "-circuit1 $dev" parallel {w add} + property "-circuit1 $dev" parallel {value par} + property "-circuit1 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit1 $dev" delete mult + } + if {[lsearch $cells2 $dev] >= 0} { + permute "-circuit2 $dev" 1 2 + property "-circuit2 $dev" series enable + property "-circuit2 $dev" series {w critical} + property "-circuit2 $dev" series {l add} + property "-circuit2 $dev" parallel enable + property "-circuit2 $dev" parallel {l critical} + property "-circuit2 $dev" parallel {w add} + property "-circuit2 $dev" parallel {value par} + property "-circuit2 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit2 $dev" delete mult + } +} + +#------------------------------------------- +# MRM (metal) resistors and poly resistor +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__res_generic_po +lappend devices sky130_fd_pr__res_generic_l1 +lappend devices sky130_fd_pr__res_generic_m1 +lappend devices sky130_fd_pr__res_generic_m2 +lappend devices sky130_fd_pr__res_generic_m3 +lappend devices sky130_fd_pr__res_generic_m4 +lappend devices sky130_fd_pr__res_generic_m5 + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + permute "-circuit1 $dev" end_a end_b + property "-circuit1 $dev" series enable + property "-circuit1 $dev" series {w critical} + property "-circuit1 $dev" series {l add} + property "-circuit1 $dev" parallel enable + property "-circuit1 $dev" parallel {l critical} + property "-circuit1 $dev" parallel {w add} + property "-circuit1 $dev" parallel {value par} + property "-circuit1 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit1 $dev" delete mult + } + if {[lsearch $cells2 $dev] >= 0} { + permute "-circuit2 $dev" end_a end_b + property "-circuit2 $dev" series enable + property "-circuit2 $dev" series {w critical} + property "-circuit2 $dev" series {l add} + property "-circuit2 $dev" parallel enable + property "-circuit2 $dev" parallel {l critical} + property "-circuit2 $dev" parallel {w add} + property "-circuit2 $dev" parallel {value par} + property "-circuit2 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit2 $dev" delete mult + } +} + +#------------------------------------------- +# (MOS) transistors +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__nfet_01v8 +lappend devices sky130_fd_pr__nfet_01v8_lvt +lappend devices sky130_fd_bs_flash__special_sonosfet_star +lappend devices sky130_fd_pr__nfet_g5v0d10v5 +lappend devices sky130_fd_pr__nfet_05v0_nvt +lappend devices sky130_fd_pr__pfet_01v8 +lappend devices sky130_fd_pr__pfet_01v8_lvt +lappend devices sky130_fd_pr__pfet_01v8_mvt +lappend devices sky130_fd_pr__pfet_01v8_hvt +lappend devices sky130_fd_pr__pfet_g5v0d10v5 +lappend devices sky130_fd_pr__special_pfet_pass +lappend devices sky130_fd_pr__special_nfet_pass +lappend devices sky130_fd_pr__special_nfet_latch +lappend devices sky130_fd_pr__cap_var_lvt +lappend devices sky130_fd_pr__cap_var_hvt +lappend devices sky130_fd_pr__cap_var +lappend devices sky130_fd_pr__nfet_20v0_nvt +lappend devices sky130_fd_pr__nfet_20v0 +lappend devices sky130_fd_pr__pfet_20v0 + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + permute "-circuit1 $dev" 1 3 + property "-circuit1 $dev" parallel enable + property "-circuit1 $dev" parallel {l critical} + property "-circuit1 $dev" parallel {w add} + property "-circuit1 $dev" tolerance {w 0.01} {l 0.01} + # Ignore these properties + property "-circuit1 $dev" delete as ad ps pd mult sa sb sd nf nrd nrs + } + if {[lsearch $cells2 $dev] >= 0} { + permute "-circuit2 $dev" 1 3 + property "-circuit2 $dev" parallel enable + property "-circuit2 $dev" parallel {l critical} + property "-circuit2 $dev" parallel {w add} + property "-circuit2 $dev" tolerance {w 0.01} {l 0.01} + # Ignore these properties + property "-circuit2 $dev" delete as ad ps pd mult sa sb sd nf nrd nrs + } +} + +#------------------------------------------- +# diodes +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__diode_pw2nd_05v5 +lappend devices sky130_fd_pr__diode_pw2nd_05v5_lvt +lappend devices sky130_fd_pr__diode_pw2nd_05v5_nvt +lappend devices sky130_fd_pr__diode_pd2nw_05v5 +lappend devices sky130_fd_pr__diode_pd2nw_05v5_lvt +lappend devices sky130_fd_pr__diode_pd2nw_05v5_hvt +lappend devices sky130_fd_pr__diode_pw2nd_11v0 +lappend devices sky130_fd_pr__diode_pd2nw_11v0 + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + property "-circuit1 $dev" parallel enable + property "-circuit1 $dev" parallel {area add} + property "-circuit1 $dev" parallel {value add} + property "-circuit1 $dev" tolerance {area 0.02} + # Ignore these properties + property "-circuit1 $dev" delete mult perim + } + if {[lsearch $cells2 $dev] >= 0} { + property "-circuit2 $dev" parallel enable + property "-circuit2 $dev" parallel {area add} + property "-circuit2 $dev" parallel {value add} + property "-circuit2 $dev" tolerance {area 0.02} + # Ignore these properties + property "-circuit2 $dev" delete mult perim + } +} + +#------------------------------------------- +# capacitors +# MiM capacitors +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__cap_mim_m3_1 +lappend devices sky130_fd_pr__cap_mim_m3_2 + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + property "-circuit1 $dev" parallel enable + property "-circuit1 $dev" parallel {area add} + property "-circuit1 $dev" parallel {value add} + property "-circuit1 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit1 $dev" delete mult perim mf + } + if {[lsearch $cells2 $dev] >= 0} { + property "-circuit2 $dev" parallel enable + property "-circuit2 $dev" parallel {area add} + property "-circuit2 $dev" parallel {value add} + property "-circuit2 $dev" tolerance {l 0.01} {w 0.01} + # Ignore these properties + property "-circuit2 $dev" delete mult perim mf + } +} + +#------------------------------------------- +# Fixed-layout devices +# bipolar transistors, +# VPP capacitors +#------------------------------------------- + +set devices {} +lappend devices sky130_fd_pr__npn_05v5_W1p00L1p00 +lappend devices sky130_fd_pr__npn_05v5_W1p00L2p00 +lappend devices sky130_fd_pr__pnp_05v5_W0p68L0p68 +lappend devices sky130_fd_pr__pnp_05v5_W3p40L3p40 +lappend devices sky130_fd_pr__npn_05v5 +lappend devices sky130_fd_pr__pnp_05v5 +lappend devices sky130_fd_pr__npn_11v0 + +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_lim5_shield +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_m3_lim5_shield +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_m4_shield +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_pom4_shield +lappend devices sky130_fd_pr__cap_vpp_4p4x4p6_m3_lim5_shield +lappend devices sky130_fd_pr__cap_vpp_6p8x6p1_lim4_shield +lappend devices sky130_fd_pr__cap_vpp_6p8x6p1_polym4_shield +lappend devices sky130_fd_pr__cap_vpp_8p6x7p9_m3_lim5_shield +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_m3_li_shield +lappend devices sky130_fd_pr__cap_vpp_11p5x11p7_m3_shield +lappend devices sky130_fd_pr__cap_vpp_1p8x1p8_li_shield +lappend devices sky130_fd_pr__cap_vpp_1p8x1p8_m3_shield +lappend devices sky130_fd_pr__cap_vpp_4p4x4p6_m3_li_shield +lappend devices sky130_fd_pr__cap_vpp_4p4x4p6_m3_shield +lappend devices sky130_fd_pr__cap_vpp_8p6x7p9_m3_li_shield +lappend devices sky130_fd_pr__cap_vpp_8p6x7p9_m3_shield +lappend devices sky130_fd_pr__ind_04_01 +lappend devices sky130_fd_pr__ind_04_02 + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + property "-circuit1 $dev" parallel enable + # Ignore these properties + property "-circuit1 $dev" delete mult + } + if {[lsearch $cells2 $dev] >= 0} { + property "-circuit2 $dev" parallel enable + # Ignore these properties + property "-circuit2 $dev" delete mult + } +} + +#--------------------------------------------------------------- +# Schematic cells which are not extractable +#--------------------------------------------------------------- + +set devices {sky130_fd_io__condiode sky130_fd_io__tap_1} + +foreach dev $devices { + if {[lsearch $cells1 $dev] >= 0} { + ignore class "-circuit1 $dev" + } + if {[lsearch $cells2 $dev] >= 0} { + ignore class "-circuit2 $dev" + } +} + +#--------------------------------------------------------------- +# Digital cells (ignore decap, fill, and tap cells) +# Make a separate list for each supported library +#--------------------------------------------------------------- +# e.g., ignore class "-circuit2 sky130_fc_sc_hd__decap_3" +#--------------------------------------------------------------- + +if { [info exist ::env(MAGIC_EXT_USE_GDS)] && $::env(MAGIC_EXT_USE_GDS) } { + foreach cell $cells1 { +# if {[regexp {sky130_fd_sc_[^_]+__decap_[[:digit:]]+} $cell match]} { +# ignore class "-circuit1 $cell" +# } + if {[regexp {sky130_fd_sc_[^_]+__fill_[[:digit:]]+} $cell match]} { + ignore class "-circuit1 $cell" + } + if {[regexp {sky130_fd_sc_[^_]+__tapvpwrvgnd_[[:digit:]]+} $cell match]} { + ignore class "-circuit1 $cell" + } + if {[regexp {sky130_ef_sc_[^_]+__fakediode_[[:digit:]]+} $cell match]} { + ignore class "-circuit1 $cell" + } + } + foreach cell $cells2 { +# if {[regexp {sky130_fd_sc_[^_]+__decap_[[:digit:]]+} $cell match]} { +# ignore class "-circuit2 $cell" +# } + if {[regexp {sky130_fd_sc_[^_]+__fill_[[:digit:]]+} $cell match]} { + ignore class "-circuit2 $cell" + } + if {[regexp {sky130_fd_sc_[^_]+__tapvpwrvgnd_[[:digit:]]+} $cell match]} { + ignore class "-circuit2 $cell" + } + if {[regexp {sky130_ef_sc_[^_]+__fakediode_[[:digit:]]+} $cell match]} { + ignore class "-circuit2 $cell" + } + } +} + +#--------------------------------------------------------------- +# Allow the fill, decap, etc., cells to be parallelized +#--------------------------------------------------------------- + +foreach cell $cells1 { + if {[regexp {sky130_fd_sc_[^_]+__decap_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__fill_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__tapvpwrvgnd_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__diode_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__fill_diode_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } + if {[regexp {sky130_ef_sc_[^_]+__fakediode_[[:digit:]]+} $cell match]} { + property "-circuit1 $cell" parallel enable + } +} +foreach cell $cells2 { + if {[regexp {sky130_fd_sc_[^_]+__decap_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__fill_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__tapvpwrvgnd_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__diode_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } + if {[regexp {sky130_fd_sc_[^_]+__fill_diode_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } + if {[regexp {sky130_ef_sc_[^_]+__fakediode_[[:digit:]]+} $cell match]} { + property "-circuit2 $cell" parallel enable + } +} + +#--------------------------------------------------------------- +# Handle cells captured from Electric +# +# Find cells of the form "__" in the netlist +# from Electric where the extracted layout netlist has only +# "". Cross-check by ensuring that the full name +# "__" does not exist in both cells, and that +# the truncated name "" does not exist in both cells. +#--------------------------------------------------------------- +# e.g., hydra_spi_controller__hydra_spi_controller +#--------------------------------------------------------------- + +foreach cell $cells1 { + if {[regexp "(.+)__(.+)" $cell match library cellname]} { + if {([lsearch $cells2 $cell] < 0) && \ + ([lsearch $cells2 $cellname] >= 0) && \ + ([lsearch $cells1 $cellname] < 0)} { + equate classes "-circuit1 $cell" "-circuit2 $cellname" + puts stdout "Matching pins of $cell in circuit 1 and $cellname in circuit 2" + equate pins "-circuit1 $cell" "-circuit2 $cellname" + } + } +} + +foreach cell $cells2 { + if {[regexp "(.+)__(.+)" $cell match library cellname]} { + if {([lsearch $cells1 $cell] < 0) && \ + ([lsearch $cells1 $cellname] >= 0) && \ + ([lsearch $cells2 $cellname] < 0)} { + equate classes "-circuit1 $cellname" "-circuit2 $cell" + puts stdout "Matching pins of $cellname in circuit 1 and $cell in circuit 2" + equate pins "-circuit1 $cellname" "-circuit2 $cell" + } + } +} + +# Match pins on black-box cells if LVS is called with "-blackbox" +if {[model blackbox]} { + foreach cell $cells1 { + if {[model "-circuit1 $cell"] == "blackbox"} { + if {[lsearch $cells2 $cell] >= 0} { + puts stdout "Matching pins of $cell in circuits 1 and 2" + equate pins "-circuit1 $cell" "-circuit2 $cell" + } + } + } +} + +#--------------------------------------------------------------- diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py new file mode 100644 index 000000000..5e882afed --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py @@ -0,0 +1,848 @@ +import sys +from os import path, rename, environ +environ['OPENBLAS_NUM_THREADS'] = '1' +# path to glayout +sys.path.append(path.join(path.dirname(__file__), '../../')) + +from gdsfactory.read.import_gds import import_gds +from gdsfactory.components import text_freetype, rectangle +from glayout.flow.pdk.util.comp_utils import prec_array, movey, align_comp_to_port, prec_ref_center +from glayout.flow.pdk.util.port_utils import add_ports_perimeter, print_ports +from gdsfactory.component import Component +from glayout.flow.pdk.mappedpdk import MappedPDK +from ota2 import super_class_AB_OTA +from glayout.flow.routing.L_route import L_route +from glayout.flow.routing.straight_route import straight_route +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_ref_center, prec_center, align_comp_to_port +from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid +from gdsfactory.components import text_freetype, rectangle +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.primitives.via_gen import via_array, via_stack +from c_route import c_route +from gdsfactory.cell import cell, clear_cache +import numpy as np +from subprocess import Popen +from pathlib import Path +from typing import Union, Optional, Literal, Iterable +from tempfile import TemporaryDirectory +from shutil import copyfile, copytree +from multiprocessing import Pool +import matplotlib.pyplot as plt +from scipy.stats import norm +from scipy.optimize import curve_fit +from scipy.spatial.distance import pdist, squareform +import pandas as pd +import seaborn as sns +from sklearn.decomposition import PCA +from sklearn.cluster import KMeans, AgglomerativeClustering +from sklearn.metrics import silhouette_score +import argparse +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as pdk +from itertools import count, repeat +from glayout.flow.pdk.util.component_array_create import write_component_matrix +import re +import pickle +import tempfile +import subprocess +import traceback + +global _TAPEOUT_AND_RL_DIR_PATH_ +global _GET_PARAM_SET_LENGTH_ +global PDK_ROOT +global __NO_LVT_GLOBAL_ +global __SMALL_PAD_ +__SMALL_PAD_ = True +__NO_LVT_GLOBAL_ = False +_GET_PARAM_SET_LENGTH_ = False + +if 'PDK_ROOT' in environ: + PDK_ROOT = str(Path(environ['PDK_ROOT']).resolve()) +else: + PDK_ROOT = "/usr/bin/miniconda3/share/pdk/" + +_TAPEOUT_AND_RL_DIR_PATH_ = Path(__file__).resolve().parent +#print(_TAPEOUT_AND_RL_DIR_PATH_) + +# ====Build Ota==== + +def sky130_ota_add_pads(ota_in: Component, flatten=False) -> Component: + """adds the MPW-5 pads and nano pads to ota. + Also adds text labels and pin layers so that extraction is nice + this function does not need to be used with sky130_add_ota_labels + """ + ota_wpads = ota_in.copy() + ota_wpads = movey(ota_wpads, destination=0) + # create pad array and add to ota + global __SMALL_PAD_ + small_pad=__SMALL_PAD_ + if small_pad: + pad = import_gds("pads/pad_60um_flat.gds") + pad.name = "NISTpad" + else: + pad = import_gds("pads/Manhattan120umPad.gds") + pad.name = "Manhattan120umPad" + pad = add_ports_perimeter(pad, pdk.get_glayer("met5"),prefix="pad_") + if small_pad: + pad_array = prec_array(pad, rows=2, columns=(4), spacing=(80,240)) + else: + pad_array = prec_array(pad, rows=2, columns=(4), spacing=(160,240)) + pad_array_ref = prec_ref_center(pad_array) + ota_wpads.add(pad_array_ref) + # add via_array to vdd pin + """ + vddarray = via_array(pdk, "met3","met4",size=(ota_wpads.ports["VCC_top_met_N"].width,3*ota_wpads.ports["VCC_top_met_E"].width)) + via_array_ref = ota_wpads << vddarray + align_comp_to_port(via_array_ref,ota_wpads.ports["VCC_top_met_N"],alignment=('c','b')) + """ + # route to the pads + leftroutelayer="met5" + ota_wpads << L_route(pdk, ota_wpads.ports["PLUS_top_met_E"],pad_array_ref.ports["row1_col3_pad_S"], hwidth=3, vwidth=3) + ota_wpads << L_route(pdk, ota_wpads.ports["MINUS_top_met_W"],pad_array_ref.ports["row1_col0_pad_S"], hwidth=3, vwidth=3) + ota_wpads << L_route(pdk, pad_array_ref.ports["row1_col1_pad_E"],ota_wpads.ports["VCC_top_met_N"], vwidth=4, hwidth=4, vglayer='met3', hglayer='met4') + ota_wpads << L_route(pdk, ota_wpads.ports["VSS_top_met_E"],pad_array_ref.ports["row0_col3_pad_N"], hwidth=4, vwidth=4) + ota_wpads << L_route(pdk, ota_wpads.ports["IBIAS2_top_met_E"],pad_array_ref.ports["row0_col2_pad_N"], hwidth=3, vwidth=3) + ota_wpads << L_route(pdk, ota_wpads.ports["IBIAS1_top_met_W"],pad_array_ref.ports["row0_col1_pad_N"],hwidth=3, vwidth=3) + ota_wpads << L_route(pdk, ota_wpads.ports["DIFFOUT_top_met_W"],pad_array_ref.ports["row0_col0_pad_N"], hwidth=4, vwidth=4) + # add pin layer and text labels for LVS + text_pin_labels = list() + met5pin = rectangle(size=(5,5),layer=(72,16), centered=True) + for name in ["vout","nbc_10u","nb_10u","avss","inm","avdd","nc","inp"]: + pin_w_label = met5pin.copy() + pin_w_label.add_label(text=name,layer=(72,5),magnification=4) + text_pin_labels.append(pin_w_label) + for row in range(2): + for col_u in range(4): + col = col_u + port_name = "row"+str(row)+"_col"+str(col)+"_pad_S" + pad_array_port = pad_array_ref.ports[port_name] + pin_ref = ota_wpads << text_pin_labels[4*row + col_u] + align_comp_to_port(pin_ref,pad_array_port,alignment=('c','t')) + """ + # import nano pad and add to ota + nanopad = import_gds("pads/sky130_nano_pad.gds") + nanopad.name = "nanopad" + nanopad = add_ports_perimeter(nanopad, pdk.get_glayer(leftroutelayer),prefix="nanopad_") + nanopad_array = prec_array(nanopad, rows=2, columns=2, spacing=(10,10)) + nanopad_array_ref = nanopad_array.ref_center() + ota_wpads.add(nanopad_array_ref) + nanopad_array_ref.movex(ota_wpads.xmin+nanopad_array.xmax) + # route nano pad connections + ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row1_col0_nanopad_N"],pad_array_ref.ports["row1_col0_pad_S"],width=3,glayer2=leftroutelayer) + ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row0_col0_nanopad_S"],pad_array_ref.ports["row0_col0_pad_N"],width=3,glayer2=leftroutelayer) + ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row0_col1_nanopad_E"],pad_array_ref.ports["row0_col1_pad_N"],width=3,glayer2=leftroutelayer) + ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row1_col1_nanopad_E"],pad_array_ref.ports["row1_col1_pad_S"],width=3,glayer2=leftroutelayer) + """ + if flatten: + return ota_wpads.flatten() + else: + return ota_wpads + +def sky130_add_ota_labels(ota_in: Component) -> Component: + + ota_in.unlock() + # define layers + met1_pin = (68,16) + met1_label = (68,5) + met2_pin = (69,16) + met2_label = (69,5) + met3_pin = (70,16) + met3_label = (70,5) + # list that will contain all port/comp info + move_info = list() + # create labels and append to info list + # gnd + gndlabel = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + gndlabel.add_label(text="AVSS",layer=met2_label) + move_info.append((gndlabel,ota_in.ports["VSS_top_met_N"],None)) + + #currentbias + ibias1label = rectangle(layer=met3_pin,size=(0.5,0.5),centered=True).copy() + ibias1label.add_label(text="NBC_10U",layer=met3_label) + move_info.append((ibias1label,ota_in.ports["IBIAS1_top_met_N"],None)) + ibias2label = rectangle(layer=met3_pin,size=(0.5,0.5),centered=True).copy() + ibias2label.add_label(text="NB_10U",layer=met3_label) + move_info.append((ibias2label,ota_in.ports["IBIAS2_top_met_N"],None)) + + #vcc + vcclabel = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + vcclabel.add_label(text="AVDD",layer=met2_label) + move_info.append((vcclabel,ota_in.ports["VCC_top_met_N"],None)) + + # output (3rd stage) + outputlabel = rectangle(layer=met3_pin,size=(0.5,0.5),centered=True).copy() + outputlabel.add_label(text="VOUT",layer=met3_label) + move_info.append((outputlabel,ota_in.ports["DIFFOUT_top_met_N"],None)) + + # input + p_inputlabel = rectangle(layer=met3_pin,size=(0.5,0.5),centered=True).copy() + p_inputlabel.add_label(text="INP",layer=met3_label) + move_info.append((p_inputlabel,ota_in.ports["PLUS_top_met_N"], None)) + m_inputlabel = rectangle(layer=met3_pin,size=(0.5,0.5),centered=True).copy() + m_inputlabel.add_label(text="INM",layer=met3_label) + move_info.append((m_inputlabel,ota_in.ports["MINUS_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) + ota_in.add(compref) + return ota_in.flatten() + + + +def sky130_add_ota_lvt_layer(ota_in: Component) -> Component: + global __NO_LVT_GLOBAL_ + if __NO_LVT_GLOBAL_: + return ota_in + ota_in.unlock() + + lvt_layer=(125,44) + + dimensions = (evaluate_bbox(ota_in)[0], (ota_in.ports["VCC_top_met_N"].center[1] - ota_in.ports["res_1_N_tie_S_top_met_S"].center[1])) + + lvt_rectangle = rectangle(layer=lvt_layer, size=(dimensions[0], dimensions[1])) + lvt_rectangle_ref = prec_ref_center(lvt_rectangle) + lvt_rectangle_ref.movey(ota_in.ports["res_1_N_tie_S_top_met_S"].center[1] + dimensions[1]/2) + ota_in.add(lvt_rectangle_ref) + + return ota_in + + +def ota_parameters_serializer( + input_pair_params: tuple[float,float]=(4,2), + fvf_shunt_params: tuple[float,float]=(2.75,1), + local_current_bias_params: tuple[float,float]=(3.76,3.0), + diff_pair_load_params: tuple[float,float]=(9,1), + ratio: int=1, + current_mirror_params: tuple[float,float]=(2.25,1), + resistor_params: tuple[float,float,float,float]=(0.5,3,4,4), + global_current_bias_params: tuple[float,float,float]=(8.3,1.42,2) + +) -> np.array: + """converts ota params into the uniform numpy float format""" + return np.array( + [input_pair_params[0],input_pair_params[1], + fvf_shunt_params[0],fvf_shunt_params[1], + local_current_bias_params[0],local_current_bias_params[1], + diff_pair_load_params[0],diff_pair_load_params[1], + ratio, + current_mirror_params[0],current_mirror_params[1], + resistor_params[0],resistor_params[1],resistor_params[2],resistor_params[3], + global_current_bias_params[0],global_current_bias_params[1],global_current_bias_params[2]], + dtype=np.float64 + ) + +def ota_parameters_de_serializer(serialized_params: Optional[np.array]=None) -> dict: + """converts uniform numpy float format to ota kwargs""" + if serialized_params is None: + serialized_params = 18*[-987.654321] + #serialized_params[16] = int(-987.654321) + #serialized_params[17] = int(-987.654321) + if not len(serialized_params) == 18: + raise ValueError("serialized_params should be a length 18 array") + params_dict = dict() + params_dict["input_pair_params"] = tuple(serialized_params[0:2]) + params_dict["fvf_shunt_params"] = tuple(serialized_params[2:4]) + params_dict["local_current_bias_params"] = tuple(serialized_params[4:6]) + params_dict["diff_pair_load_params"] = tuple(serialized_params[6:8]) + params_dict["ratio"] = int(serialized_params[8]) + params_dict["current_mirror_params"] = tuple(serialized_params[9:11]) + params_dict["resistor_params"] = tuple(serialized_params[11:15]) + params_dict["global_current_bias_params"] = tuple(serialized_params[15:]) + return params_dict + + +def ota_results_serializer( + ugb: float = -987.654321, + dcGain: float = -987.654321, + phaseMargin: float = -987.654321, + Ibias1: float = -987.654321, + Ibias2: float = -987.654321, + area: float = -987.654321, + power: float = -987.654321, + noise: float = -987.654321, + bw_3db: float = -987.654321, + rise_slew: float = -987.654321, + fall_slew: float = -987.654321, +) -> np.array: + return np.array([ugb, dcGain, phaseMargin, Ibias1, Ibias2, area, power, noise, bw_3db, rise_slew, fall_slew], dtype=np.float64) + + +def ota_results_de_serializer( + results: Optional[np.array]=None +) -> dict: + results_length_const = 11 + if results is None: + results = results_length_const*[-987.654321] + if not len(results) == results_length_const: + raise ValueError("results should be a length "+str(results_length_const)+" array") + results_dict = dict() + results_dict["ugb"] = float(results[0]) + results_dict["dcGain"] = float(results[1]) + results_dict["phaseMargin"] = float(results[2]) + results_dict["Ibias1"] = float(results[3]) + results_dict["Ibias2"] = float(results[4]) + results_dict["area"] = float(results[5]) + results_dict["power"] = float(results[6]) + results_dict["noise"] = float(results[7]) + results_dict["bw_3db"] = float(results[8]) + results_dict["rise_slew"] = float(results[9]) + results_dict["fall_slew"] = float(results[10]) + + return results_dict + + +def get_small_parameter_list(test_mode = False) -> np.array: + """creates small parameter list intended for brute force""" + # all diffpairs to try + inputpair = list() + if test_mode: + diffpairs.append((4,2)) + else: + for width in [3,4,5]: + for length in [1.7,2,2.3]: + inputpair.append((width,length)) + # all bias2 (output amp bias) transistors + fvfshunt = list() + if test_mode: + fvfshunt.append((2.75,1)) + else: + for width in [2.5,2.75,3]: + for length in [0.8,1,1.2]: + fvfshunt.append((width,length)) + # all pmos first stage load transistors + local_cm = list() + if test_mode: + local_cm.append((3.76,3)) + else: + for width in [3.5,3.75,4]: + for length in [2.5,3,3.5]: + local_cm.append((width,length)) + # all output pmos transistors + diffp_load = list() + if test_mode: + diffp_load.append((9,1)) + else: + for width in [7,8,9,10]: + for length in [1]: + diffp_load.append((width,length)) + + ratio = list() + if test_mode: + ratio.append((1)) + else: + for amp in [1,2]: + ratio.append((amp)) + + op_cm = list() + if test_mode: + local_cm.append((2.25,1)) + else: + for width in [2,2.25,2.5]: + for length in [1]: + op_cm.append((width,length)) + + res = list() + if test_mode: + res.append((0.5,3,4,4)) + else: + for width1 in [0.5,0.6,0.7]: + for width2 in [2.8,3,3.2]: + for length1 in [4]: + for length2 in [4]: + res.append((width1,width2,length1,length2)) + + cbias = list() + if test_mode: + cbias.append((8.3,1.42,2)) + else: + for width1 in [8.3]: + for width2 in [1.4,1.8,2.2,2.6,3]: + for length in [2]: + cbias.append((width1,width2,length)) + + + short_list_len = len(inputpair) * len(fvfshunt) * len(local_cm) * len(diffp_load) * len(ratio) * len(op_cm) * len(res) *len(cbias) + short_list = np.empty(shape=(short_list_len,len(ota_parameters_serializer())),dtype=np.float64) + index = 0 + + for inputpair_v in inputpair: + for fvfshunt_v in fvfshunt: + for local_cm_v in local_cm: + for diffp_load_v in diffp_load: + for ratio_v in ratio: + for op_cm_v in op_cm: + for res_v in res: + for cbias_v in cbias: + tup_to_add = ota_parameters_serializer( + input_pair_params=inputpair_v, + fvf_shunt_params=fvfshunt_v, + local_current_bias_params=local_cm_v, + diff_pair_load_params=diffp_load_v, + ratio=ratio_v, + current_mirror_params=op_cm_v, + resistor_params=res_v, + global_current_bias_params=cbias_v, + ) + short_list[index] = tup_to_add + + global _GET_PARAM_SET_LENGTH_ + if _GET_PARAM_SET_LENGTH_: + print("created parameter set of length: "+str(len(short_list))) + import sys + sys.exit() + return short_list + + +def get_sim_results(acpath: Union[str,Path], dcpath: Union[str,Path], noisepath: Union[str,Path], slewpath: Union[str,Path]): + acabspath = Path(acpath).resolve() + dcabspath = Path(dcpath).resolve() + noiseabspath = Path(noisepath).resolve() + slewabspath = Path(slewpath).resolve() + ACColumns = None + DCColumns = None + NoiseColumns = None + SlewColumns = None + try: + with open(acabspath, "r") as ACReport: + RawAC = ACReport.readlines()[0] + ACColumns = [item for item in RawAC.split() if item] + except Exception: + pass + try: + with open(dcabspath, "r") as DCReport: + RawDC = DCReport.readlines()[0] + DCColumns = [item for item in RawDC.split() if item] + except Exception: + pass + try: + with open(noiseabspath, "r") as NoiseReport: + RawNoise = NoiseReport.readlines()[0] + NoiseColumns = [item for item in RawNoise.split() if item] + except Exception: + pass + try: + with open(slewabspath, "r") as SlewReport: + RawSlew = SlewReport.readlines()[0] + SlewColumns = [item for item in RawSlew.split() if item] + except Exception: + pass + + na = -987.654321 + noACresults = (ACColumns is None) or len(ACColumns)<10 + noDCresults = (DCColumns is None) or len(DCColumns)<2 + nonoiseresults = (NoiseColumns is None) or len(NoiseColumns)<2 + noslewresults = (SlewColumns is None) or len(SlewColumns)<3 + return_dict = { + "ugb": na if noACresults else ACColumns[1], + "Ibias1": na if noACresults else ACColumns[3], + "Ibias2": na if noACresults else ACColumns[5], + "phaseMargin": na if noACresults else ACColumns[7], + "dcGain": na if noACresults else ACColumns[9], + "bw_3db": na if noACresults else ACColumns[11], + "power": na if noDCresults else DCColumns[1], + "noise": na if nonoiseresults else NoiseColumns[1], + "rise_slew": na if noslewresults else SlewColumns[1], + "fall_slew": na if noslewresults else SlewColumns[3], + } + for key, val in return_dict.items(): + val_flt = na + try: + val_flt = float(val) + except ValueError: + val_flt = na + return_dict[key] = val_flt + return return_dict + + +def process_netlist_subckt(netlist: Union[str,Path], sim_model: Literal["normal model", "cryo model"], cload: float=80.0, noparasitics: bool=False): + netlist = Path(netlist).resolve() + if not netlist.is_file(): + raise ValueError("netlist is not a valid file") + hints = [".subckt","vout","inp","inm","avdd","avss","nb_10u","nbc_10u"] + subckt_lines = list() + with open(netlist, "r") as spice_net: + subckt_lines = spice_net.readlines() + for i,line in enumerate(subckt_lines): + #print(f"Processing line {i}: {line.strip()}") + line = line.strip().lower() + if (i+1)1: + subckt_lines[i] = subckt_lines[i].replace("sky130_fd_pr__nfet_01v8_lvt","nshortlvth") + subckt_lines[i] = subckt_lines[i].replace("sky130_fd_pr__pfet_01v8_lvt","pshort") + subckt_lines[i] = subckt_lines[i].replace("sky130_fd_pr__nfet_01v8","nshort") + if ("nshort" in subckt_lines[i]) or ("pshort" in subckt_lines[i]) or ("nshortlvth" in subckt_lines[i]): + subckt_lines[i] = "M" + subckt_lines[i][1:] + if all([hint in line for hint in hints]): + print(f"Line matches hints: {line.strip()}") + headerstr = ".subckt ota AVSS INM INP VOUT AVDD NBC_10U NB_10U" + subckt_lines[i] = headerstr+"\nCload VOUT AVSS " + str(cload) +"p\n" + print(f"Updated line: {subckt_lines[i]}") + if ("floating" in line) or (noparasitics and len(line) and (line[0]=="c" or line[0]=="r")): + subckt_lines[i] = "* "+ subckt_lines[i] + if noparasitics: + subckt_lines[i] = re.sub(r"ad=(\S*)","",subckt_lines[i]) + subckt_lines[i] = re.sub(r"as=(\S*)","",subckt_lines[i]) + subckt_lines[i] = re.sub(r"ps=(\S*)","",subckt_lines[i]) + subckt_lines[i] = re.sub(r"pd=(\S*)","",subckt_lines[i]) + with open(netlist, "w") as spice_net: + print(f"Writing updated netlist to: {netlist}") + spice_net.writelines(subckt_lines) + + +def process_spice_testbench(testbench: Union[str,Path], temperature_info: tuple[int,str]=(25,"normal model")): + global PDK_ROOT + PDK_ROOT = Path(PDK_ROOT).resolve() + testbench = Path(testbench).resolve() + if not testbench.is_file(): + raise ValueError("testbench must be file") + if not PDK_ROOT.is_dir(): + raise ValueError("PDK_ROOT is not a valid directory") + PDK_ROOT = str(PDK_ROOT) + with open(testbench, "r") as spice_file: + spicetb = spice_file.read() + spicetb = spicetb.replace('{@@TEMP}', str(int(temperature_info[0]))) + spicetb = spicetb.replace("@@PDK_ROOT", PDK_ROOT) + if temperature_info[1] == "cryo model": + spicetb = spicetb.replace("*@@cryo ","") + else: + spicetb = spicetb.replace("*@@stp ","") + with open(testbench, "w") as spice_file: + spice_file.write(spicetb) + +def __run_single_brtfrc(index, parameters_ele, save_gds_dir, temperature_info: tuple[int,str]=(25,"normal model"), cload: float=80.0, noparasitics: bool=False, output_dir: Optional[Union[int,str,Path]] = None, hardfail=False): + # pass pdk as global var to avoid pickling issues + global pdk + global PDK_ROOT + global _TAPEOUT_AND_RL_DIR_PATH_ + # generate layout + destination_gds_copy = save_gds_dir / (str(index)+".gds") + sky130pdk = pdk + params = ota_parameters_de_serializer(parameters_ele) + try: + ota_v = sky130_add_ota_labels(sky130_add_ota_lvt_layer(super_class_AB_OTA(sky130pdk, **params))) + ota_v.name = "ota"+str(index) + area = float(ota_v.area()) + # use temp dir + with TemporaryDirectory() as tmpdirname: + results=None + tmp_gds_path = Path(ota_v.write_gds(gdsdir=tmpdirname)).resolve() + if tmp_gds_path.is_file(): + destination_gds_copy.write_bytes(tmp_gds_path.read_bytes()) + extractbash_template=str() + #import pdb; pdb.set_trace() + with open(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/extract.bash.template","r") as extraction_script: + extractbash_template = extraction_script.read() + extractbash_template = extractbash_template.replace("@@PDK_ROOT",PDK_ROOT).replace("@@@PAROPT","noparasitics" if noparasitics else "na") + with open(str(tmpdirname)+"/extract.bash","w") as extraction_script: + extraction_script.write(extractbash_template) + #copyfile("extract.bash",str(tmpdirname)+"/extract.bash") + copyfile(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/ota_perf_eval.sp",str(tmpdirname)+"/ota_perf_eval.sp") + copytree(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/sky130A",str(tmpdirname)+"/sky130A") + # extract layouti + Popen(["bash","extract.bash", tmp_gds_path, ota_v.name],cwd=tmpdirname).wait() + print("Running simulation at temperature: " + str(temperature_info[0]) + "C") + process_spice_testbench(str(tmpdirname)+"/ota_perf_eval.sp",temperature_info=temperature_info) + process_netlist_subckt(str(tmpdirname)+"/ota"+str(index)+"_pex.spice", temperature_info[1], cload=cload, noparasitics=noparasitics) + rename(str(tmpdirname)+"/ota"+str(index)+"_pex.spice", str(tmpdirname)+"/ota_pex.spice") + # run sim and store result + #import pdb;pdb.set_trace() + Popen(["ngspice","-b","ota_perf_eval.sp"],cwd=tmpdirname).wait() + ac_file = str(tmpdirname)+"/result_ac.txt" + power_file = str(tmpdirname)+"/result_power.txt" + noise_file = str(tmpdirname)+"/result_noise.txt" + slew_file = str(tmpdirname)+"/result_slew.txt" + result_dict = get_sim_results(ac_file, power_file, noise_file, slew_file) + result_dict["area"] = area + results = ota_results_serializer(**result_dict) + if output_dir is not None: + if isinstance(output_dir, int): + output_dir = save_gds_dir / ("dir_"+str(output_dir)) + output_dir = Path(output_dir).resolve() + else: + output_dir = Path(output_dir).resolve() + output_dir.mkdir(parents=True, exist_ok=True) + if not output_dir.is_dir(): + raise ValueError("Output directory must be a directory") + copytree(str(tmpdirname), str(output_dir)+"/test_output", dirs_exist_ok=True) + except Exception as e_LorA: + if hardfail: + raise e_LorA + results = ota_results_serializer() + with open('get_training_data_ERRORS.log', 'a') as errlog: + errlog.write("\nota run "+str(index)+" with the following params failed: \n"+str(params)) + return results + + +def brute_force_full_layout_and_PEXsim(sky130pdk: MappedPDK, parameter_list: np.array, temperature_info: tuple[int,str]=(25,"normal model"), cload: float=80.0, noparasitics: bool=False, saverawsims: bool=False) -> np.array: + """runs the brute force testing of parameters by + 1-constructing the ota layout specfied by parameters + 2-extracting the netlist for the ota + 3-running simulations on the ota + returns the results from ota simulations as nparray + """ + if sky130pdk.name != "sky130": + raise ValueError("this is for sky130 only") + # disable adding NPC layer + add_npc_decorator = sky130pdk.default_decorator + sky130pdk.default_decorator = None + sky130pdk.activate() + # initialize empty results array + results = None + # run layout, extraction, sim + save_gds_dir = Path('./save_gds_by_index').resolve() + save_gds_dir.mkdir(parents=True) + # pass pdk as global var to avoid pickling issues + global pdk + pdk = sky130pdk + with Pool(128) as cores: + if saverawsims: + results = np.array(cores.starmap(safe_single_build_and_simulation, zip(parameter_list, repeat(temperature_info[0]), count(0), repeat(cload), repeat(noparasitics),repeat(False), count(0), repeat(save_gds_dir), repeat(False))),np.float64) + else: + results = np.array(cores.starmap(safe_single_build_and_simulation, zip(parameter_list, repeat(temperature_info[0]), repeat(None), repeat(cload), repeat(noparasitics),repeat(False), count(0), repeat(save_gds_dir), repeat(False))),np.float64) + # undo pdk modification + sky130pdk.default_decorator = add_npc_decorator + return results + + +# data gathering main function +def get_training_data(test_mode: bool=True, temperature_info: tuple[int,str]=(25,"normal model"), cload: float=80.0, noparasitics: bool=False, parameter_array: Optional[np.array]=None, saverawsims=False) -> None: + if temperature_info[1] != "normal model" and temperature_info[1] != "cryo model": + raise ValueError("model must be one of \"normal model\" or \"cryo model\"") + if parameter_array is None: + params = get_small_parameter_list(test_mode) + else: + params = parameter_array + results = brute_force_full_layout_and_PEXsim(pdk, params, temperature_info, cload=cload, noparasitics=noparasitics,saverawsims=saverawsims) + np.save("training_params.npy",params) + np.save("training_results.npy",results) + + +#util function for pure simulation. sky130 is imported automatically +def single_build_and_simulation(parameters: np.array, temp: int=25, output_dir: Optional[Union[str,Path]] = None, cload: float=80.0, noparasitics: bool=False,hardfail=False, index: int = 12345678987654321, save_gds_dir="./", return_dict: bool=True) -> dict: + """Builds, extract, and simulates a single ota + saves ota gds in current directory with name 12345678987654321.gds + returns -987.654321 for all values IF phase margin < 60 + """ + from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk + # process temperature info + temperature_info = [temp, None] + if temperature_info[0] > -20: + temperature_info[1] = "normal model" + elif temperature_info[0]!=-269: + raise ValueError("simulation temperature should be exactly -269C for cryo sim. Below -20C there are no good models for simulation") + else: + temperature_info[1] = "cryo model" + temperature_info = tuple(temperature_info) + # run single build + save_gds_dir = Path(save_gds_dir).resolve() + # pass pdk as global var to avoid pickling issues + global pdk + pdk = sky130_mapped_pdk + results = __run_single_brtfrc(index, parameters, temperature_info=temperature_info, save_gds_dir=save_gds_dir, output_dir=output_dir, cload=cload, noparasitics=noparasitics, hardfail=hardfail) + if return_dict: # default behavoir will return a dictionary and filter phase margin below 45 + results = ota_results_de_serializer(results) + if results["phaseMargin"] < 60: + for key in results: + results[key] = -987.654321 + return results + + + +# ================ safe single build and sim ================== + + +class safe_single_build_and_simulation_helperclass: + def __init__(self, *args, **kwargs): + self.passed_args = args + self.passed_kwargs = kwargs + # create and run using a temp dir to pass information + with tempfile.TemporaryDirectory() as temp_dir: + # Define the path for the pickle file + pickle_file_path = Path(temp_dir).resolve() / 'class_instance.pkl' + # Serialize the instance to the pickle file + with open(pickle_file_path, 'wb') as f: + pickle.dump(self, f) + # Define and run the subprocess + python_executable = sys.executable + command = [python_executable, "sky130_ota_tapeout.py", "safe_single_build_and_sim", "--class_pickle_file", pickle_file_path,"--PDK_ROOT",PDK_ROOT] + #process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.Popen(command,cwd=str(_TAPEOUT_AND_RL_DIR_PATH_)).wait() + # load the result back from the same pickle file which was passed + with open(pickle_file_path, 'rb') as pckfile: + restored_run = pickle.load(pckfile) + # if restored_run does not have a results attribute, that means execute did not run properly in the other session + # single build and sim probably failed + try: + self.results = restored_run.results + except AttributeError: + raise RuntimeError("\nAn error silently occurred somewhere before this point\n") + + + def execute(self): + self.results = single_build_and_simulation(*self.passed_args,**self.passed_kwargs) + +# same as calling single_build_and_simulation, but runs in a subprocess +def safe_single_build_and_simulation(*args, **kwargs) -> dict: + def get_parameter_value(param_name: str, *args, **kwargs): + # Check if the parameter is in kwargs + if param_name in kwargs: + return kwargs[param_name] + # Check if the parameter is in args + try: + # Find the index of the param_name in args and return the next item as its value + index = args.index(param_name) + return args[index + 1] + except (ValueError, IndexError): + # ValueError if param_name is not in args + # IndexError if param_name is the last item and has no value after it + return None + try: + return safe_single_build_and_simulation_helperclass(*args,**kwargs).results + except Exception as e_LorA: + if bool(get_parameter_value("hardfail",*args,**kwargs)): + raise e_LorA + results = ota_results_serializer() + with open('get_training_data_ERRORS.log', 'a') as errlog: + errlog.write("\nota run "+str(get_parameter_value("index",*args,**kwargs))+" with the following params failed: \n"+str(get_parameter_value("params",*args,**kwargs))) + return results + + + +if __name__ == "__main__": + import time + start_watch = time.time() + + parser = argparse.ArgumentParser(description="sky130 ota tapeout sample, RL generation, and statistics utility.") + + subparsers = parser.add_subparsers(title="mode", required=True, dest="mode") + + + # Subparser for gen_ota mode + gen_ota_parser = subparsers.add_parser("gen_ota", help="Run the gen_ota function. optional parameters for transistors are width,length,current multiplication ratio") + gen_ota_parser.add_argument("--input_pair_params", nargs=2, type=float, default=[4, 2], help="half_diffpair_params (default: 4 2)") + gen_ota_parser.add_argument("--fvf_shunt_params", nargs=2, type=float, default=[2.75, 1], help="fvf_shunt_params (default: 2.75 1)") + gen_ota_parser.add_argument("--local_current_bias_params", nargs=2, type=float, default=[3.76, 3], help="local_current_bias_params (default: 3.76 3)") + gen_ota_parser.add_argument("--diff_pair_load_params", nargs=2, type=float, default=[9, 1], help="diff_pair_load_params (default: 3.76 3)") + gen_ota_parser.add_argument("--ratio", type=int, default=1, help="ratio (default: 1)") + gen_ota_parser.add_argument("--current_mirror_params", nargs=2, type=float, default=[2.25,1], help="current_mirror_params (default: 2.25 1)") + gen_ota_parser.add_argument("--resistor_params", nargs=4, type=float, default=[0.5,3,4,4], help="resistor_params (default: 0.5 3 4 4)") + gen_ota_parser.add_argument("--global_current_bias_params", nargs=3, type=float, default=[8.3,1.42,2], help="global_currrent_bias_params (default: 8.3 1.42 2)") + gen_ota_parser.add_argument("--output_gds", help="Filename for outputing ota (gen_ota mode only)") + gen_ota_parser.add_argument("--add_pads",action="store_true" , help="add pads (gen_ota mode only)") + + # subparser for gen_otas mode + gen_otas_parser = subparsers.add_parser("gen_otas", help="generates the otas returned in the small parameters list but only saves GDS. Always outputs to ./outputrawotas") + gen_otas_parser.add_argument("--pdk", help="specify sky130 or gf180 pdk") + + # subparse for testing mode (create ota and run sims) + test = subparsers.add_parser("test", help="Test mode") + test.add_argument("--output_dir", type=Path, default="./", help="Directory for output GDS file") + test.add_argument("--temp", type=int, default=int(25), help="Simulation temperature") + test.add_argument("--cload", type=float, default=float(80), help="run simulation with load capacitance units=pico Farads") + test.add_argument("--noparasitics",action="store_true",help="specify that parasitics should be removed when simulating") + + + # Hidden subparser used for safe_single_build_and_simulation + safe_single_build_and_sim = subparsers.add_parser("safe_single_build_and_sim") + safe_single_build_and_sim.add_argument("--class_pickle_file",type=Path,help="see safe_single_build_and_simulation") + + for prsr in [gen_ota_parser,test,safe_single_build_and_sim]: + prsr.add_argument("--no_lvt",action="store_true",help="do not place any low threshold voltage transistors.") + prsr.add_argument("--PDK_ROOT",type=Path,default="/usr/bin/miniconda3/share/pdk/",help="path to the sky130 PDK library") + + args = parser.parse_args() + + if args.mode in ["gen_otas"]: + __SMALL_PAD_ = not args.big_pad + + if args.mode in ["test","gen_otas","safe_single_build_and_sim"]: + __NO_LVT_GLOBAL_ = args.no_lvt + PDK_ROOT = Path(args.PDK_ROOT).resolve() + if 'PDK_ROOT' in environ: + PDK_ROOT = Path(environ['PDK_ROOT']).resolve() + if not(PDK_ROOT.is_dir()): + raise ValueError("PDK_ROOT "+str(PDK_ROOT)+" is not a valid directory\n") + PDK_ROOT = str(PDK_ROOT) + + # Simulation Temperature information + if vars(args).get("temp") is not None: + temperature_info = [args.temp, None] + if temperature_info[0] > -20: + temperature_info[1] = "normal model" + elif temperature_info[0]!=-269: + raise ValueError("simulation temperature should be exactly -269C for cryo sim. Below -20C there are no good models for simulation") + else: + temperature_info[1] = "cryo model" + temperature_info = tuple(temperature_info) + + if args.mode=="gen_ota": + # Call the ota function with the parsed arguments + ota_comp = super_class_AB_OTA(pdk=pdk, + input_pair_params=tuple(args.input_pair_params), + fvf_shunt_params=tuple(args.fvf_shunt_params), + local_current_bias_params=tuple(args.local_current_bias_params), + diff_pair_load_params=tuple(args.diff_pair_load_params), + ratio = args.ratio, + current_mirror_params = tuple(args.current_mirror_params), + resistor_params = tuple(args.resistor_params), + global_current_bias_params = tuple(args.global_current_bias_params), + ) + ota_comp = sky130_add_ota_lvt_layer(ota_comp) + if args.add_pads: + ota_comp_labels = sky130_add_ota_labels(ota_comp) + ota_comp_final = sky130_ota_add_pads(ota_comp_labels) + else: + ota_comp_final = ota_comp + + ota_comp_final.show() + if args.output_gds: + ota_comp_final.write_gds(args.output_gds) + + elif args.mode == "test": + params = { + "input_pair_params": (4, 2), + "fvf_shunt_params": (2.75, 1), + "local_current_bias_params": (3.76, 3), + "diff_pair_load_params": (9, 1), + "ratio": 1, + "current_mirror_params": (2.25, 1), + "resistor_params": (0.5, 3, 4, 4), + "global_current_bias_params": (8.3, 1.42, 2) + } + results = safe_single_build_and_simulation(ota_parameters_serializer(**params), temperature_info[0], args.output_dir, cload=args.cload, noparasitics=args.noparasitics, hardfail=True) + print(results) + + elif args.mode=="safe_single_build_and_sim": + with open(args.class_pickle_file, 'rb') as pckfile: + restored_run = pickle.load(pckfile) + restored_run.execute() + with open(args.class_pickle_file, 'wb') as pckfile: + pickle.dump(restored_run, pckfile) + + elif args.mode == "gen_otas": + global usepdk + if args.pdk[0].lower()=="g": + from glayout.flow.pdk.gf180_mapped import gf180_mapped_pdk + usepdk = gf180_mapped_pdk + else: + usepdk = pdk + output_path = Path("./outputrawotas").resolve() + output_path.mkdir() + def create_func(argnparray, indx: int): + global usepdk + comp = ota(usepdk,**ota_parameters_de_serializer(argnparray)) + comp.write_gds("./outputrawotas/amp"+str(indx)+".gds") + + argnparray = get_small_parameter_list() + with Pool(120) as cores: + cores.starmap(create_func, zip(argnparray,count(0))) + + end_watch = time.time() + print("\ntotal runtime was "+str((end_watch-start_watch)/3600) + " hours\n") + From 8ab4b253f61c7120951e3baffdac58f3153ad991 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:24:18 +0530 Subject: [PATCH 13/24] Create transmission_gate.py --- .../blocks/elementary/transmission_gate/transmission_gate.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py @@ -0,0 +1 @@ + From e343b9879cc505ad1409eaa404bc8ded2bc76eb7 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:25:16 +0530 Subject: [PATCH 14/24] Update transmission_gate.py --- .../transmission_gate/transmission_gate.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py index 8b1378917..3deb20d73 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py @@ -1 +1,83 @@ +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 +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 tg_netlist(nfet: Component, pfet: Component) -> Netlist: + + netlist = Netlist(circuit_name='Transmission_Gate', nodes=['VIN', 'VSS', 'VOUT', 'VCC']) + netlist.connect_netlist(nfet.info['netlist'], [('D', 'VOUT'), ('G', 'VCC'), ('S', 'VIN'), ('B', 'VSS')]) + netlist.connect_netlist(pfet.info['netlist'], [('D', 'VOUT'), ('G', 'VSS'), ('S', 'VIN'), ('B', 'VCC')]) + + return netlist + +@cell +def transmission_gate( + pdk: MappedPDK, + width: tuple[float,float] = (1,1), + length: tuple[float,float] = (None,None), + fingers: tuple[int,int] = (1,1), + multipliers: tuple[int,int] = (1,1), + substrate_tap: bool = False, + tie_layers: tuple[str,str] = ("met2","met1"), + **kwargs + ) -> Component: + """ + creates a transmission gate + tuples are in (NMOS,PMOS) order + **kwargs are any kwarg that is supported by nmos and pmos + """ + + #top level component + top_level = Component(name="transmission_gate") + + #two fets + nfet = nmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=True, with_dnwell=False, with_substrate_tap=False, length=length[0], **kwargs) + pfet = pmos(pdk, width=width[1], fingers=fingers[1], multipliers=multipliers[1], with_dummy=True, with_substrate_tap=False, length=length[1], **kwargs) + nfet_ref = top_level << nfet + pfet_ref = top_level << pfet + pfet_ref = rename_ports_by_orientation(pfet_ref.mirror_y()) + + #Relative move + pfet_ref.movey(nfet_ref.ymax + evaluate_bbox(pfet_ref)[1]/2 + pdk.util_max_metal_seperation()) + + #Routing + top_level << c_route(pdk, nfet_ref.ports["multiplier_0_source_E"], pfet_ref.ports["multiplier_0_source_E"]) + top_level << c_route(pdk, nfet_ref.ports["multiplier_0_drain_W"], pfet_ref.ports["multiplier_0_drain_W"], viaoffset=False) + + #Renaming Ports + top_level.add_ports(nfet_ref.get_ports_list(), prefix="N_") + top_level.add_ports(pfet_ref.get_ports_list(), prefix="P_") + + #substrate tap + if substrate_tap: + substrate_tap_encloses =((evaluate_bbox(top_level)[0]+pdk.util_max_metal_seperation()), (evaluate_bbox(top_level)[1]+pdk.util_max_metal_seperation())) + guardring_ref = top_level << tapring( + pdk, + enclosed_rectangle=substrate_tap_encloses, + sdlayer="p+s/d", + horizontal_glayer='met2', + vertical_glayer='met1', + ) + guardring_ref.move(nfet_ref.center).movey(evaluate_bbox(pfet_ref)[1]/2 + pdk.util_max_metal_seperation()/2) + top_level.add_ports(guardring_ref.get_ports_list(),prefix="tap_") + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = tg_netlist(nfet, pfet) + + + return component From 52f296cfb40d81b09a31fe7e890558aedd5016c8 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:31:14 +0530 Subject: [PATCH 15/24] low voltage current mirror --- .../fvf_based_ota/low_voltage_cmirror.py | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py new file mode 100644 index 000000000..d95c902db --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py @@ -0,0 +1,196 @@ +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from gdsfactory.component import Component +from gdsfactory.component_reference import ComponentReference +from gdsfactory.cell import cell +from gdsfactory import Component +from gdsfactory.components import text_freetype, rectangle +from glayout.flow.primitives.fet import nmos, pmos, multiplier +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_center, align_comp_to_port, prec_ref_center +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 fvf import fvf_netlist, flipped_voltage_follower +from glayout.flow.primitives.via_gen import via_stack +from typing import Optional + + +def low_voltage_cmirr_netlist(bias_fvf: Component, cascode_fvf: Component, fet_1_ref: ComponentReference, fet_2_ref: ComponentReference, fet_3_ref: ComponentReference, fet_4_ref: ComponentReference) -> Netlist: + + netlist = Netlist(circuit_name='Low_voltage_current_mirror', nodes=['IBIAS1', 'IBIAS2', 'GND', 'IOUT1', 'IOUT2']) + netlist.connect_netlist(bias_fvf.info['netlist'], [('VIN','IBIAS1'),('VBULK','GND'),('Ib','IBIAS1')]) + netlist.connect_netlist(cascode_fvf.info['netlist'], [('VIN','IBIAS1'),('VBULK','GND'),('Ib', 'IBIAS2')]) + fet_1A_ref=netlist.connect_netlist(fet_2_ref.info['netlist'], [('D', 'IOUT1'),('G','IBIAS1'),('B','GND')]) + fet_2A_ref=netlist.connect_netlist(fet_4_ref.info['netlist'], [('D', 'IOUT2'),('G','IBIAS1'),('B','GND')]) + fet_1B_ref=netlist.connect_netlist(fet_1_ref.info['netlist'], [('G','IBIAS2'),('S', 'GND'),('B','GND')]) + fet_2B_ref=netlist.connect_netlist(fet_3_ref.info['netlist'], [('G','IBIAS2'),('S', 'GND'),('B','GND')]) + netlist.connect_subnets( + fet_1A_ref, + fet_1B_ref, + [('S', 'D')] + ) + netlist.connect_subnets( + fet_2A_ref, + fet_2B_ref, + [('S', 'D')] + ) + + return netlist + +def sky130_add_lvcm_labels(lvcm_in: Component) -> Component: + + lvcm_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 + gndlabel = rectangle(layer=met1_pin,size=(0.5,0.5),centered=True).copy() + gndlabel.add_label(text="VBULK",layer=met1_label) + move_info.append((gndlabel,lvcm_in.ports["M_3_B_tie_N_top_met_N"],None)) + + #currentinput + ibias1label = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + ibias1label.add_label(text="IBIAS1",layer=met2_label) + move_info.append((ibias1label,lvcm_in.ports["M_1_A_drain_top_met_N"],None)) + ibias2label = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() + ibias2label.add_label(text="IBIAS2",layer=met2_label) + move_info.append((ibias2label,lvcm_in.ports["M_2_A_drain_top_met_N"],None)) + + # currentoutput + iout1label = rectangle(layer=met1_pin,size=(0.25,0.25),centered=True).copy() + iout1label.add_label(text="IOUT1",layer=met1_label) + move_info.append((iout1label,lvcm_in.ports["M_3_A_multiplier_0_drain_N"],None)) + + iout2label = rectangle(layer=met1_pin,size=(0.25,0.25),centered=True).copy() + iout2label.add_label(text="IOUT2",layer=met1_label) + move_info.append((iout2label,lvcm_in.ports["M_4_A_multiplier_0_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) + lvcm_in.add(compref) + return lvcm_in.flatten() + +@cell +def low_voltage_cmirror( + pdk: MappedPDK, + width: tuple[float,float] = (4.15,1.42), + length: float = 2, + fingers: tuple[int,int] = (2,1), + multipliers: tuple[int,int] = (1,1), + ) -> Component: + """ + A low voltage N type current mirror + """ + #top level component + top_level = Component("Low_voltage_N-type_current_mirror") + + #input branch 2 + cascode_fvf = flipped_voltage_follower(pdk, width=(width[0],width[0]), length=(length,length), fingers=(fingers[0],fingers[0]), multipliers=(multipliers[0],multipliers[0]), with_dnwell=False) + cascode_fvf_ref = prec_ref_center(cascode_fvf) + top_level.add(cascode_fvf_ref) + + #input branch 1 + bias_fvf = flipped_voltage_follower(pdk, width=(width[0],width[1]), length=(length,length), fingers=(fingers[0],fingers[1]), multipliers=(multipliers[0],multipliers[1]), placement="vertical", with_dnwell=False) + bias_fvf_ref = prec_ref_center(bias_fvf) + bias_fvf_ref.movey(cascode_fvf_ref.ymin - 2 - (evaluate_bbox(bias_fvf)[1]/2)) + top_level.add(bias_fvf_ref) + + #creating fets for output branches + fet_1 = nmos(pdk, width=width[0], fingers=fingers[0], multipliers=multipliers[0], with_dummy=True, with_dnwell=False, with_substrate_tap=False, length=length) + fet_1_ref = prec_ref_center(fet_1) + fet_2_ref = prec_ref_center(fet_1) + fet_3_ref = prec_ref_center(fet_1) + fet_4_ref = prec_ref_center(fet_1) + + fet_1_ref.movex(cascode_fvf_ref.xmin - (evaluate_bbox(fet_1)[0]/2) - pdk.util_max_metal_seperation()) + fet_2_ref.movex(cascode_fvf_ref.xmin - (3*evaluate_bbox(fet_1)[0]/2) - 2*pdk.util_max_metal_seperation()) + fet_3_ref.movex(cascode_fvf_ref.xmax + (evaluate_bbox(fet_1)[0]/2) + pdk.util_max_metal_seperation()) + fet_4_ref.movex(cascode_fvf_ref.xmax + (3*evaluate_bbox(fet_1)[0]/2) + 2*pdk.util_max_metal_seperation()) + + top_level.add(fet_1_ref) + top_level.add(fet_2_ref) + top_level.add(fet_3_ref) + top_level.add(fet_4_ref) + + top_level << c_route(pdk, bias_fvf_ref.ports["A_multiplier_0_gate_E"], bias_fvf_ref.ports["B_gate_bottom_met_E"]) + top_level << c_route(pdk, cascode_fvf_ref.ports["A_multiplier_0_gate_W"], bias_fvf_ref.ports["A_multiplier_0_gate_W"]) + top_level << straight_route(pdk, cascode_fvf_ref.ports["B_gate_bottom_met_E"], fet_3_ref.ports["multiplier_0_gate_W"]) + + #creating vias for routing + viam2m3 = via_stack(pdk, "met2", "met3", centered=True) + gate_1_via = top_level << viam2m3 + gate_1_via.move(fet_1_ref.ports["multiplier_0_gate_W"].center).movex(-1) + gate_2_via = top_level << viam2m3 + gate_2_via.move(fet_2_ref.ports["multiplier_0_gate_W"].center).movex(-1) + gate_3_via = top_level << viam2m3 + gate_3_via.move(fet_3_ref.ports["multiplier_0_gate_E"].center).movex(1) + gate_4_via = top_level << viam2m3 + gate_4_via.move(fet_4_ref.ports["multiplier_0_gate_E"].center).movex(1) + + source_2_via = top_level << viam2m3 + drain_1_via = top_level << viam2m3 + source_2_via.move(fet_2_ref.ports["multiplier_0_source_E"].center).movex(1.5) + drain_1_via.move(fet_1_ref.ports["multiplier_0_drain_W"].center).movex(-1) + + source_4_via = top_level << viam2m3 + drain_3_via = top_level << viam2m3 + source_4_via.move(fet_4_ref.ports["multiplier_0_source_W"].center).movex(-1) + drain_3_via.move(fet_3_ref.ports["multiplier_0_drain_E"].center).movex(1.5) + + #routing + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_source_E"], source_2_via.ports["bottom_met_W"]) + top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_drain_W"], drain_1_via.ports["bottom_met_E"]) + top_level << straight_route(pdk, fet_4_ref.ports["multiplier_0_source_W"], source_4_via.ports["bottom_met_E"]) + top_level << straight_route(pdk, fet_3_ref.ports["multiplier_0_drain_E"], drain_3_via.ports["bottom_met_W"]) + top_level << c_route(pdk, source_2_via.ports["top_met_N"], drain_1_via.ports["top_met_N"], extension=0.5*evaluate_bbox(fet_1)[1], width1=0.32, width2=0.32, cwidth=0.32, e1glayer="met3", e2glayer="met3", cglayer="met2") + top_level << c_route(pdk, source_4_via.ports["top_met_N"], drain_3_via.ports["top_met_N"], extension=0.5*evaluate_bbox(fet_1)[1], width1=0.32, width2=0.32, cwidth=0.32, e1glayer="met3", e2glayer="met3", cglayer="met2") + top_level << c_route(pdk, bias_fvf_ref.ports["A_multiplier_0_gate_E"], gate_4_via.ports["bottom_met_E"], width1=0.32, width2=0.32, cwidth=0.32) + + + top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_gate_W"], gate_1_via.ports["bottom_met_E"]) + top_level << straight_route(pdk, fet_2_ref.ports["multiplier_0_gate_W"], gate_2_via.ports["bottom_met_E"]) + top_level << straight_route(pdk, fet_3_ref.ports["multiplier_0_gate_E"], gate_3_via.ports["bottom_met_W"]) + top_level << straight_route(pdk, fet_4_ref.ports["multiplier_0_gate_E"], gate_4_via.ports["bottom_met_W"]) + + top_level << c_route(pdk, gate_1_via.ports["top_met_S"], gate_3_via.ports["top_met_S"], extension=(1.2*width[0]+0.6), cglayer='met2') + top_level << c_route(pdk, gate_2_via.ports["top_met_S"], gate_4_via.ports["top_met_S"], extension=(1.2*width[0]-0.6), cglayer='met2') + + top_level << straight_route(pdk, fet_1_ref.ports["multiplier_0_source_W"], fet_1_ref.ports["tie_W_top_met_W"], glayer1='met1', width=0.2) + top_level << straight_route(pdk, fet_3_ref.ports["multiplier_0_source_W"], fet_3_ref.ports["tie_W_top_met_W"], glayer1='met1', width=0.2) + + + top_level.add_ports(bias_fvf_ref.get_ports_list(), prefix="M_1_") + top_level.add_ports(cascode_fvf_ref.get_ports_list(), prefix="M_2_") + top_level.add_ports(fet_1_ref.get_ports_list(), prefix="M_3_B_") + top_level.add_ports(fet_2_ref.get_ports_list(), prefix="M_3_A_") + top_level.add_ports(fet_3_ref.get_ports_list(), prefix="M_4_B_") + top_level.add_ports(fet_4_ref.get_ports_list(), prefix="M_4_A_") + + #for netlist + + #print(top_level.info['netlist'].generate_netlist(only_subcircuits=True)) + + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = low_voltage_cmirr_netlist(bias_fvf, cascode_fvf, fet_1_ref, fet_2_ref, fet_3_ref, fet_4_ref) + + return component + +#lvcm = low_voltage_cmirror(sky130_mapped_pdk) +#lvcm.show() + +#lvcm.name = "lvcm" +#magic_drc_result = sky130_mapped_pdk.drc_magic(lvcm, lvcm.name) +#netgen_lvs_result = sky130_mapped_pdk.lvs_netgen(lvcm, lvcm.name, netlist="lvcm.spice") + From 84d011d9d8de6b81de7f8fbd1f7fd77458753e33 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:35:03 +0530 Subject: [PATCH 16/24] Update low_voltage_cmirror.py --- .../fvf_based_ota/low_voltage_cmirror.py | 56 +------------------ 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py index d95c902db..7e101d647 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/low_voltage_cmirror.py @@ -15,7 +15,7 @@ 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 fvf import fvf_netlist, flipped_voltage_follower +from glayout.flow.blocks.elementary.FVF.fvf import fvf_netlist, flipped_voltage_follower from glayout.flow.primitives.via_gen import via_stack from typing import Optional @@ -41,47 +41,7 @@ def low_voltage_cmirr_netlist(bias_fvf: Component, cascode_fvf: Component, fet_1 ) return netlist - -def sky130_add_lvcm_labels(lvcm_in: Component) -> Component: - - lvcm_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 - gndlabel = rectangle(layer=met1_pin,size=(0.5,0.5),centered=True).copy() - gndlabel.add_label(text="VBULK",layer=met1_label) - move_info.append((gndlabel,lvcm_in.ports["M_3_B_tie_N_top_met_N"],None)) - - #currentinput - ibias1label = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() - ibias1label.add_label(text="IBIAS1",layer=met2_label) - move_info.append((ibias1label,lvcm_in.ports["M_1_A_drain_top_met_N"],None)) - ibias2label = rectangle(layer=met2_pin,size=(0.5,0.5),centered=True).copy() - ibias2label.add_label(text="IBIAS2",layer=met2_label) - move_info.append((ibias2label,lvcm_in.ports["M_2_A_drain_top_met_N"],None)) - - # currentoutput - iout1label = rectangle(layer=met1_pin,size=(0.25,0.25),centered=True).copy() - iout1label.add_label(text="IOUT1",layer=met1_label) - move_info.append((iout1label,lvcm_in.ports["M_3_A_multiplier_0_drain_N"],None)) - - iout2label = rectangle(layer=met1_pin,size=(0.25,0.25),centered=True).copy() - iout2label.add_label(text="IOUT2",layer=met1_label) - move_info.append((iout2label,lvcm_in.ports["M_4_A_multiplier_0_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) - lvcm_in.add(compref) - return lvcm_in.flatten() - + @cell def low_voltage_cmirror( pdk: MappedPDK, @@ -178,19 +138,7 @@ def low_voltage_cmirror( top_level.add_ports(fet_3_ref.get_ports_list(), prefix="M_4_B_") top_level.add_ports(fet_4_ref.get_ports_list(), prefix="M_4_A_") - #for netlist - - #print(top_level.info['netlist'].generate_netlist(only_subcircuits=True)) - component = component_snap_to_grid(rename_ports_by_orientation(top_level)) component.info['netlist'] = low_voltage_cmirr_netlist(bias_fvf, cascode_fvf, fet_1_ref, fet_2_ref, fet_3_ref, fet_4_ref) return component - -#lvcm = low_voltage_cmirror(sky130_mapped_pdk) -#lvcm.show() - -#lvcm.name = "lvcm" -#magic_drc_result = sky130_mapped_pdk.drc_magic(lvcm, lvcm.name) -#netgen_lvs_result = sky130_mapped_pdk.lvs_netgen(lvcm, lvcm.name, netlist="lvcm.spice") - From 8697e203be5ad8a0dc4254d5d06c8211eeb54d8c Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:38:07 +0530 Subject: [PATCH 17/24] Update n_block.py --- .../glayout/flow/blocks/composite/fvf_based_ota/n_block.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py index a8d0556d5..ba2416ae0 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py @@ -13,11 +13,11 @@ 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 fvf import fvf_netlist, flipped_voltage_follower -from cm import current_mirror, current_mirror_netlist +from glayout.flow.blocks.elementary.FVF.fvf import fvf_netlist, flipped_voltage_follower +from glayout.flow.blocks.elementary.current_mirror.current_mirror import current_mirror, current_mirror_netlist from glayout.flow.primitives.via_gen import via_stack, via_array from glayout.flow.primitives.fet import nmos, pmos, multiplier -from cm2 import low_voltage_cmirror, low_voltage_cmirr_netlist +from glayout.flow.blocks.composite.fvf_based_ota.low_voltage_cmirror import low_voltage_cmirror, low_voltage_cmirr_netlist def n_block_netlist(fet_inA_ref: ComponentReference, fet_inB_ref: ComponentReference, fvf_1_ref: ComponentReference, fvf_2_ref: ComponentReference, cmirror: Component, global_c_bias: Component) -> Netlist: From 2308eed41cca6a6080f5410646f82802fbdee944 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:39:29 +0530 Subject: [PATCH 18/24] Update p_block.py --- .../flow/blocks/composite/fvf_based_ota/p_block.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py index 3ad01fcef..dce63170b 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/p_block.py @@ -9,15 +9,14 @@ 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 c_route import c_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, rename_ports_by_list from glayout.flow.spice.netlist import Netlist from glayout.flow.primitives.via_gen import via_stack from gdsfactory.components import text_freetype, rectangle -from four_transistor_interdigitized import generic_4T_interdigitzed +from glayout.flow.placement.four_transistor_interdigitized import generic_4T_interdigitzed def p_block_netlist(pdk: MappedPDK, pblock: tuple[float, float, int]) -> Netlist: return Netlist( @@ -86,7 +85,6 @@ def p_block( nwell_rectangle_ref.move(p_block_ref.center) top_level.add(nwell_rectangle_ref) - #Renaming Ports top_level.add_ports(p_block.get_ports_list()) @@ -94,10 +92,4 @@ def p_block( component.info['netlist'] = p_block_netlist(pdk, pblock=(width,length,ratio)) #print(component.info['netlist'].generate_netlist()) - return component - -#p_block = p_block(sky130_mapped_pdk) -#p_block.show() -#magic_drc_result = sky130_mapped_pdk.drc_magic(p_block, p_block.name) - From 8cac9f563bdc36fc3c8eeebe3d1fc845c7a23afa Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:40:02 +0530 Subject: [PATCH 19/24] Update n_block.py --- .../glayout/flow/blocks/composite/fvf_based_ota/n_block.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py index ba2416ae0..0c8cad4f3 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/n_block.py @@ -147,9 +147,3 @@ def n_block( #print(component.info['netlist'].generate_netlist(only_subcircuits=True)) return component - -#nb = n_block(sky130_mapped_pdk) -#nb.show() -#nb.name = "n_block" -#magic_drc_result = sky130_mapped_pdk.drc_magic(nb, nb.name) - From e77f28712f484c9a10a1e60b1d3c72b66702685d Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:44:17 +0530 Subject: [PATCH 20/24] Update ota.py --- .../blocks/composite/fvf_based_ota/ota.py | 50 ++++++------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py index ee6d090c8..26185e2c1 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py @@ -12,16 +12,15 @@ from glayout.flow.routing.straight_route import straight_route -from c_route import c_route +from glayout.flow.routing.c_route import c_route from glayout.flow.routing.L_route import L_route -from fvf import fvf_netlist, flipped_voltage_follower -from cm import current_mirror, current_mirror_netlist +from glayout.flow.blocks.elementary.FVF.fvf import fvf_netlist, flipped_voltage_follower +from glayout.flow.blocks.elementary.current_mirror.current_mirror import current_mirror, current_mirror_netlist from glayout.flow.primitives.via_gen import via_stack, via_array from glayout.flow.primitives.fet import nmos, pmos, multiplier -from transmission_gate import transmission_gate,tg_netlist -from p_block import p_block,p_block_netlist -from n_block import n_block,n_block_netlist -#from lvt_cmirror import low_voltage_cmirror +from glayout.flow.blocks.elementary.transmission_gate.transmission_gate import transmission_gate,tg_netlist +from glayout.flow.blocks.composite.fvf_based_ota.p_block import p_block,p_block_netlist +from glayout.flow.blocks.composite.fvf_based_ota.n_block import n_block,n_block_netlist def super_class_AB_OTA_netlist(local_c_bias_1_ref: ComponentReference, local_c_bias_2_ref: ComponentReference, res_1_ref: ComponentReference, res_2_ref: ComponentReference, nb: Component, pblock: Component) -> Netlist: @@ -154,14 +153,10 @@ def super_class_AB_OTA( top_level << c_route(pdk, n_block_ref.ports["Min_1_multiplier_0_drain_E"], res_1_ref.ports["N_multiplier_0_source_E"], cwidth=0.6) top_level << c_route(pdk, n_block_ref.ports["Min_2_multiplier_0_drain_W"], res_2_ref.ports["N_multiplier_0_source_E"], cwidth=0.6) - top_level.add_ports(res_1_ref.get_ports_list(), prefix="res_1_") top_level.add_ports(res_2_ref.get_ports_list(), prefix="res_2_") - - #output stage N-type current mirrors - - + #adding the p_block pblock = p_block(pdk, width=diff_pair_load_params[0]/2, length=diff_pair_load_params[1], fingers=1, ratio=ratio) p_block_ref = prec_ref_center(pblock) @@ -178,21 +173,7 @@ def super_class_AB_OTA( top_level << c_route(pdk, p_block_ref.ports["bottom_B_1_drain_E"], res_2_ref.ports["P_multiplier_0_source_W"], cwidth=0.9, width2=0.29*3) top_level.add_ports(p_block_ref.get_ports_list(), prefix="pblock_") - """ - #adding lvt layer - lvt_layer=(125,44) - dimensions = (evaluate_bbox(top_level)[0], (p_block_ref.ymax - res_1_ref.ymin)) - - lvt_rectangle = rectangle(layer=lvt_layer, size=(dimensions[0], dimensions[1])) - lvt_rectangle_ref = prec_ref_center(lvt_rectangle) - lvt_rectangle_ref.movey(n_block_ref.ymax + dimensions[1]/2) - top_level.add(lvt_rectangle_ref) - #adding a pwell - pwell_rectangle = rectangle(layer=(pdk.get_glayer("pwell")), size=(85,30.25)) - pwell_rectangle_ref = prec_ref_center(pwell_rectangle,(0,-8.825)) - top_level.add(pwell_rectangle_ref) - """ #adding output pin viam2m3 = via_stack(pdk, "met2", "met3", centered=True, fulltop=True) viam3m4 = via_stack(pdk, "met3", "met4", centered=True, fulltop=True) @@ -279,14 +260,13 @@ def super_class_AB_OTA( component = component_snap_to_grid(rename_ports_by_orientation(top_level)) component.info['netlist'] = super_class_AB_OTA_netlist(local_c_bias_1_ref, local_c_bias_2_ref, res_1_ref, res_2_ref, nb, pblock) - print(component.info['netlist'].generate_netlist()) + #print(component.info['netlist'].generate_netlist()) return component -""" -OTA = sky130_add_ota_labels(super_class_AB_OTA(sky130_mapped_pdk)) -OTA.show() -OTA.name = "ota" -OTA.write_gds("./ota.gds") -magic_drc_result = sky130_mapped_pdk.drc_magic(OTA, OTA.name) -netgen_lvs_result = sky130_mapped_pdk.lvs_netgen(OTA, design_name="ota", netlist="ota.spice") -""" + +#OTA = sky130_add_ota_labels(super_class_AB_OTA(sky130_mapped_pdk)) +#OTA.show() +#OTA.name = "ota" +#OTA.write_gds("./ota.gds") +#magic_drc_result = sky130_mapped_pdk.drc_magic(OTA, OTA.name) + From a7f421109e506353bbdfe1c50b18def8f9131fe5 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:49:09 +0530 Subject: [PATCH 21/24] Update sky130_ota_tapeout.py --- .../fvf_based_ota/sky130_ota_tapeout.py | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py index 5e882afed..c5eb52301 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/sky130_ota_tapeout.py @@ -10,8 +10,9 @@ from glayout.flow.pdk.util.port_utils import add_ports_perimeter, print_ports from gdsfactory.component import Component from glayout.flow.pdk.mappedpdk import MappedPDK -from ota2 import super_class_AB_OTA +from glayout.flow.blocks.composite.fvf_based_ota.ota import super_class_AB_OTA from glayout.flow.routing.L_route import L_route +from glayout.flow.routing.c_route import c_route from glayout.flow.routing.straight_route import straight_route from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_ref_center, prec_center, align_comp_to_port from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation @@ -19,7 +20,6 @@ from gdsfactory.components import text_freetype, rectangle from glayout.flow.pdk.mappedpdk import MappedPDK from glayout.flow.primitives.via_gen import via_array, via_stack -from c_route import c_route from gdsfactory.cell import cell, clear_cache import numpy as np from subprocess import Popen @@ -77,10 +77,10 @@ def sky130_ota_add_pads(ota_in: Component, flatten=False) -> Component: global __SMALL_PAD_ small_pad=__SMALL_PAD_ if small_pad: - pad = import_gds("pads/pad_60um_flat.gds") + pad = import_gds("../../../../../tapeout/tapeout_and_RL/pads/pad_60um_flat.gds") pad.name = "NISTpad" else: - pad = import_gds("pads/Manhattan120umPad.gds") + pad = import_gds("../../../../../tapeout/tapeout_and_RL/pads/Manhattan120umPad.gds") pad.name = "Manhattan120umPad" pad = add_ports_perimeter(pad, pdk.get_glayer("met5"),prefix="pad_") if small_pad: @@ -90,11 +90,7 @@ def sky130_ota_add_pads(ota_in: Component, flatten=False) -> Component: pad_array_ref = prec_ref_center(pad_array) ota_wpads.add(pad_array_ref) # add via_array to vdd pin - """ - vddarray = via_array(pdk, "met3","met4",size=(ota_wpads.ports["VCC_top_met_N"].width,3*ota_wpads.ports["VCC_top_met_E"].width)) - via_array_ref = ota_wpads << vddarray - align_comp_to_port(via_array_ref,ota_wpads.ports["VCC_top_met_N"],alignment=('c','b')) - """ + # route to the pads leftroutelayer="met5" ota_wpads << L_route(pdk, ota_wpads.ports["PLUS_top_met_E"],pad_array_ref.ports["row1_col3_pad_S"], hwidth=3, vwidth=3) @@ -118,21 +114,7 @@ def sky130_ota_add_pads(ota_in: Component, flatten=False) -> Component: pad_array_port = pad_array_ref.ports[port_name] pin_ref = ota_wpads << text_pin_labels[4*row + col_u] align_comp_to_port(pin_ref,pad_array_port,alignment=('c','t')) - """ - # import nano pad and add to ota - nanopad = import_gds("pads/sky130_nano_pad.gds") - nanopad.name = "nanopad" - nanopad = add_ports_perimeter(nanopad, pdk.get_glayer(leftroutelayer),prefix="nanopad_") - nanopad_array = prec_array(nanopad, rows=2, columns=2, spacing=(10,10)) - nanopad_array_ref = nanopad_array.ref_center() - ota_wpads.add(nanopad_array_ref) - nanopad_array_ref.movex(ota_wpads.xmin+nanopad_array.xmax) - # route nano pad connections - ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row1_col0_nanopad_N"],pad_array_ref.ports["row1_col0_pad_S"],width=3,glayer2=leftroutelayer) - ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row0_col0_nanopad_S"],pad_array_ref.ports["row0_col0_pad_N"],width=3,glayer2=leftroutelayer) - ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row0_col1_nanopad_E"],pad_array_ref.ports["row0_col1_pad_N"],width=3,glayer2=leftroutelayer) - ota_wpads << straight_route(pdk, nanopad_array_ref.ports["row1_col1_nanopad_E"],pad_array_ref.ports["row1_col1_pad_S"],width=3,glayer2=leftroutelayer) - """ + if flatten: return ota_wpads.flatten() else: From edab537423480ad02935a0f43a013c8178a17297 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:22:52 +0530 Subject: [PATCH 22/24] Update README.md --- .../blocks/composite/fvf_based_ota/README.md | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md index 660951111..c1777ce90 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md @@ -1 +1,55 @@ -FVF based super class AB OTA +# FVF based super class AB OTA +This topology of class AB OTA uses flipped voltage followers as voltage shifters to boost gain and slew rate. It can provide **slew performance independent of bias current**. LCMFB is also used to boost the slew rate even more. +## Pcells used +![WhatsApp Image 2024-12-01 at 22 18 40](https://github.com/user-attachments/assets/99d3a1b1-7842-42dc-9033-9e7f452b4a54) +![otagds](https://github.com/user-attachments/assets/4da02a37-eacb-4d2e-9e33-c0ddd4d95a79) +### Flipped Voltage Follower +Used as voltage shifters. Also used to crete a low voltage current mirror for biasing. Pcell can be found under ``` glayout/flow/blocks/elementary/FVF/ ``` +### Transmission gate +Due to unavailability of resistors in Glayout, trasmission gates were used as LCMFB resistors. However, this limits ther slew performance. Pcell can be found here ``` glayout/flow/blocks/elementary/trasmission_gate/ ``` +### Low Voltage Current Mirror +Low voltage current mirror are used to set a **bias current of 10uA**. The python code can be found in this directory itself. +### Others +Some already existing pcells were used, like current mirrors and four_transistor_interdigitized block. +## Parameterization +``` +def super_class_AB_OTA( + pdk: MappedPDK, + input_pair_params: tuple[float,float]=(4,2), + fvf_shunt_params: tuple[float,float]=(2.75,1), + local_current_bias_params: tuple[float,float]=(3.76,3.0), + diff_pair_load_params: tuple[float,float]=(9,1), + ratio: int=1, + current_mirror_params: tuple[float,float]=(2.25,1), + resistor_params: tuple[float,float,float,float]=(0.5,3,4,4), + global_current_bias_params: tuple[float,float,float]=(8.3,1.42,2) + ) -> Component: + """ + creates a super class AB OTA using flipped voltage follower at biasing stage and local common mode feedback to give dynamic current and gain boost much less dependent on biasing current + NB:- This block can only support device dimensions which achieve our design goal. In future steps will be taken to make it more flexible. + pdk: pdk to use + input_pair_params: differential input pair(N-type) - (width,length), input nmoses of the fvf get the same dimensions + fvf_shunt_params: feedback fet of fvf - (width,length) + local_current_bias_params: local currrent mirror which directly biases each fvf - (width,length) + diff_pair_load_params: creates a p_block consisting of both input stage pmos loads and output stage pmoses - (width,length) + ratio: current mirroring ratio from input stage to output stage + current_mirror_params: output stage N-type currrent mirrors - (width, length) + resistor_params: passgates are used as resistors for LCMFB - ((width of nmos, width of pmos),(length of nmos, length of pmos)) + global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - ((W,W'),L) + """ +``` +## Layout generation, PEX and post-layout simulations +### sky130_ota_tapeout.py +This file is used to generate layout genration, PEX and post-layout simulations. [sky130_nist_tapeout.py](https://github.com/idea-fasoc/OpenFASOC/blob/main/openfasoc/generators/glayout/tapeout/tapeout_and_RL/sky130_nist_tapeout.py) was taken as a reference. +Run this command to see various modes in which it can be run +``` python3 sky130_ota_tapeout_py --h ``` +#### gen_ota mode +This generates a complete layout, **with LVT layers and labels added by default**. Custom parameters can be given. Run ``` python3 sky130_ota_tapeout.py gen_ota --h ``` to see the options. + +**N.B-** +_1. The default widths and lengths assume that the lvt layer is added. Different widths and lengths must be given to get an OTA with desired performance if no lvt layer is added. + +2. There is an option to add pads. For now this is set as False by default._ +#### test mode +This mode creates a complete layout with default parameter values, performs PEX (add --noparasitics to do just LVS but PEX is encouraged for better results) and then does some transient, ac, power and noise analysis to get results. The spice testbench ``` ota_perf_eval.sp ``` can be found in this directory itself. +Run python3 ``` sky130_ota_tapeout.py test --output_dir test ```. This puts the simulation results inside test directory. From 66fbee68f0b3b261ef7ce14bd82cdc054ebe4a68 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:24:58 +0530 Subject: [PATCH 23/24] Updated comments --- .../glayout/flow/blocks/composite/fvf_based_ota/ota.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py index 26185e2c1..2efb62102 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/ota.py @@ -85,16 +85,14 @@ def super_class_AB_OTA( ) -> Component: """ creates a super class AB OTA using flipped voltage follower at biasing stage and local common mode feedback to give dynamic current and gain boost much less dependent on biasing current - NB:- This block can only support device dimensions which achieve our design goal. In future steps will be taken to make it more flexible. - pdk: pdk to use input_pair_params: differential input pair(N-type) - (width,length), input nmoses of the fvf get the same dimensions fvf_shunt_params: feedback fet of fvf - (width,length) local_current_bias_params: local currrent mirror which directly biases each fvf - (width,length) diff_pair_load_params: creates a p_block consisting of both input stage pmos loads and output stage pmoses - (width,length) - ratio: current mirroring ratio from input stage to output stage, currently suports only identical mirroring + ratio: current mirroring ratio from input stage to output stage, set to 1 by default. current_mirror_params: output stage N-type currrent mirrors - (width, length) - resistor_params: passgates are used as resistors for LCMFB - ((width of nmos, width of pmos),(length of nmos, length of pmos)) - global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - ((W,W'),L) + resistor_params: passgates are used as resistors for LCMFB - (width of nmos, width of pmos,length of nmos, length of pmos) + global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - (W,W',L) """ # Create a top level component top_level = Component("Super_class_AB_OTA") From b5072a0b80c7f58f7fb3dbbd0fadafecdb2e2636 Mon Sep 17 00:00:00 2001 From: Subhampal9 <122683549+Subhampal9@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:25:35 +0530 Subject: [PATCH 24/24] Update README.md --- .../flow/blocks/composite/fvf_based_ota/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md index c1777ce90..179b7194a 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/fvf_based_ota/README.md @@ -26,17 +26,15 @@ def super_class_AB_OTA( ) -> Component: """ creates a super class AB OTA using flipped voltage follower at biasing stage and local common mode feedback to give dynamic current and gain boost much less dependent on biasing current - NB:- This block can only support device dimensions which achieve our design goal. In future steps will be taken to make it more flexible. - pdk: pdk to use input_pair_params: differential input pair(N-type) - (width,length), input nmoses of the fvf get the same dimensions fvf_shunt_params: feedback fet of fvf - (width,length) local_current_bias_params: local currrent mirror which directly biases each fvf - (width,length) diff_pair_load_params: creates a p_block consisting of both input stage pmos loads and output stage pmoses - (width,length) - ratio: current mirroring ratio from input stage to output stage + ratio: current mirroring ratio from input stage to output stage, set to 1 by default. current_mirror_params: output stage N-type currrent mirrors - (width, length) - resistor_params: passgates are used as resistors for LCMFB - ((width of nmos, width of pmos),(length of nmos, length of pmos)) - global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - ((W,W'),L) - """ + resistor_params: passgates are used as resistors for LCMFB - (width of nmos, width of pmos,length of nmos, length of pmos) + global_current_bias_params: A low voltage current mirror for biasing - consists of 5 nmoses of (W/L) and one nmos of (W'/L) - (W,W',L) + """ ``` ## Layout generation, PEX and post-layout simulations ### sky130_ota_tapeout.py