add vccs_limit.sym and vcvs_limit.sym that use the XSPICE limit code model (saturated controlled sources). [WIP] support for spectre netlist format (for the VACASK simulator) - still incomplete
This commit is contained in:
parent
f5bd459082
commit
5a3c97d64e
|
|
@ -3,7 +3,7 @@ put /local/src {
|
|||
icon.c callback.c actions.c move.c check.c clip.c draw.c globals.c
|
||||
main.c netlist.c hash_iterator.c findnet.c scheduler.c store.c xinit.c
|
||||
select.c font.c editprop.c save.c paste.c token.c psprint.c node_hash.c
|
||||
hilight.c options.c vhdl_netlist.c svgdraw.c spice_netlist.c
|
||||
hilight.c options.c vhdl_netlist.c svgdraw.c spice_netlist.c spectre_netlist.c
|
||||
tedax_netlist.c verilog_netlist.c parselabel.c expandlabel.c
|
||||
eval_expr.c in_memory_undo.c cairo_jpg.c
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ put /local/src {
|
|||
put /local/install_shares {
|
||||
keys.help xschem.help xschem.tcl break.awk convert_to_verilog2001.awk
|
||||
flatten.awk flatten_tedax.awk flatten_savenodes.awk make_sym.awk make_sym_lcc.awk
|
||||
symgen.awk order_labels.awk sort_labels.awk spice.awk tedax.awk verilog.awk
|
||||
symgen.awk order_labels.awk sort_labels.awk spice.awk spectre.awk tedax.awk verilog.awk
|
||||
vhdl.awk hspice_backannotate.tcl add_custom_menu.tcl create_graph.tcl
|
||||
add_custom_button.tcl change_index.tcl icon.xpm resources.tcl xschemrc
|
||||
ngspice_backannotate.tcl gschemtoxschem.awk mouse_bindings.tcl cadence_style_rc
|
||||
|
|
|
|||
|
|
@ -806,6 +806,12 @@ int set_sym_flags(xSymbol *sym)
|
|||
else if(!strboolcmp(ptr, "true") || !strcmp(ptr, "open"))
|
||||
sym->flags |= SPICE_IGNORE;
|
||||
|
||||
ptr = get_tok_value(sym->prop_ptr,"spectre_ignore",0);
|
||||
if(!strcmp(ptr, "short"))
|
||||
sym->flags |= SPECTRE_SHORT;
|
||||
else if(!strboolcmp(ptr, "true") || !strcmp(ptr, "open"))
|
||||
sym->flags |= SPECTRE_IGNORE;
|
||||
|
||||
ptr = get_tok_value(sym->prop_ptr,"verilog_ignore",0);
|
||||
if(!strcmp(ptr, "short"))
|
||||
sym->flags |= VERILOG_SHORT;
|
||||
|
|
@ -858,6 +864,12 @@ int set_inst_flags(xInstance *inst)
|
|||
inst->flags |= SPICE_SHORT;
|
||||
else if(!strboolcmp(ptr, "true") || !strcmp(ptr, "open"))
|
||||
inst->flags |= SPICE_IGNORE;
|
||||
|
||||
ptr = get_tok_value(inst->prop_ptr,"spectre_ignore",0);
|
||||
if(!strcmp(ptr, "short"))
|
||||
inst->flags |= SPECTRE_SHORT;
|
||||
else if(!strboolcmp(ptr, "true") || !strcmp(ptr, "open"))
|
||||
inst->flags |= SPECTRE_IGNORE;
|
||||
|
||||
ptr = get_tok_value(inst->prop_ptr,"verilog_ignore",0);
|
||||
if(!strcmp(ptr, "short"))
|
||||
|
|
@ -979,9 +991,10 @@ void clear_drawing(void)
|
|||
my_free(_ALLOC_ID_, &xctx->schsymbolprop);
|
||||
my_free(_ALLOC_ID_, &xctx->schprop);
|
||||
my_free(_ALLOC_ID_, &xctx->schvhdlprop);
|
||||
my_free(_ALLOC_ID_, &xctx->schverilogprop);
|
||||
my_free(_ALLOC_ID_, &xctx->schspectreprop);
|
||||
my_free(_ALLOC_ID_, &xctx->version_string);
|
||||
if(xctx->header_text) my_free(_ALLOC_ID_, &xctx->header_text);
|
||||
my_free(_ALLOC_ID_, &xctx->schverilogprop);
|
||||
for(i=0;i<xctx->wires; ++i)
|
||||
{
|
||||
my_free(_ALLOC_ID_, &xctx->wire[i].prop_ptr);
|
||||
|
|
@ -1977,10 +1990,11 @@ void toggle_ignore(void)
|
|||
int i, n, first = 1;
|
||||
char *attr;
|
||||
int flag = 0; /* 1: spice_ignore=true, 2: spice_ignore=short */
|
||||
const char *spice_ignore_str;
|
||||
const char *ignore_str;
|
||||
if(xctx->netlist_type == CAD_VERILOG_NETLIST) attr="verilog_ignore";
|
||||
else if(xctx->netlist_type == CAD_VHDL_NETLIST) attr="vhdl_ignore";
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST) attr="tedax_ignore";
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST) attr="spectre_ignore";
|
||||
else if(xctx->netlist_type == CAD_SPICE_NETLIST) attr="spice_ignore";
|
||||
else attr = NULL;
|
||||
if(attr) {
|
||||
|
|
@ -1993,9 +2007,9 @@ void toggle_ignore(void)
|
|||
first = 0;
|
||||
}
|
||||
flag = 0;
|
||||
spice_ignore_str = get_tok_value(xctx->inst[i].prop_ptr, attr, 0);
|
||||
if(!strcmp(spice_ignore_str, "short")) flag = 2;
|
||||
else if(!strboolcmp(spice_ignore_str, "true")) flag = 1;
|
||||
ignore_str = get_tok_value(xctx->inst[i].prop_ptr, attr, 0);
|
||||
if(!strcmp(ignore_str, "short")) flag = 2;
|
||||
else if(!strboolcmp(ignore_str, "true")) flag = 1;
|
||||
|
||||
if(flag == 0) flag = 1;
|
||||
else if(flag == 1) flag = 2;
|
||||
|
|
@ -2043,6 +2057,7 @@ void get_additional_symbols(int what)
|
|||
char *spice_sym_def = NULL;
|
||||
char *vhdl_sym_def = NULL;
|
||||
char *verilog_sym_def = NULL;
|
||||
char *spectre_sym_def = NULL;
|
||||
char *default_schematic = NULL;
|
||||
char *sch = NULL;
|
||||
char symbol_base_sch[PATH_MAX] = "";
|
||||
|
|
@ -2052,6 +2067,7 @@ void get_additional_symbols(int what)
|
|||
dbg(1, "get_additional_symbols(): inst=%d (%s) sch=%s\n",i, xctx->inst[i].name, sch);
|
||||
/* copy instance based *_sym_def attributes to symbol */
|
||||
my_strdup(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"spice_sym_def",6));
|
||||
my_strdup(_ALLOC_ID_, &spectre_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"spectre_sym_def",6));
|
||||
my_strdup(_ALLOC_ID_, &verilog_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"verilog_sym_def",4));
|
||||
my_strdup(_ALLOC_ID_, &vhdl_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"vhdl_sym_def",4));
|
||||
|
||||
|
|
@ -2099,7 +2115,10 @@ void get_additional_symbols(int what)
|
|||
translate3(spice_sym_def, 1, xctx->inst[i].prop_ptr,
|
||||
symptr->templ,
|
||||
symname_attr, NULL));
|
||||
dbg(1, "get_additional_symbols(): spice_sym_def=%s\n", spice_sym_def);
|
||||
my_strdup(_ALLOC_ID_, &spectre_sym_def,
|
||||
translate3(spectre_sym_def, 1, xctx->inst[i].prop_ptr,
|
||||
symptr->templ,
|
||||
symname_attr, NULL));
|
||||
my_free(_ALLOC_ID_, &symname_attr);
|
||||
/* if instance symbol has default_schematic set to ignore copy the symbol anyway, since
|
||||
* the base symbol will not be netlisted by *_block_netlist() */
|
||||
|
|
@ -2129,6 +2148,10 @@ void get_additional_symbols(int what)
|
|||
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
|
||||
subst_token(xctx->sym[j].prop_ptr, "spice_sym_def", spice_sym_def));
|
||||
}
|
||||
if(spectre_sym_def) {
|
||||
my_strdup(_ALLOC_ID_, &xctx->sym[j].prop_ptr,
|
||||
subst_token(xctx->sym[j].prop_ptr, "spectre_sym_def", spectre_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));
|
||||
|
|
@ -2146,6 +2169,7 @@ void get_additional_symbols(int what)
|
|||
} /* if(xctx->tok_size && sch[0]) */
|
||||
my_free(_ALLOC_ID_, &sch);
|
||||
my_free(_ALLOC_ID_, &spice_sym_def);
|
||||
my_free(_ALLOC_ID_, &spectre_sym_def);
|
||||
my_free(_ALLOC_ID_, &vhdl_sym_def);
|
||||
my_free(_ALLOC_ID_, &verilog_sym_def);
|
||||
} /* for(i=0;i<xctx->instances; ++i) */
|
||||
|
|
|
|||
|
|
@ -3145,6 +3145,8 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
|
|||
err = global_spice_netlist(0, 1);
|
||||
else if(xctx->netlist_type == CAD_VHDL_NETLIST)
|
||||
err = global_vhdl_netlist(0, 1);
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST)
|
||||
err = global_spectre_netlist(0, 1);
|
||||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST)
|
||||
err = global_verilog_netlist(0, 1);
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST)
|
||||
|
|
@ -3545,7 +3547,7 @@ static void handle_key_press(int event, KeySym key, int state, int rstate, int m
|
|||
}
|
||||
else if(rstate == ControlMask) { /* toggle spice/vhdl netlist */
|
||||
xctx->netlist_type++;
|
||||
if(xctx->netlist_type==6) xctx->netlist_type=1;
|
||||
if(xctx->netlist_type==7) xctx->netlist_type=1;
|
||||
set_tcl_netlist_type();
|
||||
draw(); /* needed to ungrey or grey out components due to *_ignore attribute */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1947,6 +1947,12 @@ void edit_property(int x)
|
|||
else
|
||||
tclsetvar("retval","");
|
||||
}
|
||||
else if(xctx->netlist_type==CAD_SPECTRE_NETLIST) {
|
||||
if(xctx->schspectreprop!=NULL)
|
||||
tclsetvar("retval",xctx->schspectreprop);
|
||||
else
|
||||
tclsetvar("retval","");
|
||||
}
|
||||
else if(xctx->netlist_type==CAD_SPICE_NETLIST) {
|
||||
if(xctx->schprop!=NULL)
|
||||
tclsetvar("retval",xctx->schprop);
|
||||
|
|
@ -1992,6 +1998,12 @@ void edit_property(int x)
|
|||
xctx->push_undo();
|
||||
my_strdup(_ALLOC_ID_, &xctx->schverilogprop, (char *) tclgetvar("retval"));
|
||||
|
||||
} else if(xctx->netlist_type==CAD_SPECTRE_NETLIST &&
|
||||
(!xctx->schspectreprop || strcmp(xctx->schspectreprop, tclgetvar("retval") ) ) ) {
|
||||
modified = 1;
|
||||
xctx->push_undo();
|
||||
my_strdup(_ALLOC_ID_, &xctx->schspectreprop, (char *) tclgetvar("retval"));
|
||||
|
||||
} else if(xctx->netlist_type==CAD_SPICE_NETLIST &&
|
||||
(!xctx->schprop || strcmp(xctx->schprop, tclgetvar("retval") ) ) ) {
|
||||
modified = 1;
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ void mem_push_undo(void)
|
|||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].gptr, xctx->schvhdlprop);
|
||||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].vptr, xctx->schverilogprop);
|
||||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].sptr, xctx->schprop);
|
||||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].fptr, xctx->schspectreprop);
|
||||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].kptr, xctx->schsymbolprop);
|
||||
my_strdup(_ALLOC_ID_, &xctx->uslot[slot].eptr, xctx->schtedaxprop);
|
||||
|
||||
|
|
@ -435,6 +436,7 @@ void mem_pop_undo(int redo, int set_modify_status)
|
|||
|
||||
my_strdup(_ALLOC_ID_, &xctx->schvhdlprop, xctx->uslot[slot].gptr);
|
||||
my_strdup(_ALLOC_ID_, &xctx->schverilogprop, xctx->uslot[slot].vptr);
|
||||
my_strdup(_ALLOC_ID_, &xctx->schspectreprop, xctx->uslot[slot].fptr);
|
||||
my_strdup(_ALLOC_ID_, &xctx->schprop, xctx->uslot[slot].sptr);
|
||||
my_strdup(_ALLOC_ID_, &xctx->schsymbolprop, xctx->uslot[slot].kptr);
|
||||
my_strdup(_ALLOC_ID_, &xctx->schtedaxprop, xctx->uslot[slot].eptr);
|
||||
|
|
|
|||
|
|
@ -653,6 +653,8 @@ void set_tcl_netlist_type(void)
|
|||
tclsetvar("netlist_type", "verilog");
|
||||
} else if(xctx->netlist_type == CAD_VHDL_NETLIST) {
|
||||
tclsetvar("netlist_type", "vhdl");
|
||||
} else if(xctx->netlist_type == CAD_SPECTRE_NETLIST) {
|
||||
tclsetvar("netlist_type", "spectre");
|
||||
} else if(xctx->netlist_type == CAD_TEDAX_NETLIST) {
|
||||
tclsetvar("netlist_type", "tedax");
|
||||
} else if(xctx->netlist_type == CAD_SYMBOL_ATTRS) {
|
||||
|
|
@ -719,6 +721,7 @@ int record_global_node(int what, FILE *fp, const char *node)
|
|||
} else if(what == 0) {
|
||||
for(i = 0;i < xctx->max_globals; ++i) {
|
||||
if(xctx->netlist_type == CAD_SPICE_NETLIST) fprintf(fp, ".GLOBAL %s\n", xctx->globals[i]);
|
||||
if(xctx->netlist_type == CAD_SPECTRE_NETLIST) fprintf(fp, "global %s\n", xctx->globals[i]); /*<<<<*/
|
||||
if(xctx->netlist_type == CAD_TEDAX_NETLIST) fprintf(fp, "__GLOBAL__ %s\n", xctx->globals[i]);
|
||||
}
|
||||
} else if(what == 2) {
|
||||
|
|
@ -1051,6 +1054,8 @@ int shorted_instance(int i, int lvs_ignore)
|
|||
if((inst[i].flags & SPICE_SHORT) || (sym[inst[i].ptr].flags & SPICE_SHORT) ) shorted = 1;
|
||||
} else if(xctx->netlist_type == CAD_VERILOG_NETLIST) {
|
||||
if((inst[i].flags & VERILOG_SHORT) || (sym[inst[i].ptr].flags & VERILOG_SHORT) ) shorted = 1;
|
||||
} else if(xctx->netlist_type == CAD_SPECTRE_NETLIST) {
|
||||
if((inst[i].flags & SPECTRE_SHORT) || (sym[inst[i].ptr].flags & SPECTRE_SHORT) ) shorted = 1;
|
||||
} else if(xctx->netlist_type == CAD_VHDL_NETLIST) {
|
||||
if((inst[i].flags & VHDL_SHORT) || (sym[inst[i].ptr].flags & VHDL_SHORT) ) shorted = 1;
|
||||
} else if(xctx->netlist_type == CAD_TEDAX_NETLIST)
|
||||
|
|
@ -1077,6 +1082,8 @@ int skip_instance(int i, int skip_short, int lvs_ignore)
|
|||
skip = skip_instance2(i, lvs_ignore, (skip_short ? SPICE_SHORT : 0) | SPICE_IGNORE);
|
||||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST)
|
||||
skip = skip_instance2(i, lvs_ignore, (skip_short ? VERILOG_SHORT : 0) | VERILOG_IGNORE);
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST)
|
||||
skip = skip_instance2(i, lvs_ignore, (skip_short ? SPECTRE_SHORT : 0) | SPECTRE_IGNORE);
|
||||
else if(xctx->netlist_type == CAD_VHDL_NETLIST)
|
||||
skip = skip_instance2(i, lvs_ignore, (skip_short ? VHDL_SHORT : 0) | VHDL_IGNORE);
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST)
|
||||
|
|
@ -1154,6 +1161,10 @@ static int instcheck(int n, int p)
|
|||
((inst[n].flags & VERILOG_IGNORE) ||
|
||||
(k >= 0 && (sym[k].flags & VERILOG_IGNORE))) ) return 0;
|
||||
|
||||
if( xctx->netlist_type == CAD_SPECTRE_NETLIST &&
|
||||
((inst[n].flags & SPECTRE_IGNORE) ||
|
||||
(k >= 0 && (sym[k].flags & SPECTRE_IGNORE))) ) return 0;
|
||||
|
||||
if( xctx->netlist_type == CAD_SPICE_NETLIST &&
|
||||
((inst[n].flags & SPICE_IGNORE) ||
|
||||
(k >= 0 && (sym[k].flags & SPICE_IGNORE))) ) return 0;
|
||||
|
|
@ -1315,6 +1326,7 @@ static int name_nodes_of_pins_labels_and_propagate()
|
|||
if( xctx->netlist_type == CAD_VERILOG_NETLIST && (inst[i].flags & VERILOG_IGNORE)) continue;
|
||||
if( xctx->netlist_type == CAD_SPICE_NETLIST && (inst[i].flags & SPICE_IGNORE)) continue;
|
||||
if( xctx->netlist_type == CAD_VHDL_NETLIST && (inst[i].flags & VHDL_IGNORE)) continue;
|
||||
if( xctx->netlist_type == CAD_SPECTRE_NETLIST && (inst[i].flags & SPECTRE_IGNORE)) continue;
|
||||
if( xctx->netlist_type == CAD_TEDAX_NETLIST && (inst[i].flags & TEDAX_IGNORE)) continue;
|
||||
if( netlist_lvs_ignore && (inst[i].flags & LVS_IGNORE_OPEN)) continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,10 @@ static void check_opt(char *opt, char *optval, int type)
|
|||
dbg(1, "process_options(): set netlist type to spice\n");
|
||||
cli_opt_netlist_type = CAD_SPICE_NETLIST;
|
||||
|
||||
} else if( type == LONG && !strcmp("spectre", opt) ) {
|
||||
dbg(1, "process_options(): set netlist type to spectre\n");
|
||||
cli_opt_netlist_type = CAD_SPECTRE_NETLIST;
|
||||
|
||||
} else if( (type == SHORT && *opt == 'y') || (type == LONG && !strcmp("symbol", opt)) ) {
|
||||
dbg(1, "process_options(): set netlist type to symbol\n");
|
||||
cli_opt_netlist_type = CAD_SYMBOL_ATTRS;
|
||||
|
|
|
|||
13
src/save.c
13
src/save.c
|
|
@ -2746,6 +2746,9 @@ static void write_xschem_file(FILE *fd)
|
|||
fprintf(fd, "S ");
|
||||
save_ascii_string(xctx->schprop,fd, 1);
|
||||
|
||||
fprintf(fd, "F ");
|
||||
save_ascii_string(xctx->schspectreprop,fd, 1);
|
||||
|
||||
fprintf(fd, "E ");
|
||||
save_ascii_string(xctx->schtedaxprop,fd, 1);
|
||||
|
||||
|
|
@ -3096,8 +3099,8 @@ static void read_xschem_file(FILE *fd)
|
|||
case '#':
|
||||
read_line(fd, 1);
|
||||
break;
|
||||
case 'F': /* extension for future symbol floater labels */
|
||||
read_line(fd, 1);
|
||||
case 'F': /* spectre global attribute */
|
||||
load_ascii_string(&xctx->schspectreprop,fd);
|
||||
break;
|
||||
case 'E':
|
||||
load_ascii_string(&xctx->schtedaxprop,fd);
|
||||
|
|
@ -4362,15 +4365,15 @@ int load_sym_def(const char *name, FILE *embed_fd)
|
|||
case '#':
|
||||
read_line(lcc[level].fd, 1);
|
||||
break;
|
||||
case 'F': /* extension for future symbol floater labels */
|
||||
read_line(lcc[level].fd, 1);
|
||||
break;
|
||||
case 'E':
|
||||
load_ascii_string(&aux_ptr, lcc[level].fd);
|
||||
break;
|
||||
case 'V':
|
||||
load_ascii_string(&aux_ptr, lcc[level].fd);
|
||||
break;
|
||||
case 'F':
|
||||
load_ascii_string(&aux_ptr, lcc[level].fd);
|
||||
break;
|
||||
case 'S':
|
||||
load_ascii_string(&aux_ptr, lcc[level].fd);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1519,6 +1519,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST) {
|
||||
my_snprintf(f, S(f), "%s.v", get_cell(xctx->current_name, 0));
|
||||
}
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST) {
|
||||
my_snprintf(f, S(f), "%s.sim", get_cell(xctx->current_name, 0));
|
||||
}
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST) {
|
||||
my_snprintf(f, S(f), "%s.tdx", get_cell(xctx->current_name, 0));
|
||||
}
|
||||
|
|
@ -1542,6 +1545,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
else if(xctx->netlist_type == CAD_VHDL_NETLIST) {
|
||||
Tcl_SetResult(interp, "vhdl", TCL_STATIC);
|
||||
}
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST) {
|
||||
Tcl_SetResult(interp, "spectre", TCL_STATIC);
|
||||
}
|
||||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST) {
|
||||
Tcl_SetResult(interp, "verilog", TCL_STATIC);
|
||||
}
|
||||
|
|
@ -1631,6 +1637,10 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
{
|
||||
Tcl_SetResult(interp, xctx->schverilogprop ? xctx->schverilogprop : "", TCL_VOLATILE);
|
||||
}
|
||||
else if(!strcmp(argv[2], "schspectreprop")) /* get schematic "spectre" global attributes */
|
||||
{
|
||||
Tcl_SetResult(interp, xctx->schspectreprop ? xctx->schspectreprop : "", TCL_VOLATILE);
|
||||
}
|
||||
else if(!strcmp(argv[2], "schsymbolprop")) /* get schematic "symbol" global attributes */
|
||||
{
|
||||
Tcl_SetResult(interp, xctx->schsymbolprop ? xctx->schsymbolprop : "", TCL_VOLATILE);
|
||||
|
|
@ -3476,6 +3486,8 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
err = global_vhdl_netlist(hier_netlist, alert);
|
||||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST)
|
||||
err = global_verilog_netlist(hier_netlist, alert);
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST)
|
||||
err = global_spectre_netlist(hier_netlist, alert);
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST)
|
||||
global_tedax_netlist(hier_netlist, alert);
|
||||
else
|
||||
|
|
@ -5398,6 +5410,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
else if(!strcmp(argv[3], "vhdl")) {
|
||||
xctx->netlist_type=CAD_VHDL_NETLIST;
|
||||
}
|
||||
else if(!strcmp(argv[3], "spectre")) {
|
||||
xctx->netlist_type=CAD_SPECTRE_NETLIST;
|
||||
}
|
||||
else if(!strcmp(argv[3], "verilog")) {
|
||||
xctx->netlist_type=CAD_VERILOG_NETLIST;
|
||||
}
|
||||
|
|
@ -5459,6 +5474,10 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
|
||||
my_strdup(_ALLOC_ID_, &xctx->schverilogprop, argv[3]);
|
||||
}
|
||||
else if(!strcmp(argv[2], "schspectreprop")) { /* set schematic global spectre attribute string */
|
||||
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
|
||||
my_strdup(_ALLOC_ID_, &xctx->schspectreprop, argv[3]);
|
||||
}
|
||||
else if(!strcmp(argv[2], "schvhdlprop")) { /* set schematic global vhdl attribute string */
|
||||
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
|
||||
my_strdup(_ALLOC_ID_, &xctx->schvhdlprop, argv[3]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,346 @@
|
|||
#!/usr/bin/awk -f
|
||||
#
|
||||
# File: spice.awk
|
||||
#
|
||||
# This file is part of XSCHEM,
|
||||
# a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
||||
# simulation.
|
||||
# Copyright (C) 1998-2024 Stefan Frederik Schippers
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
BEGIN{
|
||||
lines = 0;
|
||||
first=1
|
||||
user_code=0 #20180129
|
||||
|
||||
# used to handle strange primitives that have a type word before the instance name
|
||||
special_devs["ymemristor"] = 1
|
||||
special_devs["ylin"] = 1
|
||||
special_devs["ydelay"] = 1
|
||||
special_devs["ytransline"] = 1
|
||||
special_devs["ypgbr"] = 1
|
||||
special_devs["ypowergridbranch"] = 1
|
||||
special_devs["yacc"] = 1
|
||||
special_devs[".model"] = 1
|
||||
special_devs[".subckt"] = 1
|
||||
|
||||
while( (ARGV[1] ~ /^[-]/) || (ARGV[1] ~ /^$/) ) {
|
||||
if(ARGV[1] == "-xyce") { xyce = 1}
|
||||
for(i=2; i<= ARGC;i++) {
|
||||
ARGV[i-1] = ARGV[i]
|
||||
}
|
||||
ARGC--
|
||||
}
|
||||
}
|
||||
|
||||
# join split lines
|
||||
{
|
||||
|
||||
if($0 ~ /^\*\*\*\* begin user (architecture|header) code/) {
|
||||
user_code = 1
|
||||
}
|
||||
if($0 ~ /^[+]/ && !user_code) {
|
||||
yy = yy " " substr($0,2)
|
||||
next
|
||||
}
|
||||
else {
|
||||
zz = yy
|
||||
yy = $0
|
||||
$0 = zz
|
||||
if(first) {
|
||||
first=0
|
||||
next
|
||||
}
|
||||
line[lines++] = $0
|
||||
}
|
||||
if($0 ~ /^\*\*\*\* end user (architecture|header) code/) {
|
||||
user_code = 0
|
||||
}
|
||||
}
|
||||
|
||||
END{
|
||||
user_code = 0
|
||||
$0=yy
|
||||
line[lines++] = $0
|
||||
|
||||
## resolve parametric instance name vector multiplicity
|
||||
substitute_instance_param()
|
||||
|
||||
for(i=0; i<lines; i++) {
|
||||
$0 = line[i]
|
||||
|
||||
## /place to insert processing awk hooks
|
||||
if(xyce == 1) {
|
||||
## transform ".save" lines into ".print tran" *only* for spice_probe elements, not user code
|
||||
if(tolower($0) ~/^[ \t]*\.save[ \t]+.*\?-?[0-9]+/) { # .save file=test1.raw format=raw v( ?1 C2 )
|
||||
$1 = ""
|
||||
$0 = ".print " $0
|
||||
}
|
||||
gsub(/ [mM] *= *1 *$/,"") # xyce does not like m=# fields (multiplicity) removing m=1 is no an issue anyway
|
||||
}
|
||||
process()
|
||||
}
|
||||
}
|
||||
|
||||
## if .param m=10 n=5 is defined and R1[m:n] instance name is present in netlist --> R1[10],R1[9],...,R1[5]
|
||||
## before further processing netlist.
|
||||
function substitute_instance_param( i, j, name, first, last)
|
||||
{
|
||||
IGNORECASE=1
|
||||
for(i = 0;i < lines; i++) {
|
||||
$0 = line[i]
|
||||
if($0 ~/^\.param/) {
|
||||
gsub(/ *= */, "=")
|
||||
for(j = 2; j <= NF; j++) {
|
||||
param = value = $j
|
||||
sub(/=.*/, "", param)
|
||||
sub(/.*=/,"", value)
|
||||
par[param] = value
|
||||
# print "*** " param " = " value
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i = 0;i < lines; i++) {
|
||||
$0 = line[i]
|
||||
if($1 ~ /^[a-zA-Z][^\[\]:]+\[[a-zA-Z_][a-zA-Z0-9_]*:[a-zA-Z_][a-zA-Z0-9_]*\]$/) {
|
||||
name = first = last = $1
|
||||
sub(/\[.*/, "", name)
|
||||
sub(/^.*\[/, "", first)
|
||||
sub(/:.*/,"", first)
|
||||
sub(/^.*:/,"", last)
|
||||
sub(/\]/,"", last)
|
||||
if(first in par) first = par[first]
|
||||
if(last in par) last = par[last]
|
||||
|
||||
n=""
|
||||
for(j= first;;) {
|
||||
if(j!=first) n = n ","
|
||||
n = n name "[" j "]"
|
||||
if(j == last) break
|
||||
j+= sign(last - first)
|
||||
}
|
||||
# print "*** " n
|
||||
$1 = n
|
||||
line[i] = $0
|
||||
}
|
||||
}
|
||||
IGNORECASE=0
|
||||
}
|
||||
|
||||
|
||||
function sign(x)
|
||||
{
|
||||
return x<0 ? -1 : x>0 ? 1 : 0
|
||||
}
|
||||
|
||||
function process( i,j, iprefix, saveinstr, savetype, saveanalysis)
|
||||
{
|
||||
|
||||
if($0 ~/\*\*\*\* end_element/){
|
||||
spiceprefix=""
|
||||
return
|
||||
}
|
||||
if($0 ~/\*\*\*\* spice_prefix/){
|
||||
spiceprefix=$3
|
||||
return
|
||||
}
|
||||
if($0 ~/\*\*\*\* begin user header code/){ #20180129
|
||||
user_code=1
|
||||
return
|
||||
}
|
||||
if($0 ~/\*\*\*\* begin user architecture code/){ #20180129
|
||||
user_code=1
|
||||
print
|
||||
return
|
||||
}
|
||||
if($0 ~/\*\*\*\* end user architecture code/){ #20180129
|
||||
user_code=0
|
||||
print
|
||||
return
|
||||
}
|
||||
if($0 ~/\*\*\*\* end user header code/){ #20180129
|
||||
user_code=0
|
||||
return
|
||||
}
|
||||
if(user_code) { #20180129
|
||||
print
|
||||
return
|
||||
}
|
||||
|
||||
# 20181208 do not process commented lines
|
||||
if($1 ~/^\*/) {
|
||||
print
|
||||
return
|
||||
}
|
||||
|
||||
#20150922 handle the case of pmos elements that netlist also a diode
|
||||
# format="@name @pinlist @model w=@w l=@l geomod=0 m=@m
|
||||
# #dx#name 0 @@b dnwell area=... pj=..."
|
||||
# replace #dx#name with dx prefix added on all @name elements
|
||||
# example:
|
||||
# m6[3] GWL WLDECF[3] WL[3] HDD phv w=50u l=10u geomod=0 m=1
|
||||
# m6[2] GWL WLDECF[2] WL[2] HDD phv w=50u l=10u geomod=0 m=1
|
||||
# m6[1] GWL WLDECF[1] WL[1] HDD phv w=50u l=10u geomod=0 m=1
|
||||
# m6[0] GWL WLDECF[0] WL[0] HDD phv w=50u l=10u geomod=0 m=1
|
||||
# dxm6[3] 0 HDD dnwell area='(50u + 73u)*(10u + 32u)' pj='2*(50u +73u)+2*(10u +32u)'
|
||||
# dxm6[2] 0 HDD dnwell area='(50u + 73u)*(10u + 32u)' pj='2*(50u +73u)+2*(10u +32u)'
|
||||
# dxm6[1] 0 HDD dnwell area='(50u + 73u)*(10u + 32u)' pj='2*(50u +73u)+2*(10u +32u)'
|
||||
# dxm6[0] 0 HDD dnwell area='(50u + 73u)*(10u + 32u)' pj='2*(50u +73u)+2*(10u +32u)'
|
||||
#20151027 do this for all fields
|
||||
for(i=1; i<=NF;i++) {
|
||||
|
||||
if($i ~/^##[a-zA-Z_]+/) {
|
||||
sub(/^##/, "", $i)
|
||||
} else
|
||||
if($i ~/^#[a-zA-Z_0-9]+#[a-zA-Z_]+/) {
|
||||
iprefix=$i
|
||||
sub(/^#/,"",iprefix)
|
||||
sub(/#.*/,"",iprefix)
|
||||
sub("#" iprefix "#", iprefix,$i)
|
||||
gsub(/,/, "," iprefix,$i)
|
||||
## 20160301 add '?1' if missing in format string
|
||||
if(i>1 && ( $(i-1) !~/^\?/) ) {
|
||||
$i = "?1 " $i
|
||||
}
|
||||
$0 = $0 # reparse input line
|
||||
}
|
||||
}
|
||||
## 20140506 do not transform {} of variation groups
|
||||
## nmos N {
|
||||
## ...
|
||||
## }
|
||||
gsub(/PARAM:/,"") # stefan 20110627
|
||||
|
||||
if($0 ~/^[gG]/) {
|
||||
IGNORECASE=1
|
||||
sub(/ value=/," cur=")
|
||||
IGNORECASE=0
|
||||
}
|
||||
if($0 ~/^[eE]/) {
|
||||
IGNORECASE=1
|
||||
sub(/ value=/," vol=")
|
||||
IGNORECASE=0
|
||||
}
|
||||
if($0 ~/^[rR]/) {
|
||||
IGNORECASE=1
|
||||
sub(/ value=/," r=")
|
||||
IGNORECASE=0
|
||||
}
|
||||
if($0 ~/^[cC]/) {
|
||||
IGNORECASE=1
|
||||
sub(/ value=/," c=")
|
||||
IGNORECASE=0
|
||||
}
|
||||
### ?? too dangerous
|
||||
# gsub(/ value=/," ")
|
||||
# gsub(/ VALUE=/," ")
|
||||
|
||||
if($0 ~ /^D/ ) sub(/PERI[ \t]*=/,"PJ=")
|
||||
|
||||
## .save tran v(?1 GB ) v(?1 SB )
|
||||
## ? may be followed by -1 in some cases
|
||||
if(tolower($1) ~ /^\.(save|print)$/ && $0 ~/\?-?[0-9]/) {
|
||||
$0 = tolower($0)
|
||||
saveinstr = $1
|
||||
if(!xyce) {
|
||||
$1=""
|
||||
$0 = $0 # reparse line for field splitting
|
||||
|
||||
gsub(/ *\?-?[0-9]+ */, "") # in some cases ?-1 is printed (unknow multiplicity)
|
||||
gsub(/\( */, "(")
|
||||
gsub(/ *\)/, ")")
|
||||
for(i=1; i<=NF; i++) {
|
||||
savetype=$i; sub(/\(.*/,"", savetype) # v(...) --> v
|
||||
sub(/^.*\(/,"", $i)
|
||||
sub(/\).*/,"", $i)
|
||||
num = split($i, name, ",")
|
||||
for(j=1; j<= num; j++) {
|
||||
print saveinstr " " savetype "(" name[j] ")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if( $1 ~ /^\*\.(ipin|opin|iopin)/ ) {
|
||||
num=split($2,name,",")
|
||||
for(i=1;i<=num;i++) print $1 " " name[i]
|
||||
} else if( tolower($1) ~ /\.subckt/) {
|
||||
# remove m=.. from subcircuit definition since m= is a multiplier not a param
|
||||
sub(/ m=[0-9]+/," ",$0)
|
||||
gsub(","," ",$0)
|
||||
print $0
|
||||
} else {
|
||||
# handle uncommon primitives that have a prefix before the device name
|
||||
if(tolower($1) in special_devs) {
|
||||
devprefix = $1
|
||||
num = split($3, name, ",")
|
||||
$1 = ""
|
||||
for(i = 0; i < num; i++) {
|
||||
if(i) $1 = $1 ","
|
||||
$1 = $1 devprefix
|
||||
}
|
||||
num = split($1, name, ",")
|
||||
$0 = $0
|
||||
} else {
|
||||
num = split($1, name, ",")
|
||||
}
|
||||
if(num==0) print ""
|
||||
|
||||
|
||||
for(j=2;j<=NF;j+=1) # start from 2 not from 3 20070221
|
||||
{
|
||||
# ............ --> matches ?n and ?-n
|
||||
# some CDL netlists have this: $SUB=?1 B where B is a node
|
||||
if($j ~/^(.*=)?\?-?[0-9]+$/) continue # handle the case that $2 not pinlist 20070221
|
||||
arg_num[j]=split($j,tmp,",")
|
||||
for(k=1;k<=arg_num[j]; k++) {
|
||||
arg_name[j,k]=tmp[k]
|
||||
}
|
||||
}
|
||||
for(i=1;i<=num;i++)
|
||||
{
|
||||
printf "%s ", spiceprefix name[i]
|
||||
|
||||
for(j=2;j<=NF;j++)
|
||||
{
|
||||
# ............ --> matches ?n and ?-n
|
||||
# some CDL netlists have this: $SUB=?1 B where B is a node
|
||||
if($j !~ /^(.*=)?\?-?[0-9]+$/)
|
||||
{
|
||||
printf "%s ", $j # if not a node just print it
|
||||
}
|
||||
else
|
||||
{
|
||||
nmult=$(j)
|
||||
if(nmult ~ /^(.*=)/) { # some CDL netlists have this: $SUB=?1 B where B is a node
|
||||
sub(/=.*/, "=", nmult)
|
||||
printf "%s", nmult
|
||||
}
|
||||
nmult=$(j++)
|
||||
sub(/(.*=)?\?/,"",nmult)
|
||||
if(nmult+0==-1) nmult=arg_num[j]
|
||||
for(l=0;l<nmult+0;l++)
|
||||
{
|
||||
ii=(l+nmult*(i-1))%arg_num[j]+1
|
||||
printf "%s ", arg_name[j,ii]
|
||||
}
|
||||
}
|
||||
}
|
||||
printf "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,611 @@
|
|||
/* File: spice_netlist.c
|
||||
*
|
||||
* This file is part of XSCHEM,
|
||||
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
||||
* simulation.
|
||||
* Copyright (C) 1998-2024 Stefan Frederik Schippers
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "xschem.h"
|
||||
|
||||
static Str_hashtable model_table = {NULL, 0}; /* safe even with multiple schematics */
|
||||
|
||||
static char *model_name_result = NULL; /* safe even with multiple schematics */
|
||||
|
||||
static char *model_name(const char *m)
|
||||
{
|
||||
char *m_lower = NULL;
|
||||
char *modelname = NULL;
|
||||
char *ptr;
|
||||
int n;
|
||||
size_t l = strlen(m) + 1;
|
||||
my_strdup(_ALLOC_ID_, &m_lower, m);
|
||||
strtolower(m_lower);
|
||||
my_realloc(_ALLOC_ID_, &modelname, l);
|
||||
my_realloc(_ALLOC_ID_, &model_name_result, l);
|
||||
if((ptr = strstr(m_lower, "subckt"))) {
|
||||
n = sscanf(ptr, "subckt %s %s", model_name_result, modelname);
|
||||
} else if((ptr = strstr(m_lower, "model"))) {
|
||||
n = sscanf(ptr, "model %s %s", model_name_result, modelname);
|
||||
} else {
|
||||
n = sscanf(m_lower, " %s %s", model_name_result, modelname);
|
||||
}
|
||||
if(n<2) my_strncpy(model_name_result, m_lower, l);
|
||||
else {
|
||||
/* build a hash key value with no spaces to make device_model attributes with different spaces equivalent*/
|
||||
my_strcat(_ALLOC_ID_, &model_name_result, modelname);
|
||||
}
|
||||
my_free(_ALLOC_ID_, &modelname);
|
||||
my_free(_ALLOC_ID_, &m_lower);
|
||||
return model_name_result;
|
||||
}
|
||||
|
||||
static int spectre_netlist(FILE *fd, int spectre_stop )
|
||||
{
|
||||
int err = 0;
|
||||
int i, flag = 0;
|
||||
const char *type;
|
||||
int lvs_netlist = tclgetboolvar("lvs_netlist");
|
||||
int top_sub = lvs_netlist || tclgetboolvar("top_is_subckt");
|
||||
int lvs_ignore = tclgetboolvar("lvs_ignore");
|
||||
if(lvs_netlist) my_strdup(_ALLOC_ID_, &xctx->format, "lvs_format");
|
||||
else my_strdup(_ALLOC_ID_, &xctx->format, xctx->custom_format);
|
||||
if(!spectre_stop) {
|
||||
dbg(1, "spectre_netlist(): invoke prepare_netlist_structs for %s\n", xctx->current_name);
|
||||
xctx->prep_net_structs = 0;
|
||||
err |= prepare_netlist_structs(1);
|
||||
err |= traverse_node_hash(); /* print all warnings about unconnected floatings etc */
|
||||
for(i=0;i<xctx->instances; ++i) /* print first ipin/opin defs ... */
|
||||
{
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
type = (xctx->inst[i].ptr+ xctx->sym)->type;
|
||||
if( type && IS_PIN(type) ) {
|
||||
if(top_sub && !flag) {
|
||||
fprintf(fd, "*.PININFO ");
|
||||
flag = 1;
|
||||
}
|
||||
if(top_sub) {
|
||||
int d = 'X';
|
||||
if(!strcmp(type, "ipin")) d = 'I';
|
||||
if(!strcmp(type, "opin")) d = 'O';
|
||||
if(!strcmp(type, "iopin")) d = 'B';
|
||||
fprintf(fd, "%s:%c ",xctx->inst[i].lab, d);
|
||||
} else {
|
||||
print_spectre_element(fd, i) ; /* this is the element line */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(top_sub) fprintf(fd, "\n");
|
||||
for(i=0;i<xctx->instances; ++i) /* ... then print other lines */
|
||||
{
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
type = (xctx->inst[i].ptr+ xctx->sym)->type;
|
||||
|
||||
if( type && !IS_LABEL_OR_PIN(type) ) {
|
||||
/* already done in global_spectre_netlist */
|
||||
if(!strcmp(type,"netlist_commands") && xctx->netlist_count==0) continue;
|
||||
if(xctx->netlist_count &&
|
||||
!strboolcmp(get_tok_value(xctx->inst[i].prop_ptr, "only_toplevel", 0), "true")) continue;
|
||||
if(!strcmp(type,"netlist_commands")) {
|
||||
fprintf(fd,"**** begin user architecture code\n");
|
||||
print_spectre_element(fd, i) ; /* this is the element line */
|
||||
fprintf(fd,"**** end user architecture code\n");
|
||||
} else {
|
||||
char *val = NULL;
|
||||
const char *m;
|
||||
if(print_spectre_element(fd, i)) {
|
||||
fprintf(fd, "**** end_element\n");
|
||||
}
|
||||
/* hash device_model attribute if any */
|
||||
my_strdup2(_ALLOC_ID_, &val, get_tok_value(xctx->inst[i].prop_ptr, "device_model", 2));
|
||||
m = val;
|
||||
if(strchr(val, '@')) m = translate(i, val);
|
||||
else m = tcl_hook2(m);
|
||||
if(m[0]) str_hash_lookup(&model_table, model_name(m), m, XINSERT);
|
||||
else {
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr, "device_model", 2));
|
||||
m = val;
|
||||
if(strchr(val, '@')) m = translate(i, val);
|
||||
else m = tcl_hook2(m);
|
||||
if(m[0]) str_hash_lookup(&model_table, model_name(m), m, XINSERT);
|
||||
}
|
||||
my_free(_ALLOC_ID_, &model_name_result);
|
||||
my_free(_ALLOC_ID_, &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!spectre_stop && !xctx->netlist_count) redraw_hilights(0); /* draw_hilight_net(1); */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* alert: if set show alert if file missing */
|
||||
int global_spectre_netlist(int global, int alert) /* netlister driver */
|
||||
{
|
||||
int err = 0;
|
||||
int first;
|
||||
FILE *fd;
|
||||
const char *str_tmp;
|
||||
int multip;
|
||||
unsigned int *stored_flags;
|
||||
int i;
|
||||
const char *type;
|
||||
char *place=NULL;
|
||||
char netl_filename[PATH_MAX]; /* overflow safe 20161122 */
|
||||
char tcl_cmd_netlist[PATH_MAX + 100]; /* 20081211 overflow safe 20161122 */
|
||||
char cellname[PATH_MAX]; /* 20081211 overflow safe 20161122 */
|
||||
char *subckt_name;
|
||||
char *abs_path = NULL;
|
||||
int split_f;
|
||||
Str_hashtable subckt_table = {NULL, 0};
|
||||
Str_hashentry *model_entry;
|
||||
int save_prev_mod = xctx->prev_set_modify;
|
||||
struct stat buf;
|
||||
char *top_symbol_name = NULL;
|
||||
/* if top level has a symbol use it for pin ordering
|
||||
* top_symbol_name == 1: a symbol file matching schematic has been found.
|
||||
* top_symbol_name == 3: the found symbol has type=subcircuit and has ports */
|
||||
int found_top_symbol = 0;
|
||||
int npins = 0; /* top schematic number of i/o ports */
|
||||
Sch_pin_record *pinnumber_list = NULL; /* list of top sch i/o ports ordered wrt sim_pinnumber attr */
|
||||
int uppercase_subckt = tclgetboolvar("uppercase_subckt");
|
||||
int lvs_netlist = tclgetboolvar("lvs_netlist");
|
||||
int top_sub = lvs_netlist || tclgetboolvar("top_is_subckt");
|
||||
int lvs_ignore = tclgetboolvar("lvs_ignore");
|
||||
|
||||
if(lvs_netlist) my_strdup(_ALLOC_ID_, &xctx->format, "lvs_format");
|
||||
else my_strdup(_ALLOC_ID_, &xctx->format, xctx->custom_format);
|
||||
exit_code = 0; /* reset exit code */
|
||||
split_f = tclgetboolvar("split_files");
|
||||
dbg(1, "global_spectre_netlist(): invoking push_undo()\n");
|
||||
xctx->push_undo();
|
||||
xctx->netlist_unconn_cnt=0; /* unique count of unconnected pins while netlisting */
|
||||
statusmsg("",2); /* clear infowindow */
|
||||
str_hash_init(&subckt_table, HASHSIZE);
|
||||
str_hash_init(&model_table, HASHSIZE);
|
||||
record_global_node(2, NULL, NULL); /* delete list of global nodes */
|
||||
bus_char[0] = bus_char[1] = '\0';
|
||||
xctx->hiersep[0]='.'; xctx->hiersep[1]='\0';
|
||||
str_tmp = tclgetvar("bus_replacement_char");
|
||||
if(str_tmp && str_tmp[0] && str_tmp[1]) {
|
||||
bus_char[0] = str_tmp[0];
|
||||
bus_char[1] = str_tmp[1];
|
||||
}
|
||||
xctx->netlist_count=0;
|
||||
my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d",
|
||||
tclgetvar("netlist_dir"), get_cell(xctx->sch[xctx->currsch], 0), getpid());
|
||||
dbg(1, "global_spectre_netlist(): opening %s for writing\n",netl_filename);
|
||||
fd=fopen(netl_filename, "w");
|
||||
if(fd==NULL) {
|
||||
dbg(0, "global_spectre_netlist(): problems opening netlist file\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(fd, "** sch_path: %s\n", xctx->sch[xctx->currsch]);
|
||||
|
||||
if(xctx->netlist_name[0]) {
|
||||
my_snprintf(cellname, S(cellname), "%s", get_cell_w_ext(xctx->netlist_name, 0));
|
||||
} else {
|
||||
my_snprintf(cellname, S(cellname), "%s.spice", get_cell(xctx->sch[xctx->currsch], 0));
|
||||
}
|
||||
|
||||
first = 0;
|
||||
for(i=0;i<xctx->instances; ++i) /* print netlist_commands of top level cell with 'place=header' property */
|
||||
{
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
type = (xctx->inst[i].ptr+ xctx->sym)->type;
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr,"place",0));
|
||||
if( type && !strcmp(type,"netlist_commands") ) {
|
||||
if(!place) {
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->inst[i].prop_ptr,"place",0));
|
||||
}
|
||||
if(place && !strcmp(place, "header" )) {
|
||||
if(first == 0) fprintf(fd,"**** begin user header code\n");
|
||||
++first;
|
||||
print_spectre_element(fd, i) ; /* this is the element line */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(first) fprintf(fd,"**** end user header code\n");
|
||||
|
||||
/* netlist_options */
|
||||
for(i=0;i<xctx->instances; ++i) {
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
if(!(xctx->inst[i].ptr+ xctx->sym)->type) continue;
|
||||
if( !strcmp((xctx->inst[i].ptr+ xctx->sym)->type,"netlist_options") ) {
|
||||
netlist_options(i);
|
||||
}
|
||||
}
|
||||
if(!top_sub) fprintf(fd,"**");
|
||||
if(uppercase_subckt)
|
||||
fprintf(fd,"SUBCKT %s ( ", get_cell(xctx->sch[xctx->currsch], 0));
|
||||
else
|
||||
fprintf(fd,"subckt %s ( ", get_cell(xctx->sch[xctx->currsch], 0));
|
||||
pinnumber_list = sort_schematic_pins(&npins); /* sort pins according to sim_pinnumber attr */
|
||||
|
||||
/* print top subckt ipin/opins */
|
||||
my_strdup2(_ALLOC_ID_, &top_symbol_name, abs_sym_path(add_ext(xctx->current_name, ".sym"), ""));
|
||||
if(!stat(top_symbol_name, &buf)) { /* if top level has a symbol use the symbol for pin ordering */
|
||||
dbg(1, "found top level symbol %s\n", top_symbol_name);
|
||||
load_sym_def(top_symbol_name, NULL);
|
||||
found_top_symbol = 1;
|
||||
if(xctx->sym[xctx->symbols - 1].type != NULL &&
|
||||
/* only use the symbol if it has pins and is a subcircuit ? */
|
||||
/* !strcmp(xctx->sym[xctx->symbols - 1].type, "subcircuit") && */
|
||||
xctx->sym[xctx->symbols - 1].rects[PINLAYER] > 0) {
|
||||
fprintf(fd," ");
|
||||
print_spectre_subckt_nodes(fd, xctx->symbols - 1);
|
||||
found_top_symbol = 3;
|
||||
err |= sym_vs_sch_pins(xctx->symbols - 1);
|
||||
}
|
||||
remove_symbol(xctx->symbols - 1);
|
||||
}
|
||||
my_free(_ALLOC_ID_, &top_symbol_name);
|
||||
if(found_top_symbol != 3) {
|
||||
for(i=0;i<npins; ++i) {
|
||||
int n = pinnumber_list[i].n;
|
||||
str_tmp = expandlabel ( (xctx->inst[n].lab ? xctx->inst[n].lab : ""), &multip);
|
||||
/*must handle invalid node names */
|
||||
fprintf(fd, " %s", str_tmp ? str_tmp : "<NULL>" );
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &pinnumber_list);
|
||||
fprintf(fd,")\n");
|
||||
|
||||
err |= spectre_netlist(fd, 0);
|
||||
|
||||
first = 0;
|
||||
for(i=0;i<xctx->instances; ++i) /* print netlist_commands of top level cell with no 'place=end' property
|
||||
and no place=header */
|
||||
{
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
type = (xctx->inst[i].ptr+ xctx->sym)->type;
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr,"place",0));
|
||||
if( type && !strcmp(type,"netlist_commands") ) {
|
||||
if(!place) {
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->inst[i].prop_ptr,"place",0));
|
||||
}
|
||||
if(!place || (strcmp(place, "end") && strcmp(place, "header")) ) {
|
||||
if(first == 0) fprintf(fd,"**** begin user architecture code\n");
|
||||
++first;
|
||||
print_spectre_element(fd, i) ; /* this is the element line */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xctx->netlist_count++;
|
||||
|
||||
if(xctx->schprop && xctx->schprop[0]) {
|
||||
if(first == 0) fprintf(fd,"**** begin user architecture code\n");
|
||||
++first;
|
||||
fprintf(fd, "%s\n", xctx->schprop);
|
||||
}
|
||||
if(first) fprintf(fd,"**** end user architecture code\n");
|
||||
/* /20100217 */
|
||||
|
||||
if(!top_sub) fprintf(fd,"**");
|
||||
if(uppercase_subckt)
|
||||
fprintf(fd, "ENDS\n");
|
||||
else
|
||||
fprintf(fd, "ends\n");
|
||||
|
||||
|
||||
if(split_f) {
|
||||
int save;
|
||||
fclose(fd);
|
||||
my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} noshow {%s}", netl_filename, cellname);
|
||||
save = xctx->netlist_type;
|
||||
xctx->netlist_type = CAD_SPECTRE_NETLIST;
|
||||
set_tcl_netlist_type();
|
||||
tcleval(tcl_cmd_netlist);
|
||||
xctx->netlist_type = save;
|
||||
set_tcl_netlist_type();
|
||||
|
||||
if(debug_var==0) xunlink(netl_filename);
|
||||
}
|
||||
|
||||
/* warning if two symbols perfectly overlapped */
|
||||
err |= warning_overlapped_symbols(0);
|
||||
/* preserve current level instance flags before descending hierarchy for netlisting, restore later */
|
||||
stored_flags = my_calloc(_ALLOC_ID_, xctx->instances, sizeof(unsigned int));
|
||||
for(i=0;i<xctx->instances; ++i) stored_flags[i] = xctx->inst[i].color;
|
||||
|
||||
if(global)
|
||||
{
|
||||
int saved_hilight_nets = xctx->hilight_nets;
|
||||
int web_url = is_from_web(xctx->current_dirname);
|
||||
char *current_dirname_save = NULL;
|
||||
|
||||
my_strdup2(_ALLOC_ID_, ¤t_dirname_save, xctx->current_dirname);
|
||||
unselect_all(1);
|
||||
/* ensure all unused symbols purged before descending hierarchy */
|
||||
if(!tclgetboolvar("keep_symbols")) remove_symbols();
|
||||
/* reload data without popping undo stack, this populates embedded symbols if any */
|
||||
dbg(1, "global_spectre_netlist(): invoking pop_undo(2, 0)\n");
|
||||
xctx->pop_undo(2, 0);
|
||||
/* link_symbols_to_instances(-1); */ /* done in xctx->pop_undo() */
|
||||
my_strdup(_ALLOC_ID_, &xctx->sch_path[xctx->currsch+1], xctx->sch_path[xctx->currsch]);
|
||||
my_strcat(_ALLOC_ID_, &xctx->sch_path[xctx->currsch+1], "->netlisting");
|
||||
xctx->sch_path_hash[xctx->currsch+1] = 0;
|
||||
xctx->currsch++;
|
||||
subckt_name=NULL;
|
||||
dbg(2, "global_spectre_netlist(): last defined symbol=%d\n",xctx->symbols);
|
||||
get_additional_symbols(1);
|
||||
for(i=0;i<xctx->symbols; ++i)
|
||||
{
|
||||
if(xctx->sym[i].flags & (SPICE_IGNORE | SPICE_SHORT)) continue;
|
||||
if(lvs_ignore && (xctx->sym[i].flags & LVS_IGNORE)) continue;
|
||||
if(!xctx->sym[i].type) continue;
|
||||
/* store parent symbol template attr (before descending into it) and parent instance prop_ptr
|
||||
* into xctx->hier_attr[0].templ and xctx->hier_attr[0.prop_ptr,
|
||||
* to resolve subschematic instances with model=@modp in format string,
|
||||
* modp will be first looked up in instance prop_ptr string, and if not found
|
||||
* in parent symbol template string */
|
||||
my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].templ,
|
||||
tcl_hook2(xctx->sym[i].templ));
|
||||
/* only additional symbols (created with instance schematic=... attr) will have this attribute */
|
||||
my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].prop_ptr,
|
||||
tcl_hook2(xctx->sym[i].parent_prop_ptr));
|
||||
my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].sym_extra,
|
||||
get_tok_value(xctx->sym[i].prop_ptr, "extra", 0));
|
||||
my_strdup(_ALLOC_ID_, &abs_path, abs_sym_path(xctx->sym[i].name, ""));
|
||||
if(strcmp(xctx->sym[i].type,"subcircuit")==0 && check_lib(1, abs_path))
|
||||
{
|
||||
if(!web_url) {
|
||||
tclvareval("get_directory [list ", xctx->sch[xctx->currsch - 1], "]", NULL);
|
||||
my_strncpy(xctx->current_dirname, tclresult(), S(xctx->current_dirname));
|
||||
}
|
||||
/* xctx->sym can be SCH or SYM, use hash to avoid writing duplicate subckt */
|
||||
my_strdup(_ALLOC_ID_, &subckt_name, get_cell(xctx->sym[i].name, 0));
|
||||
dbg(1, "global_spectre_netlist(): subckt_name=%s\n", subckt_name);
|
||||
if (str_hash_lookup(&subckt_table, subckt_name, "", XLOOKUP)==NULL)
|
||||
{
|
||||
/* do not insert symbols with default_schematic attribute set to ignore in hash since these symbols
|
||||
* will not be processed by *_block_netlist() */
|
||||
if(strcmp(get_tok_value(xctx->sym[i].prop_ptr, "default_schematic", 0), "ignore"))
|
||||
str_hash_lookup(&subckt_table, subckt_name, "", XINSERT);
|
||||
if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"vhdl_netlist",0),"true")==0 )
|
||||
err |= vhdl_block_netlist(fd, i, alert);
|
||||
else if(split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"verilog_netlist",0),"true")==0 )
|
||||
err |= verilog_block_netlist(fd, i, alert);
|
||||
else if(split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spice_netlist",0),"true")==0 )
|
||||
err |= spice_block_netlist(fd, i, alert);
|
||||
else
|
||||
if( strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spectre_primitive",0),"true") )
|
||||
err |= spectre_block_netlist(fd, i, alert);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(xctx->hier_attr[xctx->currsch - 1].templ)
|
||||
my_free(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].templ);
|
||||
if(xctx->hier_attr[xctx->currsch - 1].prop_ptr)
|
||||
my_free(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].prop_ptr);
|
||||
if(xctx->hier_attr[xctx->currsch - 1].sym_extra)
|
||||
my_free(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].sym_extra);
|
||||
my_free(_ALLOC_ID_, &abs_path);
|
||||
/* get_additional_symbols(0); */
|
||||
my_free(_ALLOC_ID_, &subckt_name);
|
||||
/*clear_drawing(); */
|
||||
my_free(_ALLOC_ID_, &xctx->sch[xctx->currsch]);
|
||||
xctx->currsch--;
|
||||
unselect_all(1);
|
||||
dbg(1, "global_spectre_netlist(): invoking pop_undo(0, 0)\n");
|
||||
/* symbol vs schematic pin check, we do it here since now we have ALL symbols loaded */
|
||||
err |= sym_vs_sch_pins(-1);
|
||||
if(!tclgetboolvar("keep_symbols")) remove_symbols();
|
||||
xctx->pop_undo(4, 0);
|
||||
xctx->prev_set_modify = save_prev_mod;
|
||||
if(web_url) {
|
||||
my_strncpy(xctx->current_dirname, current_dirname_save, S(xctx->current_dirname));
|
||||
} else {
|
||||
tclvareval("get_directory [list ", xctx->sch[xctx->currsch], "]", NULL);
|
||||
my_strncpy(xctx->current_dirname, tclresult(), S(xctx->current_dirname));
|
||||
}
|
||||
my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name));
|
||||
dbg(1, "spectre_netlist(): invoke prepare_netlist_structs for %s\n", xctx->current_name);
|
||||
err |= prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */
|
||||
if(!xctx->hilight_nets) xctx->hilight_nets = saved_hilight_nets;
|
||||
my_free(_ALLOC_ID_, ¤t_dirname_save);
|
||||
}
|
||||
/* restore hilight flags from errors found analyzing top level before descending hierarchy */
|
||||
for(i=0;i<xctx->instances; ++i) if(!xctx->inst[i].color) xctx->inst[i].color = stored_flags[i];
|
||||
propagate_hilights(1, 0, XINSERT_NOREPLACE);
|
||||
draw_hilight_net(1);
|
||||
my_free(_ALLOC_ID_, &stored_flags);
|
||||
|
||||
/* print globals nodes found in netlist 28032003 */
|
||||
if(!split_f) {
|
||||
record_global_node(0,fd,NULL);
|
||||
/* record_global_node(2, NULL, NULL); */ /* delete list --> do it in xwin_exit() */
|
||||
}
|
||||
|
||||
/* =================================== 20121223 */
|
||||
first = 0;
|
||||
if(!split_f) {
|
||||
for(i=0;i<xctx->instances; ++i) /* print netlist_commands of top level cell with 'place=end' property */
|
||||
{
|
||||
if(skip_instance(i, 1, lvs_ignore)) continue;
|
||||
type = (xctx->inst[i].ptr+ xctx->sym)->type;
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->sym[xctx->inst[i].ptr].prop_ptr,"place",0));
|
||||
if( type && !strcmp(type,"netlist_commands") ) {
|
||||
if(place && !strcmp(place, "end" )) {
|
||||
if(first == 0) fprintf(fd,"**** begin user architecture code\n");
|
||||
++first;
|
||||
print_spectre_element(fd, i) ;
|
||||
} else {
|
||||
my_strdup(_ALLOC_ID_, &place,get_tok_value(xctx->inst[i].prop_ptr,"place",0));
|
||||
if(place && !strcmp(place, "end" )) {
|
||||
if(first == 0) fprintf(fd,"**** begin user architecture code\n");
|
||||
++first;
|
||||
print_spectre_element(fd, i) ;
|
||||
}
|
||||
}
|
||||
} /* netlist_commands */
|
||||
}
|
||||
|
||||
}
|
||||
/* print device_model attributes */
|
||||
for(i=0;i<model_table.size; ++i) {
|
||||
model_entry=model_table.table[i];
|
||||
while(model_entry) {
|
||||
if(first == 0) fprintf(fd,"**** begin user architecture code\n");
|
||||
++first;
|
||||
fprintf(fd, "%s\n", model_entry->value);
|
||||
model_entry = model_entry->next;
|
||||
}
|
||||
}
|
||||
str_hash_free(&model_table);
|
||||
str_hash_free(&subckt_table);
|
||||
if(first) fprintf(fd,"**** end user architecture code\n");
|
||||
|
||||
|
||||
/* 20150922 added split_files check */
|
||||
if( !top_sub && !split_f) fprintf(fd, ".end\n");
|
||||
|
||||
dbg(1, "global_spectre_netlist(): starting awk on netlist!\n");
|
||||
|
||||
|
||||
if(!split_f) {
|
||||
fclose(fd);
|
||||
if(tclgetboolvar("netlist_show")) {
|
||||
my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} show {%s}", netl_filename, cellname);
|
||||
tcleval(tcl_cmd_netlist);
|
||||
}
|
||||
else {
|
||||
my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} noshow {%s}", netl_filename, cellname);
|
||||
tcleval(tcl_cmd_netlist);
|
||||
}
|
||||
if(!debug_var) xunlink(netl_filename);
|
||||
}
|
||||
my_free(_ALLOC_ID_, &place);
|
||||
xctx->netlist_count = 0;
|
||||
tclvareval("show_infotext ", my_itoa(err), NULL); /* critical error: force ERC window showing */
|
||||
exit_code = err ? 10 : 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* alert: if set show alert if file missing */
|
||||
int spectre_block_netlist(FILE *fd, int i, int alert)
|
||||
{
|
||||
int err = 0;
|
||||
int spectre_stop=0;
|
||||
char netl_filename[PATH_MAX];
|
||||
char tcl_cmd_netlist[PATH_MAX + 100];
|
||||
char cellname[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
/* int j; */
|
||||
/* int multip; */
|
||||
char *extra=NULL;
|
||||
int split_f;
|
||||
char *sym_def = NULL;
|
||||
char *name = NULL;
|
||||
const char *default_schematic;
|
||||
int uppercase_subckt = tclgetboolvar("uppercase_subckt");
|
||||
|
||||
split_f = tclgetboolvar("split_files");
|
||||
|
||||
if(!strboolcmp( get_tok_value(xctx->sym[i].prop_ptr,"spectre_stop",0),"true") )
|
||||
spectre_stop=1;
|
||||
else
|
||||
spectre_stop=0;
|
||||
if(!strcmp(get_tok_value(xctx->sym[i].prop_ptr, "format", 0), "")) {
|
||||
return err;
|
||||
}
|
||||
get_sch_from_sym(filename, xctx->sym + i, -1, 0);
|
||||
default_schematic = get_tok_value(xctx->sym[i].prop_ptr, "default_schematic", 0);
|
||||
if(!strcmp(default_schematic, "ignore")) {
|
||||
return err;
|
||||
}
|
||||
my_strdup(_ALLOC_ID_, &name, tcl_hook2(xctx->sym[i].name));
|
||||
|
||||
dbg(1, "spectre_block_netlist(): filename=%s\n", filename);
|
||||
if(split_f) {
|
||||
my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d",
|
||||
tclgetvar("netlist_dir"), get_cell(name, 0), getpid());
|
||||
dbg(1, "spectre_block_netlist(): split_files: netl_filename=%s\n", netl_filename);
|
||||
fd=fopen(netl_filename, "w");
|
||||
if(!fd) {
|
||||
dbg(0, "spectre_block_netlist(): unable to write file %s\n", netl_filename);
|
||||
err = 1;
|
||||
goto err;
|
||||
}
|
||||
my_snprintf(cellname, S(cellname), "%s.spice", get_cell(name, 0));
|
||||
}
|
||||
fprintf(fd, "\n* expanding symbol: %s # of pins=%d\n", name,xctx->sym[i].rects[PINLAYER] );
|
||||
if(xctx->sym[i].base_name) fprintf(fd, "** sym_path: %s\n", abs_sym_path(xctx->sym[i].base_name, ""));
|
||||
else fprintf(fd, "** sym_path: %s\n", sanitized_abs_sym_path(name, ""));
|
||||
my_strdup(_ALLOC_ID_, &sym_def, get_tok_value(xctx->sym[i].prop_ptr,"spectre_sym_def",0));
|
||||
if(sym_def) {
|
||||
char *symname_attr = NULL;
|
||||
const char *translated_sym_def;
|
||||
my_mstrcat(_ALLOC_ID_, &symname_attr, "symname=", get_cell(name, 0), NULL);
|
||||
translated_sym_def = translate3(sym_def, 1, xctx->sym[i].templ, symname_attr, NULL, NULL);
|
||||
my_free(_ALLOC_ID_, &symname_attr);
|
||||
fprintf(fd, "%s\n", translated_sym_def);
|
||||
my_free(_ALLOC_ID_, &sym_def);
|
||||
} else {
|
||||
const char *s = get_cell(sanitize(name), 0);
|
||||
fprintf(fd, "** sch_path: %s\n", sanitized_abs_sym_path(filename, ""));
|
||||
if(uppercase_subckt)
|
||||
fprintf(fd, "SUBCKT %s ( ", s);
|
||||
else
|
||||
fprintf(fd, "subckt %s ( ", s);
|
||||
print_spectre_subckt_nodes(fd, i);
|
||||
fprintf(fd, ") ");
|
||||
my_strdup(_ALLOC_ID_, &extra, get_tok_value(xctx->sym[i].prop_ptr,"extra",0) );
|
||||
/* this is now done in print_spectre_subckt_nodes */
|
||||
/*
|
||||
* fprintf(fd, "%s ", extra ? extra : "" );
|
||||
*/
|
||||
|
||||
/* 20081206 new get_sym_template does not return token=value pairs where token listed in extra */
|
||||
fprintf(fd, "\nparameters %s", get_sym_template(xctx->sym[i].templ, extra));
|
||||
my_free(_ALLOC_ID_, &extra);
|
||||
fprintf(fd, "\n");
|
||||
|
||||
spectre_stop ? load_schematic(0,filename, 0, alert) : load_schematic(1,filename, 0, alert);
|
||||
get_additional_symbols(1);
|
||||
err |= spectre_netlist(fd, spectre_stop); /* 20111113 added spectre_stop */
|
||||
err |= warning_overlapped_symbols(0);
|
||||
if(xctx->schprop && xctx->schprop[0]) {
|
||||
fprintf(fd,"**** begin user architecture code\n");
|
||||
fprintf(fd, "%s\n", xctx->schprop);
|
||||
fprintf(fd,"**** end user architecture code\n");
|
||||
}
|
||||
if(uppercase_subckt)
|
||||
fprintf(fd, "ENDS\n\n");
|
||||
else
|
||||
fprintf(fd, "ends\n\n");
|
||||
}
|
||||
if(split_f) {
|
||||
int save;
|
||||
fclose(fd);
|
||||
my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} noshow {%s}", netl_filename, cellname);
|
||||
save = xctx->netlist_type;
|
||||
xctx->netlist_type = CAD_SPECTRE_NETLIST;
|
||||
set_tcl_netlist_type();
|
||||
tcleval(tcl_cmd_netlist);
|
||||
xctx->netlist_type = save;
|
||||
set_tcl_netlist_type();
|
||||
if(debug_var==0) xunlink(netl_filename);
|
||||
}
|
||||
err:
|
||||
xctx->netlist_count++;
|
||||
my_free(_ALLOC_ID_, &name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -496,6 +496,8 @@ int global_spice_netlist(int global, int alert) /* netlister driver */
|
|||
err |= vhdl_block_netlist(fd, i, alert);
|
||||
else if(split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"verilog_netlist",0),"true")==0 )
|
||||
err |= verilog_block_netlist(fd, i, alert);
|
||||
else if(split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spectre_netlist",0),"true")==0 )
|
||||
err |= spectre_block_netlist(fd, i, alert);
|
||||
else
|
||||
if( strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spice_primitive",0),"true") )
|
||||
err |= spice_block_netlist(fd, i, alert);
|
||||
|
|
|
|||
563
src/token.c
563
src/token.c
|
|
@ -2159,6 +2159,163 @@ void print_spice_subckt_nodes(FILE *fd, int symbol)
|
|||
}
|
||||
|
||||
|
||||
void print_spectre_subckt_nodes(FILE *fd, int symbol)
|
||||
{
|
||||
int i=0, multip;
|
||||
const char *str_ptr=NULL;
|
||||
register int c, state=TOK_BEGIN, space;
|
||||
char *format=NULL, *format1 = NULL, *s, *token=NULL;
|
||||
int pin_number;
|
||||
size_t sizetok=0;
|
||||
size_t token_pos=0;
|
||||
int escape=0;
|
||||
int no_of_pins=0;
|
||||
char *result = NULL;
|
||||
const char *tclres, *fmt_attr = NULL;
|
||||
|
||||
fmt_attr = xctx->format ? xctx->format : "spectre_format";
|
||||
my_strdup(_ALLOC_ID_, &format1, get_tok_value(xctx->sym[symbol].prop_ptr, fmt_attr, 2));
|
||||
if(!xctx->tok_size && strcmp(fmt_attr, "spectre_format") )
|
||||
my_strdup(_ALLOC_ID_, &format1, get_tok_value(xctx->sym[symbol].prop_ptr, "spectre_format", 2));
|
||||
dbg(1, "print_spectre_subckt(): format1=%s\n", format1);
|
||||
|
||||
/* can not do this, since @symname is used as a token later in format parser */
|
||||
/* my_strdup(_ALLOC_ID_, &format1,
|
||||
* str_replace(format1, "@symname", get_cell(xctx->sym[symbol].name, 0), '\\', -1)); */
|
||||
|
||||
if(format1 && strstr(format1, "tcleval(") == format1) {
|
||||
tclres = tcl_hook2(format1);
|
||||
if(!strcmp(tclres, "?\n")) {
|
||||
char *ptr = strrchr(format1 + 8, ')');
|
||||
*ptr = '\0';
|
||||
my_strdup(_ALLOC_ID_, &format, format1 + 8);
|
||||
} else my_strdup(_ALLOC_ID_, &format, tclres);
|
||||
} else {
|
||||
my_strdup(_ALLOC_ID_, &format, format1);
|
||||
}
|
||||
if(format1) my_free(_ALLOC_ID_, &format1);
|
||||
dbg(1, "print_spectre_subckt(): format=%s\n", format);
|
||||
if( format==NULL ) {
|
||||
return; /* no format */
|
||||
}
|
||||
no_of_pins= xctx->sym[symbol].rects[PINLAYER];
|
||||
s=format;
|
||||
|
||||
/* begin parsing format string */
|
||||
while(1)
|
||||
{
|
||||
c=*s++;
|
||||
if(c=='\\') {
|
||||
escape=1;
|
||||
c=*s++;
|
||||
}
|
||||
else escape=0;
|
||||
if(c=='\n' && escape ) c=*s++; /* 20171030 eat escaped newlines */
|
||||
space=SPACE(c);
|
||||
if( state==TOK_BEGIN && (c=='@' || c=='%') && !escape) state=TOK_TOKEN;
|
||||
else if(state==TOK_TOKEN && token_pos > 1 &&
|
||||
(
|
||||
( (space || c == '%' || c == '@') && !escape ) ||
|
||||
( (!space && c != '%' && c != '@') && escape )
|
||||
)
|
||||
) {
|
||||
state = TOK_SEP;
|
||||
}
|
||||
|
||||
STR_ALLOC(&token, token_pos, &sizetok);
|
||||
if(state==TOK_TOKEN) {
|
||||
token[token_pos++]=(char)c;
|
||||
}
|
||||
else if(state==TOK_SEP) /* got a token */
|
||||
{
|
||||
token[token_pos]='\0';
|
||||
token_pos=0;
|
||||
if(!strcmp(token, "@spiceprefix")) {
|
||||
/* do nothing */
|
||||
}
|
||||
else if(!strcmp(token, "@name")) {
|
||||
/* do nothing */
|
||||
}
|
||||
else if(strcmp(token, "@symname")==0) {
|
||||
break ;
|
||||
}
|
||||
else if(strcmp(token, "@pinlist")==0) {
|
||||
Int_hashtable table = {NULL, 0};
|
||||
int_hash_init(&table, 37);
|
||||
for(i=0;i<no_of_pins; ++i)
|
||||
{
|
||||
if(strboolcmp(get_tok_value(xctx->sym[symbol].rect[PINLAYER][i].prop_ptr,"spectre_ignore",0), "true")) {
|
||||
const char *name = get_tok_value(xctx->sym[symbol].rect[PINLAYER][i].prop_ptr,"name",0);
|
||||
if(!int_hash_lookup(&table, name, 1, XINSERT_NOREPLACE)) {
|
||||
str_ptr= expandlabel(name, &multip);
|
||||
/* fprintf(fd, "%s ", str_ptr); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, str_ptr, " ", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
int_hash_free(&table);
|
||||
}
|
||||
else if(token[0]=='@' && token[1]=='@') { /* recognize single pins 15112003 */
|
||||
char *prop=NULL;
|
||||
for(i = 0; i<no_of_pins; ++i) {
|
||||
prop = xctx->sym[symbol].rect[PINLAYER][i].prop_ptr;
|
||||
if(!strcmp(get_tok_value(prop, "name",0), token + 2)) break;
|
||||
}
|
||||
if(i<no_of_pins && strboolcmp(get_tok_value(prop,"spectre_ignore",0), "true")) {
|
||||
/* fprintf(fd, "%s ", expandlabel(token+2, &multip)); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, expandlabel(token+2, &multip), " ", NULL);
|
||||
}
|
||||
}
|
||||
/* reference by pin number instead of pin name, allows faster lookup of the attached net name 20180911 */
|
||||
else if(token[0]=='@' && token[1]=='#') {
|
||||
char *pin_attr = NULL;
|
||||
char *pin_num_or_name = NULL;
|
||||
get_pin_and_attr(token, &pin_num_or_name, &pin_attr);
|
||||
pin_number = get_sym_pin_number(symbol, pin_num_or_name);
|
||||
if(pin_number >= 0 && pin_number < no_of_pins) {
|
||||
if(strboolcmp(get_tok_value(xctx->sym[symbol].rect[PINLAYER][pin_number].prop_ptr,"spectre_ignore",0), "true")) {
|
||||
str_ptr = get_tok_value(xctx->sym[symbol].rect[PINLAYER][pin_number].prop_ptr,"name",0);
|
||||
/* fprintf(fd, "%s ", expandlabel(str_ptr, &multip)); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, expandlabel(str_ptr, &multip), " ", NULL);
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &pin_attr);
|
||||
my_free(_ALLOC_ID_, &pin_num_or_name);
|
||||
|
||||
}
|
||||
/* this will print the other @parameters, usually "extra" nodes so they will be in the order
|
||||
* specified by the format string. The 'extra' attribute is no more used to print extra nodes
|
||||
* in spice_block_netlist(). */
|
||||
else if(token[0] == '@') { /* given previous if() conditions not followed by @ or # */
|
||||
/* if token not followed by white space it is not an extra node */
|
||||
if( ( (space || c == '%' || c == '@') && !escape ) ) {
|
||||
/* fprintf(fd, "%s ", token + 1); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, token + 1, " ", NULL);
|
||||
}
|
||||
}
|
||||
/* if(c!='%' && c!='@' && c!='\0' ) fputc(c,fd); */
|
||||
if(c == '@' || c =='%') s--;
|
||||
state=TOK_BEGIN;
|
||||
}
|
||||
/* 20151028 dont print escaping backslashes */
|
||||
else if(state==TOK_BEGIN && c!='\0') {
|
||||
/* do nothing */
|
||||
}
|
||||
if(c=='\0')
|
||||
{
|
||||
my_mstrcat(_ALLOC_ID_, &result, "\n", NULL);
|
||||
break ;
|
||||
}
|
||||
}
|
||||
if(result) {
|
||||
fprintf(fd, "%s", result);
|
||||
my_free(_ALLOC_ID_, &result);
|
||||
}
|
||||
my_free(_ALLOC_ID_, &format1);
|
||||
my_free(_ALLOC_ID_, &format);
|
||||
my_free(_ALLOC_ID_, &token);
|
||||
}
|
||||
|
||||
int has_token(const char *s, const char *tok)
|
||||
{
|
||||
int i = 1;
|
||||
|
|
@ -2572,6 +2729,398 @@ int print_spice_element(FILE *fd, int inst)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int print_spectre_element(FILE *fd, int inst)
|
||||
{
|
||||
int i=0, multip, itmp;
|
||||
const char *str_ptr=NULL;
|
||||
register int c, state=TOK_BEGIN, space;
|
||||
char *template=NULL,*format=NULL, *s, *name=NULL, *token=NULL;
|
||||
const char *lab;
|
||||
const char *value = NULL;
|
||||
/* char *translatedvalue = NULL; */
|
||||
size_t sizetok=0;
|
||||
size_t token_pos=0;
|
||||
int escape=0;
|
||||
int no_of_pins=0;
|
||||
char *result = NULL;
|
||||
size_t size = 0;
|
||||
char *spiceprefixtag = NULL;
|
||||
const char *fmt_attr = NULL;
|
||||
|
||||
size = CADCHUNKALLOC;
|
||||
my_realloc(_ALLOC_ID_, &result, size);
|
||||
result[0] = '\0';
|
||||
|
||||
my_strdup(_ALLOC_ID_, &template, (xctx->inst[inst].ptr + xctx->sym)->templ);
|
||||
my_strdup(_ALLOC_ID_, &name,xctx->inst[inst].instname);
|
||||
if (!name) my_strdup(_ALLOC_ID_, &name, get_tok_value(template, "name", 0));
|
||||
|
||||
fmt_attr = xctx->format ? xctx->format : "spectre_format";
|
||||
/* allow format string override in instance */
|
||||
my_strdup(_ALLOC_ID_, &format, get_tok_value(xctx->inst[inst].prop_ptr, fmt_attr, 2));
|
||||
/* get netlist format rule from symbol */
|
||||
if(!xctx->tok_size)
|
||||
my_strdup(_ALLOC_ID_, &format, get_tok_value(xctx->sym[xctx->inst[inst].ptr].prop_ptr, fmt_attr, 2));
|
||||
/* allow format string override in instance */
|
||||
if(!xctx->tok_size && strcmp(fmt_attr, "spectre_format") )
|
||||
my_strdup(_ALLOC_ID_, &format, get_tok_value(xctx->inst[inst].prop_ptr, "spectre_format", 2));
|
||||
/* get netlist format rule from symbol */
|
||||
if(!xctx->tok_size && strcmp(fmt_attr, "spectre_format"))
|
||||
my_strdup(_ALLOC_ID_, &format, get_tok_value(xctx->sym[xctx->inst[inst].ptr].prop_ptr, "spectre_format", 2));
|
||||
if ((name==NULL) || (format==NULL)) {
|
||||
my_free(_ALLOC_ID_, &template);
|
||||
my_free(_ALLOC_ID_, &format);
|
||||
my_free(_ALLOC_ID_, &name);
|
||||
my_free(_ALLOC_ID_, &result);
|
||||
return 0; /* do no netlist unwanted insts(no format) */
|
||||
}
|
||||
no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER];
|
||||
s=format;
|
||||
dbg(1, "print_spectre_element(): name=%s, format=%s xctx->netlist_count=%d\n",name,format, xctx->netlist_count);
|
||||
/* begin parsing format string */
|
||||
while(1)
|
||||
{
|
||||
/* always make room for some characters so the single char writes to result do not need reallocs */
|
||||
c=*s++;
|
||||
if(c=='\\') {
|
||||
escape=1;
|
||||
c=*s++;
|
||||
}
|
||||
else escape=0;
|
||||
|
||||
if (c=='\n' && escape) c=*s++; /* 20171030 eat escaped newlines */
|
||||
space=SPACE(c);
|
||||
if ( state==TOK_BEGIN && (c=='@'|| c=='%') && !escape ) state=TOK_TOKEN;
|
||||
else if(state==TOK_TOKEN && token_pos > 1 &&
|
||||
(
|
||||
( (space || c == '%' || c == '@') && !escape ) ||
|
||||
( (!space && c != '%' && c != '@') && escape )
|
||||
)
|
||||
) {
|
||||
dbg(1, "print_spectre_element(): c=%c, space=%d, escape=%d token_pos=%d\n", c, space, escape, token_pos);
|
||||
state=TOK_SEP;
|
||||
}
|
||||
STR_ALLOC(&token, token_pos, &sizetok);
|
||||
if(state==TOK_TOKEN) {
|
||||
token[token_pos++]=(char)c;
|
||||
}
|
||||
else if (state==TOK_SEP) /* got a token */
|
||||
{
|
||||
char *val = NULL;
|
||||
size_t token_exists = 0;
|
||||
token[token_pos]='\0';
|
||||
token_pos=0;
|
||||
|
||||
if(strcmp(token,"@symref")==0)
|
||||
{
|
||||
const char *s = get_sym_name(inst, 9999, 1, 0);
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
}
|
||||
else if (strcmp(token,"@symname")==0) /* of course symname must not be present in attributes */
|
||||
{
|
||||
const char *s = sanitize(translate(inst, get_sym_name(inst, 0, 0, 0)));
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
}
|
||||
else if (strcmp(token,"@symname_ext")==0) /* of course symname_ext must not be present in attributes */
|
||||
{
|
||||
const char *s = sanitize(translate(inst, get_sym_name(inst, 0, 1, 0)));
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@topschname")==0) /* of course topschname must not be present in attributes */
|
||||
{
|
||||
const char *topsch;
|
||||
topsch = get_trailing_path(xctx->sch[0], 0, 1);
|
||||
my_mstrcat(_ALLOC_ID_, &result, topsch, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@schname_ext")==0) /* of course schname must not be present in attributes */
|
||||
{
|
||||
my_mstrcat(_ALLOC_ID_, &result, xctx->current_name, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@savecurrent")==0)
|
||||
{
|
||||
char *instname = xctx->inst[inst].instname;
|
||||
|
||||
const char *sc = get_tok_value(xctx->inst[inst].prop_ptr, "savecurrent", 0);
|
||||
if(!sc[0]) sc = get_tok_value(template, "savecurrent", 0);
|
||||
if(!strboolcmp(sc , "true")) {
|
||||
my_mstrcat(_ALLOC_ID_, &result, "\n.save I( ?1 ", instname, " )", NULL);
|
||||
}
|
||||
}
|
||||
else if(strcmp(token,"@schname")==0) /* of course schname must not be present in attributes */
|
||||
{
|
||||
const char *schname = get_cell(xctx->current_name, 0);
|
||||
my_mstrcat(_ALLOC_ID_, &result, schname, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@pinlist")==0) /* of course pinlist must not be present in attributes */
|
||||
/* print multiplicity */
|
||||
{ /* and node number: m1 n1 m2 n2 .... */
|
||||
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 spectre_ignore = !strboolcmp(get_tok_value(prop, "spectre_ignore", 0), "true");
|
||||
const char *name = get_tok_value(prop, "name", 0);
|
||||
if(!spectre_ignore) {
|
||||
if(!int_hash_lookup(&table, name, 1, XINSERT_NOREPLACE)) {
|
||||
str_ptr = net_name(inst, i, &multip, 0, 1);
|
||||
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
int_hash_free(&table);
|
||||
}
|
||||
else if(token[0]=='@' && token[1]=='@') { /* recognize single pins 15112003 */
|
||||
for(i=0;i<no_of_pins; ++i) {
|
||||
char *prop = (xctx->inst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr;
|
||||
if (!strcmp( get_tok_value(prop,"name",0), token+2)) {
|
||||
if(strboolcmp(get_tok_value(prop,"spectre_ignore",0), "true")) {
|
||||
str_ptr = net_name(inst,i, &multip, 0, 1);
|
||||
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* reference by pin number instead of pin name, allows faster lookup of the attached net name
|
||||
* @#0, @#1:net_name, @#2:name, ... */
|
||||
else if(token[0]=='@' && token[1]=='#') {
|
||||
int n;
|
||||
char *pin_attr = NULL;
|
||||
char *pin_num_or_name = NULL;
|
||||
|
||||
get_pin_and_attr(token, &pin_num_or_name, &pin_attr);
|
||||
n = get_inst_pin_number(inst, pin_num_or_name);
|
||||
if(n>=0 && pin_attr[0] && n < (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]) {
|
||||
char *pin_attr_value = NULL;
|
||||
int is_net_name = !strcmp(pin_attr, "net_name");
|
||||
/* get pin_attr value from instance: "pinnumber(ENABLE)=5" --> return 5, attr "pinnumber" of pin "ENABLE"
|
||||
* "pinnumber(3)=6 --> return 6, attr "pinnumber" of 4th pin */
|
||||
if(!is_net_name) {
|
||||
pin_attr_value = get_pin_attr_from_inst(inst, n, pin_attr);
|
||||
/* get pin_attr from instance pin attribute string */
|
||||
if(!pin_attr_value) {
|
||||
my_strdup(_ALLOC_ID_, &pin_attr_value,
|
||||
get_tok_value(xctx->sym[xctx->inst[inst].ptr].rect[PINLAYER][n].prop_ptr, pin_attr, 0));
|
||||
}
|
||||
}
|
||||
/* @#n:net_name attribute (n = pin number or name) will translate to net name attached to pin */
|
||||
if(!pin_attr_value && is_net_name) {
|
||||
prepare_netlist_structs(0);
|
||||
my_strdup(_ALLOC_ID_, &pin_attr_value,
|
||||
xctx->inst[inst].node && xctx->inst[inst].node[n] ? xctx->inst[inst].node[n] : "?");
|
||||
}
|
||||
if(!pin_attr_value ) my_strdup(_ALLOC_ID_, &pin_attr_value, "--UNDEF--");
|
||||
value = pin_attr_value;
|
||||
/* recognize slotted devices: instname = "U3:3", value = "a:b:c:d" --> value = "c" */
|
||||
if(value[0] && !strcmp(pin_attr, "pinnumber") ) {
|
||||
char *ss;
|
||||
int slot;
|
||||
char *tmpstr = NULL;
|
||||
tmpstr = my_malloc(_ALLOC_ID_, sizeof(xctx->inst[inst].instname));
|
||||
if( (ss=strchr(xctx->inst[inst].instname, ':')) ) {
|
||||
sscanf(ss+1, "%s", tmpstr);
|
||||
if(isonlydigit(tmpstr)) {
|
||||
slot = atoi(tmpstr);
|
||||
if(strstr(value,":")) value = find_nth(value, ":", "", 0, slot);
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &tmpstr);
|
||||
}
|
||||
my_mstrcat(_ALLOC_ID_, &result, value, NULL);
|
||||
my_free(_ALLOC_ID_, &pin_attr_value);
|
||||
}
|
||||
else if(n>=0 && n < (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]) {
|
||||
const char *si;
|
||||
char *prop = (xctx->inst[inst].ptr + xctx->sym)->rect[PINLAYER][n].prop_ptr;
|
||||
si = get_tok_value(prop, "spectre_ignore",0);
|
||||
if(strboolcmp(si, "true")) {
|
||||
str_ptr = net_name(inst,n, &multip, 0, 1);
|
||||
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &pin_attr);
|
||||
my_free(_ALLOC_ID_, &pin_num_or_name);
|
||||
}
|
||||
else if (!strncmp(token,"@tcleval", 8)) {
|
||||
size_t s;
|
||||
char *tclcmd=NULL;
|
||||
const char *res;
|
||||
s = token_pos + strlen(name) + strlen(xctx->inst[inst].name) + 100;
|
||||
tclcmd = my_malloc(_ALLOC_ID_, s);
|
||||
Tcl_ResetResult(interp);
|
||||
my_snprintf(tclcmd, s, "tclpropeval {%s} {%s} {%s}", token, name, xctx->inst[inst].name);
|
||||
dbg(1, "print_spectre_element(): tclpropeval {%s} {%s} {%s}", token, name, xctx->inst[inst].name);
|
||||
res = tcleval(tclcmd);
|
||||
|
||||
my_mstrcat(_ALLOC_ID_, &result, res, NULL);
|
||||
my_free(_ALLOC_ID_, &tclcmd);
|
||||
}
|
||||
/* if spiceprefix==0 and token == @spiceprefix then set empty value */
|
||||
else if (!tclgetboolvar("spiceprefix") && !strcmp(token, "@spiceprefix")) {
|
||||
value=NULL;
|
||||
/* else tcl var spiceprefix is enabled */
|
||||
}
|
||||
|
||||
else {
|
||||
/* here a @token in format string will be replaced by value in instance prop_ptr
|
||||
* or symbol template */
|
||||
size_t tok_val_len;
|
||||
char *parent_prop_ptr = NULL;
|
||||
char *parent_templ = NULL;
|
||||
/* char *parent_sym_extra = NULL; */
|
||||
|
||||
if(xctx->currsch > 0) {
|
||||
parent_prop_ptr = xctx->hier_attr[xctx->currsch - 1].prop_ptr;
|
||||
parent_templ = xctx->hier_attr[xctx->currsch - 1].templ;
|
||||
/* parent_sym_extra = xctx->hier_attr[xctx->currsch - 1].sym_extra; */
|
||||
}
|
||||
|
||||
/* consider this scenario:
|
||||
* instance of passgate.sym: W_N=5 L_N=0.2 W_P=10 L_P=0.3 m=1
|
||||
* instance based schematic (schematic=mypippo attr) will have also modeln=pippon
|
||||
* passgate.sym:
|
||||
* format="@name @pinlist @symname W_N=@W_N L_N=@L_N W_P=@W_P L_P=@L_P m=@m"
|
||||
* template=" ... modeln=nfet_01v8 modelp=pfet_01v8 m=1"
|
||||
* passgate.sch:
|
||||
* instance of nmos.sym: L=L_N W=W_N nf=1 m=1 model=@modeln
|
||||
* nmos.sym:
|
||||
* format="@name @pinlist @model L=@L W=@W nf=@nf
|
||||
* + ad=@ad as=@as pd=@pd .... m=@m
|
||||
* template="name=M1 W=1 L=0.15 m=1
|
||||
* ad=\"expr('int((@nf + 1)/2) * @W / @nf * 0.29')\"
|
||||
* ..."
|
||||
* model=nfet_01v8
|
||||
*/
|
||||
|
||||
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(token, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL));
|
||||
/* can not put template in above translate3: ---------------------------^^^^
|
||||
* if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3
|
||||
* we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */
|
||||
if(strchr(val, '@')) {
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL));
|
||||
}
|
||||
/* nmos instance format string: @model --> @modeln */
|
||||
dbg(1, "print_spectre_element(): 1st round: val: |%s|\n", val);
|
||||
if(strchr(val, '@')) {
|
||||
#if 0
|
||||
if(parent_prop_ptr) {
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, parent_templ, NULL));
|
||||
/* instance based passgate.sym placement, nmos instance format string: @modeln --> pippon */
|
||||
/* ad="expr('int((@nf + 1)/2) * @W / @nf * 0.29')" --> ad="expr('int((1 + 1)/2) * W_N / 1 * 0.29')" */
|
||||
if(strchr(val, '@')) {
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, parent_templ, NULL));
|
||||
/* ad="expr('int((1 + 1)/2) * W_N / 1 * 0.29')" --> ad="expr('int((1 + 1)/2) * 5 / 1 * 0.29')" */
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(val, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL));
|
||||
dbg(1, "print_spectre_element(): 2nd round: val: |%s|\n", val);
|
||||
/* normal passgate.sym placement, nmos instance format string:
|
||||
ad="expr('int((@nf + 1)/2) * @W / @nf * 0.29')" --> ad="expr('int((1 + 1)/2) * W_N/ 1 * 0.29')" */
|
||||
if(strchr(val, '@')) {
|
||||
my_strdup2(_ALLOC_ID_, &val,
|
||||
translate3(val, 0, xctx->inst[inst].prop_ptr, parent_templ, NULL, NULL));
|
||||
dbg(1, "print_spectre_element(): 3nd round: val: |%s|\n", val);
|
||||
/* normal passgate.sym placement, nmos instance format string:
|
||||
* @modeln --> nfet_01v8 */
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
dbg(1, "print_spectre_element(): final: val: |%s|\n", val);
|
||||
}
|
||||
/* still unresolved: set to empty */
|
||||
if(val[0] == '@') value = "";
|
||||
else value = val;
|
||||
token_exists = xctx->tok_size;
|
||||
tok_val_len = strlen(value);
|
||||
/* @spiceprefix needs a special tag for postprocessing */
|
||||
if(!strcmp(token, "@spiceprefix") && value[0]) {
|
||||
my_realloc(_ALLOC_ID_, &spiceprefixtag, tok_val_len+22);
|
||||
my_snprintf(spiceprefixtag, tok_val_len+22, "**** spice_prefix %s\n", value);
|
||||
value = spiceprefixtag;
|
||||
}
|
||||
|
||||
if(is_expr(value)) {
|
||||
value = eval_expr(value);
|
||||
}
|
||||
/* token=%xxxx and xxxx is not defined in prop_ptr or template: return xxxx */
|
||||
if(!token_exists && token[0] =='%') {
|
||||
my_mstrcat(_ALLOC_ID_, &result, token + 1, NULL);
|
||||
}
|
||||
/* And finally set the value of token into result string */
|
||||
else if (value && value[0]!='\0') {
|
||||
/* instance names (name) and node labels (lab) go thru the expandlabel function. */
|
||||
/*if something else must be parsed, put an if here! */
|
||||
if (!(strcmp(token+1,"name") && strcmp(token+1,"lab")) /* expand name/labels */
|
||||
&& ((lab = expandlabel(value, &itmp)) != NULL)) {
|
||||
my_mstrcat(_ALLOC_ID_, &result, lab, NULL);
|
||||
} else {
|
||||
my_mstrcat(_ALLOC_ID_, &result, value, NULL);
|
||||
}
|
||||
}
|
||||
} /* else */
|
||||
|
||||
/* append token separator to output result ... */
|
||||
if(c != '%' && c != '@' && c!='\0' ) {
|
||||
char str[2];
|
||||
str[0] = (unsigned char) c;
|
||||
str[1] = '\0';
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
}
|
||||
/* ... unless it is the start of another token, so push back to input string */
|
||||
if(c == '@' || c == '%' ) s--;
|
||||
state=TOK_BEGIN;
|
||||
my_free(_ALLOC_ID_, &val);
|
||||
} /* else if (state==TOK_SEP) */
|
||||
|
||||
else if(state==TOK_BEGIN && c!='\0') {
|
||||
char str[2];
|
||||
str[0] = (unsigned char) c;
|
||||
str[1] = '\0';
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
}
|
||||
if(c=='\0')
|
||||
{
|
||||
char str[2];
|
||||
str[0] = '\n';
|
||||
str[1] = '\0';
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
break;
|
||||
}
|
||||
} /* while(1) */
|
||||
|
||||
|
||||
/* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions
|
||||
* can be calculated */
|
||||
if(result) {
|
||||
my_strdup(_ALLOC_ID_, &result, tcl_hook2(result));
|
||||
}
|
||||
if(is_expr(result)) {
|
||||
my_strdup2(_ALLOC_ID_, &result, eval_expr(result));
|
||||
}
|
||||
if(result) fprintf(fd, "%s", result);
|
||||
dbg(1, "print_spectre_element(): returning |%s|\n", result);
|
||||
my_free(_ALLOC_ID_, &template);
|
||||
my_free(_ALLOC_ID_, &format);
|
||||
my_free(_ALLOC_ID_, &name);
|
||||
my_free(_ALLOC_ID_, &token);
|
||||
my_free(_ALLOC_ID_, &result);
|
||||
if(spiceprefixtag) my_free(_ALLOC_ID_, &spiceprefixtag);
|
||||
/* my_free(_ALLOC_ID_, &translatedvalue); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void print_tedax_element(FILE *fd, int inst)
|
||||
{
|
||||
int i=0, multip;
|
||||
|
|
@ -3331,7 +3880,8 @@ void print_verilog_element(FILE *fd, int inst)
|
|||
if(strcmp(token, "name") && xctx->tok_size && (!extra || !strstr(extra, token))) {
|
||||
if(value[0] != '\0') /* token has a value */
|
||||
{
|
||||
if(strcmp(token,"spice_ignore") && strcmp(token,"vhdl_ignore") && strcmp(token,"tedax_ignore")) {
|
||||
if(strcmp(token,"spice_ignore") && strcmp(token,"vhdl_ignore") &&
|
||||
strcmp(token,"tedax_ignore") && strcmp(token,"spectre_ignore")) {
|
||||
if(tmp == 0) {
|
||||
fprintf(fd, "#(\n---- start parameters\n");
|
||||
++tmp;
|
||||
|
|
@ -4595,7 +5145,15 @@ const char *translate(int inst, const char* s)
|
|||
memcpy(result+result_pos,xctx->schvhdlprop, tmp+1);
|
||||
result_pos+=tmp;
|
||||
}
|
||||
|
||||
|
||||
else if(strcmp(token,"@schspectreprop")==0 && xctx->schspectreprop)
|
||||
{
|
||||
tmp=strlen(xctx->schspectreprop);
|
||||
STR_ALLOC(&result, tmp + result_pos, &size);
|
||||
memcpy(result+result_pos,xctx->schspectreprop, tmp+1);
|
||||
result_pos+=tmp;
|
||||
}
|
||||
|
||||
else if(strcmp(token,"@schprop")==0 && xctx->schprop)
|
||||
{
|
||||
tmp=strlen(xctx->schprop);
|
||||
|
|
@ -4612,6 +5170,7 @@ const char *translate(int inst, const char* s)
|
|||
memcpy(result+result_pos,xctx->schsymbolprop, tmp+1);
|
||||
result_pos+=tmp;
|
||||
}
|
||||
|
||||
else if(strcmp(token,"@schtedaxprop")==0 && xctx->schtedaxprop)
|
||||
{
|
||||
tmp=strlen(xctx->schtedaxprop);
|
||||
|
|
|
|||
|
|
@ -351,6 +351,8 @@ int global_verilog_netlist(int global, int alert) /* netlister driver */
|
|||
str_hash_lookup(&subckt_table, subckt_name, "", XINSERT);
|
||||
if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"vhdl_netlist",0),"true")==0 )
|
||||
err |= vhdl_block_netlist(fd, i, alert);
|
||||
if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spectre_netlist",0),"true")==0 )
|
||||
err |= spectre_block_netlist(fd, i, alert);
|
||||
else if(split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spice_netlist",0),"true")==0 )
|
||||
err |= spice_block_netlist(fd, i, alert);
|
||||
else if( strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"verilog_primitive",0), "true"))
|
||||
|
|
@ -451,7 +453,7 @@ int verilog_block_netlist(FILE *fd, int i, int alert)
|
|||
if(split_f) {
|
||||
my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d",
|
||||
tclgetvar("netlist_dir"), get_cell(name, 0), getpid());
|
||||
dbg(1, "global_vhdl_netlist(): split_files: netl_filename=%s\n", netl_filename);
|
||||
dbg(1, "verilog_block_netlist(): split_files: netl_filename=%s\n", netl_filename);
|
||||
fd=fopen(netl_filename, "w");
|
||||
if(!fd) {
|
||||
dbg(0, "verilog_block_netlist(): unable to write file %s\n", netl_filename);
|
||||
|
|
|
|||
|
|
@ -441,6 +441,8 @@ int global_vhdl_netlist(int global, int alert) /* netlister driver */
|
|||
str_hash_lookup(&subckt_table, subckt_name, "", XINSERT);
|
||||
if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"verilog_netlist",0),"true")==0 )
|
||||
err |= verilog_block_netlist(fd, i, alert);
|
||||
if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spectre_netlist",0),"true")==0 )
|
||||
err |= spectre_block_netlist(fd, i, alert);
|
||||
else if( split_f && strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"spice_netlist",0),"true")==0 )
|
||||
err |= spice_block_netlist(fd, i, alert);
|
||||
else if( strboolcmp(get_tok_value(xctx->sym[i].prop_ptr,"vhdl_primitive",0),"true"))
|
||||
|
|
|
|||
|
|
@ -2792,6 +2792,7 @@ int Tcl_AppInit(Tcl_Interp *inter)
|
|||
if(!strcmp(n, "spice")) xctx->netlist_type = CAD_SPICE_NETLIST;
|
||||
else if(!strcmp(n, "vhdl")) xctx->netlist_type = CAD_VHDL_NETLIST;
|
||||
else if(!strcmp(n, "verilog")) xctx->netlist_type = CAD_VERILOG_NETLIST;
|
||||
else if(!strcmp(n, "spectre")) xctx->netlist_type = CAD_SPECTRE_NETLIST;
|
||||
else if(!strcmp(n, "tedax")) xctx->netlist_type = CAD_TEDAX_NETLIST;
|
||||
else if(!strcmp(n, "symbol")) xctx->netlist_type = CAD_SYMBOL_ATTRS;
|
||||
}
|
||||
|
|
@ -3038,6 +3039,8 @@ int Tcl_AppInit(Tcl_Interp *inter)
|
|||
global_vhdl_netlist(1, 1); /* 1 means global netlist */
|
||||
else if(xctx->netlist_type == CAD_VERILOG_NETLIST)
|
||||
global_verilog_netlist(1, 1); /* 1 means global netlist */
|
||||
else if(xctx->netlist_type == CAD_SPECTRE_NETLIST)
|
||||
global_spectre_netlist(1, 1); /* 1 means global netlist */
|
||||
else if(xctx->netlist_type == CAD_TEDAX_NETLIST)
|
||||
global_tedax_netlist(1, 1); /* 1 means global netlist */
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -192,6 +192,8 @@ extern char win_temp_dir[PATH_MAX];
|
|||
#define VERILOG_SHORT 8192
|
||||
#define VHDL_SHORT 16384
|
||||
#define TEDAX_SHORT 32768
|
||||
#define SPECTRE_SHORT 65536
|
||||
#define SPECTRE_IGNORE 131072
|
||||
#define LVS_IGNORE (LVS_IGNORE_SHORT | LVS_IGNORE_OPEN)
|
||||
#define CADMAXGRIDPOINTS 512
|
||||
#define CADMAXHIER 40
|
||||
|
|
@ -212,6 +214,7 @@ extern char win_temp_dir[PATH_MAX];
|
|||
#define CAD_VERILOG_NETLIST 3
|
||||
#define CAD_TEDAX_NETLIST 4
|
||||
#define CAD_SYMBOL_ATTRS 5
|
||||
#define CAD_SPECTRE_NETLIST 6
|
||||
|
||||
/* possible states, encoded in global 'ui_state' */
|
||||
#define STARTWIRE 1U
|
||||
|
|
@ -666,6 +669,7 @@ typedef struct
|
|||
char *gptr;
|
||||
char *vptr;
|
||||
char *sptr;
|
||||
char *fptr; /* spectre global attr */
|
||||
char *kptr;
|
||||
char *eptr;
|
||||
int *lines;
|
||||
|
|
@ -929,6 +933,7 @@ typedef struct {
|
|||
char *schvhdlprop;
|
||||
char *schsymbolprop;
|
||||
char *schverilogprop;
|
||||
char *schspectreprop;
|
||||
char *sch[CADMAXHIER];
|
||||
int currsch;
|
||||
char *version_string;
|
||||
|
|
@ -1495,12 +1500,14 @@ extern void store_arc(int pos, double x, double y, double r, double a, double b,
|
|||
|
||||
extern void hier_psprint(char **res, int what);
|
||||
extern int global_spice_netlist(int global, int alert);
|
||||
extern int global_spectre_netlist(int global, int alert);
|
||||
extern int global_tedax_netlist(int global, int alert);
|
||||
extern int global_vhdl_netlist(int global, int alert);
|
||||
extern int global_verilog_netlist(int global, int alert);
|
||||
extern int vhdl_block_netlist(FILE *fd, int i, int alert);
|
||||
extern int verilog_block_netlist(FILE *fd, int i, int alert);
|
||||
extern int spice_block_netlist(FILE *fd, int i, int alert);
|
||||
extern int spectre_block_netlist(FILE *fd, int i, int alert);
|
||||
extern void remove_symbols(void);
|
||||
extern void remove_symbol(int i);
|
||||
extern void clear_drawing(void);
|
||||
|
|
@ -1636,6 +1643,8 @@ extern const char *translate3(const char* s, int eat_escapes, const char *s1,
|
|||
extern void print_tedax_element(FILE *fd, int inst);
|
||||
extern int print_spice_element(FILE *fd, int inst);
|
||||
extern void print_spice_subckt_nodes(FILE *fd, int symbol);
|
||||
extern int print_spectre_element(FILE *fd, int inst);
|
||||
extern void print_spectre_subckt_nodes(FILE *fd, int symbol);
|
||||
extern void print_tedax_subckt(FILE *fd, int symbol);
|
||||
extern void print_vhdl_element(FILE *fd, int inst);
|
||||
extern void print_verilog_element(FILE *fd, int inst);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ Options:
|
|||
-N <file> Set name (only name or full path) of top level netlist file.
|
||||
-t --tedax Set netlist type to tEDAx.
|
||||
-s --spice Set netlist type to SPICE.
|
||||
--spice Set netlist type to SPECTRE.
|
||||
-y --symbol Set netlist type to SYMBOL (used when drawing symbols)
|
||||
-x --no_x Don't use X (only command mode).
|
||||
-z --rainbow Use a raibow-looking layer color table.
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,15 @@ proc netlist {source_file show netlist_file} {
|
|||
textwindow $dest
|
||||
}
|
||||
}
|
||||
|
||||
if {$netlist_type eq {spectre}} {
|
||||
set cmd ${XSCHEM_SHAREDIR}/spectre.awk
|
||||
eval exec {awk -f $cmd -- $source_file > $dest}
|
||||
if ![string compare $show "show"] {
|
||||
textwindow $dest
|
||||
}
|
||||
}
|
||||
|
||||
if {$netlist_type eq {vhdl}} {
|
||||
set cmd $XSCHEM_SHAREDIR/vhdl.awk
|
||||
eval exec {awk -f $cmd $source_file > $dest}
|
||||
|
|
@ -1563,7 +1572,7 @@ proc set_sim_defaults {{reset {}}} {
|
|||
if {( $reset eq {reset} ) || ![info exists sim] || $failure} {
|
||||
if {[info exists sim]} {unset sim}
|
||||
# no simrc, set a reasonable default
|
||||
set sim(tool_list) {spice spicewave verilog verilogwave vhdl vhdlwave}
|
||||
set sim(tool_list) {spice spicewave spectre verilog verilogwave vhdl vhdlwave}
|
||||
if {$OS == "Windows"} {
|
||||
set_ne sim(spice,0,cmd) {ngspice -i "$N" -a}
|
||||
} else {
|
||||
|
|
@ -1626,6 +1635,16 @@ proc set_sim_defaults {{reset {}}} {
|
|||
set_ne sim(spicewave,n) 4
|
||||
set_ne sim(spicewave,default) 0
|
||||
|
||||
### spectre (vacask simulator)
|
||||
set_ne sim(spectre,0,cmd) {vacask "$N"}
|
||||
set sim(spectre,0,name) {Vacask}
|
||||
set_ne sim(spectre,0,fg) 0
|
||||
set_ne sim(spectre,0,st) 1
|
||||
|
||||
# number of configured spectre simulators, and default one
|
||||
set_ne sim(spectre,n) 1
|
||||
set_ne sim(spectre,default) 0
|
||||
|
||||
### icarus verilog
|
||||
set_ne sim(verilog,0,cmd) {sh -c "iverilog -o .verilog_object -g2012 '$N' && vvp .verilog_object"}
|
||||
set sim(verilog,0,name) {Icarus verilog}
|
||||
|
|
@ -8996,6 +9015,9 @@ proc build_widgets { {topwin {} } } {
|
|||
}
|
||||
$topwin.menubar.option.netlist add checkbutton -label "Split netlist" -variable split_files \
|
||||
-selectcolor $selectcolor -accelerator {}
|
||||
$topwin.menubar.option.netlist add radiobutton -label "Spectre netlist"\
|
||||
-background grey60 -variable netlist_type -value spectre -accelerator {Ctrl+Shift+V} \
|
||||
-selectcolor $selectcolor -command "xschem set netlist_type spectre; xschem redraw"
|
||||
$topwin.menubar.option.netlist add radiobutton -label "Spice netlist"\
|
||||
-background grey60 -variable netlist_type -value spice -accelerator {Ctrl+Shift+V} \
|
||||
-selectcolor $selectcolor -command "xschem set netlist_type spice; xschem redraw"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
v {xschem version=3.4.6 file_version=1.2
|
||||
v {xschem version=3.4.8RC file_version=1.2
|
||||
*
|
||||
* This file is part of XSCHEM,
|
||||
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
||||
|
|
@ -23,9 +23,11 @@ G {}
|
|||
K {type=nmos
|
||||
format="@spiceprefix@name @pinlist @model w=@w l=@l @extra m=@m"
|
||||
template="name=M1 model=nmos w=5u l=0.18u del=0 m=1"
|
||||
verilog_format="nmos #@del @name ( @@d , @@s , @@g );"}
|
||||
verilog_format="nmos #@del @name ( @@d , @@s , @@g );"
|
||||
spectre_format="@name ( @pinlist ) @model w=@w l=@l @extra $mfactor=@m"}
|
||||
V {}
|
||||
S {}
|
||||
F {}
|
||||
E {}
|
||||
L 4 5 -30 5 30 {}
|
||||
L 4 5 -20 20 -20 {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
v {xschem version=3.4.8RC file_version=1.2}
|
||||
G {}
|
||||
K {type=xline
|
||||
format="@name \\\\%vd( @@CP @@CM ) \\\\%id( @@P @@M ) @name
|
||||
.model @name limit %( gain=@gain out_lower_limit=@lower_limit out_upper_limit=@upper_limit %)"
|
||||
template="name=alimit1 gain=1e-6 lower_limit=-1u upper_limit=1u"
|
||||
}
|
||||
V {}
|
||||
S {}
|
||||
F {}
|
||||
E {}
|
||||
L 4 -20 -0 -0 -20 {}
|
||||
L 4 -20 -0 -0 20 {}
|
||||
L 4 -0 20 20 0 {}
|
||||
L 4 0 -20 20 0 {}
|
||||
L 4 -40 -20 -35 -20 {}
|
||||
L 4 -30 -20 -25 -20 {}
|
||||
L 4 -20 -20 -15 -20 {}
|
||||
L 4 -40 20 -35 20 {}
|
||||
L 4 -30 20 -25 20 {}
|
||||
L 4 -20 20 -15 20 {}
|
||||
L 4 2.5 -22.5 7.5 -22.5 {}
|
||||
L 4 5 -25 5 -20 {}
|
||||
L 4 -5 5 0 10 {}
|
||||
L 4 -5 5 5 5 {}
|
||||
L 4 0 10 5 5 {}
|
||||
L 4 0 -5 0 5 {}
|
||||
L 4 -37.5 -12.5 -32.5 -12.5 {}
|
||||
L 4 -35 -15 -35 -10 {}
|
||||
L 4 -37.5 12.5 -32.5 12.5 {}
|
||||
L 4 0 20 0 30 {}
|
||||
L 4 0 -30 -0 -20 {}
|
||||
B 5 -2.5 -32.5 2.5 -27.5 {name=P dir=inout}
|
||||
B 5 -2.5 27.5 2.5 32.5 {name=M dir=inout}
|
||||
B 5 -42.5 -22.5 -37.5 -17.5 {name=CP dir=in}
|
||||
B 5 -42.5 17.5 -37.5 22.5 {name=CM dir=in}
|
||||
T {@#0:net_name} 5 -42.5 0 0 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#1:net_name} 5 32.5 0 0 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#2:net_name} -45 -32.5 0 1 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#3:net_name} -45 22.5 0 1 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@name
|
||||
@symname
|
||||
gain=@gain
|
||||
upper_limit=@upper_limit
|
||||
lower_limit=@lower_limit} 25 -20 0 0 0.15 0.15 {}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
v {xschem version=3.4.8RC file_version=1.2}
|
||||
G {}
|
||||
K {type=xline
|
||||
format="@name \\\\%vd( @@CP @@CM ) \\\\%vd( @@P @@M ) @name
|
||||
.model @name limit %( gain=@gain out_lower_limit=@lower_limit out_upper_limit=@upper_limit %)"
|
||||
template="name=alimit1 gain=3 lower_limit=-5.0 upper_limit=5.0"
|
||||
}
|
||||
V {}
|
||||
S {}
|
||||
F {}
|
||||
E {}
|
||||
L 4 2.5 -22.5 7.5 -22.5 {}
|
||||
L 4 5 -25 5 -20 {}
|
||||
L 4 -0 -30 -0 30 {}
|
||||
L 4 -20 -0 -0 -20 {}
|
||||
L 4 -20 -0 -0 20 {}
|
||||
L 4 -0 20 20 0 {}
|
||||
L 4 0 -20 20 0 {}
|
||||
L 4 -40 -20 -35 -20 {}
|
||||
L 4 -30 -20 -25 -20 {}
|
||||
L 4 -20 -20 -15 -20 {}
|
||||
L 4 -40 20 -35 20 {}
|
||||
L 4 -30 20 -25 20 {}
|
||||
L 4 -20 20 -15 20 {}
|
||||
B 5 -2.5 -32.5 2.5 -27.5 {name=P dir=inout}
|
||||
B 5 -2.5 27.5 2.5 32.5 {name=M dir=inout}
|
||||
B 5 -42.5 -22.5 -37.5 -17.5 {name=CP dir=in}
|
||||
B 5 -42.5 17.5 -37.5 22.5 {name=CM dir=in}
|
||||
T {@#0:net_name} 5 -42.5 0 0 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#1:net_name} 5 32.5 0 0 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#2:net_name} -45 -32.5 0 1 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@#3:net_name} -45 22.5 0 1 0.15 0.15 {layer=15 hide=instance}
|
||||
T {@name
|
||||
@symname
|
||||
gain=@gain
|
||||
upper_limit=@upper_limit
|
||||
lower_limit=@lower_limit} 25 -20 0 0 0.15 0.15 {}
|
||||
Loading…
Reference in New Issue