aboutsummaryrefslogtreecommitdiffstats
path: root/frontend
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2018-06-13 12:38:28 +0200
committerClifford Wolf <clifford@clifford.at>2018-06-13 12:38:28 +0200
commit145c849596bdcd24f3b4e617eeb4ee06e1b93452 (patch)
tree243d63251d31498f4e92bfdae3ae0d0f087f9957 /frontend
parent4d7f18dd98a7ef9540a279a8e27cb9dbef355af7 (diff)
parentde0918c28758b09f638e02ffc04fad989321da1b (diff)
downloadnextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.tar.gz
nextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.tar.bz2
nextpnr-145c849596bdcd24f3b4e617eeb4ee06e1b93452.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr
Diffstat (limited to 'frontend')
-rw-r--r--frontend/json/jsonparse.cc154
1 files changed, 118 insertions, 36 deletions
diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc
index 3f965ce4..79ee0a4d 100644
--- a/frontend/json/jsonparse.cc
+++ b/frontend/json/jsonparse.cc
@@ -341,24 +341,25 @@ void json_import_cell_params(Design *design, string &modname, CellInfo *cell,
modname.c_str());
}
-void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
- string &port_name, JsonNode *dir_node,
- JsonNode *wire_group_node)
+template <typename F>
+void json_import_ports(Design *design, const string &modname,
+ const string &obj_name, const string &port_name,
+ JsonNode *dir_node, JsonNode *wire_group_node, F visitor)
{
- // Examine and connect a single port of the given cell to its nets,
- // generating them as necessary
-
+ // 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
+ // with (PortType dir, std::string name, NetInfo *net)
assert(dir_node);
if (json_debug)
log_info(" Examining port %s, node %s\n", port_name.c_str(),
- cell->name.c_str());
+ obj_name.c_str());
if (!wire_group_node)
log_error("JSON no connection match "
"for port_direction \'%s\' of node \'%s\' "
"in module \'%s\'\n",
- port_name.c_str(), cell->name.c_str(), modname.c_str());
+ port_name.c_str(), obj_name.c_str(), modname.c_str());
assert(wire_group_node);
@@ -377,7 +378,7 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
else
log_error("JSON unknown port direction \'%s\' in node \'%s\' "
"of module \'%s\'\n",
- dir_node->data_string.c_str(), cell->name.c_str(),
+ dir_node->data_string.c_str(), obj_name.c_str(),
modname.c_str());
//
// Find an update, or create a net to connect
@@ -398,18 +399,12 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
// There is/are no connections to this port.
//
// Create the port, but leave the net NULL
- PortInfo this_port;
-
- //
- this_port.name = port_info.name;
- this_port.type = port_info.type;
- this_port.net = NULL;
- cell->ports[this_port.name] = this_port;
+ visitor(port_info.type, port_info.name, nullptr);
if (json_debug)
log_info(" Port \'%s\' has no connection in \'%s\'\n",
- this_port.name.c_str(), cell->name.c_str());
+ port_info.name.c_str(), obj_name.c_str());
} else
for (int index = 0; index < wire_group_node->data_array.size();
@@ -417,13 +412,10 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
//
JsonNode *wire_node;
PortInfo this_port;
- PortRef port_ref;
bool const_input = false;
IdString net_id;
//
wire_node = wire_group_node->data_array[index];
- port_ref.cell = cell;
-
//
// Pick a name for this port
if (is_bus)
@@ -433,8 +425,6 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
this_port.name = port_info.name;
this_port.type = port_info.type;
- port_ref.port = this_port.name;
-
if (wire_node->type == 'N') {
int net_num;
@@ -500,7 +490,7 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
"\'%s\' of port \'%s\' "
"in cell \'%s\' of module \'%s\'\n",
wire_node->data_string.c_str(),
- port_name.c_str(), cell->name.c_str(),
+ port_name.c_str(), obj_name.c_str(),
modname.c_str());
} else
@@ -511,17 +501,8 @@ void json_import_cell_ports(Design *design, string &modname, CellInfo *cell,
if (json_debug)
log_info(" Inserting port \'%s\' into cell \'%s\'\n",
- this_port.name.c_str(), cell->name.c_str());
-
- this_port.net = this_net;
-
- cell->ports[this_port.name] = this_port;
-
- if (this_port.type == PORT_OUT) {
- assert(this_net->driver.cell == NULL);
- this_net->driver = port_ref;
- } else
- this_net->users.push_back(port_ref);
+ this_port.name.c_str(), obj_name.c_str());
+ visitor(this_port.type, this_port.name, this_net);
if (design->nets.count(this_net->name) == 0)
design->nets[this_net->name] = this_net;
@@ -632,14 +613,98 @@ void json_import_cell(Design *design, string modname, JsonNode *cell_node,
dir_node = pdir_node->data_dict.at(port_name);
wire_group_node = connections->data_dict.at(port_name);
- json_import_cell_ports(design, modname, cell, port_name, dir_node,
- wire_group_node);
+ json_import_ports(
+ design, modname, cell->name, port_name, dir_node,
+ wire_group_node,
+ [cell](PortType type, const std::string &name, NetInfo *net) {
+ cell->ports[name] = PortInfo{name, net, type};
+ PortRef pr;
+ pr.cell = cell;
+ pr.port = name;
+ if (net != nullptr) {
+ if (type == PORT_IN || type == PORT_INOUT) {
+ net->users.push_back(pr);
+ } else if (type == PORT_OUT) {
+ assert(net->driver.cell == nullptr);
+ net->driver = pr;
+ }
+ }
+ });
}
design->cells[cell->name] = cell;
// check_all_nets_driven(design);
}
+static void insert_iobuf(Design *design, NetInfo *net, PortType type,
+ const string &name)
+{
+ // Instantiate a architecture-independent IO buffer connected to a given
+ // net, of a given type, and named after the IO port.
+ //
+ // During packing, this generic IO buffer will be converted to an
+ // architecure primitive.
+ //
+ CellInfo *iobuf = new CellInfo();
+ iobuf->name = name;
+ std::copy(net->attrs.begin(), net->attrs.end(),
+ std::inserter(iobuf->attrs, iobuf->attrs.begin()));
+ if (type == PORT_IN) {
+ log_info("processing input port %s\n", name.c_str());
+ iobuf->type = "$nextpnr_ibuf";
+ iobuf->ports["O"] = PortInfo{"O", net, PORT_OUT};
+
+ assert(net->driver.cell == nullptr);
+ net->driver.port = "O";
+ net->driver.cell = iobuf;
+ } else if (type == PORT_OUT) {
+ log_info("processing output port %s\n", name.c_str());
+ iobuf->type = "$nextpnr_obuf";
+ iobuf->ports["I"] = PortInfo{"I", net, PORT_IN};
+ PortRef ref;
+ ref.cell = iobuf;
+ ref.port = "I";
+ net->users.push_back(ref);
+ } else if (type == PORT_INOUT) {
+ log_info("processing inout port %s\n", name.c_str());
+ iobuf->type = "$nextpnr_iobuf";
+ iobuf->ports["I"] = PortInfo{"I", nullptr, PORT_IN};
+ if (net->driver.cell != NULL) {
+ // Split the input and output nets for bidir ports
+ NetInfo *net2 = new NetInfo();
+ net2->name = "$" + net->name.str() + "$iobuf_i";
+ net2->driver = net->driver;
+ net2->driver.cell->ports[net2->driver.port].net = net2;
+ net->driver.cell = nullptr;
+ design->nets[net2->name] = net2;
+ iobuf->ports["I"].net = net2;
+ PortRef ref;
+ ref.cell = iobuf;
+ ref.port = "I";
+ net2->users.push_back(ref);
+ }
+ iobuf->ports["O"] = PortInfo{"O", net, PORT_OUT};
+ assert(net->driver.cell == nullptr);
+ net->driver.port = "O";
+ net->driver.cell = iobuf;
+ } else {
+ assert(false);
+ }
+ design->cells[iobuf->name] = iobuf;
+}
+
+void json_import_toplevel_port(Design *design, const string &modname,
+ const string &portname, JsonNode *node)
+{
+ JsonNode *dir_node = node->data_dict.at("direction");
+ JsonNode *nets_node = node->data_dict.at("bits");
+ json_import_ports(
+ design, modname, "Top Level IO", portname, dir_node, nets_node,
+ [design](PortType type, const std::string &name, NetInfo *net) {
+ insert_iobuf(design, net, type, name);
+ });
+}
+
void json_import(Design *design, string modname, JsonNode *node)
{
if (is_blackbox(node))
@@ -665,6 +730,23 @@ void json_import(Design *design, string modname, JsonNode *node)
}
}
+ if (node->data_dict.count("ports")) {
+ JsonNode *ports_parent = node->data_dict.at("ports");
+
+ // N.B. ports must be imported after cells for tristate behaviour
+ // to be correct
+ // Loop through all ports
+ for (int portid = 0; portid < GetSize(ports_parent->data_dict_keys);
+ portid++) {
+ JsonNode *here, *param_node;
+
+ here = ports_parent->data_dict.at(
+ ports_parent->data_dict_keys[portid]);
+ json_import_toplevel_port(design, modname,
+ ports_parent->data_dict_keys[portid],
+ here);
+ }
+ }
check_all_nets_driven(design);
}