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;