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 --- frontend/frontend_base.h | 192 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 frontend/frontend_base.h (limited to 'frontend/frontend_base.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 -- cgit v1.2.3 From 6aaa9f5a3d02224f2760d993d114163ce7678e1f Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Nov 2019 12:11:17 +0000 Subject: frontend/base: Functions for port import Signed-off-by: David Shah --- frontend/frontend_base.h | 145 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 8b76cc85..42be2bfd 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -101,6 +101,7 @@ * */ +#include "design_utils.h" #include "log.h" #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN @@ -121,7 +122,7 @@ template struct GenericFrontend // Used for hierarchy resolution struct ModuleInfo { - mod_dat_t *mod_data; + 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 instantiated_celltypes; @@ -184,6 +185,148 @@ template struct GenericFrontend log_error("Failed to autodetect top module, please specify using --top.\n"); top = *(candidate_top.begin()); } + + // Create a unique name (guaranteed collision free) for a net or a cell; based on + // a base name and suffix. __unique__i will be be appended with increasing i + // if a collision is found until no collision + IdString unique_name(const std::string &base, const std::string &suffix, bool is_net) + { + IdString name; + int incr = 0; + do { + std::string comb = base + suffix; + if (incr > 0) { + comb += "__unique__"; + comb += std::to_string(incr); + } + name = ctx->id(comb); + incr++; + } while (is_net ? ctx->nets.count(name) : ctx->cells.count(name)); + return name; + } + + // A flat index of map; designed to cope with renaming + // A net's udata points into this index + std::vector net_flatindex; + + // This structure contains some structures specific to the import of a module at + // a certain point in the hierarchy + struct HierModuleState + { + bool is_toplevel; + std::string prefix; + // Map from index in module to "flat" index of nets + std::vector index_to_net_flatindex; + // Get a reference to index_to_net; resizing if + // appropriate + NetInfo *&net_by_idx(int idx) + { + NPNR_ASSERT(idx >= 0); + if (idx >= int(index_to_net_flatindex.size())) + index_to_net_flatindex.resize(idx + 1, nullptr); + return index_to_net_flatindex.at(idx); + } + std::unordered_map> port_to_bus; + }; + + void import_module(HierModuleState &m, mod_dat_t *data) + { + std::vector index_to_net; + // Import port connections; for submodules only + if (!m.is_toplevel) { + import_port_connections(m, data); + } + } + + // Add a constant-driving VCC or GND cell to make a net constant + // (constval can be [01xz], x and z or no-ops) + int const_autoidx = 0; + void add_constant_driver(HierModuleState &m, NetInfo *net, char constval) + { + + if (constval == 'x' || constval == 'z') + return; // 'x' or 'z' is the same as undriven + NPNR_ASSERT(constval == '0' || constval == '1'); + IdString cell_name = unique_name( + m.prefix, net->name.str(ctx) + (constval == '1' ? "$VCC$" : "$GND$") + std::to_string(const_autoidx++), + false); + CellInfo *cc = ctx->createCell(cell_name, ctx->id(constval == '1' ? "VCC" : "GND")); + cc->ports[ctx->id("Y")].name = ctx->id("Y"); + cc->ports[ctx->id("Y")].type = PORT_OUT; + if (net->driver.cell != nullptr) + log_error("Net '%s' is multiply driven by port %s.%s and constant '%c'\n", ctx->nameOf(net), + ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), constval); + connect_port(ctx, net, cc, ctx->id("Y")); + } + + // Merge two nets - e.g. if one net in a submodule bifurcates to two output bits and therefore two different + // parent nets + void merge_nets(NetInfo *base, NetInfo *mergee) + { + // Resolve drivers + if (mergee->driver.cell != nullptr) { + if (base->driver.cell != nullptr) + log_error("Attempting to merge nets '%s' and '%s' due to port connectivity; but this would result in a " + "multiply driven net\n", + ctx->nameOf(base), ctx->nameOf(mergee)); + else { + mergee->driver.cell->ports[mergee->driver.port].net = base; + base->driver = mergee->driver; + } + } + // Combine users + for (auto &usr : mergee->users) { + usr.cell->ports[usr.port].net = base; + base->users.push_back(usr); + } + // Point aliases to the new net + for (IdString alias : mergee->aliases) { + ctx->net_aliases[alias] = base->name; + base->aliases.push_back(alias); + } + // Create a new alias from mergee's name to new base name + ctx->net_aliases[mergee->name] = base->name; + // Update flat index of nets + net_flatindex.at(mergee->udata) = base; + // Remove merged net from context + ctx->nets.erase(mergee->name); + } + + // Import connections between a submodule and its parent + void import_port_connections(HierModuleState &m, const mod_dat_t &data) + { + impl.foreach_port(data, [&](const std::string &name, const mod_port_dat_t &port) { + // CHECK: should disconnected module inputs really just be skipped; or is it better + // to insert a ground driver? + if (!m.port_to_bus.count(ctx->id(name))) + return; + auto &p2b = m.port_to_bus.at(ctx->id(name)); + // Get direction and vector of port bits + PortType dir = impl.get_port_dir(port); + const auto &bv = impl.get_port_bits(port); + int bv_size = impl.get_vector_length(bv); + // Iterate over bits of port; making connections + for (int i = 0; i < std::min(bv_size, p2b.size()); i++) { + NetInfo *conn_net = p2b.at(i); + if (conn_net == nullptr) + continue; + if (impl.is_vector_bit_constant(bv, i)) { + // It is a constant, we might need to insert a constant driver here to drive the corresponding + // net in the parent + char constval = impl.get_vector_bit_constval(bv, i); + // Inputs cannot be driving a constant back to the parent + if (dir == PORT_IN) + log_error("Input port %s%s[%d] cannot be driving a constant '%c'.\n", m.prefix.c_str(), + port.c_str(), i, constval); + // Insert the constant driver + add_constant_driver(m, conn_net, constval); + } else { + // If not driving a constant; simply make the port bit net index in the submodule correspond + // to connected net in the parent module + } + } + }); + } }; } // namespace -- cgit v1.2.3 From 25867e3f231cc8ffe3ce87e6f1af1ca1d4c46146 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Nov 2019 13:51:28 +0000 Subject: frontend/base: Improve net indexing Signed-off-by: David Shah --- frontend/frontend_base.h | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 42be2bfd..35d4409c 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -205,9 +205,10 @@ template struct GenericFrontend return name; } - // A flat index of map; designed to cope with renaming + // A flat index of map; designed to cope with merging nets where pointers to nets would go stale // A net's udata points into this index std::vector net_flatindex; + std::vector> net_old_indices; // the other indices of a net in net_flatindex for merging // This structure contains some structures specific to the import of a module at // a certain point in the hierarchy @@ -216,17 +217,17 @@ template struct GenericFrontend bool is_toplevel; std::string prefix; // Map from index in module to "flat" index of nets - std::vector index_to_net_flatindex; + std::vector index_to_net_flatindex; // Get a reference to index_to_net; resizing if // appropriate - NetInfo *&net_by_idx(int idx) + int &net_by_idx(int idx) { NPNR_ASSERT(idx >= 0); if (idx >= int(index_to_net_flatindex.size())) - index_to_net_flatindex.resize(idx + 1, nullptr); + index_to_net_flatindex.resize(idx + 1, -1); return index_to_net_flatindex.at(idx); } - std::unordered_map> port_to_bus; + std::unordered_map> port_to_bus; }; void import_module(HierModuleState &m, mod_dat_t *data) @@ -287,7 +288,13 @@ template struct GenericFrontend // Create a new alias from mergee's name to new base name 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_flatindex.at(old_idx) = base; + } + net_old_indices.at(base).push_back(mergee->udata); net_flatindex.at(mergee->udata) = base; + net_old_indices.at(mergee->udata).clear(); // Remove merged net from context ctx->nets.erase(mergee->name); } @@ -307,9 +314,11 @@ template struct GenericFrontend int bv_size = impl.get_vector_length(bv); // Iterate over bits of port; making connections for (int i = 0; i < std::min(bv_size, p2b.size()); i++) { - NetInfo *conn_net = p2b.at(i); - if (conn_net == nullptr) + int conn_net = p2b.at(i); + if (conn_net == -1) continue; + NetInfo *conn_ni = net_flatindex.at(conn_net); + NPNR_ASSERT(conn_ni != nullptr); if (impl.is_vector_bit_constant(bv, i)) { // It is a constant, we might need to insert a constant driver here to drive the corresponding // net in the parent @@ -319,10 +328,20 @@ template struct GenericFrontend log_error("Input port %s%s[%d] cannot be driving a constant '%c'.\n", m.prefix.c_str(), port.c_str(), i, constval); // Insert the constant driver - add_constant_driver(m, conn_net, constval); + add_constant_driver(m, conn_ni, constval); } else { // If not driving a constant; simply make the port bit net index in the submodule correspond // to connected net in the parent module + int &submod_net = m.net_by_idx(impl.get_vector_bit_signal(bv, i)); + if (submod_net == -1) { + // A net at this index doesn't yet exist + // We can simply set this index to point to the net in the parent + submod_net = conn_net; + } else { + // A net at this index already exists (this would usually be a submodule net + // connected to more than one I/O port) + merge_nets(net_flatindex.at(submod_net), net_flatindex.at(conn_net)); + } } } }); -- cgit v1.2.3 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/frontend_base.h | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 35d4409c..426d9431 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -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 instantiated_celltypes; +}; + template struct GenericFrontend { GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {} @@ -119,14 +127,6 @@ template 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 instantiated_celltypes; - }; std::unordered_map mods; IdString top; @@ -137,7 +137,6 @@ template 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 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 struct GenericFrontend std::unordered_map> port_to_bus; }; - void import_module(HierModuleState &m, mod_dat_t *data) + void import_module(HierModuleState &m, const mod_dat_t &data) { std::vector index_to_net; // Import port connections; for submodules only @@ -289,10 +288,10 @@ template 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 struct GenericFrontend }; } // namespace -template void run_frontend(Context *ctx, const FrontendType &impl) {} +template void run_frontend(Context *ctx, const FrontendType &impl) +{ + GenericFrontend(ctx, impl); +} NEXTPNR_NAMESPACE_END \ No newline at end of file -- cgit v1.2.3 From 21b4965966048402424e76027ee9807d071e2b1c Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 14 Nov 2019 19:07:38 +0000 Subject: frontend/base: Functions for net[name] import Signed-off-by: David Shah --- frontend/frontend_base.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 426d9431..6d0e04c7 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -227,6 +227,8 @@ template struct GenericFrontend return index_to_net_flatindex.at(idx); } std::unordered_map> port_to_bus; + // All of the names given to a net + std::vector> net_names; }; void import_module(HierModuleState &m, const mod_dat_t &data) @@ -238,6 +240,120 @@ template struct GenericFrontend } } + // Multiple labels might refer to the same net. Resolve conflicts for the primary name thus: + // - (toplevel) ports are always preferred + // - names with fewer $ are always prefered + // - between equal $ counts, fewer .s are prefered + // - ties are resolved alphabetically + bool prefer_netlabel(HierModuleState &m, const std::string &a, const std::string &b) + { + if (m.port_to_bus.count(ctx->id(a))) + return true; + if (m.port_to_bus.count(ctx->id(b))) + return false; + + if (b.empty()) + return true; + long a_dollars = std::count(a.begin(), a.end(), '$'), b_dollars = std::count(b.begin(), b.end(), '$'); + if (a_dollars < b_dollars) + return true; + else if (a_dollars > b_dollars) + return false; + long a_dots = std::count(a.begin(), a.end(), '.'), b_dots = std::count(b.begin(), b.end(), '.'); + if (a_dots < b_dots) + return true; + else if (a_dots > b_dots) + return false; + return a < b; + }; + + // Get a net by index in modulestate (not flatindex); creating it if it doesn't already exist + NetInfo *create_or_get_net(HierModuleState &m, int idx) + { + std::string name; + if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { + // Use the rule above to find the preferred name for a net + name = m.net_names.at(idx).at(0); + for (size_t j = 1; j < m.net_names.at(idx).size(); j++) + if (prefer_netlabel(m.net_names.at(idx).at(j), name)) + name = m.net_names.at(idx).at(j); + } else { + name = "$frontend$" + std::to_string(idx); + } + NetInfo *net = ctx->createNet(unique_name(m.prefix, name, true)); + // Add to the flat index of nets + net->udata = int(net_flatindex.size()); + net_flatindex.push_back(net); + // Add to the module-level index of nets + auto &midx = m.net_by_idx(idx); + // Check we don't try and create more than one net with the same index + NPNR_ASSERT(midx == -1); + midx = net->udata; + // Create aliases for all possible names + if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { + for (const auto &name : m.net_names.at(idx)) { + IdString name_id = ctx->id(name); + net->aliases.push_back(name_id); + ctx->net_aliases[name_id] = net->name; + } + } else { + net->aliases.push_back(net->name); + ctx->net_aliases[net->name] = net->name; + } + } + + // Get the name of a vector bit given basename; settings and index + std::string get_bit_name(const std::string &base, int index, int length, int offset = 0, bool upto = false) + { + std::string port = base; + if (length == 1 && offset == 0) + return port; + int real_index; + if (upto) + real_index = offset + length - index - 1; // reversed ports like [0:7] + else + real_index = offset + index; // normal 'downto' ports like [7:0] + port += '['; + port += std::to_string(real_index); + port += ']'; + return port; + } + + // Import the netnames section of a module + void import_module_netnames(HierModuleState &m, const mod_dat_t &data) + { + impl.foreach_netname(data, [&](const std::string &basename, const netname_dat_t &nn) { + bool upto = impl.is_array_upto(nn); + int offset = impl.get_array_offset(nn); + const auto &bits = impl.get_net_bits(nn); + int width = impl.get_vector_length(bits); + for (int i = 0; i < width; i++) { + if (impl.is_vector_bit_constant(bits, i)) + continue; + + std::string bit_name = get_bit_name(basename, i, width, offset, upto); + + int net_bit = impl.get_vecotr_bit_signal(bits, i); + int mapped_bit = m.net_by_idx(net_bit); + if (mapped_bit == -1) { + // Net doesn't exist yet. Add the name here to the list of candidate names so we have that for when + // we create it later + if (net_bit >= int(m.net_names.size())) + m.net_names.resize(net_bit + 1); + m.net_names.at(net_bit).push_back(bit_name); + } else { + // Net already exists; add this name as an alias + NetInfo *ni = net_flatindex.at(mapped_bit); + IdString alias_name = ctx->id(m.prefix + bit_name); + if (ctx->net_aliases.count(alias_name)) + continue; // don't add duplicate aliases + ctx->net_aliases[alias_name] = ni->name; + ni->aliases.push_back(alias_name); + } + } + }); + } + // Add a constant-driving VCC or GND cell to make a net constant // (constval can be [01xz], x and z or no-ops) int const_autoidx = 0; -- cgit v1.2.3 From bed053251eece5a45e32eebc958fd5f3c683a9c1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 14 Nov 2019 20:01:45 +0000 Subject: frontend/base: Functions for leaf cell import Signed-off-by: David Shah --- frontend/frontend_base.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 6d0e04c7..beb0e31a 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -354,6 +354,78 @@ template struct GenericFrontend }); } + void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) + { + IdString name = unique_name(m.base, name_hint); + NetInfo *ni = ctx->createNet(name); + add_constant_driver(m, ni, constval); + } + + // Import a leaf cell - (white|black)box + void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) + { + IdString inst_name = unique_name(m.base, name, false); + CellInfo *ci = ctx->createCell(inst_name, ctx->id(get_cell_type(cd))); + // Import port directions + std::unordered_map port_dirs; + impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); + // Import port connectivity + impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) { + if (!port_dirs.count(ctx->id(name))) + log_error("Failed to get direction for port '%s' of cell '%s'\n", name.c_str(), inst_name.c_str(ctx)); + PortType dir = port_dirs.at(ctx->id(name)); + int width = impl.get_vector_length(bits); + for (int i = 0; i < width; i++) { + std::string port_bit_name = get_bit_name(name, i, width); + IdString port_bit_ids = ctx->id(port_bit_name); + // Create cell port + ci->ports[port_bit_ids].name = port_bit_ids; + ci->ports[port_bit_ids].type = dir; + // Resolve connectivity + NetInfo *net; + if (impl.is_vector_bit_constant(bits, i)) { + // Create a constant driver if one is needed + net = create_constant_net(m, name + "." + port_bit_name + "$const", + impl.get_vector_bit_constval(bits, i)); + } else { + // Otherwise, lookup (creating if needed) the net with this index + net = create_or_get_net(m, impl.get_vector_bit_signal(bits, i)); + } + NPNR_ASSERT(net != nullptr); + + // Check for multiple drivers + if (dir == PORT_OUT && net->driver.cell != nullptr) + log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), + ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), + port_bit_name.c_str()); + connect_port(ctx, net, ci, port_bit_ids); + } + }); + // Import attributes and parameters + impl.foreach_attr(cd, + [&](const std::string &name, const Property &value) { ci->attrs[ctx->id(name)] = value; }); + impl.foreach_param(cd, + [&](const std::string &name, const Property &value) { ci->params[ctx->id(name)] = value; }); + } + + // Import a submodule cell + void import_submodule_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) {} + + // Import the cells section of a module + void import_module_cells(HierModuleState &m, const mod_dat_t &data) + { + m.foreach_cell(data, [&](const std::string &cellname, const cell_dat_t &cd) { + IdString type = ctx->id(get_cell_type(cd)); + if (mods.count(type) && !mods.at(type).is_box()) { + // Module type is known; and not boxed. Import as a submodule by flattening hierarchy + import_submodule_cell(m, cellname, cd); + } else { + // Module type is unknown or boxes. Import as a leaf cell (nextpnr CellInfo) + import_leaf_cell(m, cellname, cd); + } + }); + } + // Add a constant-driving VCC or GND cell to make a net constant // (constval can be [01xz], x and z or no-ops) int const_autoidx = 0; -- cgit v1.2.3 From 98f93f39be7385179036e565fdf9e51eafbce173 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 14 Nov 2019 20:13:57 +0000 Subject: frontend/base: Functions for hierarchical submodule cell import Signed-off-by: David Shah --- frontend/frontend_base.h | 121 +++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 45 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index beb0e31a..dbf4b4bc 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -128,6 +128,7 @@ template struct GenericFrontend using bitvector_t = typename FrontendType::BitVectorDataType; std::unordered_map mods; + std::unordered_map mod_refs; IdString top; // Process the list of modules and determine @@ -137,6 +138,7 @@ template 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]; + mod_refs[mod_id] = mod; impl.foreach_attr(mod, [&](const std::string &name, const Property &value) { if (name == "top") mi.is_top = (value.intval != 0); @@ -354,75 +356,104 @@ template struct GenericFrontend }); } - void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) - { + void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) { IdString name = unique_name(m.base, name_hint); NetInfo *ni = ctx->createNet(name); add_constant_driver(m, ni, constval); } // Import a leaf cell - (white|black)box - void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) - { + void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { IdString inst_name = unique_name(m.base, name, false); CellInfo *ci = ctx->createCell(inst_name, ctx->id(get_cell_type(cd))); // Import port directions std::unordered_map port_dirs; - impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); + impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { + port_dirs[ctx->id(port)] = dir; + }); // Import port connectivity impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) { - if (!port_dirs.count(ctx->id(name))) - log_error("Failed to get direction for port '%s' of cell '%s'\n", name.c_str(), inst_name.c_str(ctx)); - PortType dir = port_dirs.at(ctx->id(name)); + if (!port_dirs.count(ctx->id(name))) + log_error("Failed to get direction for port '%s' of cell '%s'\n", name.c_str(), inst_name.c_str(ctx)); + PortType dir = port_dirs.at(ctx->id(name)); + int width = impl.get_vector_length(bits); + for (int i = 0; i < width; i++) { + std::string port_bit_name = get_bit_name(name, i, width); + IdString port_bit_ids = ctx->id(port_bit_name); + // Create cell port + ci->ports[port_bit_ids].name = port_bit_ids; + ci->ports[port_bit_ids].type = dir; + // Resolve connectivity + NetInfo *net; + if (impl.is_vector_bit_constant(bits, i)) { + // Create a constant driver if one is needed + net = create_constant_net(m, name + "." + port_bit_name + "$const", impl.get_vector_bit_constval(bits, i)); + } else { + // Otherwise, lookup (creating if needed) the net with this index + net = create_or_get_net(m, impl.get_vector_bit_signal(bits, i)); + } + NPNR_ASSERT(net != nullptr); + + // Check for multiple drivers + if (dir == PORT_OUT && net->driver.cell != nullptr) + log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), + ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), port_bit_name.c_str()); + connect_port(ctx, net, ci, port_bit_ids); + } + }); + // Import attributes and parameters + impl.foreach_attr(cd, [&](const std::string &name, const Property &value) { + ci->attrs[ctx->id(name)] = value; + }); + impl.foreach_param(cd, [&](const std::string &name, const Property &value) { + ci->params[ctx->id(name)] = value; + }); + } + + // Import a submodule cell + void import_submodule_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { + HierModuleState submod; + submod.is_toplevel = false; + // Create mapping from submodule port to nets (referenced by index in flatindex) + impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) { int width = impl.get_vector_length(bits); for (int i = 0; i < width; i++) { - std::string port_bit_name = get_bit_name(name, i, width); - IdString port_bit_ids = ctx->id(port_bit_name); - // Create cell port - ci->ports[port_bit_ids].name = port_bit_ids; - ci->ports[port_bit_ids].type = dir; - // Resolve connectivity - NetInfo *net; + // Index of port net in flatindex + int net_ref = -1; if (impl.is_vector_bit_constant(bits, i)) { // Create a constant driver if one is needed - net = create_constant_net(m, name + "." + port_bit_name + "$const", - impl.get_vector_bit_constval(bits, i)); + std::string port_bit_name = get_bit_name(name, i, width); + NetInfo *cnet = create_constant_net(m, name + "." + port_bit_name + "$const", impl.get_vector_bit_constval(bits, i)); + cnet->udata = int(net_flatindex.size()); + net_flatindex.push_back(cnet); + net_ref = cnet->udata; } else { - // Otherwise, lookup (creating if needed) the net with this index - net = create_or_get_net(m, impl.get_vector_bit_signal(bits, i)); + // Otherwise, lookup (creating if needed) the net with given in-module index + net_ref = create_or_get_net(m, impl.get_vector_bit_signal(bits, i))->udata; } - NPNR_ASSERT(net != nullptr); - - // Check for multiple drivers - if (dir == PORT_OUT && net->driver.cell != nullptr) - log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), - ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), - port_bit_name.c_str()); - connect_port(ctx, net, ci, port_bit_ids); + NPNR_ASSERT(net_ref != -1); + submod.port_to_bus[ctx->id(name)].push_back(net_ref); } }); - // Import attributes and parameters - impl.foreach_attr(cd, - [&](const std::string &name, const Property &value) { ci->attrs[ctx->id(name)] = value; }); - impl.foreach_param(cd, - [&](const std::string &name, const Property &value) { ci->params[ctx->id(name)] = value; }); + // Create prefix for submodule + submod.prefix = m.prefix; + submod.prefix += name; + submod.prefix += '.'; + // Do the submodule import + import_module(submod, mod_refs.at(ctx->id(impl.get_cell_type(cd)))); } - // Import a submodule cell - void import_submodule_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) {} - // Import the cells section of a module - void import_module_cells(HierModuleState &m, const mod_dat_t &data) - { + void import_module_cells(HierModuleState &m, const mod_dat_t &data) { m.foreach_cell(data, [&](const std::string &cellname, const cell_dat_t &cd) { - IdString type = ctx->id(get_cell_type(cd)); - if (mods.count(type) && !mods.at(type).is_box()) { - // Module type is known; and not boxed. Import as a submodule by flattening hierarchy - import_submodule_cell(m, cellname, cd); - } else { - // Module type is unknown or boxes. Import as a leaf cell (nextpnr CellInfo) - import_leaf_cell(m, cellname, cd); - } + IdString type = ctx->id(get_cell_type(cd)); + if (mods.count(type) && !mods.at(type).is_box()) { + // Module type is known; and not boxed. Import as a submodule by flattening hierarchy + import_submodule_cell(m, cellname, cd); + } else { + // Module type is unknown or boxes. Import as a leaf cell (nextpnr CellInfo) + import_leaf_cell(m, cellname, cd); + } }); } -- cgit v1.2.3 From a26b1a276dbb367beec1f07da19224d11109ef51 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 15 Nov 2019 17:43:32 +0000 Subject: frontend: Top level port import Signed-off-by: David Shah --- frontend/frontend_base.h | 210 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 158 insertions(+), 52 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index dbf4b4bc..196a28a3 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -119,6 +119,14 @@ struct ModuleInfo template struct GenericFrontend { GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {} + void operator()() + { + find_top_module(); + HierModuleState m; + m.is_toplevel = true; + m.prefix = ""; + import_module(m, mod_refs.at(top)); + } Context *ctx; const FrontendType &impl; using mod_dat_t = typename FrontendType::ModuleDataType; @@ -128,7 +136,7 @@ template struct GenericFrontend using bitvector_t = typename FrontendType::BitVectorDataType; std::unordered_map mods; - std::unordered_map mod_refs; + std::unordered_map mod_refs; IdString top; // Process the list of modules and determine @@ -236,10 +244,18 @@ template struct GenericFrontend void import_module(HierModuleState &m, const mod_dat_t &data) { std::vector index_to_net; - // Import port connections; for submodules only if (!m.is_toplevel) { + // Import port connections; for submodules only import_port_connections(m, data); + } else { + // Just create a list of ports for netname resolution + impl.foreach_port(m, + [&](const std::string &name, const mod_port_dat_t &) { m.port_to_bus[ctx->id(name)]; }); } + import_module_netnames(m, data); + import_module_cells(m, data); + if (m.is_toplevel) + import_toplevel_ports(m, data); } // Multiple labels might refer to the same net. Resolve conflicts for the primary name thus: @@ -356,62 +372,63 @@ template struct GenericFrontend }); } - void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) { + void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) + { IdString name = unique_name(m.base, name_hint); NetInfo *ni = ctx->createNet(name); add_constant_driver(m, ni, constval); } // Import a leaf cell - (white|black)box - void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { + void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) + { IdString inst_name = unique_name(m.base, name, false); CellInfo *ci = ctx->createCell(inst_name, ctx->id(get_cell_type(cd))); // Import port directions std::unordered_map port_dirs; - impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { - port_dirs[ctx->id(port)] = dir; - }); + impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); // Import port connectivity impl.foreach_port_conn(cd, [&](const std::string &name, const bitvector_t &bits) { - if (!port_dirs.count(ctx->id(name))) - log_error("Failed to get direction for port '%s' of cell '%s'\n", name.c_str(), inst_name.c_str(ctx)); - PortType dir = port_dirs.at(ctx->id(name)); - int width = impl.get_vector_length(bits); - for (int i = 0; i < width; i++) { - std::string port_bit_name = get_bit_name(name, i, width); - IdString port_bit_ids = ctx->id(port_bit_name); - // Create cell port - ci->ports[port_bit_ids].name = port_bit_ids; - ci->ports[port_bit_ids].type = dir; - // Resolve connectivity - NetInfo *net; - if (impl.is_vector_bit_constant(bits, i)) { - // Create a constant driver if one is needed - net = create_constant_net(m, name + "." + port_bit_name + "$const", impl.get_vector_bit_constval(bits, i)); - } else { - // Otherwise, lookup (creating if needed) the net with this index - net = create_or_get_net(m, impl.get_vector_bit_signal(bits, i)); - } - NPNR_ASSERT(net != nullptr); - - // Check for multiple drivers - if (dir == PORT_OUT && net->driver.cell != nullptr) - log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), - ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), port_bit_name.c_str()); - connect_port(ctx, net, ci, port_bit_ids); - } + if (!port_dirs.count(ctx->id(name))) + log_error("Failed to get direction for port '%s' of cell '%s'\n", name.c_str(), inst_name.c_str(ctx)); + PortType dir = port_dirs.at(ctx->id(name)); + int width = impl.get_vector_length(bits); + for (int i = 0; i < width; i++) { + std::string port_bit_name = get_bit_name(name, i, width); + IdString port_bit_ids = ctx->id(port_bit_name); + // Create cell port + ci->ports[port_bit_ids].name = port_bit_ids; + ci->ports[port_bit_ids].type = dir; + // Resolve connectivity + NetInfo *net; + if (impl.is_vector_bit_constant(bits, i)) { + // Create a constant driver if one is needed + net = create_constant_net(m, name + "." + port_bit_name + "$const", + impl.get_vector_bit_constval(bits, i)); + } else { + // Otherwise, lookup (creating if needed) the net with this index + net = create_or_get_net(m, impl.get_vector_bit_signal(bits, i)); + } + NPNR_ASSERT(net != nullptr); + + // Check for multiple drivers + if (dir == PORT_OUT && net->driver.cell != nullptr) + log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), + ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), + port_bit_name.c_str()); + connect_port(ctx, net, ci, port_bit_ids); + } }); // Import attributes and parameters - impl.foreach_attr(cd, [&](const std::string &name, const Property &value) { - ci->attrs[ctx->id(name)] = value; - }); - impl.foreach_param(cd, [&](const std::string &name, const Property &value) { - ci->params[ctx->id(name)] = value; - }); + impl.foreach_attr(cd, + [&](const std::string &name, const Property &value) { ci->attrs[ctx->id(name)] = value; }); + impl.foreach_param(cd, + [&](const std::string &name, const Property &value) { ci->params[ctx->id(name)] = value; }); } // Import a submodule cell - void import_submodule_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { + void import_submodule_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) + { HierModuleState submod; submod.is_toplevel = false; // Create mapping from submodule port to nets (referenced by index in flatindex) @@ -423,7 +440,8 @@ template struct GenericFrontend if (impl.is_vector_bit_constant(bits, i)) { // Create a constant driver if one is needed std::string port_bit_name = get_bit_name(name, i, width); - NetInfo *cnet = create_constant_net(m, name + "." + port_bit_name + "$const", impl.get_vector_bit_constval(bits, i)); + NetInfo *cnet = create_constant_net(m, name + "." + port_bit_name + "$const", + impl.get_vector_bit_constval(bits, i)); cnet->udata = int(net_flatindex.size()); net_flatindex.push_back(cnet); net_ref = cnet->udata; @@ -444,16 +462,104 @@ template struct GenericFrontend } // Import the cells section of a module - void import_module_cells(HierModuleState &m, const mod_dat_t &data) { + void import_module_cells(HierModuleState &m, const mod_dat_t &data) + { m.foreach_cell(data, [&](const std::string &cellname, const cell_dat_t &cd) { - IdString type = ctx->id(get_cell_type(cd)); - if (mods.count(type) && !mods.at(type).is_box()) { - // Module type is known; and not boxed. Import as a submodule by flattening hierarchy - import_submodule_cell(m, cellname, cd); - } else { - // Module type is unknown or boxes. Import as a leaf cell (nextpnr CellInfo) - import_leaf_cell(m, cellname, cd); - } + IdString type = ctx->id(get_cell_type(cd)); + if (mods.count(type) && !mods.at(type).is_box()) { + // Module type is known; and not boxed. Import as a submodule by flattening hierarchy + import_submodule_cell(m, cellname, cd); + } else { + // Module type is unknown or boxes. Import as a leaf cell (nextpnr CellInfo) + import_leaf_cell(m, cellname, cd); + } + }); + } + + // Create a top level input/output buffer + CellInfo *create_iobuf(NetInfo *net, PortType dir, const std::string &name) + { + // Skip IOBUF insertion if this is a design checkpoint (where they will already exist) + if (ctx->settings.count(ctx->id("synth"))) + return nullptr; + IdString name_id = ctx->id(name); + if (ctx->cells.count(name_id)) + log_error("Cell '%s' of type '%s' with the same name as a top-level IO is not allowed.\n", name.c_str(), + ctx->cells.at(name_id)->type.c_str(ctx)); + CellInfo *iobuf = ctx->createCell(name_id, ctx->id("unknown_iob")); + // Copy attributes from net to IOB + for (auto &attr : net->attrs) + iobuf->attrs[attr.first] = attr.second; + // What we do now depends on port type + if (dir == PORT_IN) { + iobuf->type = ctx->id("$nextpnr_ibuf"); + iobuf->addOutput(ctx->id("O")); + if (net->driver.cell != nullptr) { + CellInfo *drv = net->driver.cell; + if (drv->type != ctx->id("$nextpnr_iobuf")) + log_error("Net '%s' is multiply driven by cell port %s.%s and top level input '%s'.\n", + ctx->nameOf(net), ctx->nameOf(drv), ctx->nameOf(net->driver.port), name.c_str()); + // Special case: input, etc, directly drives inout + // Use the input net of the inout instead + net = drv->ports.at(ctx->id("I")).net; + } + NPNR_ASSERT(net->driver.cell == nullptr); + // Connect IBUF output and net + connect_port(ctx, net, iobuf, ctx->id("O")); + } else if (dir == PORT_OUT) { + iobuf->type = ctx->id("$nextpnr_obuf"); + iobuf->addInput(ctx->id("I")); + // Connect IBUF input and net + connect_port(ctx, net, iobuf, ctx->id("I")); + } else if (dir == PORT_INOUT) { + iobuf->type = ctx->id("$nextpnr_iobuf"); + iobuf->addInput(ctx->id("I")); + iobuf->addOutput(ctx->id("O")); + // Need to bifurcate the net to avoid multiple drivers and split + // the input/output parts of an inout + // Create a new net connecting only the current net's driver and the IOBUF input + // Then use the IOBUF output to drive all of the current net's users + NetInfo *split_iobuf_i = ctx->createNet(unique_name("", "$" + name + "$iobuf_i", true)); + auto drv = net->driver; + if (drv.cell != nullptr) { + disconnect_port(ctx, drv.cell, drv.port); + connect_port(ctx, split_iobuf_i, drv.cell, drv.port); + } + connect_port(ctx, split_iobuf_i, iobuf, ctx->id("I")); + NPNR_ASSERT(net->driver.cell == nullptr); + connect_port(ctx, net, iobuf, ctx->id("O")); + } + + PortInfo pinfo; + pinfo.name = name_id; + pinfo.net = net; + pinfo.type = dir; + ctx->ports[pinfo.name] = pinfo; + + return iobuf; + } + + // Import ports of the top level module + void import_toplevel_ports(HierModuleState &m, const mod_dat_t &data) + { + m.foreach_port(data, [&](const std::string &portname, const mod_port_dat_t &pd) { + const auto &port_bv = impl.get_port_bits(pd); + int offset = impl.get_array_offset(pd); + bool is_upto = impl.is_array_upto(pd); + int width = impl.get_vector_length(port_bv); + PortType dir = impl.get_port_dir(pd); + for (int i = 0; i < width; i++) { + std::string pbit_name = get_bit_name(portname, i, width, offset, is_upto); + NetInfo *port_net = nullptr; + if (impl.is_vector_bit_constant(port_bv, i)) { + // Port bit is constant. Need to create a new constant net. + port_net = create_constant_net(m, pbit_name + "$const", impl.get_vector_bit_constval(port_bv, i)); + } else { + // Port bit is a signal. Need to create/get the associated net + port_net = create_or_get_net(m, impl.get_vector_bit_signal(port_bv, i)); + } + create_iobuf(port_net, dir, pbit_name); + } }); } @@ -569,7 +675,7 @@ template struct GenericFrontend template void run_frontend(Context *ctx, const FrontendType &impl) { - GenericFrontend(ctx, impl); + GenericFrontend(ctx, impl)(); } 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/frontend_base.h | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 196a28a3..3484b5b4 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -37,66 +37,66 @@ * * Functions: * - * void foreach_module(Func); + * void foreach_module(Func) const; * calls Func(const std::string &name, const ModuleDataType &mod); * for each module in the netlist * - * void foreach_port(const ModuleDataType &mod, Func); + * void foreach_port(const ModuleDataType &mod, Func) const; * 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); + * void foreach_cell(const ModuleDataType &mod, Func) const; + * calls Func(const std::string &name, const CellDataType &cell) * for each cell of mod * - * void foreach_netname(const ModuleDataType &mod, Func); + * void foreach_netname(const ModuleDataType &mod, Func) const; * calls Func(const std::string &name, const NetnameDataType &cell); * for each netname entry of mod * - * PortType get_port_dir(const ModulePortDataType &port); + * PortType get_port_dir(const ModulePortDataType &port) const; * gets the PortType direction of a module port * - * int get_array_offset(const ModulePortDataType &port); + * int get_array_offset(const ModulePortDataType &port) const; * gets the start bit number of a port or netname entry * - * bool is_array_upto(const ModulePortDataType &port); + * bool is_array_upto(const ModulePortDataType &port) const; * returns true if a port/net is an "upto" type port or netname entry * - * const BitVectorDataType &get_port_bits(const ModulePortDataType &port); + * const BitVectorDataType &get_port_bits(const ModulePortDataType &port) const; * gets the bit vector of a module port * - * const std::string& get_cell_type(const CellDataType &cell); + * const std::string& get_cell_type(const CellDataType &cell) const; * gets the type of a cell * - * void foreach_attr(const {ModuleDataType|CellDataType|ModulePortDataType|NetnameDataType} &obj, Func); + * void foreach_attr(const {ModuleDataType|CellDataType|ModulePortDataType|NetnameDataType} &obj, Func) const; * 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); + * void foreach_param(const CellDataType &obj, Func) const; * calls Func(const std::string &name, const Property &value); * for each parameter of a cell * - * void foreach_port_dir(const CellDataType &cell, Func); + * void foreach_port_dir(const CellDataType &cell, Func) const; * calls Func(const std::string &name, PortType dir); * for each port direction of a cell * - * void foreach_port_conn(const CellDataType &cell, Func); + * void foreach_port_conn(const CellDataType &cell, Func) const; * calls Func(const std::string &name, const BitVectorDataType &conn); * for each port connection of a cell * - * const BitVectorDataType &get_net_bits(const NetnameDataType &net); + * const BitVectorDataType &get_net_bits(const NetnameDataType &net) const; * gets the BitVector corresponding to the bits entry of a netname field * - * int get_vector_length(const BitVectorDataType &bits); + * int get_vector_length(const BitVectorDataType &bits) const; * gets the length of a BitVector * - * bool is_vector_bit_constant(const BitVectorDataType &bits, int i); + * bool is_vector_bit_constant(const BitVectorDataType &bits, int i) const; * returns true if bit of bits is constant * - * char get_vector_bit_constval(const BitVectorDataType &bits, int i); + * char get_vector_bit_constval(const BitVectorDataType &bits, int i) const; * returns a char [01xz] corresponding to the constant value of bit * - * int get_vector_bit_signal(const BitVectorDataType &bits, int i); + * int get_vector_bit_signal(const BitVectorDataType &bits, int i) const; * returns the signal number of vector bit * */ @@ -121,12 +121,15 @@ template struct GenericFrontend GenericFrontend(Context *ctx, const FrontendType &impl) : ctx(ctx), impl(impl) {} void operator()() { + // Find which module is top find_top_module(); HierModuleState m; m.is_toplevel = true; m.prefix = ""; + // Do the actual import, starting from the top level module import_module(m, mod_refs.at(top)); } + Context *ctx; const FrontendType &impl; using mod_dat_t = typename FrontendType::ModuleDataType; @@ -146,7 +149,7 @@ template 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]; - mod_refs[mod_id] = mod; + mod_refs.emplace(mod_id, mod); impl.foreach_attr(mod, [&](const std::string &name, const Property &value) { if (name == "top") mi.is_top = (value.intval != 0); @@ -249,7 +252,7 @@ template struct GenericFrontend import_port_connections(m, data); } else { // Just create a list of ports for netname resolution - impl.foreach_port(m, + impl.foreach_port(data, [&](const std::string &name, const mod_port_dat_t &) { m.port_to_bus[ctx->id(name)]; }); } import_module_netnames(m, data); @@ -293,7 +296,7 @@ template struct GenericFrontend // Use the rule above to find the preferred name for a net name = m.net_names.at(idx).at(0); for (size_t j = 1; j < m.net_names.at(idx).size(); j++) - if (prefer_netlabel(m.net_names.at(idx).at(j), name)) + if (prefer_netlabel(m, m.net_names.at(idx).at(j), name)) name = m.net_names.at(idx).at(j); } else { name = "$frontend$" + std::to_string(idx); @@ -318,6 +321,7 @@ template struct GenericFrontend net->aliases.push_back(net->name); ctx->net_aliases[net->name] = net->name; } + return net; } // Get the name of a vector bit given basename; settings and index @@ -351,7 +355,7 @@ template struct GenericFrontend std::string bit_name = get_bit_name(basename, i, width, offset, upto); - int net_bit = impl.get_vecotr_bit_signal(bits, i); + int net_bit = impl.get_vector_bit_signal(bits, i); int mapped_bit = m.net_by_idx(net_bit); if (mapped_bit == -1) { // Net doesn't exist yet. Add the name here to the list of candidate names so we have that for when @@ -372,18 +376,20 @@ template struct GenericFrontend }); } - void create_constant_net(HierModuleState &m, const std::string name_hint, char constval) + // Create a new constant net; given a hint for what the name should be and its value + NetInfo *create_constant_net(HierModuleState &m, const std::string &name_hint, char constval) { - IdString name = unique_name(m.base, name_hint); + IdString name = unique_name(m.prefix, name_hint, true); NetInfo *ni = ctx->createNet(name); add_constant_driver(m, ni, constval); + return ni; } // Import a leaf cell - (white|black)box void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { - IdString inst_name = unique_name(m.base, name, false); - CellInfo *ci = ctx->createCell(inst_name, ctx->id(get_cell_type(cd))); + IdString inst_name = unique_name(m.prefix, name, false); + CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd))); // Import port directions std::unordered_map port_dirs; impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); @@ -464,8 +470,8 @@ template struct GenericFrontend // Import the cells section of a module void import_module_cells(HierModuleState &m, const mod_dat_t &data) { - m.foreach_cell(data, [&](const std::string &cellname, const cell_dat_t &cd) { - IdString type = ctx->id(get_cell_type(cd)); + impl.foreach_cell(data, [&](const std::string &cellname, const cell_dat_t &cd) { + IdString type = ctx->id(impl.get_cell_type(cd)); if (mods.count(type) && !mods.at(type).is_box()) { // Module type is known; and not boxed. Import as a submodule by flattening hierarchy import_submodule_cell(m, cellname, cd); @@ -542,7 +548,7 @@ template struct GenericFrontend // Import ports of the top level module void import_toplevel_ports(HierModuleState &m, const mod_dat_t &data) { - m.foreach_port(data, [&](const std::string &portname, const mod_port_dat_t &pd) { + impl.foreach_port(data, [&](const std::string &portname, const mod_port_dat_t &pd) { const auto &port_bv = impl.get_port_bits(pd); int offset = impl.get_array_offset(pd); bool is_upto = impl.is_array_upto(pd); @@ -650,7 +656,7 @@ template struct GenericFrontend // Inputs cannot be driving a constant back to the parent if (dir == PORT_IN) log_error("Input port %s%s[%d] cannot be driving a constant '%c'.\n", m.prefix.c_str(), - port.c_str(), i, constval); + name.c_str(), i, constval); // Insert the constant driver add_constant_driver(m, conn_ni, constval); } else { @@ -673,9 +679,4 @@ template struct GenericFrontend }; } // namespace -template void run_frontend(Context *ctx, const FrontendType &impl) -{ - GenericFrontend(ctx, impl)(); -} - NEXTPNR_NAMESPACE_END \ No newline at end of file -- 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/frontend_base.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 3484b5b4..40d03863 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -104,6 +104,7 @@ #include "design_utils.h" #include "log.h" #include "nextpnr.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN namespace { @@ -193,8 +194,14 @@ template struct GenericFrontend for (auto &mod : mods) for (auto &c : mod.second.instantiated_celltypes) candidate_top.erase(c); - if (candidate_top.size() != 1) + if (candidate_top.size() != 1) { + if (candidate_top.size() == 0) + log_info("No candidate top level modules.\n"); + else + for (auto ctp : sorted(candidate_top)) + log_info("Candidate top module: '%s'\n", ctx->nameOf(ctp)); log_error("Failed to autodetect top module, please specify using --top.\n"); + } top = *(candidate_top.begin()); } -- cgit v1.2.3 From c9a0033c5c7d5bfcf75df3afb0f877e61a1d0df5 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 15 Nov 2019 18:08:27 +0000 Subject: frontend/base: Fix lookup of nets by module index Signed-off-by: David Shah --- frontend/frontend_base.h | 58 +++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 40d03863..35558d2f 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -298,37 +298,39 @@ template struct GenericFrontend // Get a net by index in modulestate (not flatindex); creating it if it doesn't already exist NetInfo *create_or_get_net(HierModuleState &m, int idx) { - std::string name; - if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { - // Use the rule above to find the preferred name for a net - name = m.net_names.at(idx).at(0); - for (size_t j = 1; j < m.net_names.at(idx).size(); j++) - if (prefer_netlabel(m, m.net_names.at(idx).at(j), name)) - name = m.net_names.at(idx).at(j); - } else { - name = "$frontend$" + std::to_string(idx); - } - NetInfo *net = ctx->createNet(unique_name(m.prefix, name, true)); - // Add to the flat index of nets - net->udata = int(net_flatindex.size()); - net_flatindex.push_back(net); - // Add to the module-level index of nets auto &midx = m.net_by_idx(idx); - // Check we don't try and create more than one net with the same index - NPNR_ASSERT(midx == -1); - midx = net->udata; - // Create aliases for all possible names - if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { - for (const auto &name : m.net_names.at(idx)) { - IdString name_id = ctx->id(name); - net->aliases.push_back(name_id); - ctx->net_aliases[name_id] = net->name; - } + if (midx != -1) { + return net_flatindex.at(midx); } else { - net->aliases.push_back(net->name); - ctx->net_aliases[net->name] = net->name; + std::string name; + if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { + // Use the rule above to find the preferred name for a net + name = m.net_names.at(idx).at(0); + for (size_t j = 1; j < m.net_names.at(idx).size(); j++) + if (prefer_netlabel(m, m.net_names.at(idx).at(j), name)) + name = m.net_names.at(idx).at(j); + } else { + name = "$frontend$" + std::to_string(idx); + } + NetInfo *net = ctx->createNet(unique_name(m.prefix, name, true)); + // Add to the flat index of nets + net->udata = int(net_flatindex.size()); + net_flatindex.push_back(net); + // Add to the module-level index of netsd + midx = net->udata; + // Create aliases for all possible names + if (idx < int(m.net_names.size()) && !m.net_names.at(idx).empty()) { + for (const auto &name : m.net_names.at(idx)) { + IdString name_id = ctx->id(name); + net->aliases.push_back(name_id); + ctx->net_aliases[name_id] = net->name; + } + } else { + net->aliases.push_back(net->name); + ctx->net_aliases[net->name] = net->name; + } + return net; } - return net; } // Get the name of a vector bit given basename; settings and index -- 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/frontend_base.h | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 35558d2f..d55e0329 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -538,6 +538,7 @@ template struct GenericFrontend auto drv = net->driver; if (drv.cell != nullptr) { disconnect_port(ctx, drv.cell, drv.port); + drv.cell->ports[drv.port].net = nullptr; connect_port(ctx, split_iobuf_i, drv.cell, drv.port); } connect_port(ctx, split_iobuf_i, iobuf, ctx->id("I")); @@ -557,25 +558,32 @@ template struct GenericFrontend // Import ports of the top level module void import_toplevel_ports(HierModuleState &m, const mod_dat_t &data) { - impl.foreach_port(data, [&](const std::string &portname, const mod_port_dat_t &pd) { - const auto &port_bv = impl.get_port_bits(pd); - int offset = impl.get_array_offset(pd); - bool is_upto = impl.is_array_upto(pd); - int width = impl.get_vector_length(port_bv); - PortType dir = impl.get_port_dir(pd); - for (int i = 0; i < width; i++) { - std::string pbit_name = get_bit_name(portname, i, width, offset, is_upto); - NetInfo *port_net = nullptr; - if (impl.is_vector_bit_constant(port_bv, i)) { - // Port bit is constant. Need to create a new constant net. - port_net = create_constant_net(m, pbit_name + "$const", impl.get_vector_bit_constval(port_bv, i)); - } else { - // Port bit is a signal. Need to create/get the associated net - port_net = create_or_get_net(m, impl.get_vector_bit_signal(port_bv, i)); + // For correct handling of inout ports driving other ports + // first import non-inouts then import inouts so that they bifurcate correctly + for (bool inout : {false, true}) { + impl.foreach_port(data, [&](const std::string &portname, const mod_port_dat_t &pd) { + const auto &port_bv = impl.get_port_bits(pd); + int offset = impl.get_array_offset(pd); + bool is_upto = impl.is_array_upto(pd); + int width = impl.get_vector_length(port_bv); + PortType dir = impl.get_port_dir(pd); + if ((dir == PORT_INOUT) != inout) + return; + for (int i = 0; i < width; i++) { + std::string pbit_name = get_bit_name(portname, i, width, offset, is_upto); + NetInfo *port_net = nullptr; + if (impl.is_vector_bit_constant(port_bv, i)) { + // Port bit is constant. Need to create a new constant net. + port_net = + create_constant_net(m, pbit_name + "$const", impl.get_vector_bit_constval(port_bv, i)); + } else { + // Port bit is a signal. Need to create/get the associated net + port_net = create_or_get_net(m, impl.get_vector_bit_signal(port_bv, i)); + } + create_iobuf(port_net, dir, pbit_name); } - create_iobuf(port_net, dir, pbit_name); - } - }); + }); + } } // Add a constant-driving VCC or GND cell to make a net constant @@ -688,4 +696,4 @@ template struct GenericFrontend }; } // namespace -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/frontend_base.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index d55e0329..c23e2196 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -76,6 +76,10 @@ * calls Func(const std::string &name, const Property &value); * for each parameter of a cell * + * void foreach_setting(const ModuleDataType &obj, Func) const; + * calls Func(const std::string &name, const Property &value); + * for each module-level setting + * * void foreach_port_dir(const CellDataType &cell, Func) const; * calls Func(const std::string &name, PortType dir); * for each port direction of a cell @@ -261,11 +265,23 @@ template struct GenericFrontend // Just create a list of ports for netname resolution impl.foreach_port(data, [&](const std::string &name, const mod_port_dat_t &) { m.port_to_bus[ctx->id(name)]; }); + // Import module-level attributes + impl.foreach_attr( + data, [&](const std::string &name, const Property &value) { ctx->attrs[ctx->id(name)] = value; }); + // Import settings + impl.foreach_setting(data, [&](const std::string &name, const Property &value) { + ctx->settings[ctx->id(name)] = value; + }); } import_module_netnames(m, data); import_module_cells(m, data); - if (m.is_toplevel) + if (m.is_toplevel) { import_toplevel_ports(m, data); + // Mark design as loaded through nextpnr + ctx->settings[ctx->id("synth")] = 1; + // Process nextpnr-specific attributes + ctx->attributesToArchInfo(); + } } // Multiple labels might refer to the same net. Resolve conflicts for the primary name thus: -- cgit v1.2.3 From 9f6031cda13a290903785a1c469af02838309b39 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 29 Nov 2019 15:58:02 +0000 Subject: frontend_base: Import cell hierarchy Signed-off-by: David Shah --- frontend/frontend_base.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index c23e2196..be764266 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -131,8 +131,10 @@ template struct GenericFrontend HierModuleState m; m.is_toplevel = true; m.prefix = ""; + m.path = top; + ctx->top_module = top; // Do the actual import, starting from the top level module - import_module(m, mod_refs.at(top)); + import_module(m, top.str(ctx), top.str(ctx), mod_refs.at(top)); } Context *ctx; @@ -239,6 +241,7 @@ template struct GenericFrontend { bool is_toplevel; std::string prefix; + IdString parent_path, path; // Map from index in module to "flat" index of nets std::vector index_to_net_flatindex; // Get a reference to index_to_net; resizing if @@ -255,8 +258,14 @@ template struct GenericFrontend std::vector> net_names; }; - void import_module(HierModuleState &m, const mod_dat_t &data) + void import_module(HierModuleState &m, const std::string &name, const std::string &type, const mod_dat_t &data) { + NPNR_ASSERT(!ctx->hierarchy.count(m.path)); + ctx->hierarchy[m.path].name = ctx->id(name); + ctx->hierarchy[m.path].type = ctx->id(type); + ctx->hierarchy[m.path].parent = m.parent_path; + ctx->hierarchy[m.path].fullpath = m.path; + std::vector index_to_net; if (!m.is_toplevel) { // Import port connections; for submodules only @@ -414,6 +423,7 @@ template struct GenericFrontend void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { IdString inst_name = unique_name(m.prefix, name, false); + ctx->hierarchy[m.path].leaf_cells[ctx->id(name)] = inst_name; CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd))); // Import port directions std::unordered_map port_dirs; @@ -488,8 +498,11 @@ template struct GenericFrontend submod.prefix = m.prefix; submod.prefix += name; submod.prefix += '.'; + submod.parent_path = m.path; + submod.path = ctx->id(m.path.str(ctx) + "/" + name); // Do the submodule import - import_module(submod, mod_refs.at(ctx->id(impl.get_cell_type(cd)))); + auto type = impl.get_cell_type(cd); + import_module(submod, name, type, mod_refs.at(ctx->id(type))); } // Import the cells section of a module -- cgit v1.2.3 From b1000870244dbb1a73198e23a859825865938b4c Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 29 Nov 2019 16:25:11 +0000 Subject: python: Add bindings for hierarchy structures Signed-off-by: David Shah --- frontend/frontend_base.h | 1 + 1 file changed, 1 insertion(+) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index be764266..9e16cb24 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -500,6 +500,7 @@ template struct GenericFrontend submod.prefix += '.'; submod.parent_path = m.path; submod.path = ctx->id(m.path.str(ctx) + "/" + name); + ctx->hierarchy[m.path].hier_cells[ctx->id(name)] = submod.path; // Do the submodule import auto type = impl.get_cell_type(cd); import_module(submod, name, type, mod_refs.at(ctx->id(type))); -- cgit v1.2.3 From fe40094216d0007797c51ff8894127b37a4ff045 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 1 Dec 2019 14:03:23 +0000 Subject: Preserve hierarchy through packing Signed-off-by: David Shah --- frontend/frontend_base.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontend/frontend_base.h') diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index 9e16cb24..45847e21 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -423,8 +423,10 @@ template struct GenericFrontend void import_leaf_cell(HierModuleState &m, const std::string &name, const cell_dat_t &cd) { IdString inst_name = unique_name(m.prefix, name, false); + ctx->hierarchy[m.path].leaf_cells_by_gname[inst_name] = ctx->id(name); ctx->hierarchy[m.path].leaf_cells[ctx->id(name)] = inst_name; CellInfo *ci = ctx->createCell(inst_name, ctx->id(impl.get_cell_type(cd))); + ci->hierpath = m.path; // Import port directions std::unordered_map port_dirs; impl.foreach_port_dir(cd, [&](const std::string &port, PortType dir) { port_dirs[ctx->id(port)] = dir; }); -- cgit v1.2.3