adding klayout tech file script

This commit is contained in:
Edward Arthur Bingham 2024-01-04 22:17:07 +00:00
parent 49daa2f891
commit f7df0398fb

796
generate_klayout.py Executable file
View File

@ -0,0 +1,796 @@
#!/usr/bin/python3
import os
import sys
import copy
import csv
import lxml.etree
import lxml.builder
import pprint
def isIn(searches, string):
for search in searches:
if search in string:
return True
return False
def startsWithAny(searches, string):
for search in searches:
if string.startswith(search):
return True
return False
def splitLayerID(layerID):
name = layerID
purpose = ""
if "." in name:
name, purpose = layerID.rsplit(".", 1)
return name, purpose
def purposeToID(purpose):
if purpose in ["drawing", "dg", "drw"]:
return "dg"
elif purpose in ["pin", "pn"]:
return "pn"
elif purpose in ["boundary", "by", "bnd"]:
return "by"
elif purpose in ["net", "nt"]:
return "nt"
elif purpose in ["res", "rs"]:
return "rs"
elif purpose in ["label", "ll", "lbl"]:
return "ll"
elif purpose in ["cut", "ct"]:
return "ct"
elif purpose in ["short", "st", "sho"]:
return "st"
elif purpose in ["gate", "ge", "gat"]:
return "ge"
elif purpose in ["probe", "pe", "pro"]:
return "pe"
elif purpose in ["blockage", "be", "blo"]:
return "be"
elif purpose in ["model", "ml", "mod"]:
return "ml"
elif startsWithAny(["option", "o", "opt"], purpose):
return "o"
elif purpose in ["fuse", "fe", "fus"]:
return "fe"
elif purpose in ["mask", "mk"]:
return "mk"
elif purpose in ["maskAdd", "md"]:
return "md"
elif purpose in ["maskDrop", "mp"]:
return "mp"
elif startsWithAny(["waffleAdd", "w"], purpose):
return "w"
elif purpose in ["waffleDrop", "wp", "waf"]:
return "wp"
elif purpose in ["error", "er", "err"]:
return "er"
elif purpose in ["warning", "wg", "wng"]:
return "wg"
elif purpose in ["dummy", "dy", "dmy"]:
return "dy"
else:
return "no"
def parseLine(line):
result = list(csv.reader([line.strip()], delimiter=' ', quotechar='"'))[0]
for i, elem in enumerate(result):
if elem.startswith("#"):
result = result[0:i]
break
return [elem.strip() for elem in result if elem.strip()]
def loadActConf(path):
result = dict()
stack = [result]
with open(path, "r") as fptr:
for number, line in enumerate(fptr):
args = parseLine(line)
if len(args) > 0:
if args[0] == "include":
result = result | loadActConf(args[1])
elif args[0] == "begin":
stack[-1][args[1]] = dict()
stack.append(stack[-1][args[1]])
elif args[0] == "end":
stack.pop()
elif args[0] == "string":
stack[-1][args[1]] = args[2]
elif args[0] == "int":
stack[-1][args[1]] = int(args[2])
elif args[0] == "real":
stack[-1][args[1]] = float(args[2])
elif args[0] == "int_table":
stack[-1][args[1]] = [int(arg) for arg in args[2:]]
elif args[0] == "string_table":
stack[-1][args[1]] = args[2:]
return result
def writeLayerMap(path, conf):
# See https://github.com/KLayout/klayout/blob/766dd675c11d98b2461c448035197f6e934cb497/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc#L1085
# Purpose Name = Placement Code
# LEFPIN = LEFPIN
# PIN = PIN
# LEFPINNAME = LEFLABEL
# PINNAME = LABEL
# FILL = FILL
# FILLOPC = FILLOPC
# LEFOBS = OBS
# SPNET = SPNET
# NET = NET
# VIA = VIA
# BLOCKAGE = BLK
# ALL = [LEFPIN, PIN, FILL, FILLOPC, OBS, SPNET, NET, VIA]
layers = zip(conf["gds"]["layers"], conf["gds"]["major"], conf["gds"]["minor"])
with open(path, "w") as fptr:
for layer in layers:
name, purpose = splitLayerID(layer[0])
if purpose in ["drawing", "dg", "drw"]:
print(f"{name} LEFOBS,FILL,FILLOPC,VIA {layer[1]} {layer[2]}", file=fptr)
elif purpose in ["label", "ll", "lbl"]:
print(f"NAME {name}/PINNAME {layer[1]} {layer[2]}", file=fptr)
print(f"NAME {name}/PIN {layer[1]} {layer[2]}", file=fptr)
print(f"NAME {name}/LEFPINNAME {layer[1]} {layer[2]}", file=fptr)
print(f"NAME {name}/LEFPIN {layer[1]} {layer[2]}", file=fptr)
elif purpose in ["net", "nt"]:
print(f"{name} NET,SPNET {layer[1]} {layer[2]}", file=fptr)
elif purpose in ["pin", "pin1", "pn"]:
print(f"{name} PIN,LEFPIN {layer[1]} {layer[2]}", file=fptr)
elif purpose in ["blockage", "block", "be", "blo"]:
print(f"{name} BLOCKAGE {layer[1]} {layer[2]}", file=fptr)
if name.lower().startswith("areaid") and name.lower().endswith("sc"):
print(f"DIEAREA ALL {layer[1]} {layer[2]}", file=fptr)
class Parser(object):
def __init__(self):
self.syntax = dict()
# key -> value
self.stack = [("", self.syntax)]
def start(self, tag, attrs):
insert = dict()
if self.stack:
if tag in self.stack[-1][1]:
if isinstance(self.stack[-1][1][tag], list):
self.stack[-1][1][tag].append(insert)
else:
self.stack[-1][1][tag] = [
self.stack[-1][1][tag],
insert
]
else:
self.stack[-1][1][tag] = insert
self.stack.append((tag, insert))
def end(self, tag):
if tag == self.stack[-1][0]:
self.stack.pop()
def data(self, data):
if self.stack and data.strip():
if len(self.stack) > 1 and isinstance(self.stack[-1][1], dict) and not self.stack[-1][1]:
if isinstance(self.stack[-2][1][self.stack[-1][0]], list):
self.stack[-2][1][self.stack[-1][0]][-1] = data
else:
self.stack[-2][1][self.stack[-1][0]] = data
elif isinstance(self.stack[-1][1], str):
self.stack[-2][1][self.stack[-1][0]] += data
else:
print("syntax error", self.stack, data)
def close(self):
return self
def readKLayoutConf(path):
parser = lxml.etree.XMLParser(target = Parser())
with open(path, "r") as fptr:
parser.feed(fptr.read())
return parser.close().syntax
def buildKLayoutConf(conf, e=lxml.builder.ElementMaker(), key=None):
result = []
if isinstance(conf, dict):
for key, value in conf.items():
if not isinstance(value, list):
value = [value]
result += buildKLayoutConf(value, e, key)
elif isinstance(conf, list):
for item in conf:
child = e(key)
elems = buildKLayoutConf(item, e)
for elem in elems:
if isinstance(elem, lxml.etree._Element):
child.append(elem)
elif elem is not None:
if isinstance(elem, bool):
child.text = str(elem).lower()
else:
child.text = str(elem)
result.append(child)
else:
result.append(conf)
return result
def writeKLayoutConf(path, conf):
with open(path, "wb") as fptr:
klays = buildKLayoutConf(conf)
for klay in klays:
fptr.write(lxml.etree.tostring(klay, encoding='utf-8', xml_declaration=True, pretty_print=True))
def createLYTFromACT(prs2net, layout, actHome):
lyt = readKLayoutConf("default.lyt")
layers = {
layer: (major, minor)
for layer, major, minor in zip(
layout["gds"]["layers"],
layout["gds"]["major"],
layout["gds"]["minor"]
)
}
layerMap = "layer_map(" + ";".join([
f"'{layer} : {gds[0]}/{gds[1]}'"
for layer, gds in layers.items()
]) + ")"
techName = layout["info"]["name"]
dbu = float(layout["general"]["scale"])*1e-3
# build the tech file (lyt)
if "technology" not in lyt:
lyt["technology"] = dict()
lyt["technology"] |= {
"name": techName,
"description": layout["info"]["date"],
"dbu": dbu,
"base-path": f"{actHome}/conf/{techName}/klayout",
"layer-properties_file": f"{techName}.lyp",
}
if "reader-options" not in lyt["technology"]:
lyt["technology"]["reader-options"] = dict()
if "common" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["common"] = dict()
# LEFDEF Layer Purposes
# from https://github.com/KLayout/klayout/blob/6c8d97adc97bf992ccbdb5f7950cb95a28ffeab9/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h#L1037
# Routing from DEF only
# Pins from DEF
# Fills from DEF
# FillsOPC from DEF
# SpecialRouting from DEF only
# LEFPins from LEF
# ViaGeometry from LEF+DEF
# Label from DEF
# LEFLabel from LEF
# Obstructions from LEF only
# Outline from LEF+DEF
# Blockage from DEF only
# PlacementBlockage from DEF only
# Regions from DEF only
# RegionsNone from DEF only
# RegionsFence from DEF only
# RegionsGuide from DEF only
# All from DEF only
if "lefdef" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["lefdef"] = dict()
lyt["technology"]["reader-options"]["lefdef"] |= {
"layer-map": layerMap,
"dbu": dbu,
# these options are not part of the technology, but are specific to the cell placer
"produce-placement-blockages": True,
"placement-blockage-layer": "place.block", # tell the placer to avoid placing cells in an area
"produce-regions": True,
"region-layer": "place.mask", # tell the placer to put cells in an area
"produce-net-names": True,
#"net-property-name": "#23", # guessing this is the gds datatype of the *.net layers?
"produce-inst-names": True,
#"inst-property-name": "#1", # TODO dump standard cell gds and look for "shape properties"
"produce-pin-names": True,
#"pin-property-name": "#1",
"produce-cell-outlines": True,
"cell-outline-layer": "areaid_sc.identifier",
"produce-via-geometry": True,
"via-geometry-suffix-string": ".drawing",
#"via-geometry-datatype-string": None,
"produce-pins": True,
"pins-suffix-string": ".pin",
#"pins-datatype-string": None,
"produce-lef-pins": True,
"lef_pins-suffix-string": ".pin",
#"lef_pins-datatype-string": None,
"produce-fills": True,
"fills-suffix-string": ".drawing",
#"fills-datatype-string": None,
"produce-obstructions": True,
"obstructions-suffix": ".drawing",
#"obstructions-datatype": None,
"produce-blockages": True,
"blockages-suffix": ".block",
#"blockages-datatype": None,
"produce-labels": True,
"labels-suffix": ".label",
#"labels-datatype": None,
"produce-lef-labels": True,
"lef-labels-suffix": ".label",
#"lef-labels-datatype": None,
"produce-routing": True,
"routing-suffix-string": ".drawing",
#"routing-datatype-string": None,
"produce-special-routing": True,
"special-routing-suffix-string": ".drawing",
#"special-routing-datatype-string": None,
"via-cellname-prefix": None,
"lef-files": None,
}
if "mebes" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["mebes"] = dict()
if "dxf" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["dxf"] = dict()
lyt["technology"]["reader-options"]["dxf"] |= {
"dbu": dbu,
"unit": round(prs2net["net"]["lambda"]*1e6/dbu),
}
if "cif" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["cif"] = dict()
lyt["technology"]["reader-options"]["cif"] |= {
"dbu": dbu,
}
if "mag" not in lyt["technology"]["reader-options"]:
lyt["technology"]["reader-options"]["mag"] = dict()
lyt["technology"]["reader-options"]["mag"] |= {
"dbu": dbu,
"lambda": round(prs2net["net"]["lambda"]*1e6/dbu),
}
if "connectivity" not in lyt["technology"]:
lyt["technology"]["connectivity"] = dict()
matMap = dict()
for name, mat in layout["materials"].items():
if isinstance(mat, dict) and "gds" in mat:
if name not in matMap:
matMap[name] = []
matMap[name] += [layers[layer] for layer in mat["gds"] if layer in layers]
metMap = list()
for name, met in layout["materials"]["metal"].items():
if name.startswith("m") and name.endswith("_gds"):
mid = int(name[1:-4])
if len(metMap) <= mid:
metMap += [[]]*(mid+1-len(metMap))
metMap[mid] += [layers[layer] for layer in met if layer in layers]
if len(matMap)+len(metMap) > 0:
if "symbols" not in lyt["technology"]["connectivity"]:
lyt["technology"]["connectivity"]["symbols"] = list()
for name, mat in matMap.items():
lyt["technology"]["connectivity"]["symbols"].append(
f"{name}='" + "+".join(f"{gds[0]}/{gds[1]}" for gds in mat) + "'"
)
for mid, met in enumerate(metMap):
lyt["technology"]["connectivity"]["symbols"].append(
f"m{mid}='" + "+".join(f"{gds[0]}/{gds[1]}" for gds in met) + "'"
)
if "connection" not in lyt["technology"]["connectivity"]:
lyt["technology"]["connectivity"]["connection"] = list()
for name, via in layout["vias"].items():
if name.endswith("_gds"):
dn = name[0:-4]
up = "m1"
if dn.startswith("m") and dn[1:].isdigit():
up = int(dn[1:])+1
viaMap = [layers[layer] for layer in via if layer in layers]
lyt["technology"]["connectivity"]["connection"].append(
f"{dn}," + "+".join(f"{gds[0]}/{gds[1]}" for gds in viaMap) + f",{up}"
)
#pprint.pprint(lyt)
return lyt
def createLYPFromACT(layout, actHome):
lyp = readKLayoutConf("default.lyp")
userPurpose = ["dg", "pn", "ll", "er", "wg"]
userLayers = ["areaid_sc.identifier", "text.drawing"]
layers = [(layer, major, minor, purposeToID(splitLayerID(layer)[1]))
for layer, major, minor in zip(layout["gds"]["layers"], layout["gds"]["major"], layout["gds"]["minor"])]
layers = sorted([
layer for layer in layers if layer[0] in userLayers], key=lambda x: (x[1], -x[2])) + sorted([
layer for layer in layers if layer[3] in userPurpose and layer[0] not in userLayers], key=lambda x: (x[1], -x[2])) + [
layer for layer in layers if layer[3] not in userPurpose and layer[0] not in userLayers
]
# build the properties file (lyp)
if "layer-properties" not in lyp:
lyp["layer-properties"] = dict()
defaultProperties = dict()
if "properties" in lyp["layer-properties"]:
defaultProperties = lyp["layer-properties"]["properties"]
lyp["layer-properties"]["properties"] = []
ndiffs = set()
for diff in layout["diff"]["ntype"]:
if diff in layout["materials"] and "gds" in layout["materials"][diff]:
ndiffs.update(layout["materials"][diff]["gds"])
for well in layout["diff"]["pfet_well"]:
well = well.split(":")[1]
if len(well) > 0 and well in layout["materials"] and "gds" in layout["materials"][well]:
ndiffs.update(layout["materials"][well]["gds"])
pdiffs = set()
for diff in layout["diff"]["ptype"]:
if diff in layout["materials"] and "gds" in layout["materials"][diff]:
pdiffs.update(layout["materials"][diff]["gds"])
for well in layout["diff"]["nfet_well"]:
well = well.split(":")[1]
if len(well) > 0 and well in layout["materials"] and "gds" in layout["materials"][well]:
pdiffs.update(layout["materials"][well]["gds"])
diffs = ndiffs & pdiffs
ndiffs = list(ndiffs - diffs)
pdiffs = list(pdiffs - diffs)
diffs = list(diffs)
diffsSupport = [splitLayerID(layer)[0] for layer in diffs]
ndiffsSupport = [splitLayerID(layer)[0] for layer in ndiffs]
pdiffsSupport = [splitLayerID(layer)[0] for layer in pdiffs]
pwells = set()
for well in layout["diff"]["nfet_well"]:
well = well.split(":")[0]
if len(well) > 0 and well in layout["materials"] and "gds" in layout["materials"][well]:
pwells.update(layout["materials"][well]["gds"])
nwells = set()
for well in layout["diff"]["pfet_well"]:
well = well.split(":")[0]
if len(well) > 0 and well in layout["materials"] and "gds" in layout["materials"][well]:
nwells.update(layout["materials"][well]["gds"])
wells = nwells & pwells
nwells = list(nwells - wells)
pwells = list(pwells - wells)
wells = list(wells)
wellsSupport = [splitLayerID(layer)[0] for layer in wells]
nwellsSupport = [splitLayerID(layer)[0] for layer in nwells]
pwellsSupport = [splitLayerID(layer)[0] for layer in pwells]
poly = set()
if "polysilicon" in layout["materials"] and "gds" in layout["materials"]["polysilicon"]:
poly = set(layout["materials"]["polysilicon"]["gds"])
poly = list(poly)
polySupport = [splitLayerID(layer)[0] for layer in poly]
metals = list()
if "metals" in layout["general"] and "metal" in layout["materials"]:
for mid in range(0, layout["general"]["metals"]):
key = f"m{mid+1}_gds"
if key in layout["materials"]["metal"]:
metals.append(layout["materials"]["metal"][key])
metalsSupport = [[splitLayerID(layer)[0] for layer in metal] for metal in metals]
metalCol = ["#0000ff", "#ff0080", "#ffa900", "#d700ff", "#00feff", "#13ff00"]
metalDith = ["I6", "I4", "I8", "I4", "I8", "I4"]
metalSupportDith = ["I10", "I8", "I4", "I8", "I4", "I8"]
viaDiffs = set()
if "vias" in layout:
for diff in layout["diff"]["ntype"]:
if f"{diff}_gds" in layout["vias"]:
viaDiffs.update(layout["vias"][f"{diff}_gds"])
for diff in layout["diff"]["ptype"]:
if f"{diff}_gds" in layout["vias"]:
viaDiffs.update(layout["vias"][f"{diff}_gds"])
for well in layout["diff"]["nfet_well"]:
well = well.split(":")[1]
if len(well) > 0 and f"{well}_gds" in layout["vias"]:
viaDiffs.update(layout["vias"][f"{well}_gds"])
for well in layout["diff"]["pfet_well"]:
well = well.split(":")[1]
if len(well) > 0 and f"{well}_gds" in layout["vias"]:
viaDiffs.update(layout["vias"][f"{well}_gds"])
viaDiffs = list(viaDiffs)
viaDiffsSupport = [splitLayerID(layer)[0] for layer in viaDiffs]
viaWells = set()
if "vias" in layout:
for well in layout["diff"]["nfet_well"]:
well = well.split(":")[0]
if len(well) > 0 and f"{well}_gds" in layout["vias"]:
viaWells.update(layout["vias"][f"{well}_gds"])
for well in layout["diff"]["pfet_well"]:
well = well.split(":")[0]
if len(well) > 0 and f"{well}_gds" in layout["vias"]:
viaWells.update(layout["vias"][f"{well}_gds"])
viaWells = list(viaWells)
viaWellsSupport = [splitLayerID(layer)[0] for layer in viaWells]
vias = list()
if "metals" in layout["general"] and "vias" in layout:
for mid in range(0, layout["general"]["metals"]-1):
key = f"m{mid+1}_gds"
if key in layout["vias"]:
vias.append(layout["vias"][key])
viasSupport = [[splitLayerID(layer)[0] for layer in via] for via in vias]
viaCol = ["#aaaaff", "#ff9acd", "#ffe1a6", "#f2abff", "#b6ffff", "#c9ffc4"]
for layer, major, minor, purpose in layers:
properties = copy.deepcopy(defaultProperties)
name, purposeFull = splitLayerID(layer)
properties |= {
"name": f"{layer} - {major}/{minor}",
"source": f"{major}/{minor}",
"visible": purpose in userPurpose or layer in userLayers,
}
if purpose == "er":
properties |= {
"frame-color": "#ff0000",
"fill-color": "#ff0000",
"dither-pattern": "blank",
"line-style": "C",
"xfill": True,
}
elif purpose == "wg":
properties |= {
"frame-color": "#ffff00",
"fill-color": "#ffff00",
"dither-pattern": "blank",
"line-style": "C0",
"xfill": True,
}
elif layer in diffs:
idx = diffs.index(layer)
properties |= {
"frame-color": "#ffc280",
"fill-color": "#ffc280",
"dither-pattern": "I2",
"line-style": "C0",
}
elif layer in ndiffs:
idx = ndiffs.index(layer)
properties |= {
"frame-color": "#80a8ff",
"fill-color": "#80a8ff",
"dither-pattern": "I3",
"line-style": "C0",
}
elif layer in pdiffs:
idx = pdiffs.index(layer)
properties |= {
"frame-color": "#ff9d9d",
"fill-color": "#ff9d9d",
"dither-pattern": "I3",
"line-style": "C0",
}
elif layer in wells:
idx = wells.index(layer)
properties |= {
"frame-color": "#ffc280",
"fill-color": "#ffc280",
"dither-pattern": "I1",
"line-style": "C0",
}
elif layer in nwells:
idx = nwells.index(layer)
properties |= {
"frame-color": "#ff0000",
"fill-color": "#ff0000",
"dither-pattern": "I1",
"line-style": "C0",
}
elif layer in pwells:
idx = pwells.index(layer)
properties |= {
"frame-color": "#0000ff",
"fill-color": "#0000ff",
"dither-pattern": "I1",
"line-style": "C0",
}
elif layer in poly:
idx = poly.index(layer)
properties |= {
"frame-color": "#01ff6b",
"fill-color": "#01ff6b",
"dither-pattern": "I2",
"line-style": "C0",
}
elif layer in set(sum(metals, [])):
for mid, met in enumerate(metals):
if layer in met:
idx = met.index(layer)
properties |= {
"frame-color": metalCol[mid%len(metalCol)],
"fill-color": metalCol[mid%len(metalCol)],
"dither-pattern": metalDith[mid%len(metalDith)],
"line-style": "C0",
}
elif layer in set(sum(vias, [])):
for vid, via in enumerate(vias):
if layer in via:
idx = via.index(layer)
properties |= {
"frame-color": viaCol[vid%len(viaCol)],
"fill-color": viaCol[vid%len(viaCol)],
"dither-pattern": "I0",
"line-style": "C0",
}
elif layer in viaDiffs:
idx = viaDiffs.index(layer)
properties |= {
"frame-color": "#ffffff",
"fill-color": "#ffffff",
"dither-pattern": "I0",
"line-style": "C0",
}
elif layer in viaWells:
idx = viaWells.index(layer)
properties |= {
"frame-color": "#aaffff",
"fill-color": "#aaffff",
"dither-pattern": "I0",
"line-style": "C0",
}
elif purpose == "ll":
properties |= {
"frame-color": "#ffffff",
"fill-color": "#ffffff",
"dither-pattern": "I0",
"line-style": "C0",
}
elif name in diffsSupport:
idx = diffsSupport.index(name)
properties |= {
"frame-color": "#ffc280",
"fill-color": "#ffc280",
"dither-pattern": "I0",
"line-style": "C0",
}
elif name in ndiffsSupport:
idx = ndiffsSupport.index(name)
properties |= {
"frame-color": "#80a8ff",
"fill-color": "#80a8ff",
"dither-pattern": "I2",
"line-style": "C0",
}
elif name in pdiffsSupport:
idx = pdiffsSupport.index(name)
properties |= {
"frame-color": "#ff9d9d",
"fill-color": "#ff9d9d",
"dither-pattern": "I2",
"line-style": "C0",
}
elif name in wellsSupport:
idx = wellsSupport.index(name)
properties |= {
"frame-color": "#ffc280",
"fill-color": "#ffc280",
"dither-pattern": "I3",
"line-style": "C0",
}
elif name in nwellsSupport:
idx = nwellsSupport.index(name)
properties |= {
"frame-color": "#ff0000",
"fill-color": "#ff0000",
"dither-pattern": "I3",
"line-style": "C0",
}
elif name in pwellsSupport:
idx = pwellsSupport.index(name)
properties |= {
"frame-color": "#0000ff",
"fill-color": "#0000ff",
"dither-pattern": "I3",
"line-style": "C0",
}
elif name in polySupport:
idx = polySupport.index(name)
properties |= {
"frame-color": "#01ff6b",
"fill-color": "#01ff6b",
"dither-pattern": "I0",
"line-style": "C0",
}
elif name in viaDiffsSupport:
idx = viaDiffsSupport.index(name)
properties |= {
"frame-color": "#000000",
"fill-color": "#ffffff",
"dither-pattern": "I1",
"line-style": "C0",
}
elif name in viaWellsSupport:
idx = viaWellsSupport.index(name)
properties |= {
"frame-color": "#000000",
"fill-color": "#aaffff",
"dither-pattern": "I1",
"line-style": "C0",
}
elif name in set(sum(metalsSupport, [])):
for mid, met in enumerate(metalsSupport):
if name in met:
idx = met.index(name)
properties |= {
"frame-color": metalCol[mid%len(metalCol)],
"fill-color": metalCol[mid%len(metalCol)],
"dither-pattern": metalSupportDith[mid%len(metalDith)],
"line-style": "C0",
}
elif name in set(sum(viasSupport, [])):
for vid, via in enumerate(viasSupport):
if name in via:
idx = via.index(name)
properties |= {
"frame-color": viaCol[vid%len(viaCol)],
"fill-color": viaCol[vid%len(viaCol)],
"dither-pattern": "I0",
"line-style": "C0",
}
else:
pass
lyp["layer-properties"]["properties"].append(properties)
#pprint.pprint(lyp)
return lyp
def print_help():
print("Usage: generate_klayout_tech.py [options]")
print("\t-T<tech>\tidentify the technology used for this translation.")
if __name__ == "__main__":
if len(sys.argv) >= 2 and (sys.argv[1] == '--help' or sys.argv[1] == '-h'):
print_help()
else:
techName = "sky130"
actHome = os.environ.get('ACT_HOME', "/opt/cad")
for arg in sys.argv[1:]:
if arg[0] == '-':
if arg[1] == 'T':
techName = arg[2:]
else:
print(f"error: unrecognized option '{arg}'")
print("")
print_help()
sys.exit()
layout = loadActConf(actHome + "/conf/" + techName + "/layout.conf")
prs2net = loadActConf(actHome + "/conf/" + techName + "/prs2net.conf")
writeKLayoutConf(f"{techName}.lyt", createLYTFromACT(prs2net, layout, actHome))
writeKLayoutConf(f"{techName}.lyp", createLYPFromACT(layout, actHome))
writeLayerMap("layermap.txt", layout)