diff options
Diffstat (limited to 'json')
-rw-r--r-- | json/jsonparse.cc | 258 | ||||
-rw-r--r-- | json/jsonparse.h | 2 | ||||
-rw-r--r-- | json/jsonwrite.cc | 180 | ||||
-rw-r--r-- | json/jsonwrite.h | 33 |
4 files changed, 414 insertions, 59 deletions
diff --git a/json/jsonparse.cc b/json/jsonparse.cc index d463d8ce..29dcac0a 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,50 @@ 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 +669,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 +763,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 +882,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 +949,56 @@ 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..ca971e5f 100644 --- a/json/jsonparse.h +++ b/json/jsonparse.h @@ -27,7 +27,7 @@ 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..552cd398 --- /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> ¶meters, bool for_module=false) +{ + bool first = true; + for (auto ¶m : 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 |