push layout for pex
This commit is contained in:
parent
b5cccf4f55
commit
b6f9f668de
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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,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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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()
|
||||
|
|
@ -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)/"
|
||||
|
|
@ -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}
|
||||
|
|
@ -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 :../../
|
||||
|
|
@ -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 {}
|
||||
|
|
@ -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 {}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1 @@
|
|||
asdf asdf asd fasd fasdf asd
|
||||
Loading…
Reference in New Issue