xilinx: Add LUT route-thru pips (#1703)

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
myrtle 2026-04-20 11:47:38 +02:00 committed by GitHub
parent 68978f076f
commit 2a84cc9c55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 89 additions and 42 deletions

View File

@ -55,6 +55,8 @@ struct FasmBackend
std::vector<std::string> fasm_ctx;
dict<int, std::vector<PipId>> pips_by_tile;
dict<std::pair<int, int>, unsigned> lut_route_throughs;
dict<IdString, pool<IdString>> invertible_pins;
FasmBackend(Context *ctx, XilinxImpl *uarch, std::ostream &out) : ctx(ctx), uarch(uarch), out(out) {};
@ -616,59 +618,75 @@ struct FasmBackend
bool is_slicem = is_mtile && (half == 0);
const auto &lts = uarch->tile_status.at(tile).lts;
if (!lts)
return;
push(tname);
push(get_half_name(half, is_mtile));
BelId bel_in_half =
ctx->getBelByLocation(Loc(tile % ctx->chip_info->width, tile / ctx->chip_info->width, half << 6));
// Write route through pips
for (int i = 0; i < 4; i++) {
CellInfo *lut6 = lts->cells[(half << 6) | (i << 4) | BEL_6LUT];
CellInfo *lut5 = lts->cells[(half << 6) | (i << 4) | BEL_5LUT];
// Write LUT initialisation
if (lut6 != nullptr || lut5 != nullptr) {
auto found_rt = lut_route_throughs.find(std::make_pair(tile, half * 4 + i));
if (found_rt != lut_route_throughs.end()) {
std::string lutname = stringf("%cLUT", "ABCD"[i]);
push(lutname);
write_vector("INIT[63:0]", get_lut_init(lut6, lut5));
// Write LUT mode config
bool is_small = false, is_ram = false, is_srl = false;
for (int j = 0; j < 2; j++) {
CellInfo *lut = (j == 1) ? lut5 : lut6;
if (lut == nullptr)
continue;
std::string type = str_or_default(lut->attrs, id_X_ORIG_TYPE);
if (type == "RAMD64E" || type == "RAMS64E") {
is_ram = true;
} else if (type == "RAMD32" || type == "RAMS32") {
is_ram = true;
is_small = true;
} else if (type == "SRL16E") {
is_srl = true;
is_small = true;
} else if (type == "SRLC32E") {
is_srl = true;
}
wa7_used |= (lut->getPort(id_WA7) != nullptr);
wa8_used |= (lut->getPort(id_WA8) != nullptr);
std::vector<bool> rt_init(64, false);
for (unsigned b = 0; b < 64; b++) {
if (b & (1U << found_rt->second))
rt_init[b] = true;
}
if (is_slicem && i != 3) {
write_routing_bel(get_site_wire(bel_in_half, stringf("%cDI1MUX_OUT", "ABCD"[i])));
}
write_bit("SMALL", is_small);
write_bit("RAM", is_ram);
write_bit("SRL", is_srl);
write_vector("INIT[63:0]", rt_init);
pop();
}
write_routing_bel(get_site_wire(bel_in_half, stringf("%cMUX", "ABCD"[i])));
}
write_bit("WA7USED", wa7_used);
write_bit("WA8USED", wa8_used);
if (is_slicem)
write_routing_bel(get_site_wire(bel_in_half, "WEMUX_OUT"));
if (lts) {
// Write logic
BelId bel_in_half =
ctx->getBelByLocation(Loc(tile % ctx->chip_info->width, tile / ctx->chip_info->width, half << 6));
for (int i = 0; i < 4; i++) {
CellInfo *lut6 = lts->cells[(half << 6) | (i << 4) | BEL_6LUT];
CellInfo *lut5 = lts->cells[(half << 6) | (i << 4) | BEL_5LUT];
// Write LUT initialisation
if (lut6 != nullptr || lut5 != nullptr) {
std::string lutname = stringf("%cLUT", "ABCD"[i]);
push(lutname);
write_vector("INIT[63:0]", get_lut_init(lut6, lut5));
// Write LUT mode config
bool is_small = false, is_ram = false, is_srl = false;
for (int j = 0; j < 2; j++) {
CellInfo *lut = (j == 1) ? lut5 : lut6;
if (lut == nullptr)
continue;
std::string type = str_or_default(lut->attrs, id_X_ORIG_TYPE);
if (type == "RAMD64E" || type == "RAMS64E") {
is_ram = true;
} else if (type == "RAMD32" || type == "RAMS32") {
is_ram = true;
is_small = true;
} else if (type == "SRL16E") {
is_srl = true;
is_small = true;
} else if (type == "SRLC32E") {
is_srl = true;
}
wa7_used |= (lut->getPort(id_WA7) != nullptr);
wa8_used |= (lut->getPort(id_WA8) != nullptr);
}
if (is_slicem && i != 3) {
write_routing_bel(get_site_wire(bel_in_half, stringf("%cDI1MUX_OUT", "ABCD"[i])));
}
write_bit("SMALL", is_small);
write_bit("RAM", is_ram);
write_bit("SRL", is_srl);
pop();
}
write_routing_bel(get_site_wire(bel_in_half, stringf("%cMUX", "ABCD"[i])));
}
write_bit("WA7USED", wa7_used);
write_bit("WA8USED", wa8_used);
if (is_slicem)
write_routing_bel(get_site_wire(bel_in_half, "WEMUX_OUT"));
}
pop(2);
}
@ -705,6 +723,22 @@ struct FasmBackend
if (uarch->is_logic_tile(cell.second->bel))
used_logic_tiles.insert(cell.second->bel.tile);
}
for (auto &net : ctx->nets) {
for (const auto &wire_pair : net.second->wires) {
PipId pip = wire_pair.second.pip;
if (pip == PipId())
continue;
const auto &pip_data = chip_pip_info(ctx->chip_info, pip);
const auto &extra_data = *reinterpret_cast<const XlnxPipExtraDataPOD *>(pip_data.extra_data.get());
unsigned pip_type = pip_data.flags;
if (pip_type != PIP_LUT_ROUTETHRU)
continue;
unsigned lut_idx = (extra_data.pip_config >> 8);
unsigned lut_input = (extra_data.pip_config >> 1) & 0x7;
lut_route_throughs[std::make_pair(pip.tile, lut_idx)] = lut_input;
used_logic_tiles.insert(pip.tile);
}
}
for (int tile : used_logic_tiles) {
write_luts_config(tile, 0);
write_luts_config(tile, 1);

View File

@ -183,7 +183,20 @@ def import_tiletype(ch: Chip, tile: xilinx_device.Tile):
site_key=(s.index << 8),
timing="SITE_NULL"
)
# Add LUT route-through pseudo-pip
rt_config = ("ABCDEFGH".index(swn[0]) << 8)
if s.rel_xy()[0] == 1:
rt_config |= (4 << 8)
rt_config |= ((i - 1) << 1)
add_pip(pin.tile_wire().name(), s.pin(f"{swn[0]}").tile_wire().name(),
pip_class=PipClass.LUT_ROUTETHRU,
pip_config=rt_config,
site_key=(s.index << 8),
timing="SITE_NULL"
)
return
add_pip(pin.tile_wire().name(), lookup_site_wire(pin.site_wire()),
pip_class=PipClass.SITE_ENTRANCE, timing="SITE_NULL")