add parasitic extraction of inverter
This commit is contained in:
parent
8fcd0e14fb
commit
531ce53ae5
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 {}
|
||||
|
|
@ -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}
|
||||
Binary file not shown.
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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/"
|
||||
|
|
@ -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.")
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 {}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
||||
Loading…
Reference in New Issue