diff options
Diffstat (limited to 'nexus')
-rw-r--r-- | nexus/arch.h | 29 | ||||
-rw-r--r-- | nexus/pack.cc | 86 |
2 files changed, 106 insertions, 9 deletions
diff --git a/nexus/arch.h b/nexus/arch.h index 0b058bd7..47276f42 100644 --- a/nexus/arch.h +++ b/nexus/arch.h @@ -771,15 +771,26 @@ enum CellPinStyle PINDEF_0 = 0x10, // connect to 0 if not used PINDEF_1 = 0x20, // connect to 1 if not used - PINSTYLE_CIB = 0x11, // 'CIB' signal, floats high but explicitly zeroed if not used - PINSTYLE_CLK = 0x07, // CLK type signal, invertible and defaults to disconnected - PINSTYLE_CE = 0x27, // CE type signal, invertible and defaults to enabled - PINSTYLE_LSR = 0x17, // LSR type signal, invertible and defaults to not reset - PINSTYLE_DEDI = 0x00, // dedicated signals, leave alone - PINSTYLE_PU = 0x21, // signals that float high and default high - - PINSTYLE_INV_PD = 0x17, // invertible, pull down by default - PINSTYLE_INV_PU = 0x27, // invertible, pull up by default + PINGLB_CLK = 0x100, // pin is a 'clock' for global purposes + + PINSTYLE_CIB = 0x011, // 'CIB' signal, floats high but explicitly zeroed if not used + PINSTYLE_CLK = 0x107, // CLK type signal, invertible and defaults to disconnected + PINSTYLE_CE = 0x027, // CE type signal, invertible and defaults to enabled + PINSTYLE_LSR = 0x017, // LSR type signal, invertible and defaults to not reset + PINSTYLE_DEDI = 0x000, // dedicated signals, leave alone + PINSTYLE_PU = 0x021, // signals that float high and default high + + PINSTYLE_INV_PD = 0x017, // invertible, pull down by default + PINSTYLE_INV_PU = 0x027, // invertible, pull up by default +}; + +// This represents the mux options for a pin +enum CellPinMux +{ + PINMUX_SIG = 0, + PINMUX_0 = 1, + PINMUX_1 = 2, + PINMUX_INV = 3, }; // ----------------------------------------------------------------------- diff --git a/nexus/pack.cc b/nexus/pack.cc index eb740858..f367c3f8 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -261,6 +261,92 @@ struct NexusPacker generic_xform(ff_rules, true); } + std::unordered_map<IdString, BelId> reference_bels; + + void autocreate_ports(CellInfo *cell) + { + // Automatically create ports for all inputs of a cell; even if they were left off the instantiation + // so we can tie them to constants as appropriate + // This also checks for any cells that don't have corresponding bels + + if (!reference_bels.count(cell->type)) { + // We need to look up a corresponding bel to get the list of input ports + BelId ref_bel; + for (BelId bel : ctx->getBels()) { + if (ctx->getBelType(bel) != cell->type) + continue; + ref_bel = bel; + break; + } + if (ref_bel == BelId()) + log_error("Cell type '%s' instantiated as '%s' is not supported by this device.\n", + ctx->nameOf(cell->type), ctx->nameOf(cell)); + reference_bels[cell->type] = ref_bel; + } + + BelId bel = reference_bels.at(cell->type); + for (IdString pin : ctx->getBelPins(bel)) { + PortType dir = ctx->getBelPinType(bel, pin); + if (dir != PORT_IN) + continue; + if (cell->ports.count(pin)) + continue; + cell->ports[pin].name = pin; + cell->ports[pin].type = dir; + } + } + + bool is_port_inverted(CellInfo *cell, IdString port) + { + NetInfo *net = get_net_or_empty(cell, port); + if (net == nullptr || net->driver.cell == nullptr) + return false; + return (net->driver.cell->type == id_INV); + } + + void uninvert_port(CellInfo *cell, IdString port) + { + // Rewire a port so it is driven by the input to an inverter + NetInfo *net = get_net_or_empty(cell, port); + NPNR_ASSERT(net != nullptr && net->driver.cell != nullptr && net->driver.cell->type == id_INV); + CellInfo *inv = net->driver.cell; + disconnect_port(ctx, cell, port); + + NetInfo *inv_a = get_net_or_empty(inv, id_A); + if (inv_a != nullptr) { + connect_port(ctx, inv_a, cell, port); + } + } + + void trim_design() + { + // Remove unused inverters and high/low drivers + std::vector<IdString> trim_cells; + std::vector<IdString> trim_nets; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type != id_INV && ci->type != id_VLO && ci->type != id_VHI) + continue; + NetInfo *z = get_net_or_empty(ci, id_Z); + if (z == nullptr) { + trim_cells.push_back(ci->name); + continue; + } + if (!z->users.empty()) + continue; + + disconnect_port(ctx, ci, id_A); + + trim_cells.push_back(ci->name); + trim_nets.push_back(z->name); + } + + for (IdString rem_net : trim_nets) + ctx->nets.erase(rem_net); + for (IdString rem_cell : trim_cells) + ctx->cells.erase(rem_cell); + } + explicit NexusPacker(Context *ctx) : ctx(ctx) {} void operator()() |