push layout for pex

This commit is contained in:
PhillipRambo 2026-02-10 11:47:10 +01:00
parent b5cccf4f55
commit b6f9f668de
31 changed files with 1 additions and 836 deletions

View File

@ -1,30 +0,0 @@
#!/bin/bash
set -e
# Hardcoded paths (except PDK stuff)
PYTHON_ENV="/home/pedersen/misc/klayout_pex/bin/activate"
KPEX_MAGIC_EXE="/home/pedersen/.local/bin/magic"
LAYOUT_PATH="../layout/inverter.gds"
SCHEMATIC="../simulations/inverter.spice"
PDK_NAME="ihp_sg13g2"
MAGICRC="$PDK_ROOT/$PDK_NAME/libs.tech/magic/ihp-sg13g2.magicrc"
# Activate Python environment
source "$PYTHON_ENV"
# Run parasitic extraction with kpex
kpex \
--pdk "$PDK_NAME" \
--magic \
--schematic "$SCHEMATIC" \
--gds "$LAYOUT_PATH" \
--magicrc "$MAGICRC" \
--magic_mode RC \
--magic_cthresh 0.02 \
--magic_rthresh 50 \
--magic_short resistor \
--magic_merge conservative \
--out_dir ./pex_output

View File

@ -1,23 +0,0 @@
timestamp 0
version 8.3
tech ihp-sg13g2
style ngspice()
scale 1000 1 0.5
resistclasses 3000000 67000 110 88 88 88 88 18 11
parameters sg13_lv_nmos l=l w=w a1=as p1=ps a2=ad p2=pd
parameters sg13_lv_pmos l=l w=w a1=as p1=ps a2=ad p2=pd
port "Vout" 2 266 -211 298 -173 m1
port "Vin" 3 95 -213 127 -175 m1
port "Vdd" 5 -205 318 -173 356 m1
port "Gnd" 4 20 -732 52 -694 m1
node "ptap1_0.sub!" 0 0 28 -796 isosub 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
node "Vout" 1 392.446 266 -211 m1 0 0 0 0 91916 2354 0 0 0 0 0 0 0 0 0 0 0 0
node "Vin" 0 646.659 95 -213 m1 0 0 0 0 13590 482 0 0 0 0 0 0 0 0 0 0 0 0
node "Vdd" 1 153.076 -205 318 m1 0 0 0 0 42800 1364 0 0 0 0 0 0 0 0 0 0 0 0
equiv "Vdd" "ntap1_0.well"
substrate "Gnd" 0 0 20 -732 m1 0 0 0 0 21536 1036 0 0 0 0 0 0 0 0 0 0 0 0
cap "Vdd" "Vin" 144.819
cap "Vdd" "Vout" 131.55
cap "Vout" "Vin" 100.772
device msubckt sg13_lv_nmos 67 -562 68 -561 l=90 w=200 "Gnd" "Vin" 180 0 "Gnd" 200 13600,536 "Vout" 200 13600,536
device msubckt sg13_lv_pmos 67 9 68 10 l=90 w=400 "Vdd" "Vin" 180 0 "Vdd" 400 27200,936 "Vout" 400 27200,936

View File

@ -1,28 +0,0 @@
scale 1000 1 0.5
rnode "Gnd.t1" 0 0 29 -462 0
rnode "Gnd.t0" 0 0 112 -462 0
rnode "Gnd.n0" 0 0 62 -754 0
rnode "Gnd" 0 0 20 -732 0
resist "Gnd" "Gnd.n0" 0.0257609
resist "Gnd.n0" "Gnd.t1" 6.29433
resist "Gnd.n0" "Gnd.t0" 1079.2
rnode "Vout.t1" 0 0 195 311 0
rnode "Vout.t0" 0 0 195 -462 0
rnode "Vout" 0 0 266 -211 0
resist "Vout" "Vout.t1" 3.28762
resist "Vout" "Vout.t0" 6.19274
rnode "Vdd" 0 0 -205 318 0
rnode "Vdd.t0" 0 0 29 379 0
rnode "Vdd.n0" 0 0 -153 379 0
rnode "Vdd.n1" 0 0 -153 379 0
rnode "ntap1_0.well" 0 0 112 209 0
resist "Vdd.n0" "Vdd" 0.0476667
resist "Vdd.n0" "Vdd.t0" 3.15328
resist "ntap1_0.well" "Vdd.n1" 4.25
resist "Vdd.n1" "Vdd.n0" 8.5
resist "Vdd.n1" "Vdd" 8.51467
rnode "Vin.t0" 0 0 111 -158 0
rnode "Vin" 0 0 95 -213 0
resist "Vin" "Vin.t0" 7.52198
device msubckt sg13_lv_nmos 67 -562 68 -561 "Gnd.t0" "Vin.t0" 180 0 "Gnd.t1" 200 13600,536 "Vout.t0" 200 13600,536
device msubckt sg13_lv_pmos 67 9 68 10 "ntap1_0.well" "Vin.t0" 180 0 "Vdd.t0" 400 27200,936 "Vout.t1" 400 27200,936

View File

@ -1,25 +0,0 @@
# Generated by kpex 0.3.7
crashbackups stop
drc off
gds read /home/pedersen/misc/inverter_example/layout/inverter.gds
load inverter
select top cell
flatten inverter_flat
load inverter_flat
cellname delete inverter -noprompt
cellname rename inverter_flat inverter
select top cell
extract path /home/pedersen/misc/inverter_example/pex/pex_output/inverter__inverter/magic_RC
extract all
ext2sim labels on
ext2sim -p /home/pedersen/misc/inverter_example/pex/pex_output/inverter__inverter/magic_RC
extresist tolerance 1
extresist all
ext2spice short resistor
ext2spice merge conservative
ext2spice cthresh 0.02
ext2spice extresist on
ext2spice subcircuits top on
ext2spice format ngspice
ext2spice -p /home/pedersen/misc/inverter_example/pex/pex_output/inverter__inverter/magic_RC -o /home/pedersen/misc/inverter_example/pex/pex_output/inverter__inverter/magic_RC/inverter.pex.spice
quit -noprompt

View File

@ -1,24 +0,0 @@
timestamp 0
version 8.3
tech ihp-sg13g2
style ngspice()
scale 1000 1 0.5
resistclasses 3000000 67000 110 88 88 88 88 18 11
parameters sg13_lv_nmos l=l w=w a1=as p1=ps a2=ad p2=pd
parameters sg13_lv_pmos l=l w=w a1=as p1=ps a2=ad p2=pd
port "Vout" 3 266 -211 298 -173 m1
port "Vin" 4 95 -213 127 -175 m1
port "Vdd" 6 -237 285 -137 405 m1
port "well" 2 -265 267 -109 423 nw
port "Gnd" 5 -22 -770 78 -670 m1
node "sub!" 0 0 28 -796 isosub 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
node "Vout" 1 392.446 266 -211 m1 0 0 0 0 91916 2354 0 0 0 0 0 0 0 0 0 0 0 0
node "Vin" 0 646.659 95 -213 m1 0 0 0 0 13590 482 0 0 0 0 0 0 0 0 0 0 0 0
node "Vdd" 1 153.076 -237 285 m1 0 0 0 0 42800 1364 0 0 0 0 0 0 0 0 0 0 0 0
equiv "Vdd" "well"
substrate "Gnd" 0 0 -22 -770 m1 0 0 0 0 21536 1036 0 0 0 0 0 0 0 0 0 0 0 0
cap "Vout" "Vdd" 131.55
cap "Vout" "Vin" 100.772
cap "Vdd" "Vin" 144.819
device msubckt sg13_lv_nmos 67 -562 68 -561 l=90 w=200 "Gnd" "Vin" 180 0 "Gnd" 200 13600,536 "Vout" 200 13600,536
device msubckt sg13_lv_pmos 67 9 68 10 l=90 w=400 "Vdd" "Vin" 180 0 "Vdd" 400 27200,936 "Vout" 400 27200,936

View File

@ -1,28 +0,0 @@
scale 1000 1 0.5
rnode "well" 0 0 -265 267 0
rnode "Vdd" 0 -0 -237 285 0
resist "Vdd" "well" 8.53119
rnode "Gnd.t1" 0 0 29 -462 0
rnode "Gnd.t0" 0 0 112 -462 0
rnode "Gnd.n0" 0 0 62 -754 0
rnode "Gnd" 0 0 -22 -770 0
resist "Gnd" "Gnd.n0" 0.055709
resist "Gnd.n0" "Gnd.t1" 6.307
resist "Gnd.n0" "Gnd.t0" 1079.19
rnode "Vout.t1" 0 0 195 311 0
rnode "Vout.t0" 0 0 195 -462 0
rnode "Vout" 0 0 266 -211 0
resist "Vout" "Vout.t1" 3.28762
resist "Vout" "Vout.t0" 6.19274
rnode "Vdd" 0 0 -237 285 0
rnode "Vdd.t0" 0 0 29 379 0
rnode "Vdd.n0" 0 0 -153 379 0
rnode "well" 0 0 112 209 0
resist "Vdd.n0" "Vdd" 0.0465926
resist "Vdd.n0" "Vdd.t0" 3.18546
resist "well" "Vdd.n0" 8.48516
rnode "Vin.t0" 0 0 111 -158 0
rnode "Vin" 0 0 95 -213 0
resist "Vin" "Vin.t0" 7.52198
device msubckt sg13_lv_nmos 67 -562 68 -561 "Gnd.t0" "Vin.t0" 180 0 "Gnd.t1" 200 13600,536 "Vout.t0" 200 13600,536
device msubckt sg13_lv_pmos 67 9 68 10 "well" "Vin.t0" 180 0 "Vdd.t0" 400 27200,936 "Vout.t1" 400 27200,936

View File

@ -1,25 +0,0 @@
# Generated by kpex 0.3.7
crashbackups stop
drc off
gds read /home/pedersen/misc/inverter_example/layout/inverter_flat.gds
load inverter
select top cell
flatten inverter_flat
load inverter_flat
cellname delete inverter -noprompt
cellname rename inverter_flat inverter
select top cell
extract path /home/pedersen/misc/inverter_example/pex/pex_output/inverter_flat__inverter/magic_RC
extract all
ext2sim labels on
ext2sim -p /home/pedersen/misc/inverter_example/pex/pex_output/inverter_flat__inverter/magic_RC
extresist tolerance 1
extresist all
ext2spice short resistor
ext2spice merge conservative
ext2spice cthresh 0.02
ext2spice extresist on
ext2spice subcircuits top on
ext2spice format ngspice
ext2spice -p /home/pedersen/misc/inverter_example/pex/pex_output/inverter_flat__inverter/magic_RC -o /home/pedersen/misc/inverter_example/pex/pex_output/inverter_flat__inverter/magic_RC/inverter.pex.spice
quit -noprompt

View File

@ -1,74 +0,0 @@
import sys
import os
def extract_netlist_and_topcell(spice_path):
with open(spice_path, 'r') as f:
lines = f.readlines()
netlist = []
topcell = None
inside_subckt = False
for line in lines:
if line.strip().startswith(".subckt"):
parts = line.strip().split()
if len(parts) > 1:
topcell = parts[1]
inside_subckt = True
if inside_subckt:
netlist.append(line.rstrip())
if line.strip().startswith(".ends"):
break
if not topcell:
raise ValueError("Topcell name not found in SPICE file.")
return topcell, "\n".join(netlist)
def modify_sym_file(sym_path, output_dir, topcell, netlist):
with open(sym_path, 'r') as f:
sym_lines = f.readlines()
new_sym_lines = []
inserted = False
for line in sym_lines:
if line.strip().startswith("K {type=subcircuit"):
new_sym_lines.append(line)
continue
elif line.strip().startswith("template=") and not inserted:
new_template = (
f'template="name=x1\n'
f'schematic={topcell}\n'
f'spice_sym_def=\n'
f'\\\\"\n'
f'{netlist}\n'
f'\\\\"\n'
f'"'
)
new_sym_lines.append(new_template + "\n")
inserted = True
else:
new_sym_lines.append(line)
filename = os.path.basename(sym_path)
out_path = os.path.join(output_dir, filename)
os.makedirs(output_dir, exist_ok=True)
with open(out_path, 'w') as f:
f.writelines(new_sym_lines)
print(f"Saved modified .sym to: {out_path}")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: python insert_netlist_to_sym.py <netlist.spice> <symbol.sym> <output_folder>")
sys.exit(1)
spice_file = sys.argv[1]
sym_file = sys.argv[2]
output_folder = sys.argv[3]
topcell, netlist = extract_netlist_and_topcell(spice_file)
modify_sym_file(sym_file, output_folder, topcell, netlist)

View File

@ -1,123 +0,0 @@
import sys
import os
def load_text_file(file_path):
with open(file_path, 'r') as f:
return f.read()
def save_text_file(file_path, text):
with open(file_path, 'w') as f:
f.write(text)
def read_spice_definition(spice_path):
with open(spice_path, "r") as f:
lines = f.readlines()
subckt_line_index = next((i for i, line in enumerate(lines) if line.strip().lower().startswith(".subckt")), None)
if subckt_line_index is None:
raise ValueError(f"No .subckt line found in SPICE file: {spice_path}")
parts = lines[subckt_line_index].strip().split()
subckt_name = parts[1]
new_subckt_name = subckt_name
parts[1] = new_subckt_name
lines[subckt_line_index] = ' '.join(parts) + '\n'
definition_lines = []
recording = False
for line in lines:
if line.strip().lower().startswith(".subckt"):
recording = True
if recording:
definition_lines.append(line.rstrip())
if line.strip().lower() == ".ends":
break
return new_subckt_name, '\n'.join(definition_lines)
def find_subckt_location(subckt_name, schematic_file):
text_content = load_text_file(schematic_file)
return text_content.find(subckt_name + '.sym')
def find_first_curly_brackets_span(text, start_pos):
open_pos = text.find('{', start_pos)
if open_pos == -1:
return None, None
depth = 1
for i in range(open_pos + 1, len(text)):
if text[i] == '{':
depth += 1
elif text[i] == '}':
depth -= 1
if depth == 0:
return open_pos, i
return None, None
def replace_curly_brackets_content(text, start_idx, end_idx, new_content, subckt_name):
content = text[start_idx+1:end_idx].strip('\n ')
lines = content.splitlines()
name_line_index = next((i for i, line in enumerate(lines) if line.strip().startswith("name=")), None)
schematic_line = "schematic=" + subckt_name
if name_line_index is None:
new_lines = ['spice_sym_def="', new_content.strip(), '"'] + lines
else:
new_lines = (
lines[:name_line_index+1] +
[schematic_line] +
['spice_sym_def="', new_content.strip(), '"'] +
lines[name_line_index+1:]
)
return text[:start_idx+1] + '\n' + '\n'.join(new_lines) + '\n' + text[end_idx:]
def process_pair(spice_path, schematic_path):
print(f"\nProcessing:\n SPICE: {spice_path}\n Schematic: {schematic_path}")
try:
subckt_name, definition = read_spice_definition(spice_path)
print(f" Subcircuit name: {subckt_name}")
except Exception as e:
print(f" Error reading spice file: {e}")
return
# If subckt_name ends with '_pex', strip it for schematic search
search_subckt_name = subckt_name
if subckt_name.endswith("_pex"):
search_subckt_name = subckt_name[:-4]
location = find_subckt_location(search_subckt_name, schematic_path)
if location == -1:
print(f" '{search_subckt_name}.sym' not found in schematic file.")
return
schematic_content = load_text_file(schematic_path)
start_idx, end_idx = find_first_curly_brackets_span(schematic_content, location)
if start_idx is None:
print(" No matching curly brackets found after .sym device.")
return
new_schematic_content = replace_curly_brackets_content(
schematic_content, start_idx, end_idx, definition, subckt_name
)
# Save the file in the current working directory (where script is run)
base_name = os.path.basename(schematic_path)
name, ext = os.path.splitext(base_name)
new_filename = os.path.join(os.getcwd(), f"{name}_pex{ext}")
save_text_file(new_filename, new_schematic_content)
print(f" Replacement done and new schematic file saved as:\n {new_filename}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage:\n python3 script.py <schematic.sch> <spice_file.spice>")
sys.exit(1)
schematic = sys.argv[1]
spice_path = sys.argv[2]
print(f"Starting processing with schematic='{schematic}', spice='{spice_path}'") # Debug print
process_pair(spice_path, schematic)

View File

@ -1,59 +0,0 @@
import sys
import re
from pathlib import Path
def get_original_io_order(original_netlist_path):
io_pins = []
with open(original_netlist_path, "r") as f:
for line in f:
stripped = line.strip()
# Look for .subckt line, case-insensitive
if stripped.lower().startswith(".subckt"):
tokens = stripped.split()
if len(tokens) >= 3:
io_pins = tokens[2:]
break
if not io_pins:
raise ValueError("Could not find IO pins in original schematic")
return io_pins
def reorder_pex_subckt(pex_path, correct_order):
with open(pex_path, "r") as f:
lines = f.readlines()
new_lines = []
subckt_found = False
for line in lines:
if line.strip().lower().startswith(".subckt") and not subckt_found:
tokens = line.strip().split()
subckt_name = tokens[1]
ports = tokens[2:]
if set(ports) != set(correct_order):
raise ValueError("Port names in PEX netlist don't match original IO pins")
reordered_line = ".subckt " + subckt_name + "_pex " + " ".join(correct_order) + "\n"
new_lines.append(reordered_line)
subckt_found = True
else:
new_lines.append(line)
with open(pex_path, "w") as f:
f.writelines(new_lines)
print(f"Rewrote subckt line in {pex_path}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python patch_pex_order.py <pex_spice_path> <original_schematic_spice_path>")
sys.exit(1)
pex_spice = Path(sys.argv[1])
original_schematic = Path(sys.argv[2])
io_order = get_original_io_order(original_schematic)
reorder_pex_subckt(pex_spice, io_order)

View File

@ -1,37 +0,0 @@
import sys
def generate_xschemrc(custom_paths):
lines = [
"# xschemrc - Custom configuration file for xschem",
"# This file sources another xschemrc file from a known location",
"",
"# Source the base configuration from a known location",
"source $::env(PDK_ROOT)/$::env(PDK)/libs.tech/xschem/xschemrc",
"",
"# (Optional) Add any custom overrides or extensions below",
'# set xschem_library_path /home/user/my_libs',
'# set xschem_gui_font "Monospace 10"',
"",
"append XSCHEM_LIBRARY_PATH :$PDK_ROOT/ihp-sg13g2/libs.tech/xschem"
]
# Append each custom path with the prefix "../"
for path in custom_paths:
lines.append(f"append XSCHEM_LIBRARY_PATH :{path}")
return "\n".join(lines) + "\n"
def main():
if len(sys.argv) < 2:
print("Usage: python3 make_xschemrc.py <path1> [<path2> ... <pathN>]")
sys.exit(1)
custom_paths = sys.argv[1:]
content = generate_xschemrc(custom_paths)
with open("xschemrc", "w") as f:
f.write(content)
print(f"xschemrc file generated with {len(custom_paths)} custom paths.")
if __name__ == "__main__":
main()

View File

@ -1,103 +0,0 @@
#!/bin/bash
set -e
###############################################################################
# ⬇⬇⬇ USER CONFIGURATION ⬇⬇⬇ #
###############################################################################
# Activate Python environment (adjust this path to your Python venv activate script) Or if you python version is >3.12 ignore asuming klayout_pex is installed
PYTHON_ENV="$HOME/misc/klayout_pex/bin/activate"
# Example: /home/username/misc/klayout_pex/bin/activate
# Path to Magic executable used by kpex (adjust if installed elsewhere)
KPEX_MAGIC_EXE="$HOME/.local/bin/magic"
# Example: /usr/local/bin/magic or ~/.local/bin/magic
# Cell and schematic names (do NOT include file extensions)
SYM_DIR="../inverter.sym" # The name of your top cell / device under test (DUT)
#TESTBENCH_NAME="inverter_tb" # Name of your testbench schematic (without extension)
# Paths relative to this script or absolute paths
#SPICE_DIR="../simulations" # Directory containing netlist/spice files for testbench
LAYOUT_DIR="../layout/inverter_flat.gds" # Directory containing layout files (.gds etc.)
# Important: Path to your PDK root directory must be set externally in env variable PDK_ROOT
PDK_NAME="ihp_sg13g2" # Your PDK name (must match PDK_ROOT contents)
MAGICRC="$PDK_ROOT/$PDK/libs.tech/magic/ihp-sg13g2.magicrc"
# The magicrc file for your PDK, used during extraction
SCHEMATIC="../simulations/inverter.spice"
##############################################################################################################################################################
# ⛔ DO NOT TOUCH BELOW THIS LINE ⛔ Unless you see clear issue with your setup :) #
##############################################################################################################################################################
# Check if required files exist before proceeding
if [[ ! -f "$PYTHON_ENV" ]]; then
echo "[ERROR] Python environment activate script not found: $PYTHON_ENV"
exit 1
fi
if [[ ! -x "$KPEX_MAGIC_EXE" ]]; then
echo "[ERROR] Magic executable not found or not executable: $KPEX_MAGIC_EXE"
exit 1
fi
if [[ ! -f "$LAYOUT_DIR" ]]; then
echo "[ERROR] Layout GDS file not found: $LAYOUT_DIR"
exit 1
fi
if [[ ! -f "$MAGICRC" ]]; then
echo "[ERROR] Magicrc file for PDK not found: $MAGICRC"
exit 1
fi
# Activate Python virtual environment
echo "[INFO] Activating Python environment..."
source "$PYTHON_ENV"
echo "[INFO] Using MAGIC executable: $KPEX_MAGIC_EXE"
# Run parasitic extraction with kpex
echo "[INFO] Running parasitic extraction with KPEX..."
kpex \
--pdk "$PDK_NAME" \
--magic \
--schematic "$SCHEMATIC"\
--gds "$LAYOUT_DIR" \
--magicrc "$MAGICRC" \
--magic_mode RC \
--magic_cthresh 0.02 \
--magic_rthresh 50 \
--magic_short resistor \
--magic_merge conservative \
--out_dir ./pex_output
# Find the generated spice file (assuming only one)
spice_location=$(find ./pex_output -type f -name "*.spice" ! -name "*_dummy_schematic.spice" | head -n 1)
if [[ -z "$spice_location" ]]; then
echo "[ERROR] No .spice file found in pex_output directory"
exit 1
fi
echo "[INFO] Found extracted spice file: $spice_location"
# Run Python script to fix port ordering in the extracted netlist
echo "[INFO] Reordering subcircuit pins to match original schematic..."
echo "$spice_location"
echo "$SCHEMATIC"
#python3 python/match_subckt_order.py "$spice_location" "$SCHEMATIC"
echo "[INFO] Creating DUT symbol with pex netlist"
python3 python/insert_netlist_to_sym.py "$spice_location" "$SYM_DIR" xschem_pex_symbol
cd xschem_pex_symbol
echo "[✅ DONE] Modified symbol, including pex netlist generated and saved in: $(pwd)/"

View File

@ -1,84 +0,0 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {}
V {}
S {}
E {}
B 2 710 -550 1510 -150 {flags=graph
y1=-0.0023
y2=1.3
ypos1=0
ypos2=2
divy=5
subdivy=1
unity=1
x1=0
x2=2e-06
divx=5
subdivx=1
xlabmag=1.0
ylabmag=1.0
node=vout
color=4
dataset=-1
unitx=1
logx=0
logy=0
}
N 150 -170 150 -140 {lab=Vin}
N 70 -170 70 -140 {lab=Vdd}
N 70 -80 70 -60 {lab=GND}
N 110 -60 150 -60 {lab=GND}
N 150 -80 150 -60 {lab=GND}
N 110 -60 110 -50 {lab=GND}
N 70 -60 110 -60 {lab=GND}
N 320 -410 320 -380 {lab=Vdd}
N 320 -210 320 -190 {lab=GND}
N 220 -300 240 -300 {lab=Vin}
N 520 -300 540 -300 {lab=Vout}
C {vsource.sym} 150 -110 0 0 {name=V1 value="PULSE(0 1.2 0.5u 10n 10n 1u 2u 1)" savecurrent=false}
C {vsource.sym} 70 -110 0 0 {name=V2 value=1.2 savecurrent=false}
C {gnd.sym} 110 -50 0 0 {name=l2 lab=GND}
C {lab_pin.sym} 150 -170 0 0 {name=p1 sig_type=std_logic lab=Vin}
C {lab_pin.sym} 70 -170 0 0 {name=p3 sig_type=std_logic lab=Vdd}
C {code_shown.sym} 40 -660 0 0 {name=NGSPICE
only_toplevel=true
value="
.control
save all
tran 50n 2u
write test_inverter.raw
.endc
" }
C {devices/code_shown.sym} 280 -540 0 0 {name=MODEL only_toplevel=true
format="tcleval( @value )"
value="
.lib cornerMOSlv.lib mos_tt
.lib cornerRES.lib res_typ
"}
C {launcher.sym} 770 -120 0 0 {name=h5
descr="load waves"
tclcommand="xschem raw_read $netlist_dir/test_inverter.raw tran"
}
C {inverter.sym} 390 -300 0 0 {
name=x1
schematic=inverter_pex
spice_sym_def="
.subckt inverter_pex Vdd Vin Vout Gnd
X0 Vout Vin Vdd Vdd sg13_lv_pmos ad=0.68p pd=4.68u as=0.68p ps=4.68u w=2u l=0.45u
X1 Vout Vin Gnd Gnd sg13_lv_nmos ad=0.34p pd=2.68u as=0.34p ps=2.68u w=1u l=0.45u
C0 Vout Vin 0.10077f
C1 Vin Vdd 0.14482f
C2 Vout Vdd 0.13155f
R0 Vin Vin.n0 7.52248
C3 Vout Gnd 0.39245f
C4 Vin Gnd 0.64666f
C5 Vdd Gnd 0.15308f
.ends
"
}
C {lab_pin.sym} 220 -300 0 0 {name=p2 sig_type=std_logic lab=Vin}
C {gnd.sym} 320 -190 0 0 {name=l1 lab=GND}
C {lab_pin.sym} 320 -410 0 0 {name=p4 sig_type=std_logic lab=Vdd}
C {lab_pin.sym} 540 -300 0 1 {name=p5 sig_type=std_logic lab=Vout}

View File

@ -1,12 +0,0 @@
# xschemrc - Custom configuration file for xschem
# This file sources another xschemrc file from a known location
# Source the base configuration from a known location
source $::env(PDK_ROOT)/$::env(PDK)/libs.tech/xschem/xschemrc
# (Optional) Add any custom overrides or extensions below
# set xschem_library_path /home/user/my_libs
# set xschem_gui_font "Monospace 10"
append XSCHEM_LIBRARY_PATH :$PDK_ROOT/ihp-sg13g2/libs.tech/xschem
append XSCHEM_LIBRARY_PATH :../../

View File

@ -1,45 +0,0 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {type=subcircuit
format="@name @pinlist @symname"
template="name=x1
schematic=inverter
spice_sym_def=
\\"
.subckt inverter well Vout Vin Gnd Vdd
R0 Vdd well 0.000000
X0 Vout Vin Vdd Vdd sg13_lv_pmos ad=0.68p pd=4.68u as=0.68p ps=4.68u w=2u l=0.45u
X1 Vout Vin Gnd Gnd sg13_lv_nmos ad=0.34p pd=2.68u as=0.34p ps=2.68u w=1u l=0.45u
C0 Vdd Vout 0.13155f
C1 Vin Vout 0.10077f
C2 Vin Vdd 0.14482f
R1 Vdd well 8.53169
R2 Vin Vin.n0 7.52248
R3 well Vdd 8.53069
C3 Vout Gnd 0.39245f
C4 Vin Gnd 0.64666f
C5 Vdd Gnd 0.15308f
.ends
\\"
"
V {}
S {}
E {}
L 7 -70 -80 -70 -60 {}
L 7 -150 0 -130 0 {}
L 7 110 0 130 0 {}
L 7 -70 70 -70 90 {}
B 5 -72.5 -82.5 -67.5 -77.5 {name=Vdd dir=inout}
B 5 -152.5 -2.5 -147.5 2.5 {name=Vin dir=inout}
B 5 127.5 -2.5 132.5 2.5 {name=Vout dir=inout}
B 5 -72.5 87.5 -67.5 92.5 {name=Gnd dir=inout}
A 4 105 0 7.071067811865476 135 360 {}
P 4 5 100 0 -130 -80 -130 90 100 0 100 0 {}
T {@symname
} -84 -6 0 0 0.3 0.3 {}
T {@name} -45 -32 0 0 0.2 0.2 {}
T {Vdd} -74 -55 3 1 0.2 0.2 {}
T {Vin} -125 -4 0 0 0.2 0.2 {}
T {Vout} 80 -9 0 1 0.2 0.2 {}
T {Gnd} -66 65 1 1 0.2 0.2 {}

View File

@ -1,42 +0,0 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {type=subcircuit
format="@name @pinlist @symname"
template="name=x1
schematic=inverter_pex
spice_sym_def=
\\"
.subckt inverter_pex Vdd Vin Vout Gnd
X0 Vout Vin Vdd Vdd sg13_lv_pmos ad=0.68p pd=4.68u as=0.68p ps=4.68u w=2u l=0.45u
X1 Vout Vin Gnd Gnd sg13_lv_nmos ad=0.34p pd=2.68u as=0.34p ps=2.68u w=1u l=0.45u
C0 Vout Vin 0.10077f
C1 Vin Vdd 0.14482f
C2 Vout Vdd 0.13155f
R0 Vin Vin.n0 7.52248
C3 Vout Gnd 0.39245f
C4 Vin Gnd 0.64666f
C5 Vdd Gnd 0.15308f
.ends
\\"
"
V {}
S {}
E {}
L 7 -70 -80 -70 -60 {}
L 7 -150 0 -130 0 {}
L 7 110 0 130 0 {}
L 7 -70 70 -70 90 {}
B 5 -72.5 -82.5 -67.5 -77.5 {name=Vdd dir=inout}
B 5 -152.5 -2.5 -147.5 2.5 {name=Vin dir=inout}
B 5 127.5 -2.5 132.5 2.5 {name=Vout dir=inout}
B 5 -72.5 87.5 -67.5 92.5 {name=Gnd dir=inout}
A 4 105 0 7.071067811865476 135 360 {}
P 4 5 100 0 -130 -80 -130 90 100 0 100 0 {}
T {@symname
} -84 -6 0 0 0.3 0.3 {}
T {@name} -45 -32 0 0 0.2 0.2 {}
T {Vdd} -74 -55 3 1 0.2 0.2 {}
T {Vin} -125 -4 0 0 0.2 0.2 {}
T {Vout} 80 -9 0 1 0.2 0.2 {}
T {Gnd} -66 65 1 1 0.2 0.2 {}

View File

@ -1,74 +0,0 @@
import sys
import os
def extract_netlist_and_topcell(spice_path):
with open(spice_path, 'r') as f:
lines = f.readlines()
netlist = []
topcell = None
inside_subckt = False
for line in lines:
if line.strip().startswith(".subckt"):
parts = line.strip().split()
if len(parts) > 1:
topcell = parts[1]
inside_subckt = True
if inside_subckt:
netlist.append(line.rstrip())
if line.strip().startswith(".ends"):
break
if not topcell:
raise ValueError("Topcell name not found in SPICE file.")
return topcell, "\n".join(netlist)
def modify_sym_file(sym_path, output_dir, topcell, netlist):
with open(sym_path, 'r') as f:
sym_lines = f.readlines()
new_sym_lines = []
inserted = False
for line in sym_lines:
if line.strip().startswith("K {type=subcircuit"):
new_sym_lines.append(line)
continue
elif line.strip().startswith("template=") and not inserted:
new_template = (
f'template="name=x1\n'
f'schematic={topcell}\n'
f'spice_sym_def=\n'
f'\\\\"\n'
f'{netlist}\n'
f'\\\\"\n'
f'"'
)
new_sym_lines.append(new_template + "\n")
inserted = True
else:
new_sym_lines.append(line)
filename = os.path.basename(sym_path)
out_path = os.path.join(output_dir, filename)
os.makedirs(output_dir, exist_ok=True)
with open(out_path, 'w') as f:
f.writelines(new_sym_lines)
print(f"Saved modified .sym to: {out_path}")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: python insert_netlist_to_sym.py <netlist.spice> <symbol.sym> <output_folder>")
sys.exit(1)
spice_file = sys.argv[1]
sym_file = sys.argv[2]
output_folder = sys.argv[3]
topcell, netlist = extract_netlist_and_topcell(spice_file)
modify_sym_file(sym_file, output_folder, topcell, netlist)

1
utils/README.md Normal file
View File

@ -0,0 +1 @@
asdf asdf asd fasd fasdf asd