blob: 8297498bc54d2708737bc1aecf91470581fb399c [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0-or-later
# PDKMaster & co. don't put a license requirement on the generated files.
# The generated gds files in this project are released under the LGPL 2.0 or later license.
from pathlib import Path
from typing import Any, cast
import pya as _pya
# Disable type checking
pya = cast(Any, _pya)
from pdkmaster.technology import geometry as _geo
from pdkmaster.design import library as _lib
from pdkmaster.io.klayout import export as _klexp
from c4m.pdk import sky130
from . import frame as _frm, sram as _ram, bandgap as _bg
__all__ = ["gen_gds"]
def _postprocess(*, klay: "pya.Layout"):
# Post process
# - split tapdiff into tap and diff layers
# - remove pad drawing layer to avoid interacting with RDL
nwell_idx = klay.layer(64, 20)
diff_idx = klay.layer(65, 20)
tap_idx = klay.layer(65, 44)
nsdm_idx = klay.layer(93, 44)
psdm_idx = klay.layer(94, 20)
pad_idx = klay.layer(76, 20)
for cell in klay.each_cell():
nwell = pya.Region(cell.shapes(nwell_idx))
nsdm = pya.Region(cell.shapes(nsdm_idx))
psdm = pya.Region(cell.shapes(psdm_idx))
tap_cover = (nsdm & nwell) + (psdm - nwell)
diff_shapes = cell.shapes(diff_idx)
tap_shapes = cell.shapes(tap_idx)
difftap = pya.Region(cell.shapes(diff_idx)) # Original difftap layer to be split
tap = difftap & tap_cover
diff = difftap - tap
diff_shapes.clear()
diff_shapes.insert(diff)
tap_shapes.insert(tap)
cell.shapes(pad_idx).clear()
def gen_gds(*, name: str, gds_out: Path, gds_empty: Path):
top_name = "user_analog_project_wrapper"
lib = _lib.Library(
name=name, tech=sky130.tech, cktfab=sky130.cktfab, layoutfab=sky130.layoutfab,
)
# Create user_analog_project_wrapper top cell
top = lib.new_cell(name=top_name)
ckt = top.new_circuit()
layouter = top.new_circuitlayouter()
# Add the BandGap
bandgap_cell = _bg.ConnectedBandGap(lib=lib)
bandgap_inst = ckt.instantiate(bandgap_cell, name="bandgaptop")
layouter.place(bandgap_inst, x=0.0, y=0.0)
# Add the SRAM
sram_cell = _ram.ConnectedSRAM(lib=lib)
sram_inst = ckt.instantiate(sram_cell, name="sramtop")
layouter.place(sram_inst, origin=_geo.origin)
lib.cells += (bandgap_cell, sram_cell)
# Add circuit and
layouter.layout.boundary = _frm.boundary
# Convert to klayout
klay = _klexp.export2db(
obj=lib, add_pin_label=True, gds_layers=sky130.gds_layers, cell_name=None, merge=True,
)
_postprocess(klay=klay)
# Instantiate the empty cell in top cell
emptylib = pya.Library()
emptylib.register("empty")
emptylayout = emptylib.layout()
emptylayout.read(str(gds_empty))
emptylibcell_idx = emptylayout.cell("user_analog_project_wrapper_empty").cell_index()
emptycell_idx = klay.add_lib_cell(emptylib, emptylibcell_idx)
ktop = klay.cell(top_name)
ktop.insert(pya.CellInstArray(emptycell_idx, pya.Trans.R0))
ktech = pya.Technology.technology_by_name("Skywater_S8")
ksaveopts = ktech.save_layout_options.dup()
ksaveopts.write_context_info = False
klay.write(str(gds_out), ksaveopts)