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