aboutsummaryrefslogtreecommitdiffstats
path: root/json/jsonparse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'json/jsonparse.cc')
-rw-r--r--json/jsonparse.cc93
1 files changed, 76 insertions, 17 deletions
diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index 5f4df0a2..d463d8ce 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -285,7 +285,7 @@ void vcc_net(Context *ctx, NetInfo *net)
// true, false otherwise
bool is_blackbox(JsonNode *node)
{
- JsonNode *attr_node, *bbox_node;
+ JsonNode *attr_node, *bbox_node = nullptr, *wbox_node = nullptr;
if (node->data_dict.count("attributes") == 0)
return false;
@@ -296,14 +296,19 @@ bool is_blackbox(JsonNode *node)
return false;
if (GetSize(attr_node->data_dict) == 0)
return false;
- if (attr_node->data_dict.count("blackbox") == 0)
+ if (attr_node->data_dict.count("blackbox"))
+ bbox_node = attr_node->data_dict.at("blackbox");
+ if (attr_node->data_dict.count("whitebox"))
+ wbox_node = attr_node->data_dict.at("whitebox");
+ if (bbox_node == NULL && wbox_node == NULL)
return false;
- bbox_node = attr_node->data_dict.at("blackbox");
- if (bbox_node == NULL)
+ if (bbox_node && bbox_node->type != 'N')
+ log_error("JSON module blackbox attribute value is not a number\n");
+ if (bbox_node && bbox_node->data_number == 0)
return false;
- if (bbox_node->type != 'N')
- log_error("JSON module blackbox is not a number\n");
- if (bbox_node->data_number == 0)
+ if (wbox_node && wbox_node->type != 'N')
+ log_error("JSON module whitebox attribute value is not a number\n");
+ if (wbox_node && wbox_node->data_number == 0)
return false;
return true;
}
@@ -337,7 +342,7 @@ static int const_net_idx = 0;
template <typename F>
void json_import_ports(Context *ctx, const string &modname, const std::vector<IdString> &netnames,
const string &obj_name, const string &port_name, JsonNode *dir_node, JsonNode *wire_group_node,
- F visitor)
+ bool upto, int start_offset, F visitor)
{
// Examine a port of a cell or the design. For every bit of the port,
// the connected net will be processed and `visitor` will be called
@@ -406,8 +411,11 @@ void json_import_ports(Context *ctx, const string &modname, const std::vector<Id
wire_node = wire_group_node->data_array[index];
//
// Pick a name for this port
+ int ndx = index + start_offset;
+ if (upto)
+ ndx = start_offset + wire_group_node->data_array.size() - index - 1;
if (is_bus)
- this_port.name = ctx->id(port_info.name.str(ctx) + "[" + std::to_string(index) + "]");
+ this_port.name = ctx->id(port_info.name.str(ctx) + "[" + std::to_string(ndx) + "]");
else
this_port.name = port_info.name;
this_port.type = port_info.type;
@@ -584,7 +592,7 @@ void json_import_cell(Context *ctx, string modname, const std::vector<IdString>
dir_node = pdir_node->data_dict.at(port_name);
wire_group_node = connections->data_dict.at(port_name);
- json_import_ports(ctx, modname, netnames, cell->name.str(ctx), port_name, dir_node, wire_group_node,
+ json_import_ports(ctx, modname, netnames, cell->name.str(ctx), port_name, dir_node, wire_group_node, false, 0,
[&cell, ctx](PortType type, const std::string &name, NetInfo *net) {
cell->ports[ctx->id(name)] = PortInfo{ctx->id(name), net, type};
PortRef pr;
@@ -680,8 +688,20 @@ void json_import_toplevel_port(Context *ctx, const string &modname, const std::v
{
JsonNode *dir_node = node->data_dict.at("direction");
JsonNode *nets_node = node->data_dict.at("bits");
+ bool upto = false;
+ int start_offset = 0;
+ if (node->data_dict.count("upto") != 0) {
+ JsonNode *val = node->data_dict.at("upto");
+ if (val->type == 'N')
+ upto = val->data_number != 0;
+ }
+ if (node->data_dict.count("offset") != 0) {
+ JsonNode *val = node->data_dict.at("offset");
+ if (val->type == 'N')
+ start_offset = val->data_number;
+ }
json_import_ports(
- ctx, modname, netnames, "Top Level IO", portname, dir_node, nets_node,
+ ctx, modname, netnames, "Top Level IO", portname, dir_node, nets_node, upto, start_offset,
[ctx](PortType type, const std::string &name, NetInfo *net) { insert_iobuf(ctx, net, type, name); });
}
@@ -692,11 +712,22 @@ void json_import(Context *ctx, string modname, JsonNode *node)
log_info("Importing module %s\n", modname.c_str());
+ JsonNode *ports_parent = nullptr;
+ if (node->data_dict.count("ports") > 0)
+ ports_parent = node->data_dict.at("ports");
+
// Multiple labels might refer to the same net. For now we resolve conflicts thus:
+ // - (toplevel) ports are always preferred
// - names with fewer $ are always prefered
// - between equal $ counts, fewer .s are prefered
// - ties are resolved alphabetically
- auto prefer_netlabel = [](const std::string &a, const std::string &b) {
+ auto prefer_netlabel = [ports_parent](const std::string &a, const std::string &b) {
+ if (ports_parent != nullptr) {
+ if (ports_parent->data_dict.count(a))
+ return true;
+ if (ports_parent->data_dict.count(b))
+ return false;
+ }
if (b.empty())
return true;
long a_dollars = std::count(a.begin(), a.end(), '$'), b_dollars = std::count(b.begin(), b.end(), '$');
@@ -721,6 +752,18 @@ void json_import(Context *ctx, string modname, JsonNode *node)
here = cell_parent->data_dict.at(cell_parent->data_dict_keys[nnid]);
std::string basename = cell_parent->data_dict_keys[nnid];
+ bool upto = false;
+ int start_offset = 0;
+ if (here->data_dict.count("upto") != 0) {
+ JsonNode *val = here->data_dict.at("upto");
+ if (val->type == 'N')
+ upto = val->data_number != 0;
+ }
+ if (here->data_dict.count("offset") != 0) {
+ JsonNode *val = here->data_dict.at("offset");
+ if (val->type == 'N')
+ start_offset = val->data_number;
+ }
if (here->data_dict.count("bits")) {
JsonNode *bits = here->data_dict.at("bits");
assert(bits->type == 'A');
@@ -729,8 +772,11 @@ void json_import(Context *ctx, string modname, JsonNode *node)
int netid = bits->data_array.at(i)->data_number;
if (netid >= int(netlabels.size()))
netlabels.resize(netid + 1);
+ int ndx = i + start_offset;
+ if (upto)
+ ndx = start_offset + num_bits - i - 1;
std::string name =
- basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(i) + std::string("]"));
+ basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(ndx) + std::string("]"));
if (prefer_netlabel(name, netlabels.at(netid)))
netlabels.at(netid) = name;
}
@@ -753,16 +799,29 @@ void json_import(Context *ctx, string modname, JsonNode *node)
}
}
- if (node->data_dict.count("ports")) {
- JsonNode *ports_parent = node->data_dict.at("ports");
-
+ if (ports_parent != nullptr) {
// N.B. ports must be imported after cells for tristate behaviour
// to be correct
- // Loop through all ports
+ // Loop through all ports, first non-tristate then tristate to handle
+ // interconnected ports correctly
for (int portid = 0; portid < GetSize(ports_parent->data_dict_keys); portid++) {
JsonNode *here;
here = ports_parent->data_dict.at(ports_parent->data_dict_keys[portid]);
+ JsonNode *dir_node = here->data_dict.at("direction");
+ NPNR_ASSERT(dir_node->type == 'S');
+ if (dir_node->data_string == "inout")
+ continue;
+ json_import_toplevel_port(ctx, modname, netids, ports_parent->data_dict_keys[portid], here);
+ }
+ for (int portid = 0; portid < GetSize(ports_parent->data_dict_keys); portid++) {
+ JsonNode *here;
+
+ here = ports_parent->data_dict.at(ports_parent->data_dict_keys[portid]);
+ JsonNode *dir_node = here->data_dict.at("direction");
+ NPNR_ASSERT(dir_node->type == 'S');
+ if (dir_node->data_string != "inout")
+ continue;
json_import_toplevel_port(ctx, modname, netids, ports_parent->data_dict_keys[portid], here);
}
}