create markdwon

This commit is contained in:
PhillipRambo 2025-03-28 15:58:23 +01:00
parent 9aef2e060d
commit 23c724be38
10 changed files with 577 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
* Extracted by KLayout with SG13G2 LVS runset on : 27/03/2025 11:05
.SUBCKT lvs_tester gnd G D
M$1 gnd G D \$1 sg13_lv_nmos L=0.45u W=1u AS=0.34p AD=0.34p PS=2.68u PD=2.68u
R$2 \$1 gnd ptap1 A=0.6084p P=3.12u
.ENDS lvs_tester

View File

@ -0,0 +1,34 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {}
V {}
S {}
E {}
P 4 1 310 -180 {}
P 4 1 310 -180 {}
N 150 -40 150 -20 {lab=gnd}
N 150 -70 230 -70 {lab=sub}
N 100 -70 110 -70 {lab=G}
N 360 -130 360 -110 {lab=sub}
N 360 -50 360 -30 {lab=gnd}
N 150 -140 150 -100 {lab=D}
C {sg13g2_pr/sg13_lv_nmos.sym} 130 -70 0 0 {name=M3
l=0.45u
w=1.0u
ng=1
m=1
model=sg13_lv_nmos
spiceprefix=X
}
C {lab_pin.sym} 230 -70 0 1 {name=p2 sig_type=std_logic lab=sub}
C {iopin.sym} 100 -70 2 0 {name=p9 lab=G}
C {iopin.sym} 150 -140 0 0 {name=p3 lab=D}
C {lab_pin.sym} 150 -20 0 1 {name=p4 sig_type=std_logic lab=gnd}
C {iopin.sym} 360 -30 0 0 {name=p5 lab=gnd}
C {lab_pin.sym} 360 -130 0 1 {name=p6 sig_type=std_logic lab=sub}
C {sg13g2_pr/ptap1.sym} 360 -80 2 0 {name=R1
model=ptap1
spiceprefix=X
w=0.78e-6
l=0.78e-6
}

0
utils/lvs_tester/test.md Normal file
View File

View File

@ -0,0 +1,379 @@
"""Module to automatically generate a gallery of devices out of spice netlist creating a new GDS file. Can be used in
Klayout's batch mode. For example:
klayout -n sg13g2 -zz -r generator.py -rd netlist=netlist.spice -rd output=macros/gallery.gds
"""
import pathlib
import sys
import re
import argparse
from typing import List, Dict
import pya
import klayout.db
LIB = 'SG13_dev'
def parse_netlist(netlist: str) -> List[Dict[str, str]]:
# Define regular expression patterns for each component type
patterns = {
'ipin': re.compile(r"^\*\.ipin\s+(\S+)\s*$", re.MULTILINE),
'opin': re.compile(r"^\*\.opin\s+(\S+)\s*$", re.MULTILINE),
'iopin': re.compile(r"^\*\.iopin\s+(\S+)\s*$", re.MULTILINE),
'bjt': re.compile(r"^XQ(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)\s+Nx=([\d\.]+)(?:\s+le=([\d\.e-]+))?\s*$", re.MULTILINE),
'capacitor': re.compile(r"^XC(\S+)\s+\S+\s+\S+\s+(\S+)\s+w=([\d\.e-]+)\s+l=([\d\.e-]+)\s+m=([\d\.]+)\s*$", re.MULTILINE),
'diode': re.compile(r"^XD(\S+)\s+\S+\s+\S+\s+(\S+)\s+l=([\d\.a-zA-Z]+)\s+w=([\d\.a-zA-Z]+)\s*$", re.MULTILINE),
'resistor': re.compile(r"^XR(\S+)\s+\S+\s+\S+\s+(\S+)\s+w=([\d\.e-]+)\s+l=([\d\.e-]+)\s+m=([\d\.]+)\s+b=([\d\.]+)\s*$", re.MULTILINE),
'mosfet': re.compile(r"^XM(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)\s+w=([\d\.u-]+)\s+l=([\d\.u-]+)\s+ng=([\d\.]+)\s+m=([\d\.]+)(?:\s+rfmode=([\d\.]+))?\s*$", re.MULTILINE),
'tap': re.compile(r"^XR(\S+)\s+\S+\s+\S+\s+(\S+)\s*$", re.MULTILINE)
}
components = []
# Parse pins
for pin_type in ['ipin', 'opin', 'iopin']:
for match in patterns[pin_type].finditer(netlist):
components.append({
'name': match.group(1),
'model': pin_type
})
# Parse BJTs
for match in patterns['bjt'].finditer(netlist):
components.append({
'name': f"XQ{match.group(1)}",
'model': match.group(2),
'Nx': match.group(3),
'le': match.group(4) if match.group(4) else None
})
# Parse capacitors
for match in patterns['capacitor'].finditer(netlist):
components.append({
'name': f"XC{match.group(1)}",
'model': match.group(2),
'w': match.group(3),
'l': match.group(4),
'm': match.group(5)
})
# Parse diodes
for match in patterns['diode'].finditer(netlist):
components.append({
'name': f"XD{match.group(1)}",
'model': match.group(2),
'l': match.group(3),
'w': match.group(4)
})
# Parse resistors
for match in patterns['resistor'].finditer(netlist):
components.append({
'name': f"XR{match.group(1)}",
'model': match.group(2),
'w': match.group(3),
'l': match.group(4),
'm': match.group(5),
'b': match.group(6)
})
# Parse MOSFETs
for match in patterns['mosfet'].finditer(netlist):
components.append({
'name': f"XM{match.group(1)}",
'model': match.group(2),
'w': match.group(3),
'l': match.group(4),
'ng': match.group(5),
'm': match.group(6),
'rfmode': match.group(7) if match.group(7) else None
})
#Parse ntap
for match in patterns['tap'].finditer(netlist):
components.append({
'name': f"XR{match.group(1)}",
'model': match.group(2) # In this case, group 4 is the ntap model
})
return components
def generate_devices(netlist: str, output: str):
components = parse_netlist(netlist)
lib = pya.Library.library_by_name(LIB)
layout = klayout.db.Layout(True)
layout.dbu = 0.001
top_cell = layout.cell(layout.add_cell('gallery'))
res = find_instances_by_model(components, 'rppd')
xstep = 0
cell_w = 0
y_offset = 100
hmax = 0
for item in res:
width = float(item['w'])*1e6
length = float(item['l'])*1e6
bends = int(item['b'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('rppd')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'b' : f'{bends}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep,y_offset ))))
cell_w = bbox.width()
cell_h = bbox.height()
if cell_h > hmax:
hmax = cell_h
# print(f'w: {cell_w}, h: {cell_h}, xstep: {xstep}')
res = find_instances_by_model(components, 'rhigh')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in res:
width = float(item['w'])*1e6
length = float(item['l'])*1e6
bends = int(item['b'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('rhigh')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'b' : f'{bends}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
res = find_instances_by_model(components, 'rsil')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in res:
width = float(item['w'])*1e6
length = float(item['l'])*1e6
bends = int(item['b'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('rsil')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'b' : f'{bends}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep,y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
mos = find_instances_by_model(components, 'sg13_lv_nmos')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in mos:
width = float(item['w'][:-1])
length = float(item['l'][:-1])
ng = int(item['ng'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('nmos')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'ng' : f'{ng}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
mos = find_instances_by_model(components, 'sg13_hv_nmos')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in mos:
width = float(item['w'][:-1])
length = float(item['l'][:-1])
ng = int(item['ng'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('nmosHV')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'ng' : f'{ng}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
mos = find_instances_by_model(components, 'sg13_lv_pmos')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in mos:
name = item['name']
width = float(item['w'][:-1])
length = float(item['l'][:-1])
ng = int(item['ng'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('pmos')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'ng' : f'{ng}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
mos = find_instances_by_model(components, 'sg13_hv_pmos')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in mos:
name = item['name']
width = float(item['w'][:-1])
length = float(item['l'][:-1])
ng = int(item['ng'])
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('pmosHV')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u', 'ng' : f'{ng}'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
cmim = find_instances_by_model(components, 'cap_cmim')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in cmim:
width = float(item['w'])*1e6
length = float(item['l'])*1e6
m = int(item['m'])
for i in range(1,m+1):
pcell_decl = lib.layout().pcell_declaration('cmim')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
dant = find_instances_by_model(components, 'dantenna')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in dant:
name = item['name']
model = item['model']
width = float(item['w'][:-1])
length = float(item['l'][:-1])
pcell_decl = lib.layout().pcell_declaration('dantenna')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
dant = find_instances_by_model(components, 'dpantenna')
xstep = 0
cell_w = 0
y_offset = y_offset + hmax
hmax = 0
for item in dant:
name = item['name']
model = item['model']
width = float(item['w'][:-1])
length = float(item['l'][:-1])
pcell_decl = lib.layout().pcell_declaration('dpantenna')
params = pcell_decl.params_as_hash(pcell_decl.get_parameters())
pcell = layout.add_pcell_variant(lib, pcell_decl.id(), {'w': f'{width}u', 'l': f'{length}u'})
cell=layout.cell(pcell)
bbox=cell.bbox()
xstep = xstep + 100 + cell_w
top_cell.insert(klayout.db.CellInstArray(pcell, klayout.db.Trans(klayout.db.Point(xstep, y_offset))))
cell_w=bbox.width()
cell_h=bbox.height()
if cell_h > hmax:
hmax = cell_h
pathlib.Path(output).parent.mkdir(parents=True, exist_ok=True)
layout.write(output)
def find_instances_by_model(components, model_name):
return [item for item in components if item['model'] == model_name]
try:
netlist
except NameError:
print("Missing netlist argument. Please define '-rd netlsit=<path-to-netlist>'")
sys.exit(1)
# sys.exit(1)
try:
output
except NameError:
print("Missing output argument. Please define '-rd output=<path-to-sealring>'")
sys.exit(1)
def main():
with open(netlist, 'r') as file:
netlist_content = file.read()
generate_devices(netlist_content, output) # pylint: disable=undefined-variable
print(f'GDS created, open it using: ->klayout {output}')
if __name__ == "__main__":
main()

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category>drc</category>
<prolog/>
<epilog/>
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<priority>0</priority>
<shortcut/>
<show-in-menu>true</show-in-menu>
<group-name>drc_scripts</group-name>
<menu-path>tools_menu.drc.end</menu-path>
<interpreter>dsl</interpreter>
<dsl-interpreter-name>drc-dsl-xml</dsl-interpreter-name>
<text># Layer Inputs
# Activ = source.input("1/0")
# Activ_pin = source.input("1/2")
# Activ_mask = source.input("1/20") # Commented out as not on the list
# Activ_filler = source.input("1/22") # Commented out as not on the list
# Activ_nofill = source.input("1/23") # Commented out as not on the list
# BiWind = source.input("3/0") # Commented out as not on the list
# GatPoly = source.input("5/0")
# GatPoly_pin = source.input("5/2")
# GatPoly_filler = source.input("5/22") # Commented out as not on the list
# GatPoly_nofill = source.input("5/23") # Commented out as not on the list
# Cont = source.input("6/0")
# nSD = source.input("7/0")
# nSD_block = source.input("7/21") # Commented out as not on the list
# Metal1 = source.input("8/0")
# Metal1_pin = source.input("8/2")
# Metal1_filler = source.input("8/22") # Commented out as not on the list
# Metal1_nofill = source.input("8/23") # Commented out as not on the list
# Metal1_slit = source.input("8/24") # Commented out as not on the list
# Passiv = source.input("9/0") # Commented out as not on the list
# Metal2 = source.input("10/0")
# Metal2_pin = source.input("10/2") # Commented out as not on the list
# Metal2_filler = source.input("10/22") # Commented out as not on the list
# Metal2_nofill = source.input("10/23") # Commented out as not on the list
# Metal2_slit = source.input("10/24") # Commented out as not on the list
# BasPoly = source.input("13/0") # Commented out as not on the list
# pSD = source.input("14/0")
# DigiBnd = source.input("16/0") # Commented out as not on the list
# Via1 = source.input("19/0")
# RES = source.input("24/0") # Commented out as not on the list
# SRAM = source.input("25/0") # Commented out as not on the list
# TRANS = source.input("26/0") # Commented out as not on the list
# IND = source.input("27/0") # Commented out as not on the list
# SalBlock = source.input("28/0")
# Via2 = source.input("29/0")
# Metal3 = source.input("30/0")
# Metal3_pin = source.input("30/2") # Commented out as not on the list
# Metal3_filler = source.input("30/22") # Commented out as not on the list
# Metal3_nofill = source.input("30/23") # Commented out as not on the list
# Metal3_slit = source.input("30/24") # Commented out as not on the list
# NWell = source.input("31/0")
# nBuLay = source.input("32/0")
# nBuLay_block = source.input("32/21") # Commented out as not on the list
# EmWind = source.input("33/0") # Commented out as not on the list
# DeepCo = source.input("35/0") # Commented out as not on the list
# MIM = source.input("36/0")
# EdgeSeal = source.input("39/0") # Commented out as not on the list
# dfpad = source.input("41/0") # Commented out as not on the list
# dfpad_pillar = source.input("41/35") # Commented out as not on the list
# dfpad_sbump = source.input("41/36") # Commented out as not on the list
# ThickGateOx = source.input("44/0")
# PWell = source.input("46/0")
# PWell_block = source.input("46/21") # Commented out as not on the list
# Via3 = source.input("49/0")
# Metal4 = source.input("50/0")
# Metal4_pin = source.input("50/2") # Commented out as not on the list
# Metal4_filler = source.input("50/22") # Commented out as not on the list
# Metal4_nofill = source.input("50/23") # Commented out as not on the list
# Metal4_slit = source.input("50/24") # Commented out as not on the list
# EmPoly = source.input("55/0") # Commented out as not on the list
# DigiSub = source.input("60/0") # Commented out as not on the list
# TEXT_0 = source.labels("63/0")
# Via4 = source.input("66/0")
# Metal5 = source.input("67/0")
# Metal5_pin = source.input("67/2")
# Metal5_filler = source.input("67/22") # Commented out as not on the list
# Metal5_nofill = source.input("67/23") # Commented out as not on the list
# Metal5_slit = source.input("67/24") # Commented out as not on the list
# Polimide = source.input("98/0") # Commented out as not on the list
# Recog = source.input("99/0") # Commented out as not on the list
# Recog_esd = source.input("99/30") # Commented out as not on the list
# Recog_diode = source.input("99/31") # Commented out as not on the list
# Recog_tsv = source.input("99/32") # Commented out as not on the list
# EXTBlock = source.input("111/0")
# TopVia1 = source.input("125/0")
# TopMetal1 = source.input("126/0")
# TopMetal1_pin = source.input("126/2")
# TopMetal1_filler = source.input("126/22") # Commented out as not on the list
# TopMetal1_nofill = source.input("126/23") # Commented out as not on the list
# TopMetal1_slit = source.input("126/24") # Commented out as not on the list
# PolyRes = source.input("128/0")
# Vmim = source.input("129/0")
# TopVia2 = source.input("133/0")
# TopMetal2 = source.input("134/0")
# TopMetal2_pin = source.input("134/2") # Commented out as not on the list
# TopMetal2_filler = source.input("134/22") # Commented out as not on the list
# TopMetal2_nofill = source.input("134/23") # Commented out as not on the list
# TopMetal2_slit = source.input("134/24") # Commented out as not on the list
# ColWind = source.input("139/0") # Commented out as not on the list
# RFMEM = source.input("147/0") # Commented out as not on the list
# DeepVia = source.input("152/0") # Commented out as not on the list
# LBE = source.input("157/0") # Commented out as not on the list
# NoMetFiller = source.input("160/0") # Commented out as not on the list
# Snapping Layers to Grid
#GatPoly.snap(5).output("5/0")
#GatPoly_pin.snap(5).output("5/2")
#GatPoly_filler.snap(5).output("5/22")
#Metal1.snap(5).output("8/0")
#Metal1_pin.snap(5).output("8/2")
#Metal1_filler.snap(5).output("8/22")
#Metal2.snap(5).output("10/0")
#Metal2_filler.snap(5).output("10/22")
#Metal3.snap(5).output("30/0")
#Metal3_filler.snap(5).output("30/22")
#Metal4.snap(5).output("50/0")
#Metal4_filler.snap(5).output("50/22")
#Metal5.snap(5).output("67/0")
#Metal5_filler.snap(5).output("67/22")
#Metal5_pin.snap(5).output("67/2")
#TopMetal1.snap(5).output("126/0")
#TopMetal1_filler.snap(5).output("126/22")
#TopMetal1_pin.snap(5).output("126/2")
#TopMetal2.snap(5).output("134/0")
#TopMetal2_filler.snap(5).output("134/22")
#TopVia2.snap(5).output("133/0")
#Via1.snap(5).output("19/0")
#Via2.snap(5).output("29/0")
#Via3.snap(5).output("49/0")
#Via4.snap(5).output("66/0")
#TopVia1.snap(5).output("125/0")
#Vmim.snap(5).output("129/0")
#MIM.snap(5).output("36/0")
#Activ.snap(5).output("1/0")
#Activ_filler.snap(5).output("1/22")
#Activ_pin.snap(5).output("1/2")
#Cont.snap(5).output("6/0")
#nSD.snap(5).output("7/0")
#pSD.snap(5).output("14/0")
#NWell.snap(5).output("31/0")
#ThickGateOx.snap(5).output("44/0")
#nBuLay.snap(5).output("32/0")
#PolyRes.snap(5).output("128/0")
#SalBlock.snap(5).output("28/0")
#EXTBlock.snap(5).output("111/0")
#dfpad.snap(5).output("41/0")
#Passiv.snap(5).output("9/0")
#EdgeSeal.snap(5).output("39/0")
</text>
</klayout-macro>