/* File: vhdl_netlist.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2020 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 struct hashentry *subckt_table[HASHSIZE]; void global_vhdl_netlist(int global) /* netlister driver */ { FILE *fd; const char *str_tmp; char *dir_tmp = NULL; char *sig_type = NULL; char *port_value = NULL; int i,j, tmp, save_ok; unsigned int *stored_flags; char netl_filename[PATH_MAX]; /* overflow safe 20161122 */ char tcl_cmd_netlist[PATH_MAX + 100]; /* 20081202 overflow safe 20161122 */ char cellname[PATH_MAX]; /* 20081202 overflow safe 20161122 */ char *type=NULL; struct stat buf; char *subckt_name; statusmsg("",2); /* clear infowindow */ /* top sch properties used for library use declarations and type definitions */ /* to be printed before any entity declarations */ if(modified) { save_ok = save_schematic(xctx.sch[xctx.currsch]); if(save_ok == -1) return; } netlist_count=0; free_hash(subckt_table); my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d", netlist_dir, skip_dir(xctx.sch[xctx.currsch]), getpid()); fd=fopen(netl_filename, "w"); if(user_top_netl_name[0]) { my_snprintf(cellname, S(cellname), "%s", get_cell(user_top_netl_name, 0)); } else { my_snprintf(cellname, S(cellname), "%s.vhdl", skip_dir(xctx.sch[xctx.currsch])); } if(fd==NULL){ dbg(0, "global_vhdl_netlist(): problems opening netlist file\n"); return; } dbg(1, "global_vhdl_netlist(): opening %s for writing\n",netl_filename); dbg(1, "global_vhdl_netlist(): printing top level packages\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(571, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"package"))==0) { if(xctx.inst[i].prop_ptr) { /* */ fprintf(fd, "//// begin package\n"); /* 20080213 mark start of packages */ fprintf(fd, "%s\n", xctx.inst[i].prop_ptr); fprintf(fd, "//// end package\n"); /* 20080213 mark end of packages */ } } } dbg(1, "global_vhdl_netlist(): printing top level use statements\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(572, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"use"))==0) { if(xctx.inst[i].prop_ptr) fprintf(fd, "%s\n", xctx.inst[i].prop_ptr); } } dbg(1, "global_vhdl_netlist(): printing top level entity\n"); /* 20071015 already done in print_generic() */ /* fprintf(fd," --- entity %s is\n", skip_dir( xctx.sch[xctx.currsch]) ); */ /* 20071015 end */ /* flush data structures (remove unused symbols) */ unselect_all(); remove_symbols(); /* removed 25122002, readded 04112003.. this removes unused symbols */ load_schematic(1, xctx.sch[xctx.currsch], 0); /* 20071009 print top level generics if defined in symbol */ str_tmp = add_ext(xctx.sch[xctx.currsch], ".sym"); if(!stat(str_tmp, &buf)) { load_sym_def(str_tmp, NULL ); print_generic(fd,"entity", xctx.symbols-1); /* added print top level params */ remove_symbol(xctx.symbols - 1); } else { fprintf(fd,"entity %s is\n", skip_dir( xctx.sch[xctx.currsch]) ); } /* 20071009 end */ /* 20071009 get generics from symbol */ /* print top subckt generics */ /* dbg(1, "global_vhdl_netlist(): printing top level generic pins\n"); */ /* tmp=0; */ /* for(i=0;itype); */ /* my_strdup(574, &sig_type,get_tok_value(xctx.inst[i].prop_ptr,"generic_type",0)); */ /* if(!sig_type || sig_type[0]=='\0') my_strdup(575, &sig_type,"std_logic"); */ /* if( type && (strcmp(type,"generic"))==0) */ /* { */ /* my_strdup(576, &port_value,get_tok_value(xctx.inst[i].prop_ptr,"value",2)); */ /* str_tmp = get_tok_value(xctx.inst[i].prop_ptr,"lab",0); */ /* if(!tmp) fprintf(fd,"generic (\n"); */ /* if(tmp) fprintf(fd," ;\n"); */ /* fprintf(fd, " %s : %s", str_tmp ? str_tmp : "(NULL)", sig_type ); */ /* if(port_value &&port_value[0]) */ /* fprintf(fd," := %s", port_value); */ /* */ /* tmp=1; */ /* } */ /* } */ /* if(tmp) fprintf(fd, "\n);\n"); */ /* print top subckt ipin/opins */ dbg(1, "global_vhdl_netlist(): printing top level out pins\n"); tmp=0; for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(577, &sig_type,get_tok_value(xctx.inst[i].prop_ptr,"sig_type",0)); if(!sig_type || sig_type[0]=='\0') my_strdup(578, &sig_type,"std_logic"); my_strdup(579, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"opin"))==0) { str_tmp = get_tok_value(xctx.inst[i].prop_ptr,"lab",0); if(!tmp) fprintf(fd,"port(\n"); if(tmp) fprintf(fd," ;\n"); fprintf(fd, " %s : out %s", str_tmp ? str_tmp : "(NULL)", sig_type ); tmp=1; } } dbg(1, "global_vhdl_netlist(): printing top level inout pins\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(580, &sig_type,get_tok_value(xctx.inst[i].prop_ptr,"sig_type",0)); if(!sig_type || sig_type[0]=='\0') my_strdup(581, &sig_type,"std_logic"); my_strdup(582, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"iopin"))==0) { str_tmp = get_tok_value(xctx.inst[i].prop_ptr,"lab",0); if(!tmp) fprintf(fd,"port(\n"); if(tmp) fprintf(fd," ;\n"); fprintf(fd, " %s : inout %s", str_tmp ? str_tmp : "(NULL)", sig_type ); tmp=1; } } dbg(1, "global_vhdl_netlist(): printing top level input pins\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(583, &sig_type,get_tok_value(xctx.inst[i].prop_ptr,"sig_type",0)); if(!sig_type || sig_type[0]=='\0') my_strdup(584, &sig_type,"std_logic"); my_strdup(585, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"ipin"))==0) { str_tmp = get_tok_value(xctx.inst[i].prop_ptr,"lab",0); if(!tmp) fprintf(fd,"port(\n"); if(tmp) fprintf(fd," ;\n"); fprintf(fd, " %s : in %s", str_tmp ? str_tmp : "", sig_type ); tmp=1; } } if(tmp) fprintf(fd,"\n);\n"); dbg(1, "global_vhdl_netlist(): printing top level port attributes\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(586, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && (strcmp(type,"port_attributes"))==0) { if(xctx.inst[i].prop_ptr) fprintf(fd, "%s\n", xctx.inst[i].prop_ptr); } } fprintf(fd,"end %s ;\n\n", skip_dir( xctx.sch[xctx.currsch]) ); fprintf(fd,"architecture arch_%s of %s is\n\n", skip_dir( xctx.sch[xctx.currsch]) , skip_dir( xctx.sch[xctx.currsch])); dbg(1, "global_vhdl_netlist(): printing top level used components\n"); /* print all components */ subckt_name=NULL; for(j=0;j", dir_tmp ? dir_tmp : "", sig_type); my_free(1085, &dir_tmp); if(port_value &&port_value[0]) fprintf(fd," := %s", port_value); tmp=1; } } if(tmp) fprintf(fd, "\n);\n"); fprintf(fd, "end component ;\n\n"); } } } free_hash(subckt_table); my_free(1086, &subckt_name); dbg(1, "global_vhdl_netlist(): netlisting top level\n"); vhdl_netlist(fd, 0); fprintf(fd,"//// begin user architecture code\n"); for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(591, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if(type && !strcmp(type,"netlist_commands")) { fprintf(fd, "%s\n", get_tok_value(xctx.inst[i].prop_ptr,"value",2)); } } if(xctx.schvhdlprop && xctx.schvhdlprop[0]) { fprintf(fd, "%s\n", xctx.schvhdlprop); } fprintf(fd, "end arch_%s ;\n\n", skip_dir( xctx.sch[xctx.currsch]) ); if(split_files) { fclose(fd); my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} noshow {%s}", netl_filename, cellname); tcleval(tcl_cmd_netlist); if(debug_var==0) xunlink(netl_filename); } netlist_count++; /* preserve current level instance flags before descending hierarchy for netlisting, restore later */ stored_flags = my_calloc(151, xctx.instances, sizeof(unsigned int)); for(i=0;itype) continue; if( strcmp(get_tok_value(xctx.inst[l].prop_ptr,"vhdl_ignore",0),"true")==0 ) continue; if(xctx.inst[l].ptr<0) continue; if(!strcmp(get_tok_value( (xctx.inst[l].ptr+ xctx.sym)->prop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } if( !strcmp((xctx.inst[l].ptr+ xctx.sym)->type, "package") ) fprintf(fd, "%s\n", xctx.inst[l].prop_ptr); } dbg(1, "vhdl_block_netlist(): use statements\n"); for(l=0;ltype) continue; if(!strcmp(get_tok_value( (xctx.inst[l].ptr+ xctx.sym)->prop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } if( !strcmp((xctx.inst[l].ptr+ xctx.sym)->type, "use") ) fprintf(fd, "%s\n", xctx.inst[l].prop_ptr); } dbg(1, "vhdl_block_netlist(): entity generics\n"); /* print entity generics */ print_generic(fd, "entity", i); dbg(1, "vhdl_block_netlist(): entity ports\n"); /* print entity ports */ tmp=0; for(j=0;j", dir_tmp ? dir_tmp : "", sig_type); my_free(1092, &dir_tmp); if(port_value &&port_value[0]) fprintf(fd," := %s", port_value); tmp=1; } } if(tmp) fprintf(fd, "\n);\n"); dbg(1, "vhdl_block_netlist(): port attributes\n"); for(l=0;lprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(596, &type,(xctx.inst[l].ptr+ xctx.sym)->type); if( type && (strcmp(type,"port_attributes"))==0) { if(xctx.inst[l].prop_ptr) fprintf(fd, "%s\n", xctx.inst[l].prop_ptr); } } fprintf(fd,"end %s ;\n\n", skip_dir(xctx.sym[i].name) ); dbg(1, "vhdl_block_netlist(): architecture\n"); fprintf(fd,"architecture arch_%s of %s is\n\n", skip_dir(xctx.sym[i].name), skip_dir(xctx.sym[i].name) ); /* skip_dir( xctx.sch[xctx.currsch]), skip_dir( xctx.sch[xctx.currsch])); */ /* load current schematic to print used components */ dbg(1, "vhdl_block_netlist(): used components\n"); /* print all components */ if(!vhdl_stop) for(j=0;jprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } if(!strcmp(xctx.sym[j].name,xctx.inst[l].name)) { found=1; break; } } if(!found) continue; /* component generics */ print_generic(fd, "component",j); /* component ports */ tmp=0; for(k=0;k", dir_tmp ? dir_tmp : "", sig_type); my_free(1093, &dir_tmp); if(port_value &&port_value[0]) fprintf(fd," := %s", port_value); tmp=1; } } if(tmp) fprintf(fd, "\n);\n"); fprintf(fd, "end component ;\n\n"); } } dbg(1, "vhdl_block_netlist(): netlisting %s\n", skip_dir( xctx.sch[xctx.currsch])); vhdl_netlist(fd, vhdl_stop); fprintf(fd,"//// begin user architecture code\n"); for(l=0;lprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } if(netlist_count && !strcmp(get_tok_value(xctx.inst[l].prop_ptr, "only_toplevel", 0), "true")) continue; my_strdup(601, &type,(xctx.inst[l].ptr+ xctx.sym)->type); if(type && !strcmp(type,"netlist_commands")) { fprintf(fd, "%s\n", get_tok_value(xctx.inst[l].prop_ptr,"value",2)); } } if(xctx.schvhdlprop && xctx.schvhdlprop[0]) fprintf(fd, "%s\n", xctx.schvhdlprop); fprintf(fd, "end arch_%s ;\n\n", skip_dir(xctx.sym[i].name) ); /* skip_dir( xctx.sch[xctx.currsch]) ); */ if(split_files) { fclose(fd); my_snprintf(tcl_cmd_netlist, S(tcl_cmd_netlist), "netlist {%s} noshow {%s}", netl_filename, cellname); tcleval(tcl_cmd_netlist); if(debug_var==0) xunlink(netl_filename); } netlist_count++; my_free(1094, &sig_type); my_free(1095, &port_value); my_free(1096, &type); } void vhdl_netlist(FILE *fd , int vhdl_stop) { int i,l; char *type=NULL; prepared_netlist_structs = 0; prepare_netlist_structs(1); /* set_modify(1); */ /* 20160302 prepare_netlist_structs could change schematic (wire node naming for example) */ traverse_node_hash(); /* print all warnings about unconnected floatings etc */ dbg(1, "vhdl_netlist(): architecture declarations\n"); fprintf(fd, "//// begin user declarations\n"); for(l=0;ltype) continue; if(xctx.inst[l].ptr<0) continue; if(!strcmp(get_tok_value( (xctx.inst[l].ptr+ xctx.sym)->prop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } if(!strcmp((xctx.inst[l].ptr+ xctx.sym)->type, "arch_declarations") ) fprintf(fd, "%s\n", xctx.inst[l].prop_ptr? xctx.inst[l].prop_ptr: ""); } fprintf(fd, "//// end user declarations\n"); dbg(1, "vhdl_netlist(): print erc checks\n"); if(!vhdl_stop) print_vhdl_signals(fd); dbg(1, "vhdl_netlist(): done print erc checks\n"); dbg(1, "vhdl_netlist(): attributes\n"); fprintf(fd, "//// begin user attributes\n"); for(l=0;lprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } my_strdup(602, &type,(xctx.inst[l].ptr+ xctx.sym)->type); if( type && (strcmp(type,"attributes"))==0) { if(xctx.inst[l].prop_ptr) fprintf(fd, "\n%s\n", xctx.inst[l].prop_ptr); } } fprintf(fd, "//// end user attributes\n"); fprintf(fd, "begin\n"); /* begin reintroduced 09122003 */ if(!vhdl_stop) { for(i=0;iprop_ptr, "vhdl_ignore",0 ), "true") ) { continue; } dbg(2, "vhdl_netlist(): into the netlisting loop\n"); my_strdup(603, &type,(xctx.inst[i].ptr+ xctx.sym)->type); if( type && ( !IS_LABEL_OR_PIN(type) && strcmp(type,"generic")&& strcmp(type,"use")&& strcmp(type,"netlist_commands")&& strcmp(type,"package") && strcmp(type,"attributes") && strcmp(type,"port_attributes") && strcmp(type,"arch_declarations") )) { if(lastselected) { if(xctx.inst[i].sel==SELECTED) { print_vhdl_element(fd, i) ; } } else { print_vhdl_element(fd, i) ; } } } } dbg(1, "vhdl_netlist(): end\n"); if(!netlist_count) redraw_hilights(); /* draw_hilight_net(1); */ my_free(1097, &type); }