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>
This commit is contained in:
parent
325d46e284
commit
bc9f2da470
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -152,6 +152,10 @@ struct ArchCellInfo
|
||||
bool lvds;
|
||||
// TODO: clk packing checks...
|
||||
} ioInfo;
|
||||
struct
|
||||
{
|
||||
bool forPadIn;
|
||||
} gbInfo;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user