1 /*
2  * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 # include "pcb_priv.h"
21 # include <map>
22 # include <string>
23 # include <cassert>
24 # include <cstdio>
25 
26 using namespace std;
27 
28 list<struct nexus_data*> nexus_list;
29 
30 map <string, element_data_t*> element_list;
31 
32 struct attr_value {
33       ivl_attribute_type_t type;
34       string str;
35       long num;
36 };
37 
38 static void sheet_box(ivl_scope_t scope, const map<string,attr_value>&attrs);
39 static void black_box(ivl_scope_t scope, const map<string,attr_value>&attrs);
40 
41 static string wire_name(ivl_signal_t sig);
42 
scan_scope(ivl_scope_t scope)43 int scan_scope(ivl_scope_t scope)
44 {
45       int black_box_flag = 0;
46 
47       map<string,attr_value> attrs;
48 
49 	// Scan the attributes, looking in particular for the
50 	// black_box attribute. While we are at it, save the collected
51 	// attributes into a map that we can pass on to the processing
52 	// functions.
53       for (unsigned idx = 0 ; idx < ivl_scope_attr_cnt(scope) ; idx += 1) {
54 	    ivl_attribute_t attr = ivl_scope_attr_val(scope, idx);
55 	    string attr_key = attr->key;
56 
57 	    if (attr_key == "ivl_black_box") {
58 		    // Ah hah, this is a black box.
59 		  black_box_flag = 1;
60 	    } else {
61 		  struct attr_value val;
62 		  val.type = attr->type;
63 		  switch (val.type) {
64 		      case IVL_ATT_VOID:
65 			break;
66 		      case IVL_ATT_STR:
67 			val.str = attr->val.str;
68 			break;
69 		      case IVL_ATT_NUM:
70 			val.num = attr->val.num;
71 			break;
72 		  }
73 		  attrs[attr_key] = val;
74 	    }
75       }
76 
77 	// If this scope is a black box, then process it
78 	// so. Otherwise, process it as a sheet, which will recurse.
79       if (black_box_flag) {
80 	    black_box(scope, attrs);
81       } else {
82 	    sheet_box(scope, attrs);
83       }
84 
85       return 0;
86 }
87 
child_scan_fun(ivl_scope_t scope,void *)88 extern "C" int child_scan_fun(ivl_scope_t scope, void*)
89 {
90       scan_scope(scope);
91       return 0;
92 }
93 
sheet_box(ivl_scope_t scope,const map<string,attr_value> &)94 void sheet_box(ivl_scope_t scope, const map<string,attr_value>&)
95 {
96       printf("Sheet %s...\n", ivl_scope_name(scope));
97       unsigned sigs = ivl_scope_sigs(scope);
98       for (unsigned idx = 0 ; idx < sigs ; idx += 1) {
99 	    ivl_signal_t sig = ivl_scope_sig(scope, idx);
100 	    printf("   Wire %s\n", ivl_signal_basename(sig));
101 
102 	    assert(ivl_signal_array_count(sig) == 1);
103 	    ivl_nexus_t nex = ivl_signal_nex(sig, 0);
104 
105 	    struct nexus_data*nex_data = reinterpret_cast<nexus_data*>
106 		  (ivl_nexus_get_private(nex));
107 	    if (nex_data == 0) {
108 		  nex_data = new nexus_data;
109 		  nex_data->name = wire_name(sig);
110 		  nexus_list.push_back(nex_data);
111 		  ivl_nexus_set_private(nex, nex_data);
112 	    }
113       }
114 
115       ivl_scope_children(scope, child_scan_fun, 0);
116 }
117 
118 /*
119  * A black box is a component. Do not process the contents, other than
120  * to get at the ports that we'll attach to the netlist.
121  */
black_box(ivl_scope_t scope,const map<string,attr_value> & attrs)122 static void black_box(ivl_scope_t scope, const map<string,attr_value>&attrs)
123 {
124       assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
125       printf("   Component %s is %s\n", ivl_scope_name(scope), ivl_scope_tname(scope));
126 
127 	// The refdes for the object is by default the name of
128 	// the instance. If the user attaches a refdes
129 	// attribute, then use that instead.
130       string refdes = ivl_scope_basename(scope);
131       map<string,attr_value>::const_iterator aptr = attrs.find("refdes");
132       if (aptr != attrs.end()) {
133 	    assert(aptr->second.type == IVL_ATT_STR);
134 	    refdes = aptr->second.str;
135       }
136 
137       element_data_t*elem_data = new element_data_t;
138 
139 	// Scan the parameters of the module for any values that may
140 	// be of interest to the PCB element.
141       unsigned params = ivl_scope_params(scope);
142       for (unsigned idx = 0 ; idx < params ; idx += 1) {
143 	    ivl_parameter_t par = ivl_scope_param(scope, idx);
144 	    string name = ivl_parameter_basename(par);
145 
146 	    if (name == "description") {
147 		  ivl_expr_t exp = ivl_parameter_expr(par);
148 		  switch (ivl_expr_type(exp)) {
149 		      case IVL_EX_STRING:
150 			elem_data->description = ivl_expr_string(exp);
151 			break;
152 		      default:
153 			assert(0);
154 		  }
155 
156 	    } else if (name == "value") {
157 		  ivl_expr_t exp = ivl_parameter_expr(par);
158 		  switch (ivl_expr_type(exp)) {
159 		      case IVL_EX_STRING:
160 			elem_data->value = ivl_expr_string(exp);
161 			break;
162 		      default:
163 			assert(0);
164 		  }
165 
166 	    } else if (name == "footprint") {
167 		  ivl_expr_t exp = ivl_parameter_expr(par);
168 		  switch (ivl_expr_type(exp)) {
169 		      case IVL_EX_STRING:
170 			elem_data->footprint = ivl_expr_string(exp);
171 			break;
172 		      default:
173 			assert(0);
174 		  }
175 	    }
176       }
177 
178 	// If there is a "description" attribute for the device, then
179 	// use that in place of the parameter.
180       if ( (aptr = attrs.find("description")) != attrs.end() ) {
181 	    assert(aptr->second.type == IVL_ATT_STR);
182 	    elem_data->description = aptr->second.str;
183       }
184 
185 	// Get the "value" attribute for the device.
186       if ( (aptr = attrs.find("value")) != attrs.end() ) {
187 	    switch (aptr->second.type) {
188 		case IVL_ATT_VOID:
189 		  break;
190 		case IVL_ATT_STR:
191 		  elem_data->value = aptr->second.str;
192 		  break;
193 		case IVL_ATT_NUM:
194 		  assert(0);
195 		  break;
196 	    }
197       }
198 
199 	// Look for the ports of the black box and make sure they are
200 	// attached to signals.  Attach the port as a pin wired to a net.
201       unsigned sigs = ivl_scope_sigs(scope);
202       for (unsigned idx = 0 ; idx < sigs ; idx += 1) {
203 	    ivl_signal_t sig = ivl_scope_sig(scope, idx);
204 	    ivl_signal_port_t sip = ivl_signal_port(sig);
205 	      // Skip signals that are not ports.
206 	    if (sip == IVL_SIP_NONE)
207 		  continue;
208 
209 	    assert(ivl_signal_array_count(sig) == 1);
210 	    ivl_nexus_t nex = ivl_signal_nex(sig, 0);
211 	    struct nexus_data*nex_data = reinterpret_cast<struct nexus_data*>(ivl_nexus_get_private(nex));
212 	    assert(nex_data);
213 
214 	    string pindes = ivl_signal_basename(sig);
215 	    string pin = refdes + "-" + pindes;
216 	    nex_data->pins.insert(pin);
217 	    printf("     port %s\n", ivl_signal_basename(sig));
218       }
219 
220       element_data_t*&eptr = element_list[refdes];
221       assert(eptr == 0);
222       eptr = elem_data;
223 }
224 
wire_name(ivl_signal_t sig)225 static string wire_name(ivl_signal_t sig)
226 {
227       string res = ivl_signal_basename(sig);
228       return res;
229 }
230