2019-11-14 02:52:13 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 David Shah <dave@ds0.me>
|
|
|
|
*
|
|
|
|
* 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 <streambuf>
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
template <typename TFunc> void foreach_module(TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
for (const auto &mod : root.object_items())
|
|
|
|
Func(mod.first, mod.second);
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
template <typename TFunc> void foreach_port(ModuleDataType &mod, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
const auto &ports = mod["ports"];
|
|
|
|
if (ports.is_null())
|
|
|
|
return;
|
|
|
|
for (const auto &port : ports.object_items())
|
|
|
|
Func(port.first, port.second);
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
template <typename TFunc> void foreach_cell(ModuleDataType &mod, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
const auto &cells = mod["cells"];
|
|
|
|
if (cells.is_null())
|
|
|
|
return;
|
|
|
|
for (const auto &cell : cells.object_items())
|
|
|
|
Func(cell.first, cell.second);
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
template <typename TFunc> void foreach_netname(ModuleDataType &mod, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
const auto &netnames = mod["netnames"];
|
|
|
|
if (netnames.is_null())
|
|
|
|
return;
|
|
|
|
for (const auto &netname : netnames.object_items())
|
|
|
|
Func(netname.first, netname.second);
|
|
|
|
}
|
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
PortType lookup_portdir(const std::string &dir) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2020-01-21 04:30:43 +08:00
|
|
|
PortType get_port_dir(ModulePortDataType &port) const { return lookup_portdir(port["direction"].string_value()); }
|
2019-11-14 02:52:13 +08:00
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
int get_array_offset(const Json &obj) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
auto offset = obj["offset"];
|
|
|
|
return offset.is_null() ? 0 : offset.int_value();
|
|
|
|
}
|
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
bool is_array_upto(const Json &obj) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
auto upto = obj["upto"];
|
|
|
|
return upto.is_null() ? false : bool(upto.int_value());
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
BitVectorDataType &get_port_bits(ModulePortDataType &port) const { return port["bits"].array_items(); }
|
2019-11-14 02:52:13 +08:00
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
const std::string &get_cell_type(CellDataType &cell) const { return cell["type"].string_value(); }
|
2019-11-14 02:52:13 +08:00
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
Property parse_property(const Json &val) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
2020-02-02 00:23:05 +08:00
|
|
|
if (val.is_number()) {
|
|
|
|
if (val.int_value() != val.number_value())
|
|
|
|
log_error("Found an out-of-range integer parameter in the JSON file.\n"
|
|
|
|
"Please regenerate the input file with an up-to-date version of yosys.\n");
|
2019-11-14 02:52:13 +08:00
|
|
|
return Property(val.int_value(), 32);
|
2020-02-02 00:23:05 +08:00
|
|
|
} else {
|
2019-11-14 02:52:13 +08:00
|
|
|
return Property::from_string(val.string_value());
|
2020-02-02 00:23:05 +08:00
|
|
|
}
|
2019-11-14 02:52:13 +08:00
|
|
|
}
|
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
template <typename TFunc> void foreach_attr(const Json &obj, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
const auto &attrs = obj["attributes"];
|
|
|
|
if (attrs.is_null())
|
|
|
|
return;
|
|
|
|
for (const auto &attr : attrs.object_items()) {
|
|
|
|
Func(attr.first, parse_property(attr.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-16 01:55:02 +08:00
|
|
|
template <typename TFunc> void foreach_param(const Json &obj, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
const auto ¶ms = obj["parameters"];
|
|
|
|
if (params.is_null())
|
|
|
|
return;
|
|
|
|
for (const auto ¶m : params.object_items()) {
|
|
|
|
Func(param.first, parse_property(param.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-23 01:29:45 +08:00
|
|
|
template <typename TFunc> 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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
template <typename TFunc> void foreach_port_dir(CellDataType &cell, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
for (const auto &pdir : cell["port_directions"].object_items())
|
|
|
|
Func(pdir.first, lookup_portdir(pdir.second.string_value()));
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
template <typename TFunc> void foreach_port_conn(CellDataType &cell, TFunc Func) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
for (const auto &pconn : cell["connections"].object_items())
|
2019-11-16 01:55:02 +08:00
|
|
|
Func(pconn.first, pconn.second.array_items());
|
2019-11-14 02:52:13 +08:00
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
BitVectorDataType &get_net_bits(NetnameDataType &net) const { return net["bits"].array_items(); }
|
2019-11-14 02:52:13 +08:00
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
int get_vector_length(BitVectorDataType &bits) const { return int(bits.size()); }
|
2019-11-14 02:52:13 +08:00
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
bool is_vector_bit_constant(BitVectorDataType &bits, int i) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
NPNR_ASSERT(i < int(bits.size()));
|
|
|
|
return bits[i].is_string();
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
char get_vector_bit_constval(BitVectorDataType &bits, int i) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
auto s = bits.at(i).string_value();
|
|
|
|
NPNR_ASSERT(s.size() == 1);
|
|
|
|
return s.at(0);
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:34:58 +08:00
|
|
|
int get_vector_bit_signal(BitVectorDataType &bits, int i) const
|
2019-11-14 02:52:13 +08:00
|
|
|
{
|
|
|
|
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<char>(in)), std::istreambuf_iterator<char>());
|
|
|
|
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());
|
2019-11-16 02:04:02 +08:00
|
|
|
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());
|
2019-11-14 02:52:13 +08:00
|
|
|
}
|
2019-11-16 01:55:02 +08:00
|
|
|
GenericFrontend<JsonFrontendImpl>(ctx, JsonFrontendImpl(root))();
|
2019-11-14 02:52:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-11-18 23:07:19 +08:00
|
|
|
NEXTPNR_NAMESPACE_END
|