2020-08-08 15:47:34 +02:00
|
|
|
/* File: tedax_netlist.c
|
2020-10-12 13:13:31 +02:00
|
|
|
*
|
2020-08-08 15:47:34 +02:00
|
|
|
* This file is part of XSCHEM,
|
2020-10-12 13:13:31 +02:00
|
|
|
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
2020-08-08 15:47:34 +02:00
|
|
|
* simulation.
|
2022-06-24 00:36:12 +02:00
|
|
|
* Copyright (C) 1998-2022 Stefan Frederik Schippers
|
2020-08-08 15:47:34 +02:00
|
|
|
*
|
|
|
|
|
* 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"
|
|
|
|
|
|
2023-03-23 18:34:14 +01:00
|
|
|
static int tedax_netlist(FILE *fd, int tedax_stop )
|
2022-02-19 14:31:55 +01:00
|
|
|
{
|
2023-03-23 18:34:14 +01:00
|
|
|
int err = 0;
|
2022-02-19 14:31:55 +01:00
|
|
|
int i;
|
|
|
|
|
char *type=NULL;
|
|
|
|
|
|
|
|
|
|
if(!tedax_stop) {
|
|
|
|
|
xctx->prep_net_structs = 0;
|
2023-03-23 18:34:14 +01:00
|
|
|
err |= prepare_netlist_structs(1);
|
|
|
|
|
err |= traverse_node_hash(); /* print all warnings about unconnected floatings etc */
|
2022-02-19 14:31:55 +01:00
|
|
|
}
|
|
|
|
|
if(!tedax_stop) {
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->instances; ++i) /* print first ipin/opin defs ... */
|
2022-02-19 14:31:55 +01:00
|
|
|
{
|
|
|
|
|
if( strcmp(get_tok_value(xctx->inst[i].prop_ptr,"tedax_ignore",0),"true")==0 ) continue;
|
|
|
|
|
if(xctx->inst[i].ptr<0) continue;
|
|
|
|
|
if(!strcmp(get_tok_value( (xctx->inst[i].ptr+ xctx->sym)->prop_ptr, "tedax_ignore",0 ), "true") ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-02-09 21:06:27 +01:00
|
|
|
my_strdup(_ALLOC_ID_, &type,(xctx->inst[i].ptr+ xctx->sym)->type);
|
2022-02-19 14:31:55 +01:00
|
|
|
if( type && IS_PIN(type) ) {
|
|
|
|
|
print_tedax_element(fd, i) ; /* this is the element line */
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->instances; ++i) /* ... then print other lines */
|
2022-02-19 14:31:55 +01:00
|
|
|
{
|
|
|
|
|
if( strcmp(get_tok_value(xctx->inst[i].prop_ptr,"tedax_ignore",0),"true")==0 ) continue;
|
|
|
|
|
if(xctx->inst[i].ptr<0) continue;
|
|
|
|
|
if(!strcmp(get_tok_value( (xctx->inst[i].ptr+ xctx->sym)->prop_ptr, "tedax_ignore",0 ), "true") ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-02-09 21:06:27 +01:00
|
|
|
my_strdup(_ALLOC_ID_, &type,(xctx->inst[i].ptr+ xctx->sym)->type);
|
2022-02-19 14:31:55 +01:00
|
|
|
|
|
|
|
|
if( type && !IS_LABEL_OR_PIN(type) ) {
|
|
|
|
|
/* already done in global_tedax_netlist */
|
|
|
|
|
if(!strcmp(type,"netlist_commands") && xctx->netlist_count==0) continue;
|
|
|
|
|
if(xctx->netlist_count &&
|
|
|
|
|
!strcmp(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_tedax_element(fd, i) ; /* this is the element line */
|
|
|
|
|
fprintf(fd,"#**** end user architecture code\n");
|
|
|
|
|
} else {
|
|
|
|
|
print_tedax_element(fd, i) ; /* this is the element line */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-09 21:06:27 +01:00
|
|
|
my_free(_ALLOC_ID_, &type);
|
2022-02-19 14:31:55 +01:00
|
|
|
}
|
|
|
|
|
if(!tedax_stop && !xctx->netlist_count) redraw_hilights(0); /* draw_hilight_net(1); */
|
2023-03-23 18:34:14 +01:00
|
|
|
return err;
|
2022-02-19 14:31:55 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-23 18:34:14 +01:00
|
|
|
static int tedax_block_netlist(FILE *fd, int i)
|
2022-02-19 14:31:55 +01:00
|
|
|
{
|
2023-03-23 18:34:14 +01:00
|
|
|
int err = 0;
|
2022-02-19 14:31:55 +01:00
|
|
|
int tedax_stop=0;
|
|
|
|
|
char filename[PATH_MAX];
|
|
|
|
|
char *extra=NULL;
|
|
|
|
|
|
|
|
|
|
if(!strcmp( get_tok_value(xctx->sym[i].prop_ptr,"tedax_stop",0),"true") )
|
|
|
|
|
tedax_stop=1;
|
|
|
|
|
else
|
|
|
|
|
tedax_stop=0;
|
2023-04-12 18:28:19 +02:00
|
|
|
get_sch_from_sym(filename, xctx->sym + i, -1);
|
2023-03-12 11:11:11 +01:00
|
|
|
|
2022-02-19 14:31:55 +01:00
|
|
|
fprintf(fd, "\n# expanding symbol: %s # of pins=%d\n",
|
|
|
|
|
xctx->sym[i].name,xctx->sym[i].rects[PINLAYER] );
|
2023-04-13 22:25:36 +02:00
|
|
|
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", abs_sym_path(xctx->sym[i].name, ""));
|
2022-02-19 14:31:55 +01:00
|
|
|
fprintf(fd, "## sch_path: %s\n", filename);
|
|
|
|
|
|
|
|
|
|
fprintf(fd, "begin netlist v1 %s\n",skip_dir(xctx->sym[i].name));
|
|
|
|
|
print_tedax_subckt(fd, i);
|
|
|
|
|
|
2023-02-09 21:06:27 +01:00
|
|
|
my_strdup(_ALLOC_ID_, &extra, get_tok_value(xctx->sym[i].prop_ptr,"extra",0) );
|
2022-02-19 14:31:55 +01:00
|
|
|
/* this is now done in print_spice_subckt */
|
|
|
|
|
/*
|
|
|
|
|
* fprintf(fd, "%s ", extra ? extra : "" );
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* 20081206 new get_sym_template does not return token=value pairs where token listed in extra */
|
|
|
|
|
fprintf(fd, "%s", get_sym_template(xctx->sym[i].templ, extra));
|
2023-02-09 21:06:27 +01:00
|
|
|
my_free(_ALLOC_ID_, &extra);
|
2022-02-19 14:31:55 +01:00
|
|
|
fprintf(fd, "\n");
|
2023-03-25 09:41:53 +01:00
|
|
|
load_schematic(1,filename, 0, 1);
|
2023-03-23 18:34:14 +01:00
|
|
|
err |= tedax_netlist(fd, tedax_stop);
|
2022-02-19 14:31:55 +01:00
|
|
|
xctx->netlist_count++;
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
fprintf(fd, "end netlist\n\n");
|
2023-03-23 18:34:14 +01:00
|
|
|
return err;
|
2022-02-19 14:31:55 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-23 18:34:14 +01:00
|
|
|
int global_tedax_netlist(int global) /* netlister driver */
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2023-03-23 18:34:14 +01:00
|
|
|
int err = 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
FILE *fd;
|
2020-11-24 02:54:45 +01:00
|
|
|
const char *str_tmp;
|
2021-11-21 23:04:48 +01:00
|
|
|
int i;
|
2020-08-08 15:47:34 +02:00
|
|
|
unsigned int *stored_flags;
|
|
|
|
|
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 */
|
2023-04-13 00:49:38 +02:00
|
|
|
char *subckt_name;
|
2021-06-14 00:35:20 +02:00
|
|
|
char *abs_path = NULL;
|
2023-04-13 00:49:38 +02:00
|
|
|
Str_hashtable subckt_table = {NULL, 0};
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2021-11-29 11:52:32 +01:00
|
|
|
xctx->push_undo();
|
2020-08-08 15:47:34 +02:00
|
|
|
statusmsg("",2); /* clear infowindow */
|
2023-04-13 00:49:38 +02:00
|
|
|
str_hash_init(&subckt_table, HASHSIZE);
|
2020-08-08 15:47:34 +02:00
|
|
|
record_global_node(2, NULL, NULL); /* delete list of global nodes */
|
2020-12-02 19:35:42 +01:00
|
|
|
bus_char[0] = bus_char[1] = '\0';
|
2021-10-25 17:05:43 +02:00
|
|
|
xctx->hiersep[0]='.'; xctx->hiersep[1]='\0';
|
2020-11-24 02:54:45 +01:00
|
|
|
str_tmp = tclgetvar("bus_replacement_char");
|
|
|
|
|
if(str_tmp && str_tmp[0] && str_tmp[1]) {
|
2020-12-02 19:35:42 +01:00
|
|
|
bus_char[0] = str_tmp[0];
|
|
|
|
|
bus_char[1] = str_tmp[1];
|
2020-11-24 02:54:45 +01:00
|
|
|
}
|
2021-10-26 00:04:13 +02:00
|
|
|
xctx->netlist_count=0;
|
2020-11-17 01:29:47 +01:00
|
|
|
my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d",
|
2021-11-23 17:02:36 +01:00
|
|
|
tclgetvar("netlist_dir"), skip_dir(xctx->sch[xctx->currsch]), getpid());
|
2020-08-08 15:47:34 +02:00
|
|
|
fd=fopen(netl_filename, "w");
|
2022-05-05 22:42:25 +02:00
|
|
|
if(fd==NULL){
|
|
|
|
|
dbg(0, "global_tedax_netlist(): problems opening netlist file\n");
|
2023-03-23 18:34:14 +01:00
|
|
|
return 1;
|
2022-05-05 22:42:25 +02:00
|
|
|
}
|
2021-12-14 12:40:32 +01:00
|
|
|
fprintf(fd, "## sch_path: %s\n", xctx->sch[xctx->currsch]);
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-12-02 15:10:47 +01:00
|
|
|
if(xctx->netlist_name[0]) {
|
2021-02-09 17:19:37 +01:00
|
|
|
my_snprintf(cellname, S(cellname), "%s", get_cell_w_ext(xctx->netlist_name, 0));
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-10-15 17:39:21 +02:00
|
|
|
my_snprintf(cellname, S(cellname), "%s.tdx", skip_dir(xctx->sch[xctx->currsch]));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2020-11-24 02:54:45 +01:00
|
|
|
/* netlist_options */
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->instances; ++i) {
|
2020-11-24 02:54:45 +01:00
|
|
|
if(!(xctx->inst[i].ptr+ xctx->sym)->type) continue;
|
|
|
|
|
if( !strcmp((xctx->inst[i].ptr+ xctx->sym)->type,"netlist_options") ) {
|
|
|
|
|
netlist_options(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(1, "global_tedax_netlist(): opening %s for writing\n",netl_filename);
|
2020-10-15 17:39:21 +02:00
|
|
|
fprintf(fd,"tEDAx v1\nbegin netlist v1 %s\n", skip_dir( xctx->sch[xctx->currsch]) );
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
tedax_netlist(fd, 0);
|
2021-10-26 00:04:13 +02:00
|
|
|
xctx->netlist_count++;
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
/*fprintf(fd,"**** begin user architecture code\n"); */
|
2020-10-15 17:39:21 +02:00
|
|
|
/*if(xctx->schprop && xctx->schprop[0]) fprintf(fd, "%s\n", xctx->schprop); */
|
2020-08-08 15:47:34 +02:00
|
|
|
/*fprintf(fd,"**** end user architecture code\n"); */
|
|
|
|
|
/* /20100217 */
|
|
|
|
|
|
|
|
|
|
fprintf(fd, "end netlist\n");
|
|
|
|
|
|
2022-08-19 10:56:26 +02:00
|
|
|
/* warning if two symbols perfectly overlapped */
|
2023-03-23 18:34:14 +01:00
|
|
|
err |= warning_overlapped_symbols(0);
|
2020-08-08 15:47:34 +02:00
|
|
|
/* preserve current level instance flags before descending hierarchy for netlisting, restore later */
|
2023-02-09 21:06:27 +01:00
|
|
|
stored_flags = my_calloc(_ALLOC_ID_, xctx->instances, sizeof(unsigned int));
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->instances; ++i) stored_flags[i] = xctx->inst[i].color;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-11-24 02:54:45 +01:00
|
|
|
if(global) /* was if(global) ... 20180901 no hierarchical tEDAx netlist for now */
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-12-20 19:48:37 +01:00
|
|
|
int saved_hilight_nets = xctx->hilight_nets;
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2020-08-08 15:47:34 +02:00
|
|
|
remove_symbols(); /* 20161205 ensure all unused symbols purged before descending hierarchy */
|
2021-11-28 14:35:55 +01:00
|
|
|
/* reload data without popping undo stack, this populates embedded symbols if any */
|
2021-11-29 11:52:32 +01:00
|
|
|
xctx->pop_undo(2, 0);
|
|
|
|
|
/* link_symbols_to_instances(-1); */ /* done in xctx->pop_undo() */
|
2023-02-09 21:06:27 +01:00
|
|
|
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");
|
2021-01-02 01:55:01 +01:00
|
|
|
xctx->sch_path_hash[xctx->currsch+1] = 0;
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->currsch++;
|
2023-04-13 00:49:38 +02:00
|
|
|
subckt_name=NULL;
|
|
|
|
|
dbg(2, "global_tedax_netlist(): last defined symbol=%d\n",xctx->symbols);
|
|
|
|
|
get_additional_symbols(1);
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->symbols; ++i)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
if( strcmp(get_tok_value(xctx->sym[i].prop_ptr,"tedax_ignore",0),"true")==0 ) continue;
|
|
|
|
|
if(!xctx->sym[i].type) continue;
|
2023-02-09 21:06:27 +01:00
|
|
|
my_strdup2(_ALLOC_ID_, &abs_path, abs_sym_path(xctx->sym[i].name, ""));
|
2021-06-15 01:15:32 +02:00
|
|
|
if(strcmp(xctx->sym[i].type,"subcircuit")==0 && check_lib(1, abs_path))
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2023-04-13 00:49:38 +02:00
|
|
|
tclvareval("get_directory ", 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));
|
|
|
|
|
if (str_hash_lookup(&subckt_table, subckt_name, "", XLOOKUP)==NULL)
|
|
|
|
|
{
|
|
|
|
|
str_hash_lookup(&subckt_table, subckt_name, "", XINSERT);
|
|
|
|
|
err |= tedax_block_netlist(fd, i);
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-09 21:06:27 +01:00
|
|
|
my_free(_ALLOC_ID_, &abs_path);
|
2023-04-13 00:49:38 +02:00
|
|
|
get_additional_symbols(0);
|
|
|
|
|
str_hash_free(&subckt_table);
|
|
|
|
|
my_free(_ALLOC_ID_, &subckt_name);
|
2020-08-08 15:47:34 +02:00
|
|
|
/*clear_drawing(); */
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch]));
|
|
|
|
|
xctx->currsch--;
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2021-11-29 11:52:32 +01:00
|
|
|
xctx->pop_undo(0, 0);
|
2021-12-22 04:39:23 +01:00
|
|
|
my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name));
|
2023-03-23 18:34:14 +01:00
|
|
|
err |= prepare_netlist_structs(1); /* so 'lab=...' attributes for unnamed nets are set */
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
/* symbol vs schematic pin check, we do it here since now we have ALL symbols loaded */
|
2023-03-28 22:32:28 +02:00
|
|
|
err |= sym_vs_sch_pins();
|
2020-12-20 19:48:37 +01:00
|
|
|
if(!xctx->hilight_nets) xctx->hilight_nets = saved_hilight_nets;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-20 19:48:37 +01:00
|
|
|
/* restore hilight flags from errors found analyzing top level before descending hierarchy */
|
2023-02-18 09:44:11 +01:00
|
|
|
for(i=0;i<xctx->instances; ++i) xctx->inst[i].color = stored_flags[i];
|
2020-12-25 21:31:15 +01:00
|
|
|
propagate_hilights(1, 0, XINSERT_NOREPLACE);
|
2020-12-20 19:48:37 +01:00
|
|
|
draw_hilight_net(1);
|
2023-02-09 21:06:27 +01:00
|
|
|
my_free(_ALLOC_ID_, &stored_flags);
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
/* print globals nodes found in netlist 28032003 */
|
|
|
|
|
record_global_node(0,fd,NULL);
|
2021-10-25 17:05:43 +02:00
|
|
|
fprintf(fd, "__HIERSEP__ %s\n", xctx->hiersep);
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(1, "global_tedax_netlist(): starting awk on netlist!\n");
|
|
|
|
|
|
|
|
|
|
fclose(fd);
|
2021-11-10 13:43:08 +01:00
|
|
|
if(tclgetboolvar("netlist_show")) {
|
2020-08-08 15:47:34 +02:00
|
|
|
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);
|
2021-10-26 00:04:13 +02:00
|
|
|
xctx->netlist_count = 0;
|
2023-03-25 09:41:53 +01:00
|
|
|
return err;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|