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