frontend: JSON implementation of the generic framework
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
240561c370
commit
77cbd70a72
@ -56,11 +56,11 @@
|
||||
* PortType get_port_dir(const ModulePortDataType &port);
|
||||
* gets the PortType direction of a module port
|
||||
*
|
||||
* int get_port_offset(const ModulePortDataType &port);
|
||||
* gets the start bit number of a port
|
||||
* int get_array_offset(const ModulePortDataType &port);
|
||||
* gets the start bit number of a port or netname entry
|
||||
*
|
||||
* bool is_port_upto(const ModulePortDataType &port);
|
||||
* returns true if a port is an "upto" type port
|
||||
* bool is_array_upto(const ModulePortDataType &port);
|
||||
* returns true if a port/net is an "upto" type port or netname entry
|
||||
*
|
||||
* const BitVectorDataType &get_port_bits(const ModulePortDataType &port);
|
||||
* gets the bit vector of a module port
|
||||
@ -108,6 +108,14 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
// Used for hierarchy resolution
|
||||
struct ModuleInfo
|
||||
{
|
||||
bool is_top = false, is_blackbox = false, is_whitebox = false;
|
||||
inline bool is_box() const { return is_blackbox || is_whitebox; }
|
||||
std::unordered_set<IdString> instantiated_celltypes;
|
||||
};
|
||||
|
||||
template <typename FrontendType> struct GenericFrontend
|
||||
{
|
||||
GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {}
|
||||
@ -119,14 +127,6 @@ template <typename FrontendType> struct GenericFrontend
|
||||
using netname_dat_t = typename FrontendType::NetnameDataType;
|
||||
using bitvector_t = typename FrontendType::BitVectorDataType;
|
||||
|
||||
// Used for hierarchy resolution
|
||||
struct ModuleInfo
|
||||
{
|
||||
const mod_dat_t *mod_data;
|
||||
bool is_top = false, is_blackbox = false, is_whitebox = false;
|
||||
inline bool is_box() const { return is_blackbox || is_whitebox; }
|
||||
std::unordered_set<IdString> instantiated_celltypes;
|
||||
};
|
||||
std::unordered_map<IdString, ModuleInfo> mods;
|
||||
IdString top;
|
||||
|
||||
@ -137,7 +137,6 @@ template <typename FrontendType> struct GenericFrontend
|
||||
impl.foreach_module([&](const std::string &name, const mod_dat_t &mod) {
|
||||
IdString mod_id = ctx->id(name);
|
||||
auto &mi = mods[mod_id];
|
||||
mi.mod_data = &mod;
|
||||
impl.foreach_attr(mod, [&](const std::string &name, const Property &value) {
|
||||
if (name == "top")
|
||||
mi.is_top = (value.intval != 0);
|
||||
@ -147,7 +146,7 @@ template <typename FrontendType> struct GenericFrontend
|
||||
mi.is_whitebox = (value.intval != 0);
|
||||
});
|
||||
impl.foreach_cell(mod, [&](const std::string &name, const cell_dat_t &cell) {
|
||||
mi.instantiated_cells.insert(ctx->id(impl.get_cell_type(cell)));
|
||||
mi.instantiated_celltypes.insert(ctx->id(impl.get_cell_type(cell)));
|
||||
});
|
||||
});
|
||||
// First of all, see if a top module has been manually specified
|
||||
@ -230,7 +229,7 @@ template <typename FrontendType> struct GenericFrontend
|
||||
std::unordered_map<IdString, std::vector<int>> port_to_bus;
|
||||
};
|
||||
|
||||
void import_module(HierModuleState &m, mod_dat_t *data)
|
||||
void import_module(HierModuleState &m, const mod_dat_t &data)
|
||||
{
|
||||
std::vector<NetInfo *> index_to_net;
|
||||
// Import port connections; for submodules only
|
||||
@ -289,10 +288,10 @@ template <typename FrontendType> struct GenericFrontend
|
||||
ctx->net_aliases[mergee->name] = base->name;
|
||||
// Update flat index of nets
|
||||
for (auto old_idx : net_old_indices.at(mergee->udata)) {
|
||||
net_old_indices.at(base).push_back(old_idx);
|
||||
net_old_indices.at(base->udata).push_back(old_idx);
|
||||
net_flatindex.at(old_idx) = base;
|
||||
}
|
||||
net_old_indices.at(base).push_back(mergee->udata);
|
||||
net_old_indices.at(base->udata).push_back(mergee->udata);
|
||||
net_flatindex.at(mergee->udata) = base;
|
||||
net_old_indices.at(mergee->udata).clear();
|
||||
// Remove merged net from context
|
||||
@ -349,6 +348,9 @@ template <typename FrontendType> struct GenericFrontend
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <typename FrontendType> void run_frontend(Context *ctx, const FrontendType &impl) {}
|
||||
template <typename FrontendType> void run_frontend(Context *ctx, const FrontendType &impl)
|
||||
{
|
||||
GenericFrontend<FrontendType>(ctx, impl);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
189
frontend/json_frontend.cc
Normal file
189
frontend/json_frontend.cc
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
template <typename TFunc> void foreach_module(TFunc Func)
|
||||
{
|
||||
for (const auto &mod : root.object_items())
|
||||
Func(mod.first, mod.second);
|
||||
}
|
||||
|
||||
template <typename TFunc> 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 <typename TFunc> 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 <typename TFunc> 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 <typename TFunc> 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 <typename TFunc> 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 <typename TFunc> 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 <typename TFunc> void foreach_port_conn(const CellDataType &cell, TFunc Func)
|
||||
{
|
||||
for (const auto &pconn : cell["connections"].object_items())
|
||||
Func(pconn.first, pconn.second);
|
||||
}
|
||||
|
||||
template <typename TFunc> 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<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());
|
||||
}
|
||||
run_frontend(ctx, JsonFrontendImpl(root));
|
||||
return true;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
26
frontend/json_frontend.h
Normal file
26
frontend/json_frontend.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 "nextpnr.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
bool parse_json(std::istream &in, const std::string &filename, Context *ctx);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
Loading…
Reference in New Issue
Block a user