fabulous: improve pcf implementation, create global clock only if necessary (#1654)

* fabulous: report port as unconstrained unless BEL attr set

Signed-off-by: Leo Moser <leomoser99@gmail.com>

* fabulous: only create global clock if needed

Signed-off-by: Leo Moser <leomoser99@gmail.com>

---------

Signed-off-by: Leo Moser <leomoser99@gmail.com>
This commit is contained in:
Leo Moser 2026-03-02 18:26:04 +01:00 committed by GitHub
parent eba9764645
commit 50c2ca21a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 10 deletions

View File

@ -163,8 +163,6 @@ struct FabulousImpl : ViaductAPI
FabricConfig cfg; // TODO: non-default config
ViaductHelpers h;
WireId global_clk_wire;
std::string fasm_file;
std::string pcf_file;
@ -222,6 +220,7 @@ struct FabulousImpl : ViaductAPI
} else if (bel_type.in(id_InPass4_frame_config, id_OutPass4_frame_config)) {
WireId clk_wire = get_wire(tile, id_CLK, id_REG_CLK);
if (ctx->wires.at(clk_wire.index).uphill.empty()) {
WireId global_clk_wire = get_wire(ctx->id("X0Y0"), id_CLK, id_CLK);
add_pseudo_pip(global_clk_wire, clk_wire, id_global_clock);
}
ctx->addBelInput(bel, id_CLK, clk_wire);
@ -234,6 +233,7 @@ struct FabulousImpl : ViaductAPI
} else if (bel_type == id_RegFile_32x4) {
WireId clk_wire = get_wire(tile, id_CLK, id_REG_CLK);
ctx->addBelInput(bel, id_CLK, clk_wire);
WireId global_clk_wire = get_wire(ctx->id("X0Y0"), id_CLK, id_CLK);
add_pseudo_pip(global_clk_wire, clk_wire, id_global_clock);
for (parser_view p : ports) {
IdString port_id = p.to_id(ctx);
@ -270,6 +270,7 @@ struct FabulousImpl : ViaductAPI
// TODO: split LC mode, LUT permutation pseudo-switchbox, LUT thru pseudo-pips
WireId clk_wire = get_wire(tile, ctx->idf("L%s_CLK", idx.c_str(ctx)), id_LUT_CLK);
ctx->addBelInput(bel, id_CLK, clk_wire);
WireId global_clk_wire = get_wire(ctx->id("X0Y0"), id_CLK, id_CLK);
add_pseudo_pip(global_clk_wire, clk_wire, id_global_clock);
blk_trk->set_bel_type(bel, BelFlags::BLOCK_CLB, BelFlags::FUNC_LC_COMB, loc.z);
for (parser_view p : ports) {
@ -303,10 +304,13 @@ struct FabulousImpl : ViaductAPI
void init_global_clock()
{
// TODO: how do we extend this to more complex clocking topologies?
BelId global_clk_bel =
ctx->addBel(IdStringList::concat(ctx->id("X0Y0"), id_CLK), id_Global_Clock, Loc(0, 0, 0), true, false);
global_clk_wire = ctx->addWire(IdStringList::concat(ctx->id("X0Y0"), id_CLK), id_CLK, 0, 0);
ctx->addBelOutput(global_clk_bel, id_CLK, global_clk_wire);
auto found = ctx->wire_by_name.find(IdStringList::concat(ctx->id("X0Y0"), id_CLK));
if (found != ctx->wire_by_name.end()) {
BelId global_clk_bel = ctx->addBel(IdStringList::concat(ctx->id("X0Y0"), id_CLK), id_Global_Clock,
Loc(0, 0, 0), true, false);
WireId global_clk_wire = get_wire(ctx->id("X0Y0"), id_CLK, id_CLK);
ctx->addBelOutput(global_clk_bel, id_CLK, global_clk_wire);
}
}
// TODO: this is for legacy fabulous only, the new code path can be a lot simpler
@ -314,7 +318,6 @@ struct FabulousImpl : ViaductAPI
{
std::ifstream in = open_data_rel("/npnroutput/bel.txt");
CsvParser csv(in);
init_global_clock();
while (csv.fetch_next_line()) {
IdString tile = csv.next_field().to_id(ctx);
int bel_x = csv.next_field().substr(1).to_int();
@ -345,6 +348,7 @@ struct FabulousImpl : ViaductAPI
BelId bel = ctx->addBel(IdStringList::concat(tile, bel_name), bel_type, loc, false, false);
handle_bel_ports(bel, tile, bel_type, ports);
}
init_global_clock();
postprocess_bels();
}
@ -352,7 +356,6 @@ struct FabulousImpl : ViaductAPI
{
std::ifstream in = open_data_rel("/.FABulous/bel.v2.txt");
CsvParser csv(in);
init_global_clock();
BelId curr_bel;
while (csv.fetch_next_line()) {
IdString cmd = csv.next_field().to_id(ctx);
@ -386,6 +389,7 @@ struct FabulousImpl : ViaductAPI
IdStringList bel_name = ctx->getBelName(curr_bel);
WireId clk_wire = get_wire(bel_name[0], ctx->idf("%s_CLK", bel_name[1].c_str(ctx)), id_REG_CLK);
ctx->addBelInput(curr_bel, id_CLK, clk_wire);
WireId global_clk_wire = get_wire(ctx->id("X0Y0"), id_CLK, id_CLK);
add_pseudo_pip(global_clk_wire, clk_wire, id_global_clock);
} else if (cmd == id_CFG) {
// TODO...
@ -396,6 +400,7 @@ struct FabulousImpl : ViaductAPI
curr_bel == BelId() ? "<none>" : ctx->nameOfBel(curr_bel));
}
}
init_global_clock();
postprocess_bels();
}

View File

@ -334,8 +334,8 @@ struct FabulousPacker
auto &ci = *cell.second;
if (!ci.type.in(ibuf, obuf, iobuf))
continue;
log_info("port is unconstrained: %s This pin will be assigned randomly\n", ctx->nameOf(&ci));
bool found_pad = false;
bool constrained = false;
for (auto &port : ci.ports) {
NetInfo *net = port.second.net;
if (!net)
@ -347,6 +347,8 @@ struct FabulousPacker
if (usr.port != id_PAD)
log_error("Top-level port '%s' connected to illegal port %s.%s (must be PAD)\n",
ctx->nameOf(&ci), ctx->nameOf(usr.cell), ctx->nameOf(usr.port));
if (usr.cell->attrs.count(id_BEL))
constrained = true;
if (found_pad)
log_error("Top-level port '%s' connected to multiple PAD ports (at least %s.%s and %s.%s)\n",
ctx->nameOf(&ci), ctx->nameOf(usr.cell), ctx->nameOf(usr.port),
@ -362,6 +364,8 @@ struct FabulousPacker
if (drv.port != id_PAD)
log_error("Top-level port '%s' connected to illegal port %s.%s (must be PAD)\n",
ctx->nameOf(&ci), ctx->nameOf(drv.cell), ctx->nameOf(drv.port));
if (drv.cell->attrs.count(id_BEL))
constrained = true;
if (found_pad)
log_error("Top-level port '%s' connected to multiple PAD ports (at least %s.%s and %s.%s)\n",
ctx->nameOf(&ci), ctx->nameOf(drv.cell), ctx->nameOf(drv.port),
@ -372,6 +376,8 @@ struct FabulousPacker
if (!found_pad)
log_error("No IO cell found connected to '%s' via PAD port. Was iopadmap run in Yosys?\n",
ctx->nameOf(&ci));
if (!constrained)
log_info("port is unconstrained: %s This pin will be assigned randomly\n", ctx->nameOf(&ci));
ci.disconnectPort(id_I);
ci.disconnectPort(id_O);
to_remove.push_back(ci.name);

View File

@ -619,4 +619,4 @@ void fabulous_pcf(Context *ctx, const std::string &filename)
log_info("Finished applying constraints from '%s'\n", filename.c_str());
}
NEXTPNR_NAMESPACE_END
NEXTPNR_NAMESPACE_END