diff options
Diffstat (limited to 'nexus/pack.cc')
-rw-r--r-- | nexus/pack.cc | 101 |
1 files changed, 92 insertions, 9 deletions
diff --git a/nexus/pack.cc b/nexus/pack.cc index 3b53ea55..0ef3eb79 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -502,7 +502,7 @@ struct NexusPacker // Might have an output buffer (OB etc) connected to it is_npnr_iob = true; NetInfo *i = get_net_or_empty(ci, id_I); - if (i == nullptr && i->driver.cell != nullptr) { + if (i != nullptr && i->driver.cell != nullptr) { if (top_port.cell != nullptr) log_error("Top level '%s' has multiple input/output buffers\n", ctx->nameOf(port.first)); top_port = i->driver; @@ -531,21 +531,104 @@ struct NexusPacker } } + BelId get_io_bel(CellInfo *ci) + { + if (!ci->attrs.count(id_BEL)) + return BelId(); + return ctx->getBelByName(ctx->id(ci->attrs.at(id_BEL).as_string())); + } + void pack_io() { + std::unordered_set<IdString> iob_types = {id_IB, id_OB, id_OBZ, id_BB, + id_BB_I3C_A, id_SEIO33, id_SEIO18, id_DIFFIO18, + id_SEIO33_CORE, id_SEIO18_CORE, id_DIFFIO18_CORE}; + + std::unordered_map<IdString, XFormRule> io_rules; + + // For the low level primitives, make sure we always preserve their type + io_rules[id_SEIO33_CORE].new_type = id_SEIO33_CORE; + io_rules[id_SEIO18_CORE].new_type = id_SEIO18_CORE; + io_rules[id_DIFFIO18_CORE].new_type = id_DIFFIO18_CORE; + + // Some IO buffer types need a bit of pin renaming, too + io_rules[id_SEIO33].new_type = id_SEIO33_CORE; + io_rules[id_SEIO33].port_xform[id_PADDI] = id_O; + io_rules[id_SEIO33].port_xform[id_PADDO] = id_I; + io_rules[id_SEIO33].port_xform[id_PADDT] = id_T; + io_rules[id_SEIO33].port_xform[id_IOPAD] = id_B; + + io_rules[id_BB_I3C_A] = io_rules[id_SEIO33]; + + io_rules[id_SEIO18] = io_rules[id_SEIO33]; + io_rules[id_SEIO18].new_type = id_SEIO18_CORE; + + io_rules[id_DIFFIO18] = io_rules[id_SEIO33]; + io_rules[id_DIFFIO18].new_type = id_DIFFIO18_CORE; + + // Stage 0: deal with top level inserted IO buffers + prepare_io(); + + // Stage 1: setup constraints for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; - if (ci->type == id_SEIO33_CORE || ci->type == id_SEIO18_CORE) { - auto fnd_loc = ci->attrs.find(id_LOC); - if (fnd_loc == ci->attrs.end()) - continue; - BelId bel = ctx->get_pin_bel(fnd_loc->second.as_string()); - if (bel == BelId()) - log_error("cannot constrain IO '%s', no PIO pin named '%s'\n", ctx->nameOf(ci), - fnd_loc->second.as_string().c_str()); + // Iterate through all IO buffer primitives + if (!iob_types.count(ci->type)) + continue; + // We need all IO constrained so we can pick the right IO bel type + // An improvement would be to allocate unconstrained IO here + if (!ci->attrs.count(id_LOC)) + log_error("Found unconstrained IO '%s', these are currently unsupported\n", ctx->nameOf(ci)); + // Convert package pin constraint to bel constraint + std::string loc = ci->attrs.at(id_LOC).as_string(); + auto pad_info = ctx->get_pkg_pin_data(loc); + if (pad_info == nullptr) + log_error("IO '%s' is constrained to invalid pin '%s'\n", ctx->nameOf(ci), loc.c_str()); + auto func = ctx->get_pad_functions(pad_info); + BelId bel = ctx->get_pad_pio_bel(pad_info); + + if (bel == BelId()) { + log_error("IO '%s' is constrained to pin %s (%s) which is not a general purpose IO pin.\n", + ctx->nameOf(ci), loc.c_str(), func.c_str()); + } else { + + // Get IO type for reporting purposes + std::string io_type = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33"); + + log_info("Constraining %s IO '%s' to pin %s (%s%sbel %s)\n", io_type.c_str(), ctx->nameOf(ci), + loc.c_str(), func.c_str(), func.empty() ? "" : "; ", ctx->nameOfBel(bel)); ci->attrs[id_BEL] = ctx->getBelName(bel).str(ctx); } } + // Stage 2: apply rules for primitives that need them + generic_xform(io_rules, false); + // Stage 3: all other IO primitives become their bel type + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + // Iterate through all IO buffer primitives + if (!iob_types.count(ci->type)) + continue; + // Skip those dealt with in stage 2 + if (io_rules.count(ci->type)) + continue; + // For non-bidirectional IO, we also need to configure tristate and rename B + if (ci->type == id_IB) { + ctx->set_cell_pinmux(ci, id_T, PINMUX_1); + rename_port(ctx, ci, id_I, id_B); + } else if (ci->type == id_OB) { + ctx->set_cell_pinmux(ci, id_T, PINMUX_0); + rename_port(ctx, ci, id_O, id_B); + } else if (ci->type == id_OBZ) { + ctx->set_cell_pinmux(ci, id_T, PINMUX_SIG); + rename_port(ctx, ci, id_O, id_B); + } + // Get the IO bel + BelId bel = get_io_bel(ci); + // Set the cell type to the bel type + IdString type = ctx->getBelType(bel); + NPNR_ASSERT(type != IdString()); + ci->type = type; + } } explicit NexusPacker(Context *ctx) : ctx(ctx) {} |