fabulous: fix block tracking of FABULOUS_LC, improve debug messages, fix masking of 1

Signed-off-by: Leo Moser <leomoser99@gmail.com>
This commit is contained in:
Leo Moser 2026-04-01 16:53:49 +02:00
parent 20de8b72e8
commit 3e0ef57793
4 changed files with 78 additions and 18 deletions

View File

@ -45,7 +45,12 @@ struct ControlSetConfig
*/
std::vector<route_mask_t> routing; // default 1 shared between all
bool have_signal = true;
int can_mask = -1;
enum MaskType
{
MASK_NONE = -1,
MASK_ZERO = 0,
MASK_ONE = 1
} can_mask = MaskType::MASK_NONE;
bool can_invert = false;
};

View File

@ -87,16 +87,16 @@ struct FabulousImpl : ViaductAPI
{
// TODO: loading from file or something
uint64_t default_routing = (1ULL << (cfg.clb.lc_per_clb * cfg.clb.ff_per_lc)) - 1;
auto setup_cfg = [&](ControlSetConfig &ctrl, int mask) {
auto setup_cfg = [&](ControlSetConfig &ctrl, ControlSetConfig::MaskType mask) {
ctrl.routing.clear();
ctrl.routing.push_back(default_routing);
ctrl.can_mask = mask;
ctrl.can_invert = false;
};
setup_cfg(cfg.clb.clk, -1);
setup_cfg(cfg.clb.en, 1);
setup_cfg(cfg.clb.sr, 0);
setup_cfg(cfg.clb.clk, ControlSetConfig::MaskType::MASK_NONE); // clk can not be masked
setup_cfg(cfg.clb.en, ControlSetConfig::MaskType::MASK_ONE); // en can be masked with 1
setup_cfg(cfg.clb.sr, ControlSetConfig::MaskType::MASK_ZERO); // sr can be masked with 0
}
void update_cell_timing(Context *ctx)
@ -154,9 +154,38 @@ struct FabulousImpl : ViaductAPI
assign_cell_info();
update_cell_timing(ctx);
}
void postPlace() override
{
if (ctx->debug) {
log_info("================== Final Placement ==================\n");
for (auto &cell : ctx->cells) {
auto ci = cell.second.get();
if (ci->bel != BelId()) {
log_info("%s: %s\n", ctx->nameOfBel(ci->bel), ctx->nameOf(ci));
if (ctx->getBelType(ci->bel).in(id_FABULOUS_LC)) {
for (IdString port : {id_CLK, id_SR, id_EN}) {
if (ci->ports.count(port)) {
WireId wire = ctx->getBelPinWire(ci->bel, port);
PortInfo pi = ci->ports[port];
if (pi.net) {
log_info("- %s/%s: %s\n", ctx->getWireName(wire)[0].c_str(ctx),
ctx->getWireName(wire)[1].c_str(ctx), pi.net->name.c_str(ctx));
}
}
}
}
} else {
log_info("unknown: %s\n", ctx->nameOf(ci));
}
}
log_break();
}
}
bool isBelLocationValid(BelId bel, bool explain_invalid) const override
{
return blk_trk->check_validity(bel, cfg, cell_tags);
return blk_trk->check_validity(bel, cfg, cell_tags, explain_invalid);
}
private:
@ -382,6 +411,11 @@ struct FabulousImpl : ViaductAPI
Loc loc = tile_loc(tile);
curr_bel = ctx->addBel(IdStringList::concat(tile, bel_name), bel_type, Loc(loc.x, loc.y, bel_z), false,
false);
// add FABULOUS_LC to the block tracker to check the control set
if (bel_type.in(id_FABULOUS_LC)) {
blk_trk->set_bel_type(curr_bel, BelFlags::BLOCK_CLB, BelFlags::FUNC_LC_COMB, bel_z);
}
} else if (cmd.in(id_I, id_O)) {
IdString port = csv.next_field().to_id(ctx);
auto wire_name = csv.next_field().split('.');

View File

@ -130,16 +130,18 @@ void BlockTracker::update_bel(BelId bel, CellInfo *old_cell, CellInfo *new_cell)
}
}
bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_data)
bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_data, bool explain_invalid)
{
SSOArray<ControlSig, 2> used_clk(cfg.clk.routing.size()), used_sr(cfg.sr.routing.size()),
used_en(cfg.en.routing.size());
auto check_ctrlsig = [&](unsigned idx, ControlSig actual, const ControlSetConfig &ctrl,
SSOArray<ControlSig, 2> &used) {
if (ctrl.can_mask != -1) {
if (ctrl.can_mask != ControlSetConfig::MaskType::MASK_NONE) {
// Using the per-entry control signal masking
if (actual.net == id___disconnected || (actual.net == id__CONST0 && ctrl.can_mask == 0) ||
(actual.net == id__CONST1 && ctrl.can_mask == 0)) {
if (actual.net == id___disconnected ||
(actual.net == id__CONST0 && ctrl.can_mask == ControlSetConfig::MaskType::MASK_ZERO) ||
(actual.net == id__CONST1 && ctrl.can_mask == ControlSetConfig::MaskType::MASK_ONE)) {
return true;
}
}
@ -164,6 +166,7 @@ bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_dat
// no option available
return false;
};
for (unsigned z = 0; z < cfg.lc_per_clb; z++) {
// flipflop control set checking
if (cfg.split_lc) {
@ -176,15 +179,28 @@ bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_dat
auto &lct = cell_data.get(lc);
if (lct.ff.ff_used) {
// check shared control signals
if (!check_ctrlsig(z, lct.ff.clk, cfg.clk, used_clk))
if (!check_ctrlsig(z, lct.ff.clk, cfg.clk, used_clk)) {
if (explain_invalid) {
log_nonfatal_error("CLK control signal invalid.\n");
}
return false;
if (cfg.en.have_signal && !check_ctrlsig(z, lct.ff.en, cfg.en, used_en))
}
if (cfg.en.have_signal && !check_ctrlsig(z, lct.ff.en, cfg.en, used_en)) {
if (explain_invalid) {
log_nonfatal_error("EN control signal invalid.\n");
}
return false;
if (cfg.sr.have_signal && !check_ctrlsig(z, lct.ff.sr, cfg.sr, used_sr))
}
if (cfg.sr.have_signal && !check_ctrlsig(z, lct.ff.sr, cfg.sr, used_sr)) {
if (explain_invalid) {
log_nonfatal_error("SR control signal invalid.\n");
}
return false;
}
}
}
}
// don't allow mixed MUX types in the classic fabulous arch where ctrl sigs are shared
int tile_mux_type = 0;
for (unsigned z = 0; z < cfg.lc_per_clb; z++) {
@ -202,14 +218,19 @@ bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_dat
NPNR_ASSERT_FALSE("unknown mux type");
if (tile_mux_type == 0)
tile_mux_type = this_mux;
else if (tile_mux_type != this_mux)
else if (tile_mux_type != this_mux) {
if (explain_invalid) {
log_nonfatal_error("Invalid mux type.\n");
}
return false;
}
}
// TODO: other checks...
return true;
}
bool BlockTracker::check_validity(BelId bel, const FabricConfig &cfg, const CellTagger &cell_data)
bool BlockTracker::check_validity(BelId bel, const FabricConfig &cfg, const CellTagger &cell_data, bool explain_invalid)
{
if (bel.index >= int(bel_data.size()))
return true; // some kind of bel not being tracked
@ -224,7 +245,7 @@ bool BlockTracker::check_validity(BelId bel, const FabricConfig &cfg, const Cell
return true; // some kind of bel not being tracked
const auto &entry = row.at(loc.x);
if (flags.block == BelFlags::BLOCK_CLB) {
return entry.clb->check_validity(cfg.clb, cell_data);
return entry.clb->check_validity(cfg.clb, cell_data, explain_invalid);
} else {
return true;
}

View File

@ -101,7 +101,7 @@ struct CLBState
std::unique_ptr<CellInfo *[]> ff;
// If there is (a) separate mux bel(s), map them to cells
std::unique_ptr<CellInfo *[]> mux;
bool check_validity(const LogicConfig &cfg, const CellTagger &cell_data);
bool check_validity(const LogicConfig &cfg, const CellTagger &cell_data, bool explain_invalid = false);
};
struct BlockTracker
@ -119,7 +119,7 @@ struct BlockTracker
// ...
};
std::vector<std::vector<TileData>> tiles;
bool check_validity(BelId bel, const FabricConfig &cfg, const CellTagger &cell_data);
bool check_validity(BelId bel, const FabricConfig &cfg, const CellTagger &cell_data, bool explain_invalid);
};
struct PseudoPipTags