From 06058e1b87cc9e45c9d856406aa04ee003c5c0ce Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 9 Jan 2023 16:02:25 -0800 Subject: [PATCH] Initial files for gf180 --- Makefile | 17 +- setpaths.sh | 1 + technology/gf180/__init__.py | 52 ++++ technology/gf180/tech/tech.py | 454 ++++++++++++++++++++++++++++++++++ 4 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 technology/gf180/__init__.py create mode 100644 technology/gf180/tech/tech.py diff --git a/Makefile b/Makefile index 99e4ce22..aa165640 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,18 @@ OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git OPEN_PDKS_GIT_COMMIT ?= 1.0.311 #OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 SKY130_PDK ?= $(PDK_ROOT)/sky130A +GF180_PDK ?= $(PDK_ROOT)/gf180 # Skywater PDK SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk SKY130_PDKS_GIT_REPO ?= https://github.com/google/skywater-pdk.git SKY130_PDKS_GIT_COMMIT ?= f70d8ca46961ff92719d8870a18a076370b85f6c +# GF180 PDK +GF180_PDKS_DIR ?= $(PDK_ROOT)/gf180mcu-pdk +GF180_PDKS_GIT_REPO ?= https://github.com/google/gf180mcu-pdk.git +GF180_PDKS_GIT_COMMIT ?= main + # Create lists of all the files to copy/link GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) GDS_FILES := $(GDS_FILES) $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dlxtn/sky130_fd_sc_hd__dlxtn_1.gds @@ -67,7 +73,16 @@ $(SKY130_PDKS_DIR): check-pdk-root @git -C $(SKY130_PDKS_DIR) checkout $(SKY130_PDKS_GIT_COMMIT) && \ git -C $(SKY130_PDKS_DIR) submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest -$(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) +$(GF180_PDKS_DIR): check-pdk-root + @echo "Cloning gf PDK..." + @[ -d $(PDK_ROOT)/gf180mcu-pdk ] || \ + git clone https://github.com/google/gf180mcu-pdk.git $(PDK_ROOT)/gf180mcu-pdk + @cd $(SKY130_PDKS_DIR) && \ + git checkout main && git pull && \ + git checkout -qf $(GF180_PDKS_GIT_COMMIT) && \ + git submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest + +$(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(GF180_PDKS_DIR) @echo "Cloning open_pdks..." @[ -d $(OPEN_PDKS_DIR) ] || \ git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) diff --git a/setpaths.sh b/setpaths.sh index efceed78..79c2ff1a 100755 --- a/setpaths.sh +++ b/setpaths.sh @@ -6,4 +6,5 @@ export OPENRAM_HOME="`pwd`/compiler" export OPENRAM_TECH="`pwd`/technology" +export PDK_ROOT="$HOME/gf/pdk" export PYTHONPATH=$OPENRAM_HOME diff --git a/technology/gf180/__init__.py b/technology/gf180/__init__.py new file mode 100644 index 00000000..45e04451 --- /dev/null +++ b/technology/gf180/__init__.py @@ -0,0 +1,52 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +#!/usr/bin/python +""" +This type of setup script should be placed in the setup_scripts directory in the trunk +""" + +import sys +import os + +TECHNOLOGY = "gf180" + +os.environ["MGC_TMPDIR"] = "/tmp" + +########################### +# OpenRAM Paths + +# OpenPDK needed for magicrc, tech file and spice models of transistors +if 'PDK_ROOT' in os.environ: + open_pdks = os.path.join(os.environ['PDK_ROOT'], 'gf180', 'libs.tech') +else: + raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.") + +# The ngspice models work with Xyce too now +spice_model_dir = os.path.join(open_pdks, "ngspice") +gf180_lib_ngspice = os.path.join(open_pdks, "ngspice", "gf180.lib.spice") +if not os.path.exists(gf180_lib_ngspice): + raise SystemError("Did not find {} under {}".format(gf180_lib_ngspice, open_pdks)) +os.environ["SPICE_MODEL_DIR"] = spice_model_dir + +open_pdks = os.path.abspath(open_pdks) +gf180_magicrc = os.path.join(open_pdks, 'magic', "gf180A.magicrc") +if not os.path.exists(gf180_magicrc): + raise SystemError("Did not find {} under {}".format(gf180_magicrc, open_pdks)) +os.environ["OPENRAM_MAGICRC"] = gf180_magicrc +gf180_netgenrc = os.path.join(open_pdks, 'netgen', "setup.tcl") +if not os.path.exists(gf180_netgenrc): + raise SystemError("Did not find {} under {}".format(gf180_netgenrc, open_pdks)) +os.environ["OPENRAM_NETGENRC"] = gf180_netgenrc + +try: + DRCLVS_HOME = os.path.abspath(os.environ.get("DRCLVS_HOME")) +except: + DRCLVS_HOME= "not-found" +os.environ["DRCLVS_HOME"] = DRCLVS_HOME + + diff --git a/technology/gf180/tech/tech.py b/technology/gf180/tech/tech.py new file mode 100644 index 00000000..9c946aee --- /dev/null +++ b/technology/gf180/tech/tech.py @@ -0,0 +1,454 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import os +import drc as d +#from drc.design_rules import design_rules +#from drc.module_type import module_type +#from drc.custom_cell_properties import cell_properties +#from drc.custom_layer_properties import layer_properties + +""" +File containing the process technology parameters for SCMOS 4m, 0.35um +""" + +################################################### +# Custom modules +################################################### + +# This uses the default classes to instantiate module from +# '$OPENRAM_HOME/compiler/modules'. +# Using tech_modules['cellname'] you can override each class by providing a custom +# implementation in '$OPENRAM_TECHDIR/modules/' +# For example: tech_modules['contact'] = 'contact_scn4m' +tech_modules = d.module_type() + +################################################### +# Custom cell properties +################################################### +cell_properties = d.cell_properties() + +################################################### +# Custom cell properties +################################################### +layer_properties = d.layer_properties() + +################################################### +# GDS file info +################################################### +GDS={} +# gds units +# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first +#is the size of a database unit in user units. The second is the size +#of a database unit in meters. For example, if your library was +#created with the default units (user unit = 1 m and 1000 database +#units per user unit), then the first number would be 0.001 and the +#second number would be 10-9. Typically, the first number is less than +#1, since you use more than 1 database unit per user unit. To +#calculate the size of a user unit in meters, divide the second number +#by the first." +GDS["unit"]=(0.001,1e-6) +# default label zoom +GDS["zoom"] = 0.5 + +################################################### +# Interconnect stacks +################################################### + +poly_stack = ("poly", "contact", "m1") +active_stack = ("active", "contact", "m1") +m1_stack = ("m1", "via1", "m2") +m2_stack = ("m2", "via2", "m3") +m3_stack = ("m3", "via3", "m4") + +layer_indices = {"poly": 0, + "active": 0, + "m1": 1, + "m2": 2, + "m3": 3, + "m4": 4} + +# The FEOL stacks get us up to m1 +feol_stacks = [poly_stack, + active_stack] + +# The BEOL stacks are m1 and up +beol_stacks = [m1_stack, + m2_stack, + m3_stack] + +layer_stacks = feol_stacks + beol_stacks + +preferred_directions = {"poly": "V", + "active": "V", + "m1": "H", + "m2": "V", + "m3": "H", + "m4": "V"} + +################################################### +# Power grid +################################################### +# Use M3/M4 +power_grid = m3_stack + +################################################### +##GDS Layer Map +################################################### + +# create the GDS layer map +layer={} +layer["pwell"] = (204, 0) +layer["nwell"] = (21, 0) +layer["dnwell"] = (12, 0) +layer["active"] = (22, 0) +layer["pimplant"] = (31, 0) +layer["nimplant"] = (32, 0) +layer["poly"] = (30, 0) +layer["contact"] = (33, 0) +layer["m1"] = (34, 0) +layer["via1"] = (35, 0) +layer["m2"] = (36, 0) +layer["via2"] = (38, 0) +layer["m3"] = (42, 0) +layer["via3"] = (40, 0) +layer["m4"] = (46, 0) +layer["via4"] = (41, 0) +layer["m5"] = (81, 0) +# Not an official layer +layer["text"] = (234, 5) +layer["mem"] = (108, 5) +layer["boundary"] = (0, 0) + +label_purpose = 10 +#use_purpose = {} + +# Layer names for external PDKs +layer_names = {} +layer_names["active"] = "active" +layer_names["pwell"] = "pwell" +layer_names["nwell"] = "nwell" +layer_names["nimplant"]= "nimplant" +layer_names["pimplant"]= "pimplant" +layer_names["poly"] = "poly" +layer_names["contact"] = "contact" +layer_names["m1"] = "metal1" +layer_names["via1"] = "via1" +layer_names["m2"] = "metal2" +layer_names["via2"] = "via2" +layer_names["m3"] = "metal3" +layer_names["via3"] = "via3" +layer_names["m4"] = "metal4" +layer_names["text"] = "text" +layer_names["mem"] = "SramCore" +layer_names["boundary"]= "boundary" + +################################################### +# DRC/LVS Rules Setup +################################################### + +# technology parameter +parameter={} +# difftap.2b +parameter["min_tx_size"] = 0.250 +parameter["beta"] = 3 + +parameter["6T_inv_nmos_size"] = 0.205 +parameter["6T_inv_pmos_size"] = 0.09 +parameter["6T_access_size"] = 0.135 + +drc = d.design_rules("gf180") + +# grid size +drc["grid"] = 0.005 + +# minwidth_tx with contact (no dog bone transistors) +# difftap.2b +drc["minwidth_tx"] = 0.360 +drc["minlength_channel"] = 0.150 + +drc["pwell_to_nwell"] = 0 +# nwell.1 Minimum width of nwell/pwell +drc.add_layer("nwell", + width=0.840, + spacing=1.270) + +# poly.1a Minimum width of poly +# poly.2 Minimum spacing of poly AND active +drc.add_layer("poly", + width=0.150, + spacing=0.210) +# poly.8 +drc["poly_extend_active"] = 0.13 +# Not a rule +drc["poly_to_contact"] = 0 +# poly.7 Minimum enclosure of active around gate +drc["active_enclose_gate"] = 0.075 +# poly.4 Minimum spacing of field poly to active +drc["poly_to_active"] = 0.075 +# poly.2 Minimum spacing of field poly +drc["poly_to_field_poly"] = 0.210 + +# difftap.1 Minimum width of active +# difftap.3 Minimum spacing of active +drc.add_layer("active", + width=0.150, + spacing=0.270) +# difftap.8 +drc.add_enclosure("nwell", + layer="active", + enclosure=0.18, + extension=0.18) + +# nsd/psd.5a +drc.add_enclosure("implant", + layer="active", + enclosure=0.125) + +# Same as active enclosure? +drc["implant_to_contact"] = 0.070 +# nsd/psd.1 nsd/psd.2 +drc.add_layer("implant", + width=0.380, + spacing=0.380, + area=0.265) + +# licon.1, licon.2 +drc.add_layer("contact", + width=0.170, + spacing=0.170) +# licon.5c (0.06 extension), (licon.7 for extension) +drc.add_enclosure("active", + layer="contact", + enclosure=0.040, + extension=0.060) +# licon.7 +drc["tap_extend_contact"] = 0.120 + +# licon.8 Minimum enclosure of poly around contact +drc.add_enclosure("poly", + layer="contact", + enclosure=0.08, + extension=0.08) +# licon.11a +drc["active_contact_to_gate"] = 0.050 +# npc.4 > licon.14 0.19 > licon.11a +drc["poly_contact_to_gate"] = 0.270 +# licon.15 +drc["npc_enclose_poly"] = 0.1 + +# li.1, li.3 +drc.add_layer("li", + width=0.170, + spacing=0.170) + +# licon.5 +drc.add_enclosure("li", + layer="contact", + enclosure=0, + extension=0.080) + +drc.add_enclosure("li", + layer="mcon", + enclosure=0, + extension=0.080) +# mcon.1, mcon.2 +drc.add_layer("mcon", + width=0.170, + spacing=0.210) + +# m1.1 Minimum width of metal1 +# m1.2 Minimum spacing of metal1 +# m1.6 Minimum area of metal1 +drc.add_layer("m1", + width=0.140, + spacing=0.140, + area=0.083) +# m1.4 Minimum enclosure of metal1 +# m1.5 Minimum enclosure around contact on two opposite sides +drc.add_enclosure("m1", + layer="mcon", + enclosure=0.030, + extension=0.060) +# via.4a Minimum enclosure around via1 +# via.5a Minimum enclosure around via1 on two opposite sides +drc.add_enclosure("m1", + layer="via1", + enclosure=0.055, + extension=0.085) + +# via.1a Minimum width of via1 +# via.2 Minimum spacing of via1 +drc.add_layer("via1", + width=0.150, + spacing=0.170) + +# m2.1 Minimum width of intermediate metal +# m2.2 Minimum spacing of intermediate metal +# m2.6 Minimum area of metal2 +drc.add_layer("m2", + width=0.140, + spacing=0.140, + area=0.0676) +# m2.4 Minimum enclosure around via1 +# m2.5 Minimum enclosure around via1 on two opposite sides +drc.add_enclosure("m2", + layer="via1", + enclosure=0.055, + extension=0.085) +# via2.4 Minimum enclosure around via2 +# via2.5 Minimum enclosure around via2 on two opposite sides +drc.add_enclosure("m2", + layer="via2", + enclosure=0.040, + extension=0.085) + +# via2.1a Minimum width of Via2 +# via2.2 Minimum spacing of Via2 +drc.add_layer("via2", + width=0.200, + spacing=0.200) + +# m3.1 Minimum width of metal3 +# m3.2 Minimum spacing of metal3 +# m3.6 Minimum area of metal3 +drc.add_layer("m3", + width=0.300, + spacing=0.300, + area=0.240) +# m3.4 Minimum enclosure around via2 +drc.add_enclosure("m3", + layer="via2", + enclosure=0.065) +# via3.4 Minimum enclosure around via3 +# via3.5 Minimum enclosure around via3 on two opposite sides +drc.add_enclosure("m3", + layer="via3", + enclosure=0.060, + extension=0.090) + +# via3.1 Minimum width of Via3 +# via3.2 Minimum spacing of Via3 +drc.add_layer("via3", + width=0.200, + spacing=0.200) + +# m4.1 Minimum width of metal4 +# m4.2 Minimum spacing of metal4 +# m4.7 Minimum area of metal4 +drc.add_layer("m4", + width=0.300, + spacing=0.300, + area=0.240) +# m4.3 Minimum enclosure around via3 +drc.add_enclosure("m4", + layer="via3", + enclosure=0.065) +# FIXME: Wrong rule m4.3 Minimum enclosure around via3 +drc.add_enclosure("m4", + layer="via4", + enclosure=0.060) + + +# via4.1 Minimum width of Via4 +# via4.2 Minimum spacing of Via4 +drc.add_layer("via4", + width=0.800, + spacing=0.800) + +# FIXME: Wrong rules +# m5.1 Minimum width of metal5 +# m5.2 Minimum spacing of metal5 +# m5.7 Minimum area of metal5 +drc.add_layer("m5", + width=1.600, + spacing=1.600, + area=4.000) +# m5.3 Minimum enclosure around via4 +drc.add_enclosure("m5", + layer="via4", + enclosure=0.310) + + + +# Metal 5-10 are ommitted + +################################################### +# Spice Simulation Parameters +################################################### + +# spice info +spice = {} +spice["nmos"] = "sky130_fd_pr__nfet_01v8" +spice["pmos"] = "sky130_fd_pr__pfet_01v8" +spice["power"]="vccd1" +spice["ground"]="vssd1" + +# whether or not the device model is actually a subckt +spice["device_prefix"] = "X" + +spice["fet_libraries"] = {"TT": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "tt"]]} + +# spice stimulus related variables +spice["feasible_period"] = 10 # estimated feasible period in ns +spice["supply_voltages"] = [1.7, 1.8, 1.9] # Supply voltage corners in [Volts] +spice["nom_supply_voltage"] = 1.8 # Nominal supply voltage in [Volts] +spice["rise_time"] = 0.005 # rise time in [Nano-seconds] +spice["fall_time"] = 0.005 # fall time in [Nano-seconds] +spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius) +spice["nom_temperature"] = 25 # Nominal temperature (celcius) + +# analytical delay parameters +spice["nom_threshold"] = 0.49 # Typical Threshold voltage in Volts +spice["wire_unit_r"] = 0.125 # Unit wire resistance in ohms/square +spice["wire_unit_c"] = 0.134 # Unit wire capacitance ff/um^2 +spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff +spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff +spice["dff_setup"] = 102.5391 # DFF setup time in ps +spice["dff_hold"] = -56 # DFF hold time in ps +spice["dff_in_cap"] = 6.89 # Input capacitance (D) [Femto-farad] +spice["dff_out_cap"] = 6.89 # Output capacitance (Q) [Femto-farad] + +# analytical power parameters, many values are temporary +spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW +spice["inv_leakage"] = 1 # Leakage power of inverter in nW +spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW +spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW +spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW +spice["dff_leakage"] = 1 # Leakage power of flop in nW + +spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz + +# Parameters related to sense amp enable timing and delay chain/RBL sizing +parameter["le_tau"] = 2.25 # In pico-seconds. +parameter["cap_relative_per_ff"] = 7.5 # Units of Relative Capacitance/ Femto-Farad +parameter["dff_clk_cin"] = 30.6 # relative capacitance +parameter["6tcell_wl_cin"] = 3 # relative capacitance +parameter["min_inv_para_delay"] = 2.4 # Tau delay units +parameter["sa_en_pmos_size"] = 0.72 # micro-meters +parameter["sa_en_nmos_size"] = 0.27 # micro-meters +parameter["sa_inv_pmos_size"] = 0.54 # micro-meters +parameter["sa_inv_nmos_size"] = 0.27 # micro-meters +parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance + +################################################### +# Technology Tool Preferences +################################################### + +if use_calibre: + drc_name = "calibre" + lvs_name = "calibre" + pex_name = "calibre" +elif use_klayout: + drc_name = "klayout" + lvs_name = "klayout" + pex_name = "klayout" +else: + drc_name = "magic" + lvs_name = "netgen" + pex_name = "magic" +