230 lines
6.6 KiB
C++
230 lines
6.6 KiB
C++
/*
|
|
* Copyright (c) 2011-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
# include "pcb_priv.h"
|
|
# include <map>
|
|
# include <string>
|
|
# include <cassert>
|
|
# include <cstdio>
|
|
|
|
using namespace std;
|
|
|
|
list<struct nexus_data*> nexus_list;
|
|
|
|
map <string, element_data_t*> element_list;
|
|
|
|
struct attr_value {
|
|
ivl_attribute_type_t type;
|
|
string str;
|
|
long num;
|
|
};
|
|
|
|
static void sheet_box(ivl_scope_t scope, const map<string,attr_value>&attrs);
|
|
static void black_box(ivl_scope_t scope, const map<string,attr_value>&attrs);
|
|
|
|
static string wire_name(ivl_signal_t sig);
|
|
|
|
int scan_scope(ivl_scope_t scope)
|
|
{
|
|
int black_box_flag = 0;
|
|
|
|
map<string,attr_value> attrs;
|
|
|
|
// Scan the attributes, looking in particular for the
|
|
// 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 (unsigned idx = 0 ; idx < ivl_scope_attr_cnt(scope) ; idx += 1) {
|
|
ivl_attribute_t attr = ivl_scope_attr_val(scope, idx);
|
|
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, attrs);
|
|
} else {
|
|
sheet_box(scope, attrs);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern "C" int child_scan_fun(ivl_scope_t scope, void*)
|
|
{
|
|
scan_scope(scope);
|
|
return 0;
|
|
}
|
|
|
|
void sheet_box(ivl_scope_t scope, const map<string,attr_value>&)
|
|
{
|
|
printf("Sheet %s...\n", ivl_scope_name(scope));
|
|
unsigned sigs = ivl_scope_sigs(scope);
|
|
for (unsigned idx = 0 ; idx < sigs ; idx += 1) {
|
|
ivl_signal_t sig = ivl_scope_sig(scope, idx);
|
|
printf(" Wire %s\n", ivl_signal_basename(sig));
|
|
|
|
assert(ivl_signal_array_count(sig) == 1);
|
|
ivl_nexus_t nex = ivl_signal_nex(sig, 0);
|
|
|
|
struct nexus_data*nex_data = reinterpret_cast<nexus_data*>
|
|
(ivl_nexus_get_private(nex));
|
|
if (nex_data == 0) {
|
|
nex_data = new nexus_data;
|
|
nex_data->name = wire_name(sig);
|
|
nexus_list.push_back(nex_data);
|
|
ivl_nexus_set_private(nex, nex_data);
|
|
}
|
|
}
|
|
|
|
ivl_scope_children(scope, child_scan_fun, 0);
|
|
}
|
|
|
|
/*
|
|
* A black box is a component. Do not process the contents, other than
|
|
* to get at the ports that we'll attach to the netlist.
|
|
*/
|
|
static void black_box(ivl_scope_t scope, const map<string,attr_value>&attrs)
|
|
{
|
|
assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
|
|
printf(" Component %s is %s\n", ivl_scope_name(scope), ivl_scope_tname(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<string,attr_value>::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);
|
|
}
|
|
|
|
} else if (name == "footprint") {
|
|
ivl_expr_t exp = ivl_parameter_expr(par);
|
|
switch (ivl_expr_type(exp)) {
|
|
case IVL_EX_STRING:
|
|
elem_data->footprint = 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);
|
|
// Skip signals that are not ports.
|
|
if (sip == IVL_SIP_NONE)
|
|
continue;
|
|
|
|
assert(ivl_signal_array_count(sig) == 1);
|
|
ivl_nexus_t nex = ivl_signal_nex(sig, 0);
|
|
struct nexus_data*nex_data = reinterpret_cast<struct nexus_data*>(ivl_nexus_get_private(nex));
|
|
assert(nex_data);
|
|
|
|
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)
|
|
{
|
|
string res = ivl_signal_basename(sig);
|
|
return res;
|
|
}
|