diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2018-11-19 01:57:47 +0100 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2018-11-19 18:20:20 +0100 |
commit | bc9f2da470b96c4e2f65324a0da1ffe099b5e586 (patch) | |
tree | 7c05b3544a4ace9d69af28922751a5cd63d0d387 /ice40 | |
parent | 325d46e284fd7944b99929c1482e641a1db53931 (diff) | |
download | nextpnr-bc9f2da470b96c4e2f65324a0da1ffe099b5e586.tar.gz nextpnr-bc9f2da470b96c4e2f65324a0da1ffe099b5e586.tar.bz2 nextpnr-bc9f2da470b96c4e2f65324a0da1ffe099b5e586.zip |
ice40: Introduce the concept of forPadIn SB_GB
Those are cells that are created mainly to handle the various sources a
global network can be driven from other than a user net.
When the flag is set, this means the global network usually driven by
this BEL is in fact driven by something else and so that SB_GB BEL and
matching global network can't be used.
This is also what gets used to set the extra bits during bitstream
generation.
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'ice40')
-rw-r--r-- | ice40/arch.cc | 2 | ||||
-rw-r--r-- | ice40/arch_place.cc | 2 | ||||
-rw-r--r-- | ice40/archdefs.h | 4 | ||||
-rw-r--r-- | ice40/bitstream.cc | 18 | ||||
-rw-r--r-- | ice40/pack.cc | 29 |
5 files changed, 53 insertions, 2 deletions
diff --git a/ice40/arch.cc b/ice40/arch.cc index 995150ac..3138b813 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -1044,6 +1044,8 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lcInfo.inputCount++; } else if (cell->type == id_SB_IO) { cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT"; + } else if (cell->type == id_SB_GB) { + cell->gbInfo.forPadIn = bool_or_default(cell->attrs, this->id("FOR_PAD_IN")); } } diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index a09a5092..41f9b640 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -161,6 +161,8 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const return getBelPackagePin(bel) != ""; } else if (cell->type == id_SB_GB) { + if (cell->gbInfo.forPadIn) + return true; NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); diff --git a/ice40/archdefs.h b/ice40/archdefs.h index b9614c07..8dcf0365 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -152,6 +152,10 @@ struct ArchCellInfo bool lvds; // TODO: clk packing checks... } ioInfo; + struct + { + bool forPadIn; + } gbInfo; }; }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 5d138798..c32680ee 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -269,6 +269,9 @@ void write_asc(const Context *ctx, std::ostream &out) config.at(y).at(x).resize(rows, std::vector<int8_t>(cols)); } } + + std::vector<std::tuple<int, int, int>> extra_bits; + out << ".comment from next-pnr" << std::endl; switch (ctx->args.type) { @@ -513,7 +516,16 @@ void write_asc(const Context *ctx, std::ostream &out) } } } else if (cell.second->type == ctx->id("SB_GB")) { - // no cell config bits + if (cell.second->gbInfo.forPadIn) { + Loc gb_loc = ctx->getBelLocation(bel); + for (int i = 0; i < ci.num_global_networks; i++) { + if ((gb_loc.x == ci.global_network_info[i].gb_x) && (gb_loc.y == ci.global_network_info[i].gb_y)) { + extra_bits.push_back(std::make_tuple(ci.global_network_info[i].pi_eb_bank, + ci.global_network_info[i].pi_eb_x, + ci.global_network_info[i].pi_eb_y)); + } + } + } } else if (cell.second->type == ctx->id("ICESTORM_RAM")) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; @@ -795,6 +807,10 @@ void write_asc(const Context *ctx, std::ostream &out) } } + // Write extra-bits + for (auto eb : extra_bits) + out << ".extra_bit " << std::get<0>(eb) << " " << std::get<1>(eb) << " " << std::get<2>(eb) << std::endl; + // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { diff --git a/ice40/pack.cc b/ice40/pack.cc index d689fa69..cae6ab8c 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -381,6 +381,33 @@ static void pack_constants(Context *ctx) } } +static std::unique_ptr<CellInfo> create_padin_gbuf(Context *ctx, CellInfo *cell, IdString port_name, + std::string gbuf_name) +{ + // Find the matching SB_GB BEL connected to the same global network + BelId gb_bel; + BelId bel = ctx->getBelByName(ctx->id(cell->attrs[ctx->id("BEL")])); + auto wire = ctx->getBelPinWire(bel, port_name); + for (auto src_bel : ctx->getWireBelPins(wire)) { + if (ctx->getBelType(src_bel.bel) == id_SB_GB && src_bel.pin == id_GLOBAL_BUFFER_OUTPUT) { + gb_bel = src_bel.bel; + break; + } + } + + NPNR_ASSERT(gb_bel != BelId()); + + // Create a SB_GB Cell and lock it there + std::unique_ptr<CellInfo> gb = create_ice_cell(ctx, ctx->id("SB_GB"), gbuf_name); + gb->attrs[ctx->id("FOR_PAD_IN")] = "1"; + gb->attrs[ctx->id("BEL")] = ctx->getBelName(gb_bel).str(ctx); + + // Reconnect the net to that port for easier identification it's a global net + replace_port(cell, port_name, gb.get(), id_GLOBAL_BUFFER_OUTPUT); + + return gb; +} + static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) { return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || @@ -1003,13 +1030,13 @@ bool Arch::pack() try { log_break(); pack_constants(ctx); - promote_globals(ctx); pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); pack_carries(ctx); pack_ram(ctx); pack_special(ctx); + promote_globals(ctx); ctx->assignArchInfo(); constrain_chains(ctx); ctx->assignArchInfo(); |