From 77cbd70a72997e659bcba70175761b9fb930c5c6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Nov 2019 18:52:13 +0000 Subject: frontend: JSON implementation of the generic framework Signed-off-by: David Shah --- frontend/json_frontend.cc | 189 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 frontend/json_frontend.cc (limited to 'frontend/json_frontend.cc') diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc new file mode 100644 index 00000000..91c9f06a --- /dev/null +++ b/frontend/json_frontend.cc @@ -0,0 +1,189 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2019 David Shah + * + * 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 "json_frontend.h" +#include "frontend_base.h" +#include "json11.hpp" +#include "log.h" +#include "nextpnr.h" + +#include + +NEXTPNR_NAMESPACE_BEGIN + +using namespace json11; + +struct JsonFrontendImpl +{ + // See specification in frontend_base.h + JsonFrontendImpl(Json &root) : root(root){}; + Json &root; + typedef const Json &ModuleDataType; + typedef const Json &ModulePortDataType; + typedef const Json &CellDataType; + typedef const Json &NetnameDataType; + typedef const Json::array &BitVectorDataType; + + template void foreach_module(TFunc Func) + { + for (const auto &mod : root.object_items()) + Func(mod.first, mod.second); + } + + template void foreach_port(const ModuleDataType &mod, TFunc Func) + { + const auto &ports = mod["ports"]; + if (ports.is_null()) + return; + for (const auto &port : ports.object_items()) + Func(port.first, port.second); + } + + template void foreach_cell(const ModuleDataType &mod, TFunc Func) + { + const auto &cells = mod["cells"]; + if (cells.is_null()) + return; + for (const auto &cell : cells.object_items()) + Func(cell.first, cell.second); + } + + template void foreach_netname(const ModuleDataType &mod, TFunc Func) + { + const auto &netnames = mod["netnames"]; + if (netnames.is_null()) + return; + for (const auto &netname : netnames.object_items()) + Func(netname.first, netname.second); + } + + PortType lookup_portdir(const std::string &dir) + { + if (dir == "input") + return PORT_IN; + else if (dir == "inout") + return PORT_INOUT; + else if (dir == "output") + return PORT_OUT; + else + NPNR_ASSERT_FALSE("invalid json port direction"); + } + + PortType get_port_dir(const ModulePortDataType &port) { return lookup_portdir(port["direction"].string_value()); } + + int get_array_offset(const Json &obj) + { + auto offset = obj["offset"]; + return offset.is_null() ? 0 : offset.int_value(); + } + + bool is_array_upto(const Json &obj) + { + auto upto = obj["upto"]; + return upto.is_null() ? false : bool(upto.int_value()); + } + + const BitVectorDataType &get_port_bits(const ModulePortDataType &port) { return port["bits"].array_items(); } + + const std::string &get_cell_type(const CellDataType &cell) { return cell["type"].string_value(); } + + Property parse_property(const Json &val) + { + if (val.is_number()) + return Property(val.int_value(), 32); + else + return Property::from_string(val.string_value()); + } + + template void foreach_attr(const Json &obj, TFunc Func) + { + const auto &attrs = obj["attributes"]; + if (attrs.is_null()) + return; + for (const auto &attr : attrs.object_items()) { + Func(attr.first, parse_property(attr.second)); + } + } + + template void foreach_param(const Json &obj, TFunc Func) + { + const auto ¶ms = obj["parameters"]; + if (params.is_null()) + return; + for (const auto ¶m : params.object_items()) { + Func(param.first, parse_property(param.second)); + } + } + + template void foreach_port_dir(const CellDataType &cell, TFunc Func) + { + for (const auto &pdir : cell["port_directions"].object_items()) + Func(pdir.first, lookup_portdir(pdir.second.string_value())); + } + + template void foreach_port_conn(const CellDataType &cell, TFunc Func) + { + for (const auto &pconn : cell["connections"].object_items()) + Func(pconn.first, pconn.second); + } + + template const BitVectorDataType &get_net_bits(const NetnameDataType &net) + { + return net["bits"].array_items(); + } + + int get_vector_length(const BitVectorDataType &bits) { return int(bits.size()); } + + bool is_vector_bit_constant(const BitVectorDataType &bits, int i) + { + NPNR_ASSERT(i < int(bits.size())); + return bits[i].is_string(); + } + + char get_vector_bit_constval(const BitVectorDataType &bits, int i) + { + auto s = bits.at(i).string_value(); + NPNR_ASSERT(s.size() == 1); + return s.at(0); + } + + int get_vector_bit_signal(const BitVectorDataType &bits, int i) + { + NPNR_ASSERT(bits.at(i).is_number()); + return bits.at(i).int_value(); + } +}; + +bool parse_json(std::istream &in, const std::string &filename, Context *ctx) +{ + Json root; + { + if (!in) + log_error("Failed to open JSON file '%s'.\n", filename.c_str()); + std::string json_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); + std::string error; + root = Json::parse(json_str, error, JsonParse::COMMENTS); + if (root.is_null()) + log_error("Failed to parse JSON file '%s': %s.\n", filename.c_str(), error.c_str()); + } + run_frontend(ctx, JsonFrontendImpl(root)); + return true; +} + +NEXTPNR_NAMESPACE_END \ No newline at end of file -- cgit v1.2.3 From eb14cf09f4d2c81a3f01f33394b78ec29df44035 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 15 Nov 2019 17:55:02 +0000 Subject: frontend: Fix template compile issues Signed-off-by: David Shah --- frontend/json_frontend.cc | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'frontend/json_frontend.cc') diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc index 91c9f06a..37c1dabd 100644 --- a/frontend/json_frontend.cc +++ b/frontend/json_frontend.cc @@ -40,13 +40,13 @@ struct JsonFrontendImpl typedef const Json &NetnameDataType; typedef const Json::array &BitVectorDataType; - template void foreach_module(TFunc Func) + template void foreach_module(TFunc Func) const { for (const auto &mod : root.object_items()) Func(mod.first, mod.second); } - template void foreach_port(const ModuleDataType &mod, TFunc Func) + template void foreach_port(const ModuleDataType &mod, TFunc Func) const { const auto &ports = mod["ports"]; if (ports.is_null()) @@ -55,7 +55,7 @@ struct JsonFrontendImpl Func(port.first, port.second); } - template void foreach_cell(const ModuleDataType &mod, TFunc Func) + template void foreach_cell(const ModuleDataType &mod, TFunc Func) const { const auto &cells = mod["cells"]; if (cells.is_null()) @@ -64,7 +64,7 @@ struct JsonFrontendImpl Func(cell.first, cell.second); } - template void foreach_netname(const ModuleDataType &mod, TFunc Func) + template void foreach_netname(const ModuleDataType &mod, TFunc Func) const { const auto &netnames = mod["netnames"]; if (netnames.is_null()) @@ -73,7 +73,7 @@ struct JsonFrontendImpl Func(netname.first, netname.second); } - PortType lookup_portdir(const std::string &dir) + PortType lookup_portdir(const std::string &dir) const { if (dir == "input") return PORT_IN; @@ -85,25 +85,28 @@ struct JsonFrontendImpl NPNR_ASSERT_FALSE("invalid json port direction"); } - PortType get_port_dir(const ModulePortDataType &port) { return lookup_portdir(port["direction"].string_value()); } + PortType get_port_dir(const ModulePortDataType &port) const + { + return lookup_portdir(port["direction"].string_value()); + } - int get_array_offset(const Json &obj) + int get_array_offset(const Json &obj) const { auto offset = obj["offset"]; return offset.is_null() ? 0 : offset.int_value(); } - bool is_array_upto(const Json &obj) + bool is_array_upto(const Json &obj) const { auto upto = obj["upto"]; return upto.is_null() ? false : bool(upto.int_value()); } - const BitVectorDataType &get_port_bits(const ModulePortDataType &port) { return port["bits"].array_items(); } + const BitVectorDataType &get_port_bits(const ModulePortDataType &port) const { return port["bits"].array_items(); } - const std::string &get_cell_type(const CellDataType &cell) { return cell["type"].string_value(); } + const std::string &get_cell_type(const CellDataType &cell) const { return cell["type"].string_value(); } - Property parse_property(const Json &val) + Property parse_property(const Json &val) const { if (val.is_number()) return Property(val.int_value(), 32); @@ -111,7 +114,7 @@ struct JsonFrontendImpl return Property::from_string(val.string_value()); } - template void foreach_attr(const Json &obj, TFunc Func) + template void foreach_attr(const Json &obj, TFunc Func) const { const auto &attrs = obj["attributes"]; if (attrs.is_null()) @@ -121,7 +124,7 @@ struct JsonFrontendImpl } } - template void foreach_param(const Json &obj, TFunc Func) + template void foreach_param(const Json &obj, TFunc Func) const { const auto ¶ms = obj["parameters"]; if (params.is_null()) @@ -131,39 +134,36 @@ struct JsonFrontendImpl } } - template void foreach_port_dir(const CellDataType &cell, TFunc Func) + template void foreach_port_dir(const CellDataType &cell, TFunc Func) const { for (const auto &pdir : cell["port_directions"].object_items()) Func(pdir.first, lookup_portdir(pdir.second.string_value())); } - template void foreach_port_conn(const CellDataType &cell, TFunc Func) + template void foreach_port_conn(const CellDataType &cell, TFunc Func) const { for (const auto &pconn : cell["connections"].object_items()) - Func(pconn.first, pconn.second); + Func(pconn.first, pconn.second.array_items()); } - template const BitVectorDataType &get_net_bits(const NetnameDataType &net) - { - return net["bits"].array_items(); - } + const BitVectorDataType &get_net_bits(const NetnameDataType &net) const { return net["bits"].array_items(); } - int get_vector_length(const BitVectorDataType &bits) { return int(bits.size()); } + int get_vector_length(const BitVectorDataType &bits) const { return int(bits.size()); } - bool is_vector_bit_constant(const BitVectorDataType &bits, int i) + bool is_vector_bit_constant(const BitVectorDataType &bits, int i) const { NPNR_ASSERT(i < int(bits.size())); return bits[i].is_string(); } - char get_vector_bit_constval(const BitVectorDataType &bits, int i) + char get_vector_bit_constval(const BitVectorDataType &bits, int i) const { auto s = bits.at(i).string_value(); NPNR_ASSERT(s.size() == 1); return s.at(0); } - int get_vector_bit_signal(const BitVectorDataType &bits, int i) + int get_vector_bit_signal(const BitVectorDataType &bits, int i) const { NPNR_ASSERT(bits.at(i).is_number()); return bits.at(i).int_value(); @@ -182,7 +182,7 @@ bool parse_json(std::istream &in, const std::string &filename, Context *ctx) if (root.is_null()) log_error("Failed to parse JSON file '%s': %s.\n", filename.c_str(), error.c_str()); } - run_frontend(ctx, JsonFrontendImpl(root)); + GenericFrontend(ctx, JsonFrontendImpl(root))(); return true; } -- cgit v1.2.3 From 3e21f894f4cbf843fbf3c9d1603886e63f2a8d5b Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 15 Nov 2019 18:04:02 +0000 Subject: frontend: Improved error handling and fixes Signed-off-by: David Shah --- frontend/json_frontend.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'frontend/json_frontend.cc') diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc index 37c1dabd..2eb0a39b 100644 --- a/frontend/json_frontend.cc +++ b/frontend/json_frontend.cc @@ -181,6 +181,10 @@ bool parse_json(std::istream &in, const std::string &filename, Context *ctx) root = Json::parse(json_str, error, JsonParse::COMMENTS); if (root.is_null()) log_error("Failed to parse JSON file '%s': %s.\n", filename.c_str(), error.c_str()); + root = root["modules"]; + if (root.is_null()) + log_error("JSON file '%s' doesn't look like a netlist (doesn't contain \"modules\" key)\n", + filename.c_str()); } GenericFrontend(ctx, JsonFrontendImpl(root))(); return true; -- cgit v1.2.3 From 28279b18fe219c182a97efa992f022c8d243ae28 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 18 Nov 2019 15:07:19 +0000 Subject: frontend/generic: Fix regressions Signed-off-by: David Shah --- frontend/json_frontend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontend/json_frontend.cc') diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc index 2eb0a39b..0debd9f2 100644 --- a/frontend/json_frontend.cc +++ b/frontend/json_frontend.cc @@ -190,4 +190,4 @@ bool parse_json(std::istream &in, const std::string &filename, Context *ctx) return true; } -NEXTPNR_NAMESPACE_END \ No newline at end of file +NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 14b18cb6fa8909cbe34bfb01c6ea43a2ccff9617 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 17:29:45 +0000 Subject: frontend: Support for loading settings and nextpnr state Signed-off-by: David Shah --- frontend/json_frontend.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'frontend/json_frontend.cc') diff --git a/frontend/json_frontend.cc b/frontend/json_frontend.cc index 0debd9f2..d2e6248e 100644 --- a/frontend/json_frontend.cc +++ b/frontend/json_frontend.cc @@ -134,6 +134,16 @@ struct JsonFrontendImpl } } + template void foreach_setting(const Json &obj, TFunc Func) const + { + const auto &settings = obj["settings"]; + if (settings.is_null()) + return; + for (const auto &setting : settings.object_items()) { + Func(setting.first, parse_property(setting.second)); + } + } + template void foreach_port_dir(const CellDataType &cell, TFunc Func) const { for (const auto &pdir : cell["port_directions"].object_items()) -- cgit v1.2.3