From 2a84cc9c55dd28d68fa2e61bd0ad75226a2cc3f6 Mon Sep 17 00:00:00 2001 From: myrtle Date: Mon, 20 Apr 2026 11:47:38 +0200 Subject: [PATCH] xilinx: Add LUT route-thru pips (#1703) Signed-off-by: gatecat --- himbaechel/uarch/xilinx/fasm.cc | 118 ++++++++++++++-------- himbaechel/uarch/xilinx/gen/xilinx_gen.py | 13 +++ 2 files changed, 89 insertions(+), 42 deletions(-) diff --git a/himbaechel/uarch/xilinx/fasm.cc b/himbaechel/uarch/xilinx/fasm.cc index 15ea4c04..dc70320c 100644 --- a/himbaechel/uarch/xilinx/fasm.cc +++ b/himbaechel/uarch/xilinx/fasm.cc @@ -55,6 +55,8 @@ struct FasmBackend std::vector fasm_ctx; dict> pips_by_tile; + dict, unsigned> lut_route_throughs; + dict> 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 <s = 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 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(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); diff --git a/himbaechel/uarch/xilinx/gen/xilinx_gen.py b/himbaechel/uarch/xilinx/gen/xilinx_gen.py index 1a18c1f4..3c33f93a 100644 --- a/himbaechel/uarch/xilinx/gen/xilinx_gen.py +++ b/himbaechel/uarch/xilinx/gen/xilinx_gen.py @@ -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")