aboutsummaryrefslogtreecommitdiffstats
path: root/json
diff options
context:
space:
mode:
Diffstat (limited to 'json')
-rw-r--r--json/jsonparse.cc256
-rw-r--r--json/jsonparse.h3
-rw-r--r--json/jsonwrite.cc180
-rw-r--r--json/jsonwrite.h33
4 files changed, 413 insertions, 59 deletions
diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index d463d8ce..caedbb5b 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -314,7 +314,7 @@ bool is_blackbox(JsonNode *node)
}
void json_import_cell_params(Context *ctx, string &modname, CellInfo *cell, JsonNode *param_node,
- std::unordered_map<IdString, std::string> *dest, int param_id)
+ std::unordered_map<IdString, Property> *dest, int param_id)
{
//
JsonNode *param;
@@ -324,9 +324,9 @@ void json_import_cell_params(Context *ctx, string &modname, CellInfo *cell, Json
pId = ctx->id(param_node->data_dict_keys[param_id]);
if (param->type == 'N') {
- (*dest)[pId] = std::to_string(param->data_number);
+ (*dest)[pId].setNumber(param->data_number);
} else if (param->type == 'S')
- (*dest)[pId] = param->data_string;
+ (*dest)[pId].setString(param->data_string);
else
log_error("JSON parameter type of \"%s\' of cell \'%s\' not supported\n", pId.c_str(ctx),
cell->name.c_str(ctx));
@@ -337,6 +337,49 @@ void json_import_cell_params(Context *ctx, string &modname, CellInfo *cell, Json
pId.c_str(ctx), cell->params[pId].c_str(), cell->name.c_str(ctx), modname.c_str());
}
+void json_import_net_attrib(Context *ctx, string &modname, NetInfo *net, JsonNode *param_node,
+ std::unordered_map<IdString, Property> *dest, int param_id)
+{
+ //
+ JsonNode *param;
+ IdString pId;
+ //
+ param = param_node->data_dict.at(param_node->data_dict_keys[param_id]);
+
+ pId = ctx->id(param_node->data_dict_keys[param_id]);
+ if (param->type == 'N') {
+ (*dest)[pId].setNumber(param->data_number);
+ } else if (param->type == 'S')
+ (*dest)[pId].setString(param->data_string);
+ else
+ log_error("JSON parameter type of \"%s\' of net \'%s\' not supported\n", pId.c_str(ctx), net->name.c_str(ctx));
+ if (json_debug)
+ log_info(" Added parameter \'%s\'=%s to net \'%s\' "
+ "of module \'%s\'\n",
+ pId.c_str(ctx), net->attrs[pId].c_str(), net->name.c_str(ctx), modname.c_str());
+}
+
+void json_import_top_attrib(Context *ctx, string &modname, JsonNode *param_node,
+ std::unordered_map<IdString, Property> *dest, int param_id)
+{
+ //
+ JsonNode *param;
+ IdString pId;
+ //
+ param = param_node->data_dict.at(param_node->data_dict_keys[param_id]);
+
+ pId = ctx->id(param_node->data_dict_keys[param_id]);
+ if (param->type == 'N') {
+ (*dest)[pId].setNumber(param->data_number);
+ } else if (param->type == 'S')
+ (*dest)[pId].setString(param->data_string);
+ else
+ log_error("JSON parameter type of \"%s\' of module not supported\n", pId.c_str(ctx));
+ if (json_debug)
+ log_info(" Added parameter \'%s\'=%s module \'%s\'\n", pId.c_str(ctx), (*dest)[pId].c_str(),
+ modname.c_str());
+}
+
static int const_net_idx = 0;
template <typename F>
@@ -625,62 +668,70 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, const string
// During packing, this generic IO buffer will be converted to an
// architecure primitive.
//
- std::unique_ptr<CellInfo> iobuf = std::unique_ptr<CellInfo>(new CellInfo());
- iobuf->name = ctx->id(name);
- std::copy(net->attrs.begin(), net->attrs.end(), std::inserter(iobuf->attrs, iobuf->attrs.begin()));
- if (type == PORT_IN) {
- if (ctx->verbose)
- log_info("processing input port %s\n", name.c_str());
- iobuf->type = ctx->id("$nextpnr_ibuf");
- iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT};
- // Special case: input, etc, directly drives inout
- if (net->driver.cell != nullptr) {
- if (net->driver.cell->type != ctx->id("$nextpnr_iobuf"))
- log_error("Top-level input '%s' also driven by %s.%s.\n", name.c_str(),
- net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx));
- net = net->driver.cell->ports.at(ctx->id("I")).net;
- }
- assert(net->driver.cell == nullptr);
- net->driver.port = ctx->id("O");
- net->driver.cell = iobuf.get();
- } else if (type == PORT_OUT) {
- if (ctx->verbose)
- log_info("processing output port %s\n", name.c_str());
- iobuf->type = ctx->id("$nextpnr_obuf");
- iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), net, PORT_IN};
- PortRef ref;
- ref.cell = iobuf.get();
- ref.port = ctx->id("I");
- net->users.push_back(ref);
- } else if (type == PORT_INOUT) {
- if (ctx->verbose)
- log_info("processing inout port %s\n", name.c_str());
- iobuf->type = ctx->id("$nextpnr_iobuf");
- iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), nullptr, PORT_IN};
-
- // Split the input and output nets for bidir ports
- std::unique_ptr<NetInfo> net2 = std::unique_ptr<NetInfo>(new NetInfo());
- net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i");
- net2->driver = net->driver;
- if (net->driver.cell != nullptr) {
- net2->driver.cell->ports[net2->driver.port].net = net2.get();
- net->driver.cell = nullptr;
+ if (ctx->settings.find(ctx->id("synth")) == ctx->settings.end()) {
+ std::unique_ptr<CellInfo> iobuf = std::unique_ptr<CellInfo>(new CellInfo());
+ iobuf->name = ctx->id(name);
+ std::copy(net->attrs.begin(), net->attrs.end(), std::inserter(iobuf->attrs, iobuf->attrs.begin()));
+ if (type == PORT_IN) {
+ if (ctx->verbose)
+ log_info("processing input port %s\n", name.c_str());
+ iobuf->type = ctx->id("$nextpnr_ibuf");
+ iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT};
+ // Special case: input, etc, directly drives inout
+ if (net->driver.cell != nullptr) {
+ if (net->driver.cell->type != ctx->id("$nextpnr_iobuf"))
+ log_error("Top-level input '%s' also driven by %s.%s.\n", name.c_str(),
+ net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx));
+ net = net->driver.cell->ports.at(ctx->id("I")).net;
+ }
+ assert(net->driver.cell == nullptr);
+ net->driver.port = ctx->id("O");
+ net->driver.cell = iobuf.get();
+ } else if (type == PORT_OUT) {
+ if (ctx->verbose)
+ log_info("processing output port %s\n", name.c_str());
+ iobuf->type = ctx->id("$nextpnr_obuf");
+ iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), net, PORT_IN};
+ PortRef ref;
+ ref.cell = iobuf.get();
+ ref.port = ctx->id("I");
+ net->users.push_back(ref);
+ } else if (type == PORT_INOUT) {
+ if (ctx->verbose)
+ log_info("processing inout port %s\n", name.c_str());
+ iobuf->type = ctx->id("$nextpnr_iobuf");
+ iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), nullptr, PORT_IN};
+
+ // Split the input and output nets for bidir ports
+ std::unique_ptr<NetInfo> net2 = std::unique_ptr<NetInfo>(new NetInfo());
+ net2->name = ctx->id("$" + net->name.str(ctx) + "$iobuf_i");
+ net2->driver = net->driver;
+ if (net->driver.cell != nullptr) {
+ net2->driver.cell->ports[net2->driver.port].net = net2.get();
+ net->driver.cell = nullptr;
+ }
+ iobuf->ports[ctx->id("I")].net = net2.get();
+ PortRef ref;
+ ref.cell = iobuf.get();
+ ref.port = ctx->id("I");
+ net2->users.push_back(ref);
+ ctx->nets[net2->name] = std::move(net2);
+
+ iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT};
+ assert(net->driver.cell == nullptr);
+ net->driver.port = ctx->id("O");
+ net->driver.cell = iobuf.get();
+ } else {
+ assert(false);
}
- iobuf->ports[ctx->id("I")].net = net2.get();
- PortRef ref;
- ref.cell = iobuf.get();
- ref.port = ctx->id("I");
- net2->users.push_back(ref);
- ctx->nets[net2->name] = std::move(net2);
-
- iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT};
- assert(net->driver.cell == nullptr);
- net->driver.port = ctx->id("O");
- net->driver.cell = iobuf.get();
- } else {
- assert(false);
+ ctx->cells[iobuf->name] = std::move(iobuf);
}
- ctx->cells[iobuf->name] = std::move(iobuf);
+
+ PortInfo pinfo;
+ pinfo.name = net->name;
+ pinfo.net = net;
+ pinfo.type = type;
+ ctx->ports[net->name] = pinfo;
}
void json_import_toplevel_port(Context *ctx, const string &modname, const std::vector<IdString> &netnames,
@@ -711,6 +762,11 @@ void json_import(Context *ctx, string modname, JsonNode *node)
return;
log_info("Importing module %s\n", modname.c_str());
+ ctx->attrs[ctx->id("module")] = modname;
+ JsonNode *attr_node = node->data_dict.at("attributes");
+ for (int attrid = 0; attrid < GetSize(attr_node->data_dict_keys); attrid++) {
+ json_import_top_attrib(ctx, modname, attr_node, &ctx->attrs, attrid);
+ }
JsonNode *ports_parent = nullptr;
if (node->data_dict.count("ports") > 0)
@@ -825,7 +881,43 @@ void json_import(Context *ctx, string modname, JsonNode *node)
json_import_toplevel_port(ctx, modname, netids, ports_parent->data_dict_keys[portid], here);
}
}
+ if (node->data_dict.count("netnames")) {
+ JsonNode *net_parent = node->data_dict.at("netnames");
+ for (int nnid = 0; nnid < GetSize(net_parent->data_dict_keys); nnid++) {
+ JsonNode *here;
+
+ here = net_parent->data_dict.at(net_parent->data_dict_keys[nnid]);
+ std::string basename = net_parent->data_dict_keys[nnid];
+ if (here->data_dict.count("bits")) {
+ JsonNode *bits = here->data_dict.at("bits");
+ assert(bits->type == 'A');
+ size_t num_bits = bits->data_array.size();
+ for (size_t i = 0; i < num_bits; i++) {
+ std::string name =
+ basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(i) + std::string("]"));
+ IdString net_id = ctx->id(name);
+ if (here->data_dict.count("attributes") && ctx->nets.find(net_id) != ctx->nets.end()) {
+ NetInfo *this_net = ctx->nets[net_id].get();
+
+ JsonNode *attr_node = here->data_dict.at("attributes");
+ if (attr_node->type != 'D')
+ log_error("JSON attribute list of \'%s\' is not a data dictionary\n",
+ this_net->name.c_str(ctx));
+
+ //
+ // Loop through all attributes, adding them into the
+ // design to annotate the cell
+ //
+ for (int attrid = 0; attrid < GetSize(attr_node->data_dict_keys); attrid++) {
+ json_import_net_attrib(ctx, modname, this_net, attr_node, &this_net->attrs, attrid);
+ }
+ }
+ }
+ }
+ }
+ }
check_all_nets_driven(ctx);
+ ctx->settings[ctx->id("synth")] = "1";
}
}; // End Namespace JsonParser
@@ -856,7 +948,55 @@ bool parse_json_file(std::istream &f, std::string &filename, Context *ctx)
log_info("Checksum: 0x%08x\n", ctx->checksum());
log_break();
- ctx->settings.emplace(ctx->id("input/json"), filename);
+ ctx->attributesToArchInfo();
+ return true;
+ } catch (log_execution_error_exception) {
+ return false;
+ }
+}
+
+bool load_json_settings(std::istream &f, std::string &filename, std::unordered_map<std::string, Property> &values)
+{
+ try {
+ using namespace JsonParser;
+
+ if (!f)
+ log_error("failed to open JSON file.\n");
+
+ int lineno = 1;
+
+ JsonNode root(f, lineno);
+
+ if (root.type != 'D')
+ log_error("JSON root node is not a dictionary.\n");
+
+ if (root.data_dict.count("modules") != 0) {
+ JsonNode *modules = root.data_dict.at("modules");
+
+ if (modules->type != 'D')
+ log_error("JSON modules node is not a dictionary.\n");
+
+ for (auto &it : modules->data_dict) {
+ JsonNode *node = it.second;
+ if (is_blackbox(node))
+ continue;
+
+ if (node->data_dict.count("settings")) {
+ JsonNode *attr_node = node->data_dict.at("settings");
+ for (int attrid = 0; attrid < GetSize(attr_node->data_dict_keys); attrid++) {
+ JsonNode *param = attr_node->data_dict.at(attr_node->data_dict_keys[attrid]);
+ std::string pId = attr_node->data_dict_keys[attrid];
+ if (param->type == 'N') {
+ values[pId].setNumber(param->data_number);
+ } else if (param->type == 'S')
+ values[pId].setString(param->data_string);
+ else
+ log_error("JSON parameter type of \"%s\' of module not supported\n", pId.c_str());
+ }
+ }
+ }
+ }
+
return true;
} catch (log_execution_error_exception) {
return false;
diff --git a/json/jsonparse.h b/json/jsonparse.h
index fe71444f..65e3f02e 100644
--- a/json/jsonparse.h
+++ b/json/jsonparse.h
@@ -27,7 +27,8 @@
NEXTPNR_NAMESPACE_BEGIN
extern bool parse_json_file(std::istream &, std::string &, Context *);
-
+extern bool load_json_settings(std::istream &f, std::string &filename,
+ std::unordered_map<std::string, Property> &values);
NEXTPNR_NAMESPACE_END
#endif
diff --git a/json/jsonwrite.cc b/json/jsonwrite.cc
new file mode 100644
index 00000000..0b7a5b25
--- /dev/null
+++ b/json/jsonwrite.cc
@@ -0,0 +1,180 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "jsonwrite.h"
+#include <assert.h>
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <log.h>
+#include <map>
+#include <string>
+#include "nextpnr.h"
+#include "version.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+namespace JsonWriter {
+
+std::string get_string(std::string str)
+{
+ std::string newstr = "\"";
+ for (char c : str) {
+ if (c == '\\')
+ newstr += c;
+ newstr += c;
+ }
+ return newstr + "\"";
+}
+
+std::string get_name(IdString name, Context *ctx) { return get_string(name.c_str(ctx)); }
+
+void write_parameters(std::ostream &f, Context *ctx, const std::unordered_map<IdString, Property> &parameters,
+ bool for_module = false)
+{
+ bool first = true;
+ for (auto &param : parameters) {
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first, ctx).c_str());
+ if (param.second.isString())
+ f << get_string(param.second);
+ else
+ f << param.second.num;
+ first = false;
+ }
+}
+
+void write_module(std::ostream &f, Context *ctx)
+{
+ auto val = ctx->attrs.find(ctx->id("module"));
+ if (val != ctx->attrs.end())
+ f << stringf(" %s: {\n", get_string(val->second.str).c_str());
+ else
+ f << stringf(" %s: {\n", get_string("top").c_str());
+ f << stringf(" \"settings\": {");
+ write_parameters(f, ctx, ctx->settings, true);
+ f << stringf("\n },\n");
+ f << stringf(" \"attributes\": {");
+ write_parameters(f, ctx, ctx->attrs, true);
+ f << stringf("\n },\n");
+ f << stringf(" \"ports\": {");
+ bool first = true;
+ for (auto &pair : ctx->ports) {
+ auto &c = pair.second;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(c.name, ctx).c_str());
+ f << stringf(" \"direction\": \"%s\",\n",
+ c.type == PORT_IN ? "input" : c.type == PORT_INOUT ? "inout" : "output");
+ f << stringf(" \"bits\": [ %d ]\n", pair.first.index);
+ f << stringf(" }");
+ first = false;
+ }
+ f << stringf("\n },\n");
+
+ f << stringf(" \"cells\": {");
+ first = true;
+ for (auto &pair : ctx->cells) {
+ auto &c = pair.second;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(c->name, ctx).c_str());
+ f << stringf(" \"hide_name\": %s,\n", c->name.c_str(ctx)[0] == '$' ? "1" : "0");
+ f << stringf(" \"type\": %s,\n", get_name(c->type, ctx).c_str());
+ f << stringf(" \"parameters\": {");
+ write_parameters(f, ctx, c->params);
+ f << stringf("\n },\n");
+ f << stringf(" \"attributes\": {");
+ write_parameters(f, ctx, c->attrs);
+ f << stringf("\n },\n");
+ f << stringf(" \"port_directions\": {");
+ bool first2 = true;
+ for (auto &conn : c->ports) {
+ auto &p = conn.second;
+ std::string direction = (p.type == PORT_IN) ? "input" : (p.type == PORT_OUT) ? "output" : "inout";
+ f << stringf("%s\n", first2 ? "" : ",");
+ f << stringf(" %s: \"%s\"", get_name(conn.first, ctx).c_str(), direction.c_str());
+ first2 = false;
+ }
+ f << stringf("\n },\n");
+ f << stringf(" \"connections\": {");
+ first2 = true;
+ for (auto &conn : c->ports) {
+ auto &p = conn.second;
+ f << stringf("%s\n", first2 ? "" : ",");
+ if (p.net)
+ f << stringf(" %s: [ %d ]", get_name(conn.first, ctx).c_str(), p.net->name.index);
+ else
+ f << stringf(" %s: [ ]", get_name(conn.first, ctx).c_str());
+
+ first2 = false;
+ }
+ f << stringf("\n }\n");
+
+ f << stringf(" }");
+ first = false;
+ }
+
+ f << stringf("\n },\n");
+
+ f << stringf(" \"netnames\": {");
+ first = true;
+ for (auto &pair : ctx->nets) {
+ auto &w = pair.second;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(w->name, ctx).c_str());
+ f << stringf(" \"hide_name\": %s,\n", w->name.c_str(ctx)[0] == '$' ? "1" : "0");
+ f << stringf(" \"bits\": [ %d ] ,\n", pair.first.index);
+ f << stringf(" \"attributes\": {");
+ write_parameters(f, ctx, w->attrs);
+ f << stringf("\n }\n");
+ f << stringf(" }");
+ first = false;
+ }
+
+ f << stringf("\n }\n");
+ f << stringf(" }");
+}
+
+void write_context(std::ostream &f, Context *ctx)
+{
+ f << stringf("{\n");
+ f << stringf(" \"creator\": %s,\n",
+ get_string("Next Generation Place and Route (git sha1 " GIT_COMMIT_HASH_STR ")").c_str());
+ f << stringf(" \"modules\": {\n");
+ write_module(f, ctx);
+ f << stringf("\n }");
+ f << stringf("\n}\n");
+}
+
+}; // End Namespace JsonWriter
+
+bool write_json_file(std::ostream &f, std::string &filename, Context *ctx)
+{
+ try {
+ using namespace JsonWriter;
+ if (!f)
+ log_error("failed to open JSON file.\n");
+ write_context(f, ctx);
+ log_break();
+ return true;
+ } catch (log_execution_error_exception) {
+ return false;
+ }
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/json/jsonwrite.h b/json/jsonwrite.h
new file mode 100644
index 00000000..9240bc96
--- /dev/null
+++ b/json/jsonwrite.h
@@ -0,0 +1,33 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef JSON_WRITER
+#define JSON_WRITER
+
+#include <ostream>
+#include <string>
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+extern bool write_json_file(std::ostream &, std::string &, Context *);
+
+NEXTPNR_NAMESPACE_END
+
+#endif