From fffc3b844730d1241d0056f989b3a9492d62005c Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Nov 2019 11:33:49 +0000 Subject: frontend/base: Top module handling Signed-off-by: David Shah --- CMakeLists.txt | 6 +- common/command.cc | 1 + frontend/frontend_base.h | 192 +++++++++++++++++++++++++++++++++++++++++++++++ frontend/generic.h | 102 ------------------------- 4 files changed, 197 insertions(+), 104 deletions(-) create mode 100644 frontend/frontend_base.h delete mode 100644 frontend/generic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9af4bb6c..e8fa4ec0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,7 +191,7 @@ if (BUILD_PYTHON) endif () endif() -include_directories(common/ json/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +include_directories(common/ json/ frontend/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) if(BUILD_HEAP) find_package (Eigen3 REQUIRED NO_MODULE) @@ -202,7 +202,9 @@ endif() aux_source_directory(common/ COMMON_SRC_FILES) aux_source_directory(json/ JSON_PARSER_FILES) -set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES}) +aux_source_directory(frontend/ FRONTEND_FILES) + +set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES} ${FRONTEND_FILES}) set(CMAKE_BUILD_TYPE Release) if(MINGW) diff --git a/common/command.cc b/common/command.cc index fd310789..13cd3498 100644 --- a/common/command.cc +++ b/common/command.cc @@ -35,6 +35,7 @@ #include #include "command.h" #include "design_utils.h" +#include "frontend_base.h" #include "jsonparse.h" #include "jsonwrite.h" #include "log.h" diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h new file mode 100644 index 00000000..8b76cc85 --- /dev/null +++ b/frontend/frontend_base.h @@ -0,0 +1,192 @@ +/* + * 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. + * + */ + +/* + * Generic Frontend Framework + * + * This is designed to make it possible to build frontends for parsing any format isomorphic to Yosys JSON [1] + * with maximal inlining and minimal need for overhead such as runtime polymorphism or extra wrapper types. + * + * [1] http://www.clifford.at/yosys/cmd_write_json.html + * + * The frontend should implement a class referred to as FrontendType that defines the following type(def)s and + * functions: + * + * Types: + * ModuleDataType: corresponds to a single entry in "modules" + * ModulePortDataType: corresponds to a single entry in "ports" of a module + * CellDataType: corresponds to a single entry in "cells" + * NetnameDataType: corresponds to a single entry in "netnames" + * BitVectorDataType: corresponds to a signal/constant bit vector (e.g. a "connections" field) + * + * Functions: + * + * void foreach_module(Func); + * calls Func(const std::string &name, const ModuleDataType &mod); + * for each module in the netlist + * + * void foreach_port(const ModuleDataType &mod, Func); + * calls Func(const std::string &name, const ModulePortDataType &port); + * for each port of mod + * + * void foreach_cell(const ModuleDataType &mod, Func); + * calls Func(const std::string &name, const CellDataType &cell); + * for each cell of mod + * + * void foreach_netname(const ModuleDataType &mod, Func); + * calls Func(const std::string &name, const NetnameDataType &cell); + * for each netname entry of mod + * + * 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 + * + * bool is_port_upto(const ModulePortDataType &port); + * returns true if a port is an "upto" type port + * + * const BitVectorDataType &get_port_bits(const ModulePortDataType &port); + * gets the bit vector of a module port + * + * const std::string& get_cell_type(const CellDataType &cell); + * gets the type of a cell + * + * void foreach_attr(const {ModuleDataType|CellDataType|ModulePortDataType|NetnameDataType} &obj, Func); + * calls Func(const std::string &name, const Property &value); + * for each attribute on a module, cell, module port or net + * + * void foreach_param(const CellDataType &obj, Func); + * calls Func(const std::string &name, const Property &value); + * for each parameter of a cell + * + * void foreach_port_dir(const CellDataType &cell, Func); + * calls Func(const std::string &name, PortType dir); + * for each port direction of a cell + * + * void foreach_port_conn(const CellDataType &cell, Func); + * calls Func(const std::string &name, const BitVectorDataType &conn); + * for each port connection of a cell + * + * const BitVectorDataType &get_net_bits(const NetnameDataType &net); + * gets the BitVector corresponding to the bits entry of a netname field + * + * int get_vector_length(const BitVectorDataType &bits); + * gets the length of a BitVector + * + * bool is_vector_bit_constant(const BitVectorDataType &bits, int i); + * returns true if bit of bits is constant + * + * char get_vector_bit_constval(const BitVectorDataType &bits, int i); + * returns a char [01xz] corresponding to the constant value of bit + * + * int get_vector_bit_signal(const BitVectorDataType &bits, int i); + * returns the signal number of vector bit + * + */ + +#include "log.h" +#include "nextpnr.h" +NEXTPNR_NAMESPACE_BEGIN + +namespace { + +template struct GenericFrontend +{ + GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {} + Context *ctx; + const FrontendType &impl; + using mod_dat_t = typename FrontendType::ModuleDataType; + using mod_port_dat_t = typename FrontendType::ModulePortDataType; + using cell_dat_t = typename FrontendType::CellDataType; + using netname_dat_t = typename FrontendType::NetnameDataType; + using bitvector_t = typename FrontendType::BitVectorDataType; + + // Used for hierarchy resolution + struct ModuleInfo + { + 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 instantiated_celltypes; + }; + std::unordered_map mods; + IdString top; + + // Process the list of modules and determine + // the top module + void find_top_module() + { + 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); + else if (name == "blackbox") + mi.is_blackbox = (value.intval != 0); + else if (name == "whitebox") + 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))); + }); + }); + // First of all, see if a top module has been manually specified + if (ctx->settings.count(ctx->id("frontend/top"))) { + IdString user_top = ctx->id(ctx->settings.at(ctx->id("frontend/top")).as_string()); + if (!mods.count(user_top)) + log_error("Top module '%s' not found!\n", ctx->nameOf(user_top)); + top = user_top; + return; + } + // If not, look for a module with the top attribute set + IdString top_by_attr; + for (auto &mod : mods) { + if (mod.second.is_top && !mod.second.is_box()) { + if (top_by_attr != IdString()) + log_error("Found multiple modules with (* top *) set (including %s and %s).\n", + ctx->nameOf(top_by_attr), ctx->nameOf(mod.first)); + top_by_attr = mod.first; + } + } + if (top_by_attr != IdString()) { + top = top_by_attr; + return; + } + // Finally, attempt to autodetect the top module using hierarchy + // (a module that is not a box and is not used as a cell by any other module) + std::unordered_set candidate_top; + for (auto &mod : mods) + if (!mod.second.is_box()) + candidate_top.insert(mod.first); + for (auto &mod : mods) + for (auto &c : mod.second.instantiated_celltypes) + candidate_top.erase(c); + if (candidate_top.size() != 1) + log_error("Failed to autodetect top module, please specify using --top.\n"); + top = *(candidate_top.begin()); + } +}; +} // namespace + +template void run_frontend(Context *ctx, const FrontendType &impl) {} + +NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/frontend/generic.h b/frontend/generic.h deleted file mode 100644 index 35428052..00000000 --- a/frontend/generic.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * - */ - -/* - * Generic Frontend Framework - * - * This is designed to make it possible to build frontends for parsing any format isomorphic to Yosys JSON [1] - * with maximal inlining and minimal need for overhead such as runtime polymorphism or extra wrapper types. - * - * [1] http://www.clifford.at/yosys/cmd_write_json.html - * - * The frontend should implement a class referred to as FrontendType that defines the following type(def)s and - * functions: - * - * Types: - * ModuleDataType: corresponds to a single entry in "modules" - * ModulePortDataType: corresponds to a single entry in "ports" of a module - * CellDataType: corresponds to a single entry in "cells" - * NetnameDataType: corresponds to a single entry in "netnames" - * BitVectorDataType: corresponds to a signal/constant bit vector (e.g. a "connections" field) - * - * Functions: - * - * void foreach_module(Func); - * calls Func(const std::string &name, const ModuleDataType &mod); - * for each module in the netlist - * - * void foreach_port(const ModuleDataType &mod, Func); - * calls Func(const std::string &name, const ModulePortDataType &port); - * for each port of mod - * - * void foreach_cell(const ModuleDataType &mod, Func); - * calls Func(const std::string &name, const CellDataType &cell); - * for each cell of mod - * - * void foreach_netname(const ModuleDataType &mod, Func); - * calls Func(const std::string &name, const NetnameDataType &cell); - * for each netname entry of mod - * - * 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 - * - * bool is_port_upto(const ModulePortDataType &port); - * returns true if a port is an "upto" type port - * - * const BitVectorDataType &get_port_bits(const ModulePortDataType &port); - * gets the bit vector of a module port - * - * const std::string& get_cell_type(const CellDataType &cell); - * gets the type of a cell - * - * void foreach_attr(const {ModuleDataType|CellDataType|ModulePortDataType|NetnameDataType} &obj, Func); - * calls Func(const std::string &name, const Property &value); - * for each attribute on a module, cell, module port or net - * - * void foreach_param(const CellDataType &obj, Func); - * calls Func(const std::string &name, const Property &value); - * for each parameter of a cell - * - * void foreach_port_dir(const CellDataType &cell, Func); - * calls Func(const std::string &name, PortType dir); - * for each port direction of a cell - * - * void foreach_port_conn(const CellDataType &cell, Func); - * calls Func(const std::string &name, const BitVectorDataType &conn); - * for each port connection of a cell - * - * const BitVectorDataType &get_net_bits(const NetnameDataType &net); - * gets the BitVector corresponding to the bits entry of a netname field - * - * int get_vector_length(const BitVectorDataType &bits); - * gets the length of a BitVector - * - * bool is_vector_bit_constant(const BitVectorDataType &bits, int i); - * returns true if bit of bits is constant - * - * char get_vector_bit_constval(const BitVectorDataType &bits, int i); - * returns a char [01xz] corresponding to the constant value of bit - * - * int get_vector_bit_signal(const BitVectorDataType &bits, int i); - * returns the signal number of vector bit - * - */ \ No newline at end of file -- cgit v1.2.3