add parasitic extraction of inverter

This commit is contained in:
PhillipRambo 2025-07-07 18:20:40 +02:00
parent 8fcd0e14fb
commit 531ce53ae5
20 changed files with 787 additions and 0 deletions

View File

@ -0,0 +1,50 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {}
V {}
S {}
E {}
N 330 -280 370 -280 {lab=Vin}
N 330 -280 330 -190 {lab=Vin}
N 330 -190 370 -190 {lab=Vin}
N 410 -230 490 -230 {lab=Vout}
N 410 -230 410 -220 {lab=Vout}
N 410 -250 410 -230 {lab=Vout}
N 410 -160 410 -130 {lab=Gnd}
N 410 -340 410 -310 {lab=Vdd}
N 410 -280 520 -280 {lab=#net1}
N 410 -340 520 -340 {lab=Vdd}
N 410 -190 520 -190 {lab=#net2}
N 410 -130 520 -130 {lab=Gnd}
C {sg13g2_pr/sg13_lv_nmos.sym} 390 -190 2 1 {name=M1
l=0.45u
w=1.0u
ng=1
m=1
model=sg13_lv_nmos
spiceprefix=X
}
C {sg13g2_pr/sg13_lv_pmos.sym} 390 -280 0 0 {name=M2
l=0.45u
w=2.0u
ng=1
m=1
model=sg13_lv_pmos
spiceprefix=X
}
C {iopin.sym} 490 -230 2 1 {name=p2 lab=Vout}
C {iopin.sym} 410 -340 2 0 {name=p5 lab=Vdd}
C {iopin.sym} 330 -240 2 0 {name=p6 lab=Vin}
C {iopin.sym} 410 -130 2 0 {name=p1 lab=Gnd}
C {sg13g2_pr/ntap1.sym} 520 -310 0 0 {name=R1
model=ntap1
spiceprefix=X
w=0.78e-6
l=0.78e-6
}
C {sg13g2_pr/ptap1.sym} 520 -160 2 1 {name=R2
model=ptap1
spiceprefix=X
w=0.78e-6
l=0.78e-6
}

View File

@ -0,0 +1,25 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {type=subcircuit
format="@name @pinlist @symname"
template="name=x1"
}
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

@ -0,0 +1,68 @@
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 -540 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}
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

@ -0,0 +1,10 @@
* Extracted by KLayout with SG13G2 LVS runset on : 07/07/2025 16:12
.SUBCKT inverter Gnd Vout Vin Vdd
M$1 Gnd Vin Vout \$1 sg13_lv_nmos L=0.45u W=1u AS=0.34p AD=0.34p PS=2.68u
+ PD=2.68u
M$2 Vdd Vin Vout \$2 sg13_lv_pmos L=0.45u W=2u AS=0.68p AD=0.68p PS=4.68u
+ PD=4.68u
R$3 \$2 Vdd ntap1 A=0.6084p P=3.12u
R$4 \$1 Gnd ptap1 A=0.6084p P=3.12u
.ENDS inverter

View File

@ -0,0 +1,58 @@
[2025-07-07 18:20:02,246] [INFO] GDS input file passed, running in LVS mode
[2025-07-07 18:20:02,248] [INFO] Found cell inverter in GDS ../layout/inverter.gds (only top cell)
[2025-07-07 18:20:02,254] [INFO] Calling MAGIC
[2025-07-07 18:20:02,255] [SUBPROCESS] magic -dnull -noconsole -rcfile /home/pedersen/IHP-Open-PDK/ihp-sg13g2/libs.tech/magic/ihp-sg13g2.magicrc ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Script.tcl, output file: ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Output.txt
[2025-07-07 18:20:02,278] [SUBPROCESS]
[2025-07-07 18:20:02,279] [SUBPROCESS] Magic 8.3 revision 530 - Compiled on Mo 7. Jul 14:09:23 CEST 2025.
[2025-07-07 18:20:02,280] [SUBPROCESS] Starting magic under Tcl interpreter
[2025-07-07 18:20:02,281] [SUBPROCESS] Using the terminal as the console.
[2025-07-07 18:20:02,281] [SUBPROCESS] Using NULL graphics device.
[2025-07-07 18:20:02,313] [SUBPROCESS] Processing system .magicrc file
[2025-07-07 18:20:02,320] [SUBPROCESS] Sourcing design .magicrc for technology ihp-sg13g2 ...
[2025-07-07 18:20:02,321] [SUBPROCESS] 2 Magic internal units = 1 Lambda
[2025-07-07 18:20:02,342] [SUBPROCESS] Input style sg13g2(): scaleFactor=2, multiplier=2
[2025-07-07 18:20:02,441] [SUBPROCESS] The following types are not handled by extraction and will be treated as non-electrical types:
[2025-07-07 18:20:02,442] [SUBPROCESS] fillfet sealcont difffill nemitter hvnemitter hvisodiffres sealvia1 sealvia2 sealvia3 sealvia4 sealvia5 sealvia6 pad seal thruvia
[2025-07-07 18:20:02,446] [SUBPROCESS] Scaled tech values by 2 / 1 to match internal grid scaling
[2025-07-07 18:20:02,447] [SUBPROCESS] Loading "./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Script.tcl" from command line.
[2025-07-07 18:20:02,447] [SUBPROCESS] Warning: Calma reading is not undoable! I hope that's OK.
[2025-07-07 18:20:02,448] [SUBPROCESS] Library written using GDS-II Release 6.0
[2025-07-07 18:20:02,448] [SUBPROCESS] Library name: LIB
[2025-07-07 18:20:02,449] [SUBPROCESS] Reading "$$$CONTEXT_INFO$$$".
[2025-07-07 18:20:02,449] [SUBPROCESS] Reading "nmos".
[2025-07-07 18:20:02,449] [SUBPROCESS] Reading "ptap1".
[2025-07-07 18:20:02,450] [SUBPROCESS] Making label "sub!" on type isosubstrate in cell ptap1 sticky.
[2025-07-07 18:20:02,450] [SUBPROCESS] Reading "ntap1".
[2025-07-07 18:20:02,451] [SUBPROCESS] Reading "pmos$1".
[2025-07-07 18:20:02,451] [SUBPROCESS] Reading "inverter".
[2025-07-07 18:20:02,454] [SUBPROCESS] Extracting inverter into /home/pedersen/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/inverter_example/pex/pex_output/inverter__inverter/magic_RC/inverter.ext:
[2025-07-07 18:20:02,455] [SUBPROCESS] Port: name = Vout is new node 0x56ea21d3d4a0
[2025-07-07 18:20:02,455] [SUBPROCESS] Location is (266, -211); drivepoint (266, -211)
[2025-07-07 18:20:02,456] [SUBPROCESS] Port: name = Vin is new node 0x56ea21d41800
[2025-07-07 18:20:02,456] [SUBPROCESS] Location is (95, -213); drivepoint (95, -213)
[2025-07-07 18:20:02,457] [SUBPROCESS] Port: name = Gnd is new node 0x56ea21ece8e0
[2025-07-07 18:20:02,457] [SUBPROCESS] Location is (20, -732); drivepoint (20, -732)
[2025-07-07 18:20:02,458] [SUBPROCESS] Port: name = Vdd is new node 0x56ea226c2f60
[2025-07-07 18:20:02,458] [SUBPROCESS] Location is (-205, 318); drivepoint (-205, 318)
[2025-07-07 18:20:02,459] [SUBPROCESS] Total Nets: 4
[2025-07-07 18:20:02,459] [SUBPROCESS] Nets extracted: 4 (1.000000)
[2025-07-07 18:20:02,460] [SUBPROCESS] Nets output: 4 (1.000000)
[2025-07-07 18:20:02,460] [SUBPROCESS] Devs merged: 0
[2025-07-07 18:20:02,461] [SUBPROCESS] exttospice finished.
[2025-07-07 18:20:02,461] [INFO] MAGIC succeeded after 0.2051s
[2025-07-07 18:20:02,467] [SUBPROCESS] Report DB saved at: ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_report.rdb.gz
[2025-07-07 18:20:02,467] [SUBPROCESS] SPICE netlist saved at: ./pex_output/inverter__inverter/magic_RC/inverter.pex.spice
[2025-07-07 18:20:02,468] [SUBPROCESS] * NGSPICE file created from inverter.ext - technology: ihp-sg13g2
.subckt inverter Vout Vin Gnd Vdd
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 Vdd 0.13155f
C1 Vout Vin 0.10077f
C2 Vdd Vin 0.14482f
R0 Vin Vin.n0 7.52248
C3 Vout Gnd 0.39245f
C4 Vin Gnd 0.64666f
C5 Vdd Gnd 0.15308f
.ends

View File

@ -0,0 +1,58 @@
GDS input file passed, running in LVS mode
Found cell inverter in GDS ../layout/inverter.gds (only top cell)
Calling MAGIC
magic -dnull -noconsole -rcfile /home/pedersen/IHP-Open-PDK/ihp-sg13g2/libs.tech/magic/ihp-sg13g2.magicrc ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Script.tcl, output file: ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Output.txt
Magic 8.3 revision 530 - Compiled on Mo 7. Jul 14:09:23 CEST 2025.
Starting magic under Tcl interpreter
Using the terminal as the console.
Using NULL graphics device.
Processing system .magicrc file
Sourcing design .magicrc for technology ihp-sg13g2 ...
2 Magic internal units = 1 Lambda
Input style sg13g2(): scaleFactor=2, multiplier=2
The following types are not handled by extraction and will be treated as non-electrical types:
fillfet sealcont difffill nemitter hvnemitter hvisodiffres sealvia1 sealvia2 sealvia3 sealvia4 sealvia5 sealvia6 pad seal thruvia
Scaled tech values by 2 / 1 to match internal grid scaling
Loading "./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_RC_Script.tcl" from command line.
Warning: Calma reading is not undoable! I hope that's OK.
Library written using GDS-II Release 6.0
Library name: LIB
Reading "$$$CONTEXT_INFO$$$".
Reading "nmos".
Reading "ptap1".
Making label "sub!" on type isosubstrate in cell ptap1 sticky.
Reading "ntap1".
Reading "pmos$1".
Reading "inverter".
Extracting inverter into /home/pedersen/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/inverter_example/pex/pex_output/inverter__inverter/magic_RC/inverter.ext:
Port: name = Vout is new node 0x56ea21d3d4a0
Location is (266, -211); drivepoint (266, -211)
Port: name = Vin is new node 0x56ea21d41800
Location is (95, -213); drivepoint (95, -213)
Port: name = Gnd is new node 0x56ea21ece8e0
Location is (20, -732); drivepoint (20, -732)
Port: name = Vdd is new node 0x56ea226c2f60
Location is (-205, 318); drivepoint (-205, 318)
Total Nets: 4
Nets extracted: 4 (1.000000)
Nets output: 4 (1.000000)
Devs merged: 0
exttospice finished.
MAGIC succeeded after 0.2051s
Report DB saved at: ./pex_output/inverter__inverter/magic_RC/inverter_MAGIC_report.rdb.gz
SPICE netlist saved at: ./pex_output/inverter__inverter/magic_RC/inverter.pex.spice
* NGSPICE file created from inverter.ext - technology: ihp-sg13g2
.subckt inverter Vout Vin Gnd Vdd
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 Vdd 0.13155f
C1 Vout Vin 0.10077f
C2 Vdd Vin 0.14482f
R0 Vin Vin.n0 7.52248
C3 Vout Gnd 0.39245f
C4 Vin Gnd 0.64666f
C5 Vdd Gnd 0.15308f
.ends

View File

@ -0,0 +1,23 @@
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

@ -0,0 +1,9 @@
scale 1000 1 0.5
rnode "Vdd" 0 -0 -205 318 0
rnode "ntap1_0.well" 0 0 -63 345 0
resist "ntap1_0.well" "Vdd" 8.51657
rnode "Gnd" 0 0 20 -732 0
rnode "Vin.n0" 0 0 111 -158 0
rnode "Vin" 0 0 95 -213 0
resist "Vin" "Vin.n0" 7.52198
rnode "Vout" 0 0 266 -211 0

View File

@ -0,0 +1,27 @@
# Generated by kpex 0.2.7
crashbackups stop
drc off
gds read /home/pedersen/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/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/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/inverter_example/pex/pex_output/inverter__inverter/magic_RC
extract do resistance
extract all
ext2sim labels on
ext2sim
extresist tolerance 1
extresist all
ext2spice short resistor
ext2spice merge conservative
ext2spice cthresh 0.02
ext2spice rthresh 50
ext2spice extresist on
ext2spice subcircuits top on
ext2spice format ngspice
ext2spice -p /home/pedersen/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/inverter_example/pex/pex_output/inverter__inverter/magic_RC -o /home/pedersen/projects/IHP-AnalogAcademy/modules/module_3_8_bit_SAR_ADC/part_5_layout/components/inverter_example/pex/pex_output/inverter__inverter/magic_RC/inverter.pex.spice
quit -noprompt

View File

@ -0,0 +1,75 @@
#!/bin/bash
set -e # Exit on error
###############################################################################
# ⬇⬇⬇ USER CONFIGURATION ⬇⬇⬇ #
###############################################################################
# Activate Python environment (edit this if your venv is in another place)
PYTHON_ENV="/home/pedersen/misc/klayout_pex/bin/activate"
# Magic executable for kpex (you can change this if needed)
export KPEX_MAGIC_EXE="$HOME/.local/bin/magic"
# Cell and schematic names (no spaces or extensions needed)
CELL_NAME="inverter"
SYMBOL_NAME="inverter.sym"
SCHEMATIC_NAME="inverter.sch"
# Paths to input files (relative to this script or absolute)
LAYOUT_GDS="../layout/${CELL_NAME}.gds"
REFERENCE_SPICE="../simulations/${CELL_NAME}.spice"
# PDK and magicrc paths
PDK_NAME="ihp_sg13g2"
MAGICRC="$PDK_ROOT/ihp-sg13g2/libs.tech/magic/ihp-sg13g2.magicrc"
###############################################################################
# ⛔ DO NOT TOUCH BELOW THIS LINE ⛔ #
###############################################################################
# Load Python environment
echo "[INFO] Activating Python environment..."
source "$PYTHON_ENV"
echo "[INFO] Using MAGIC executable: $KPEX_MAGIC_EXE"
# Run parasitic extraction
echo "[INFO] Running parasitic extraction with KPEX..."
kpex \
--pdk "$PDK_NAME" \
--magic \
--gds "$LAYOUT_GDS" \
--schematic "$REFERENCE_SPICE" \
--cell "$CELL_NAME" \
--magicrc "$MAGICRC" \
--magic_mode RC \
--magic_cthresh 0.02 \
--magic_rthresh 50 \
--magic_short resistor \
--magic_merge conservative \
--out_dir ./pex_output
# Prepare xschem directory
mkdir -p xschem
cp "../$SYMBOL_NAME" xschem/
cp "../$SCHEMATIC_NAME" xschem/
# Find the PEX spice file
spice_location=$(find ./pex_output -type f -name "*.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"
# Fix port ordering in the extracted netlist
echo "[INFO] Reordering subcircuit pins to match original schematic..."
python3 scripts/match_subckt_order.py "$spice_location" "$REFERENCE_SPICE"
# Patch the schematic with extracted spice definition
echo "[INFO] Updating schematic with PEX subcircuit..."
python3 scripts/insert_pex_subckt.py "$spice_location"
echo "[✅ DONE] Modified schematic generated and saved to: xschem/"

View File

@ -0,0 +1,147 @@
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 = next((line for line in lines if line.strip().lower().startswith(".subckt")), None)
if not subckt_line:
raise ValueError(f"No .subckt line found in SPICE file: {spice_path}")
subckt_name = subckt_line.strip().split()[1]
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
definition_text = '\n'.join(definition_lines)
return subckt_name, definition_text
def find_subckt_location(subckt_name, schematic_file):
text_content = load_text_file(schematic_file)
search_term = subckt_name + '.sym'
location = text_content.find(search_term)
return location
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):
content = text[start_idx+1:end_idx].strip('\n ')
lines = content.splitlines()
name_line_index = None
for i, line in enumerate(lines):
if line.strip().startswith("name="):
name_line_index = i
break
if name_line_index is None:
new_lines = ['spice_sym_def="', new_content.strip(), '"'] + lines
else:
new_lines = (
lines[:name_line_index+1] +
['spice_sym_def="', new_content.strip(), '"'] +
lines[name_line_index+1:]
)
new_block_content = '\n'.join(new_lines)
before = text[:start_idx+1]
after = text[end_idx:]
return before + '\n' + new_block_content + '\n' + after
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
location = find_subckt_location(subckt_name, schematic_path)
if location == -1:
print(f" '{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)
dir_name, base_name = os.path.split(schematic_path)
name, ext = os.path.splitext(base_name)
new_filename = os.path.join(dir_name, f"{name}_modified{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__":
schematic = "../inverter_tb.sch"
spice_path = "pex_output/inverter__inverter/magic_RC/inverter.pex.spice" # replace with actual path
subckt_name, definition = read_spice_definition(spice_path)
print(f"Subcircuit name: {subckt_name}")
print("Definition:")
print(definition)
location = find_subckt_location(subckt_name, schematic)
if location != -1:
print(f"Found '{subckt_name}.sym' in schematic at position: {location}")
schematic_content = load_text_file(schematic)
start_idx, end_idx = find_first_curly_brackets_span(schematic_content, location)
if start_idx is not None:
print(f"Replacing curly brackets content from {start_idx} to {end_idx}...")
new_schematic_content = replace_curly_brackets_content(schematic_content, start_idx, end_idx, definition)
# Prepare new filename with _pex suffix before extension
dir_name, base_name = os.path.split(schematic)
name, ext = os.path.splitext(base_name)
new_filename = f"{name}_pex{ext}"
# Ensure xschem/ exists and define full path there
xschem_dir = os.path.join(os.getcwd(), "xschem")
os.makedirs(xschem_dir, exist_ok=True)
xschem_path = os.path.join(xschem_dir, new_filename)
# Save to xschem/ folder
save_text_file(xschem_path, new_schematic_content)
print(f"Replacement done. New schematic saved to:\n {xschem_path}")
else:
print("No curly brackets block found after .sym line.")
else:
print(f"'{subckt_name}.sym' not found in schematic.")

View File

@ -0,0 +1,61 @@
import sys
import re
from pathlib import Path
def get_original_io_order(original_netlist_path):
io_pins = []
subckt_line = ""
with open(original_netlist_path, "r") as f:
for line in f:
if line.strip().startswith("**.subckt"):
# Use regex to extract port names
match = re.search(r"\*\*\.subckt\s+\S+\s+(.+)", line)
if match:
subckt_line = match.group(1).strip()
io_pins = subckt_line.split()
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().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")
# Create new subckt line with reordered ports
reordered_line = ".subckt " + subckt_name + " " + " ".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

@ -0,0 +1,50 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {}
V {}
S {}
E {}
N 330 -280 370 -280 {lab=Vin}
N 330 -280 330 -190 {lab=Vin}
N 330 -190 370 -190 {lab=Vin}
N 410 -230 490 -230 {lab=Vout}
N 410 -230 410 -220 {lab=Vout}
N 410 -250 410 -230 {lab=Vout}
N 410 -160 410 -130 {lab=Gnd}
N 410 -340 410 -310 {lab=Vdd}
N 410 -280 520 -280 {lab=#net1}
N 410 -340 520 -340 {lab=Vdd}
N 410 -190 520 -190 {lab=#net2}
N 410 -130 520 -130 {lab=Gnd}
C {sg13g2_pr/sg13_lv_nmos.sym} 390 -190 2 1 {name=M1
l=0.45u
w=1.0u
ng=1
m=1
model=sg13_lv_nmos
spiceprefix=X
}
C {sg13g2_pr/sg13_lv_pmos.sym} 390 -280 0 0 {name=M2
l=0.45u
w=2.0u
ng=1
m=1
model=sg13_lv_pmos
spiceprefix=X
}
C {iopin.sym} 490 -230 2 1 {name=p2 lab=Vout}
C {iopin.sym} 410 -340 2 0 {name=p5 lab=Vdd}
C {iopin.sym} 330 -240 2 0 {name=p6 lab=Vin}
C {iopin.sym} 410 -130 2 0 {name=p1 lab=Gnd}
C {sg13g2_pr/ntap1.sym} 520 -310 0 0 {name=R1
model=ntap1
spiceprefix=X
w=0.78e-6
l=0.78e-6
}
C {sg13g2_pr/ptap1.sym} 520 -160 2 1 {name=R2
model=ptap1
spiceprefix=X
w=0.78e-6
l=0.78e-6
}

View File

@ -0,0 +1,25 @@
v {xschem version=3.4.6 file_version=1.2}
G {}
K {type=subcircuit
format="@name @pinlist @symname"
template="name=x1"
}
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

@ -0,0 +1,83 @@
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 -540 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
spice_sym_def="
.subckt inverter 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 Vdd 0.13155f
C1 Vout Vin 0.10077f
C2 Vdd Vin 0.14482f
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

@ -0,0 +1,18 @@
# 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"
#### include skywater libraries. Here I use [pwd]. This works if I start xschem from here.
###only if you dont have this setup already ###
###append XSCHEM_LIBRARY_PATH :[file dirname [info script]]
#### Add custom libraries (directories with .lib files)
append XSCHEM_LIBRARY_PATH :$PDK_ROOT/ihp-sg13g2/libs.tech/xschem