diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index 328d7cf5a..9e728681a 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -45,7 +45,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = pcb.o scope.o show_netlist.o +O = pcb.o scope.o show_netlist.o show_pcb.o all: dep pcb.tgt diff --git a/tgt-pcb/pcb.cc b/tgt-pcb/pcb.cc index 7ac2e3c66..547dc3a7b 100644 --- a/tgt-pcb/pcb.cc +++ b/tgt-pcb/pcb.cc @@ -25,7 +25,6 @@ # include "version_tag.h" # include "pcb_config.h" # include -# include # include "pcb_priv.h" # include "ivl_target.h" @@ -53,18 +52,8 @@ int target_design(ivl_design_t des) ivl_scope_t*root_scopes; unsigned nroot; unsigned idx; - FILE*fnet; int rc = 0; - const char*path = ivl_design_flag(des, "-o"); - if (path == 0) { - return -1; - } - - fnet = fopen(path, "w"); - if (fnet == 0) { - perror (path); - return -2; - } + const char*pcb_path = ivl_design_flag(des, "-o"); ivl_design_roots(des, &root_scopes, &nroot); for (idx = 0 ; idx < nroot ; idx += 1) { @@ -75,9 +64,15 @@ int target_design(ivl_design_t des) } } - show_netlist(fnet); + assert(pcb_path); + show_pcb(pcb_path); + + const char*net_path = ivl_design_flag(des, "netlist"); + if (net_path != 0) { + printf("Send netlist to %s\n", net_path); + show_netlist(net_path); + } - fclose(fnet); return rc; } diff --git a/tgt-pcb/pcb_priv.h b/tgt-pcb/pcb_priv.h index 8ff7a12d8..b98fceef0 100644 --- a/tgt-pcb/pcb_priv.h +++ b/tgt-pcb/pcb_priv.h @@ -22,11 +22,16 @@ # include # include # include -# include +# include # include extern int scan_scope(ivl_scope_t scope); +/* + * This nexus_list is a list of all the nets that the scan_scope + * collects, wrapped up into a list. The show_netlist dumps that list + * as a netlist. + */ struct nexus_data { std::string name; std::set pins; @@ -34,6 +39,21 @@ struct nexus_data { extern std::list nexus_list; -extern void show_netlist(FILE*fnet); +/* + * The element_list is a collection of all the elements that were + * located by the scope scan. The key is the refdes for the element, + * and the value is the element_data_t structure that describes that + * element. + */ +struct element_data_t { + std::string description; + std::string value; +}; + +extern std::map element_list; + +extern void show_netlist(const char*net_path); + +extern void show_pcb(const char*pcb_path); #endif diff --git a/tgt-pcb/scope.cc b/tgt-pcb/scope.cc index 66ee706a2..22f8e25d4 100644 --- a/tgt-pcb/scope.cc +++ b/tgt-pcb/scope.cc @@ -18,15 +18,24 @@ */ # include "pcb_priv.h" -# include +# include +# include # include using namespace std; list nexus_list; -static void sheet_box(ivl_scope_t scope); -static void black_box(ivl_scope_t scope); +map element_list; + +struct attr_value { + ivl_attribute_type_t type; + string str; + long num; +}; + +static void sheet_box(ivl_scope_t scope, const map&attrs); +static void black_box(ivl_scope_t scope, const map&attrs); static string wire_name(ivl_signal_t sig); @@ -35,20 +44,42 @@ int scan_scope(ivl_scope_t scope) int black_box_flag = 0; int idx; + map attrs; + // Scan the attributes, looking in particular for the - // black_box attribute. + // black_box attribute. While we are at it, save the collected + // attributes into a map that we can pass on to the processing + // functions. for (idx = 0 ; idx < ivl_scope_attr_cnt(scope) ; idx += 1) { ivl_attribute_t attr = ivl_scope_attr_val(scope, idx); - if (strcmp(attr->key, "ivl_black_box") == 0) + string attr_key = attr->key; + + if (attr_key == "ivl_black_box") { + // Ah hah, this is a black box. black_box_flag = 1; + } else { + struct attr_value val; + val.type = attr->type; + switch (val.type) { + case IVL_ATT_VOID: + break; + case IVL_ATT_STR: + val.str = attr->val.str; + break; + case IVL_ATT_NUM: + val.num = attr->val.num; + break; + } + attrs[attr_key] = val; + } } // If this scope is a black box, then process it // so. Otherwise, process it as a sheet, which will recurse. if (black_box_flag) { - black_box(scope); + black_box(scope, attrs); } else { - sheet_box(scope); + sheet_box(scope, attrs); } return 0; @@ -60,7 +91,7 @@ static int child_scan_fun(ivl_scope_t scope, void*) return 0; } -void sheet_box(ivl_scope_t scope) +void sheet_box(ivl_scope_t scope, const map&attrs) { printf("Sheet %s...\n", ivl_scope_name(scope)); unsigned sigs = ivl_scope_sigs(scope); @@ -88,12 +119,76 @@ void sheet_box(ivl_scope_t scope) * A black box is a component. Do not process the contents, other then * to get at the ports that we'll attach to the netlist. */ -static void black_box(ivl_scope_t scope) +static void black_box(ivl_scope_t scope, const map&attrs) { assert(ivl_scope_type(scope) == IVL_SCT_MODULE); printf(" Component %s is %s\n", ivl_scope_name(scope), ivl_scope_tname(scope)); - unsigned sigs = ivl_scope_sigs(scope); + // The refdes for the object is by default the name of + // the instance. If the user attaches a refdes + // attribute, then use that instead. + string refdes = ivl_scope_basename(scope); + map::const_iterator aptr = attrs.find("refdes"); + if (aptr != attrs.end()) { + assert(aptr->second.type == IVL_ATT_STR); + refdes = aptr->second.str; + } + + element_data_t*elem_data = new element_data_t; + + // Scan the parameters of the module for any values that may + // be of interest to the PCB element. + unsigned params = ivl_scope_params(scope); + for (unsigned idx = 0 ; idx < params ; idx += 1) { + ivl_parameter_t par = ivl_scope_param(scope, idx); + string name = ivl_parameter_basename(par); + + if (name == "description") { + ivl_expr_t exp = ivl_parameter_expr(par); + switch (ivl_expr_type(exp)) { + case IVL_EX_STRING: + elem_data->description = ivl_expr_string(exp); + break; + default: + assert(0); + } + + } else if (name == "value") { + ivl_expr_t exp = ivl_parameter_expr(par); + switch (ivl_expr_type(exp)) { + case IVL_EX_STRING: + elem_data->value = ivl_expr_string(exp); + break; + default: + assert(0); + } + } + } + + // If there is a "description" attribute for the device, then + // use that in place of the parameter. + if ( (aptr = attrs.find("description")) != attrs.end() ) { + assert(aptr->second.type == IVL_ATT_STR); + elem_data->description = aptr->second.str; + } + + // Get the "value" attribute for the device. + if ( (aptr = attrs.find("value")) != attrs.end() ) { + switch (aptr->second.type) { + case IVL_ATT_VOID: + break; + case IVL_ATT_STR: + elem_data->value = aptr->second.str; + break; + case IVL_ATT_NUM: + assert(0); + break; + } + } + + // Look for the ports of the black box and make sure they are + // attached to signals. Attach the port as a pin wired to a net. + unsigned sigs = ivl_scope_sigs(scope); for (unsigned idx = 0 ; idx < sigs ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(scope, idx); ivl_signal_port_t sip = ivl_signal_port(sig); @@ -106,12 +201,15 @@ static void black_box(ivl_scope_t scope) struct nexus_data*nex_data = reinterpret_cast(ivl_nexus_get_private(nex)); assert(nex_data); - string refdes = ivl_scope_basename(scope); string pindes = ivl_signal_basename(sig); string pin = refdes + "-" + pindes; nex_data->pins.insert(pin); printf(" port %s\n", ivl_signal_basename(sig)); } + + element_data_t*&eptr = element_list[refdes]; + assert(eptr == 0); + eptr = elem_data; } static string wire_name(ivl_signal_t sig) diff --git a/tgt-pcb/show_netlist.cc b/tgt-pcb/show_netlist.cc index a64445663..a2a5d6be2 100644 --- a/tgt-pcb/show_netlist.cc +++ b/tgt-pcb/show_netlist.cc @@ -18,11 +18,19 @@ */ # include "pcb_priv.h" +# include using namespace std; -void show_netlist(FILE*fnet) +void show_netlist(const char*net_path) { + assert(net_path); + FILE*fnet = fopen(net_path, "w"); + if (fnet == 0) { + perror(net_path); + return; + } + for (list::iterator cur = nexus_list.begin() ; cur != nexus_list.end() ; ++ cur) { @@ -34,4 +42,6 @@ void show_netlist(FILE*fnet) } fprintf(fnet, "\n"); } + + fclose(fnet); } diff --git a/tgt-pcb/show_pcb.cc b/tgt-pcb/show_pcb.cc new file mode 100644 index 000000000..02623bb90 --- /dev/null +++ b/tgt-pcb/show_pcb.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "pcb_config.h" +# include "pcb_priv.h" + +using namespace std; + +static void show_pcb_header(FILE*fpcb) +{ + fprintf(fpcb, "PCB[\"\" 400000 220000]\n"); + fprintf(fpcb, "Grid[100.0 0 0 1]\n"); +} + + +void show_pcb(const char*pcb_path) +{ + assert(pcb_path); + FILE*fpcb = fopen(pcb_path, "w"); + if (fpcb == 0) { + perror(pcb_path); + return; + } + + show_pcb_header(fpcb); + + // Draw the collected elements + for (map::const_iterator cur = element_list.begin() + ; cur != element_list.end() ; ++ cur) { + + const string&refdes = cur->first; + const string&descr = cur->second->description; + const string&value = cur->second->value; + fprintf(fpcb, "Element[\"\" \"%s\" \"%s\" \"%s\"", + descr.c_str(), refdes.c_str(), value.c_str()); + + // Mark-X Mark-Y + fprintf(fpcb, " 0 0"); + // Text-X Text-Y text-direction Text-scale Text-flags + fprintf(fpcb, " 0 0 0 100 \"\""); + fprintf(fpcb, "]\n"); + + // Fill in the contents of the element. Should get this + // from a library. + fprintf(fpcb, "(\n"); + fprintf(fpcb, ")\n"); + } + + fclose(fpcb); +}