various improvements for automatic port order detection from included subcircuit via spice_sym_def and @pinlist in format string, documentation updates in tutorial_use_existing_subckt.html

This commit is contained in:
stefan schippers 2024-01-08 14:57:21 +01:00
parent d2c6566030
commit 0597bae9dc
7 changed files with 114 additions and 26 deletions

View File

@ -211,6 +211,11 @@ type=nmos
verilog_sym_def="tcleval(`include \"[abs_sym_path verilog_include_file.v]\")"
</pre>
</p>
<p class="important">
For spice netlists if <kbd>@pinlist</kbd> is used in format string and <kbd>spice_sym_def</kbd> attribute
is defined the port order will be derived from the subcircuit
referenced by the <kbd>spice_sym_def</kbd> attribute.
</p>
<p>
In this example a <kbd>verilog_include_file.v</kbd> is included using the verilog <kbd>`include</kbd> directive.
In order to generate a full path for it the <kbd>abs_sym_path</kbd> TCL function is used that searches for this file

View File

@ -132,6 +132,61 @@ format="@name @@GND @@TRIG @@OUT @@RESETB @@CTRL @@THRES @@DIS @@VCC @symname"
is <b>named</b> and not <b>positional</b>.
</p>
</li>
<a id="spice_sym_def">
<li>
<h3> Obtaining the pin ordering from the subcircuit definition specified via <kbd>spice_sym_def</kbd></h3>
<p>
For spice netlists if <kbd>@pinlist</kbd> is specified in format string and a symbol <kbd>spice_sym_def</kbd>
attribute is used then the order of the symbol ports will be obtained from the <kbd>.subckt</kbd> specified
by <kbd>spice_sym_def</kbd>, either directly or via a <kbd>.include</kbd> statement
</p>
<img src="tutorial_use_existing_subckt08.png">
<p>
The <kbd>symbol_include.cir</kbd> file has the following content:
</p>
<pre class="code">
* example of a subcircuit contained in a file
.subckt symbol_include Z VCC VSS
+ A B C W=10 L=1
...
...
.ends
</pre>
<p>
And as a result the following circuit:
</p>
<img src="tutorial_use_existing_subckt09.png">
<p>
is netlisted in the following way, notice the net assignment in the <kbd>x1</kbd> subcircuit call
matches the order in the <kbd>symbol_include.cir</kbd> file:
</p>
<pre class="code">
** sch_path: /home/schippes/.xschem/xschem_library/symbol_include/tb_symbol_include.sch
**.subckt tb_symbol_include XZ XVSS XVCC XC XB XA
*.opin XZ
*.ipin XVSS
*.ipin XVCC
*.ipin XC
*.ipin XB
*.ipin XA
x1 XZ XVCC XVSS XA XB XC symbol_include
**.ends
* expanding symbol: symbol_include.sym # of pins=6
** sym_path: /home/schippes/.xschem/xschem_library/symbol_include/symbol_include.sym
.include symbol_include.cir
.end
</pre>
</li>
</a>
</ol>
<h2>Specifying subcircuit netlist</h2>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -1848,7 +1848,6 @@ void get_additional_symbols(int what)
Int_hashentry *found;
Int_hashtable sym_table = {NULL, 0};
if(what == 1) { /* start */
int_hash_init(&sym_table, HASHSIZE);
num_syms = xctx->symbols;
@ -1904,15 +1903,18 @@ void get_additional_symbols(int what)
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
subst_token(xctx->sym[j].prop_ptr, "default_schematic", NULL)); /* delete attribute */
}
if(spice_sym_def)
if(spice_sym_def) {
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
subst_token(xctx->sym[j].prop_ptr, "spice_sym_def", spice_sym_def));
if(verilog_sym_def)
}
if(verilog_sym_def) {
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
subst_token(xctx->sym[j].prop_ptr, "verilog_sym_def", verilog_sym_def));
if(vhdl_sym_def)
}
if(vhdl_sym_def) {
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
subst_token(xctx->sym[j].prop_ptr, "vhdl_sym_def", vhdl_sym_def));
}
xctx->symbols++;
} else {
j = found->value;

View File

@ -1815,52 +1815,67 @@ void print_tedax_subckt(FILE *fd, int symbol)
/* This function is used to generate the @pinlist replacement getting port order
* from the spice_sym_def attribute (either directly or by loading the provided .include file),
* checking with the corresponding symbol pin name and getting the net name attached to it.
* Any name mismatch is reported and in this case the function does nothing. The default xschem
* Any name mismatch is reported, in this case the function does nothing and the default xschem
* symbol port ordering will be used. */
static int has_included_subcircuit(int inst, int symbol, char **result)
{
char *spice_sym_def = NULL;
int ret = 0;
my_strdup2(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->sym[symbol].prop_ptr, "spice_sym_def", 0));
my_strdup2(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->inst[inst].prop_ptr, "spice_sym_def", 0));
if(!spice_sym_def[0]) {
my_strdup2(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->sym[symbol].prop_ptr, "spice_sym_def", 0));
}
if(xctx->tok_size) {
tclvareval("has_included_subcircuit {", spice_sym_def, "}", NULL);
tclvareval("has_included_subcircuit {", get_cell(xctx->sym[symbol].name, 0), "} {",
spice_sym_def, "}", NULL);
if(tclresult()[0]) {
char *pinlist = NULL;
char *pin, *save;
char *pinlist_ptr;
const char *net;
char *tmp_result = NULL;
int i, no_of_pins = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER], multip;
int symbol_pins = 0;
int instance_pins = 0;
Int_hashentry *entry;
Int_hashtable table = {NULL, 0};
int_hash_init(&table, 37);
for(i = 0;i < no_of_pins; ++i) {
char *prop = (xctx->inst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr;
int spice_ignore = !strboolcmp(get_tok_value(prop, "spice_ignore", 0), "true");
const char *name = get_tok_value(prop, "name", 0);
if(!spice_ignore) {
int_hash_lookup(&table, name, i, XINSERT_NOREPLACE);
}
}
my_strdup2(_ALLOC_ID_, &pinlist, tclresult());
dbg(1, "included subcircuit: pinlist=%s\n", pinlist);
pinlist_ptr = pinlist;
while( (pin = my_strtok_r(pinlist_ptr, " ", "", 0, &save)) ) {
instance_pins++;
for(i = 0;i < no_of_pins; ++i) {
char *prop = (xctx->inst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr;
int spice_ignore = !strboolcmp(get_tok_value(prop, "spice_ignore", 0), "true");
const char *name = get_tok_value(prop, "name", 0);
if(!spice_ignore) {
if(!strcmp(pin, name)) {
symbol_pins++;
net = net_name(inst, i, &multip, 0, 1);
my_mstrcat(_ALLOC_ID_, result, "?", my_itoa(multip), " ", net, " ", NULL);
}
}
entry = int_hash_lookup(&table, pin, 0, XLOOKUP);
if(entry) {
i = entry->value;
symbol_pins++;
net = net_name(inst, i, &multip, 0, 1);
my_mstrcat(_ALLOC_ID_, &tmp_result, "?", my_itoa(multip), " ", net, " ", NULL);
}
pinlist_ptr = NULL;
}
if(instance_pins == symbol_pins) ret = 1;
else {
int_hash_free(&table);
if(instance_pins == symbol_pins) {
ret = 1;
my_mstrcat(_ALLOC_ID_, result, tmp_result, NULL);
} else {
dbg(0, "has_included_subcircuit(): symbol and .subckt pins do not match. Discard .subckt port order\n");
if(has_x)
tcleval("alert_ {has_included_subcircuit(): "
"symbol and .subckt pins do not match. Discard .subckt port order}");
}
if(tmp_result) my_free(_ALLOC_ID_, &tmp_result);
my_free(_ALLOC_ID_, &pinlist);
}
}

View File

@ -656,14 +656,17 @@ proc ev0 {args} {
# get pin ordering from included subcircuit
# return empty string if not found.
proc has_included_subcircuit {spice_sym_def} {
proc has_included_subcircuit {symname spice_sym_def} {
global has_x
set include_found 0
# puts "has_included_subcircuit: spice_sym_def=$spice_sym_def"
regsub -all {\n\+} $spice_sym_def { } spice_sym_def
set pinlist {}
# .include? get the file ...
if {[regexp -nocase {^\.include } $spice_sym_def]} {
set filename [lindex $spice_sym_def 1]
if {[regexp -nocase {^ *\.include +} $spice_sym_def]} {
regsub -nocase {^ *\.include +} $spice_sym_def {} filename
regsub -all {^"|"$} $filename {} filename
set filename [abs_sym_path $filename]
# puts "filename=$filename"
set res [catch {open $filename r} fd]
if { $res } {
@ -680,8 +683,10 @@ proc has_included_subcircuit {spice_sym_def} {
# split lines
set spice_sym_def [split $spice_sym_def \n]
foreach line $spice_sym_def {
# het 1st line with a .subckt. This is our subcircuit definition, get the pin order
if {[string tolower [lindex $line 0]] eq {.subckt} } {
# get 1st line with a matching .subckt. This is our subcircuit definition, get the pin order
if {[string tolower [lindex $line 0]] eq {.subckt} &&
[string tolower [lindex $line 1]] eq $symname} {
set include_found 1
regsub -all { *= *} $line {=} line
# pin list ends where parameter assignment begins (param=value)
set last [lsearch -regexp [string tolower $line] {=|param:}]
@ -695,6 +700,12 @@ proc has_included_subcircuit {spice_sym_def} {
}
}
# return pinlist as found in the .subckt line or empty string if not found
if {!$include_found} {
puts "has_included_subcircuit: no matching .subckt found in spice_sym_def. Ignore"
if { [info exists has_x] } {
alert_ "has_included_subcircuit: no matching .subckt found in spice_sym_def. Ignore"
}
}
return $pinlist
}