From 2d7d1e2408a38519426bf4f06c4bc2324ce2f628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Thu, 17 Jul 2025 09:50:24 +0300 Subject: [PATCH] gatemate: optimizations and cleanups (#1517) * Add log output * Optimize CC_LUT1 * Update tests * Optimize CC_LUT2 as well * Use init enumerations * Merge DFF in MX4 * Move repack code * Move ramio code to pack_cpe * Merge LUT1/2 to ADDF inputs * Note actual CPE ports * Merge DFF in ADDF * Update FF params and ports first * Check if DFFs are compatible before merging * Optimize DFF/Latch * Add reporting of optimized cells * Optimize MX2/4 * Add statistics * Use special nets for VCC/GND to skip using name * Add warning for carry chain split * Merge FFs where possible * Cleanup * Keep statistics out for now * Add logs for packing sections * review fixes --------- Co-authored-by: Lofty --- himbaechel/uarch/gatemate/gatemate.cc | 138 ++---- himbaechel/uarch/gatemate/gatemate.h | 4 +- himbaechel/uarch/gatemate/gatemate_util.h | 4 +- himbaechel/uarch/gatemate/pack.cc | 449 +++++++++++-------- himbaechel/uarch/gatemate/pack.h | 19 +- himbaechel/uarch/gatemate/pack_bram.cc | 5 +- himbaechel/uarch/gatemate/pack_clocking.cc | 9 +- himbaechel/uarch/gatemate/pack_cpe.cc | 473 ++++++++++++++++----- himbaechel/uarch/gatemate/pack_io.cc | 32 +- himbaechel/uarch/gatemate/pack_serdes.cc | 1 + himbaechel/uarch/gatemate/tests/lut.cc | 20 +- himbaechel/uarch/gatemate/tests/testing.cc | 7 - himbaechel/uarch/gatemate/tests/testing.h | 1 - 13 files changed, 725 insertions(+), 437 deletions(-) diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 35f6e2d4..b9a28ebf 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -179,112 +179,16 @@ bool GateMateImpl::getClusterPlacement(ClusterId cluster, BelId root_bel, return getChildPlacement(root_cell, root_loc, placement); } -void GateMateImpl::rename_param(CellInfo *cell, IdString name, IdString new_name, int width) -{ - if (cell->params.count(name)) { - cell->params[new_name] = Property(int_or_default(cell->params, name, 0), width); - cell->unsetParam(name); - } -} - void GateMateImpl::prePlace() { assign_cell_info(); } -void GateMateImpl::postPlace() +void GateMateImpl::postPlace() { repack(); } + +void GateMateImpl::preRoute() { ctx->assignArchInfo(); - std::vector delete_cells; - for (auto &cell : ctx->cells) { - if (cell.second->type.in(id_CPE_L2T4)) { - Loc l = ctx->getBelLocation(cell.second->bel); - if (l.z == CPE_LT_L_Z) { - if (!cell.second->params.count(id_INIT_L20)) - cell.second->params[id_INIT_L20] = Property(0b1100, 4); - } - cell.second->params[id_L2T4_UPPER] = Property((l.z == CPE_LT_U_Z) ? 1 : 0, 1); - } else if (cell.second->type.in(id_CPE_LT_L)) { - BelId bel = cell.second->bel; - PlaceStrength strength = cell.second->belStrength; - uint8_t func = int_or_default(cell.second->params, id_C_FUNCTION, 0); - Loc loc = ctx->getBelLocation(bel); - loc.z = CPE_LT_FULL_Z; - ctx->unbindBel(bel); - ctx->bindBel(ctx->getBelByLocation(loc), cell.second.get(), strength); - cell.second->renamePort(id_IN1, id_IN5); - cell.second->renamePort(id_IN2, id_IN6); - cell.second->renamePort(id_IN3, id_IN7); - cell.second->renamePort(id_IN4, id_IN8); - cell.second->renamePort(id_OUT, id_OUT1); - cell.second->renamePort(id_CPOUT, id_CPOUT1); - if (!cell.second->params.count(id_INIT_L20)) - cell.second->params[id_INIT_L20] = Property(0b1100, 4); - rename_param(cell.second.get(), id_INIT_L00, id_INIT_L02, 4); - rename_param(cell.second.get(), id_INIT_L01, id_INIT_L03, 4); - rename_param(cell.second.get(), id_INIT_L10, id_INIT_L11, 4); - - switch (func) { - case C_ADDF: - cell.second->type = id_CPE_ADDF; - break; - case C_ADDF2: - cell.second->type = id_CPE_ADDF2; - break; - case C_MULT: - cell.second->type = id_CPE_MULT; - break; - case C_MX4: - cell.second->type = id_CPE_MX4; - break; - case C_EN_CIN: - log_error("EN_CIN should be using L2T4.\n"); - break; - case C_CONCAT: - cell.second->type = id_CPE_CONCAT; - break; - case C_ADDCIN: - log_error("ADDCIN should be using L2T4.\n"); - break; - default: - break; - } - - loc.z = CPE_LT_U_Z; - CellInfo *upper = ctx->getBoundBelCell(ctx->getBelByLocation(loc)); - if (upper->params.count(id_INIT_L00)) - cell.second->params[id_INIT_L00] = Property(int_or_default(upper->params, id_INIT_L00, 0), 4); - if (upper->params.count(id_INIT_L01)) - cell.second->params[id_INIT_L01] = Property(int_or_default(upper->params, id_INIT_L01, 0), 4); - if (upper->params.count(id_INIT_L10)) - cell.second->params[id_INIT_L10] = Property(int_or_default(upper->params, id_INIT_L10, 0), 4); - if (upper->params.count(id_C_I1)) - cell.second->params[id_C_I1] = Property(int_or_default(upper->params, id_C_I1, 0), 1); - if (upper->params.count(id_C_I2)) - cell.second->params[id_C_I2] = Property(int_or_default(upper->params, id_C_I2, 0), 1); - upper->movePortTo(id_IN1, cell.second.get(), id_IN1); - upper->movePortTo(id_IN2, cell.second.get(), id_IN2); - upper->movePortTo(id_IN3, cell.second.get(), id_IN3); - upper->movePortTo(id_IN4, cell.second.get(), id_IN4); - upper->movePortTo(id_OUT, cell.second.get(), id_OUT2); - upper->movePortTo(id_CPOUT, cell.second.get(), id_CPOUT2); - - } - // Mark for deletion - else if (cell.second->type.in(id_CPE_LT_U, id_CPE_DUMMY)) { - delete_cells.push_back(cell.second->name); - } - } - for (auto pcell : delete_cells) { - for (auto &port : ctx->cells[pcell]->ports) { - ctx->cells[pcell]->disconnectPort(port.first); - } - ctx->unbindBel(ctx->cells[pcell]->bel); - ctx->cells.erase(pcell); - } - delete_cells.clear(); - ctx->assignArchInfo(); + route_clock(); } -void GateMateImpl::preRoute() { route_clock(); } - void GateMateImpl::postRoute() { ctx->assignArchInfo(); @@ -301,6 +205,25 @@ void GateMateImpl::configurePlacerHeap(PlacerHeapCfg &cfg) cfg.placeAllAtOnce = true; } +int GateMateImpl::get_dff_config(CellInfo *dff) const +{ + int val = 0; + val |= int_or_default(dff->params, id_C_CPE_EN, 0); + val <<= 2; + val |= int_or_default(dff->params, id_C_CPE_CLK, 0); + val <<= 2; + val |= int_or_default(dff->params, id_C_CPE_RES, 0); + val <<= 2; + val |= int_or_default(dff->params, id_C_CPE_SET, 0); + val <<= 2; + val |= int_or_default(dff->params, id_C_EN_SR, 0); + val <<= 1; + val |= int_or_default(dff->params, id_C_L_D, 0); + val <<= 1; + val |= int_or_default(dff->params, id_FF_INIT, 0); + return val; +} + void GateMateImpl::assign_cell_info() { fast_cell_info.resize(ctx->cells.size()); @@ -311,20 +234,7 @@ void GateMateImpl::assign_cell_info() fc.ff_en = ci->getPort(id_EN); fc.ff_clk = ci->getPort(id_CLK); fc.ff_sr = ci->getPort(id_SR); - fc.ff_config = 0; - fc.ff_config |= int_or_default(ci->params, id_C_CPE_EN, 0); - fc.ff_config <<= 2; - fc.ff_config |= int_or_default(ci->params, id_C_CPE_CLK, 0); - fc.ff_config <<= 2; - fc.ff_config |= int_or_default(ci->params, id_C_CPE_RES, 0); - fc.ff_config <<= 2; - fc.ff_config |= int_or_default(ci->params, id_C_CPE_SET, 0); - fc.ff_config <<= 2; - fc.ff_config |= int_or_default(ci->params, id_C_EN_SR, 0); - fc.ff_config <<= 1; - fc.ff_config |= int_or_default(ci->params, id_C_L_D, 0); - fc.ff_config <<= 1; - fc.ff_config |= int_or_default(ci->params, id_FF_INIT, 0); + fc.ff_config = get_dff_config(ci); fc.dff_used = true; } } diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index f63b38c6..43ecf246 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -63,7 +63,8 @@ struct GateMateImpl : HimbaechelAPI bool isPipInverting(PipId pip) const override; const GateMateTileExtraDataPOD *tile_extra_data(int tile) const; - void rename_param(CellInfo *cell, IdString name, IdString new_name, int width); + + int get_dff_config(CellInfo *dff) const; std::set available_pads; std::map bel_to_pad; @@ -83,6 +84,7 @@ struct GateMateImpl : HimbaechelAPI void assign_cell_info(); void route_clock(); + void repack(); const GateMateBelExtraDataPOD *bel_extra_data(BelId bel) const; diff --git a/himbaechel/uarch/gatemate/gatemate_util.h b/himbaechel/uarch/gatemate/gatemate_util.h index e209e22c..8b5e3a7b 100644 --- a/himbaechel/uarch/gatemate/gatemate_util.h +++ b/himbaechel/uarch/gatemate/gatemate_util.h @@ -63,7 +63,7 @@ int extract_bits(const dict &ct, const KeyType &key, int star } template -std::vector> splitNestedVector(const std::vector> &input, size_t maxSize = 32) +std::vector> splitNestedVector(const std::vector> &input, size_t maxSize = 64) { std::vector> result; @@ -73,6 +73,8 @@ std::vector> splitNestedVector(const std::vector> size_t end = std::min(i + maxSize, inner.size()); result.emplace_back(inner.begin() + i, inner.begin() + end); i = end; + if (i < inner.size()) + log_warning("Carry chain has been split, expect timing penalty.\n"); } } diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index 66a81df1..393f56c7 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -32,6 +32,8 @@ void GateMatePacker::flush_cells() for (auto &port : ctx->cells[pcell]->ports) { ctx->cells[pcell]->disconnectPort(port.first); } + if (ctx->cells[pcell]->bel != BelId()) + ctx->unbindBel(ctx->cells[pcell]->bel); ctx->cells.erase(pcell); } packed_cells.clear(); @@ -39,183 +41,13 @@ void GateMatePacker::flush_cells() void GateMatePacker::disconnect_if_gnd(CellInfo *cell, IdString input) { - NetInfo *net = cell->getPort(input); - if (!net) - return; - if (net->name.in(ctx->id("$PACKER_GND"))) { + if (cell->getPort(input) == net_PACKER_GND) cell->disconnectPort(input); - } -} - -std::pair GateMatePacker::move_ram_i(CellInfo *cell, IdString origPort, bool place, Loc cpe_loc) -{ - CellInfo *cpe_half = nullptr; - CellInfo *cpe_ramio = nullptr; - NetInfo *net = cell->getPort(origPort); - if (net) { - cpe_ramio = create_cell_ptr(id_CPE_RAMI, ctx->idf("%s$%s_rami", cell->name.c_str(ctx), origPort.c_str(ctx))); - if (place) { - cell->constr_children.push_back(cpe_ramio); - cpe_ramio->cluster = cell->cluster; - cpe_ramio->constr_abs_z = false; - cpe_ramio->constr_z = PLACE_DB_CONSTR + origPort.index; - } else { - BelId b = ctx->getBelByLocation(cpe_loc); - ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); - } - CellInfo *cpe_half = - create_cell_ptr(id_CPE_DUMMY, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), origPort.c_str(ctx))); - if (place) { - cpe_ramio->constr_children.push_back(cpe_half); - cpe_half->cluster = cell->cluster; - cpe_half->constr_abs_z = false; - cpe_half->constr_z = -4; - } else { - BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); - ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); - } - - cpe_ramio->params[id_C_RAM_I] = Property(1, 1); - - NetInfo *ram_i = ctx->createNet(ctx->idf("%s$ram_i", cpe_ramio->name.c_str(ctx))); - cell->movePortTo(origPort, cpe_ramio, id_OUT); - cell->connectPort(origPort, ram_i); - cpe_ramio->connectPort(id_RAM_I, ram_i); - } - return std::make_pair(cpe_half, cpe_ramio); -} - -std::pair GateMatePacker::move_ram_o(CellInfo *cell, IdString origPort, bool place, Loc cpe_loc) -{ - CellInfo *cpe_half = nullptr; - CellInfo *cpe_ramio = nullptr; - NetInfo *net = cell->getPort(origPort); - if (net) { - cpe_ramio = create_cell_ptr(id_CPE_RAMO, ctx->idf("%s$%s_ramo", cell->name.c_str(ctx), origPort.c_str(ctx))); - if (place) { - cell->constr_children.push_back(cpe_ramio); - cpe_ramio->cluster = cell->cluster; - cpe_ramio->constr_abs_z = false; - cpe_ramio->constr_z = PLACE_DB_CONSTR + origPort.index; - } else { - BelId b = ctx->getBelByLocation(cpe_loc); - ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); - } - cpe_half = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), origPort.c_str(ctx))); - if (place) { - cpe_ramio->constr_children.push_back(cpe_half); - cpe_half->cluster = cell->cluster; - cpe_half->constr_abs_z = false; - cpe_half->constr_z = -4; - } else { - BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); - ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); - } - if (net->name == ctx->id("$PACKER_GND")) { - cpe_half->params[id_INIT_L00] = Property(0b0000, 4); - cell->disconnectPort(origPort); - } else if (net->name == ctx->id("$PACKER_VCC")) { - cpe_half->params[id_INIT_L00] = Property(0b1111, 4); - cell->disconnectPort(origPort); - } else { - cpe_half->params[id_INIT_L00] = Property(0b1010, 4); - cell->movePortTo(origPort, cpe_half, id_IN1); - } - cpe_half->params[id_INIT_L10] = Property(0b1010, 4); - - cpe_ramio->params[id_C_RAM_O] = Property(1, 1); - NetInfo *ram_o = ctx->createNet(ctx->idf("%s$ram_o", cpe_half->name.c_str(ctx))); - cell->connectPort(origPort, ram_o); - cpe_ramio->connectPort(id_RAM_O, ram_o); - - NetInfo *out = ctx->createNet(ctx->idf("%s$out", cpe_half->name.c_str(ctx))); - cpe_half->connectPort(id_OUT, out); - cpe_ramio->connectPort(id_I, out); - } - return std::make_pair(cpe_half, cpe_ramio); -} - -std::pair GateMatePacker::move_ram_io(CellInfo *cell, IdString iPort, IdString oPort, - bool place, Loc cpe_loc) -{ - NetInfo *i_net = cell->getPort(iPort); - NetInfo *o_net = cell->getPort(oPort); - if (!i_net && !o_net) - return std::make_pair(nullptr, nullptr); - - CellInfo *cpe_ramio = - create_cell_ptr(id_CPE_RAMIO, ctx->idf("%s$%s_ramio", cell->name.c_str(ctx), oPort.c_str(ctx))); - if (place) { - cell->constr_children.push_back(cpe_ramio); - cpe_ramio->cluster = cell->cluster; - cpe_ramio->constr_abs_z = false; - cpe_ramio->constr_z = PLACE_DB_CONSTR + oPort.index; - } else { - BelId b = ctx->getBelByLocation(cpe_loc); - ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); - } - CellInfo *cpe_half = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), oPort.c_str(ctx))); - if (place) { - cpe_ramio->constr_children.push_back(cpe_half); - cpe_half->cluster = cell->cluster; - cpe_half->constr_abs_z = false; - cpe_half->constr_z = -4; - } else { - BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); - ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); - } - - if (o_net) { - if (o_net->name == ctx->id("$PACKER_GND")) { - cpe_half->params[id_INIT_L00] = Property(0b0000, 4); - cell->disconnectPort(oPort); - } else if (o_net->name == ctx->id("$PACKER_VCC")) { - cpe_half->params[id_INIT_L00] = Property(0b1111, 4); - cell->disconnectPort(oPort); - } else { - cpe_half->params[id_INIT_L00] = Property(0b1010, 4); - cell->movePortTo(oPort, cpe_half, id_IN1); - } - cpe_half->params[id_INIT_L10] = Property(0b1010, 4); - cpe_ramio->params[id_C_RAM_O] = Property(1, 1); - - NetInfo *ram_o = ctx->createNet(ctx->idf("%s$ram_o", cpe_half->name.c_str(ctx))); - cell->connectPort(oPort, ram_o); - cpe_ramio->connectPort(id_RAM_O, ram_o); - - NetInfo *out = ctx->createNet(ctx->idf("%s$out", cpe_half->name.c_str(ctx))); - cpe_half->connectPort(id_OUT, out); - cpe_ramio->connectPort(id_I, out); - } - if (i_net) { - cpe_ramio->params[id_C_RAM_I] = Property(1, 1); - - NetInfo *ram_i = ctx->createNet(ctx->idf("%s$ram_i", cpe_half->name.c_str(ctx))); - cell->movePortTo(iPort, cpe_ramio, id_OUT); - cell->connectPort(iPort, ram_i); - cpe_ramio->connectPort(id_RAM_I, ram_i); - } - return std::make_pair(cpe_half, cpe_ramio); -} - -std::pair GateMatePacker::move_ram_i_fixed(CellInfo *cell, IdString origPort, Loc fixed) -{ - return move_ram_i(cell, origPort, false, uarch->getRelativeConstraint(fixed, origPort)); -} - -std::pair GateMatePacker::move_ram_o_fixed(CellInfo *cell, IdString origPort, Loc fixed) -{ - return move_ram_o(cell, origPort, false, uarch->getRelativeConstraint(fixed, origPort)); -} - -std::pair GateMatePacker::move_ram_io_fixed(CellInfo *cell, IdString iPort, IdString oPort, - Loc fixed) -{ - return move_ram_io(cell, iPort, oPort, false, uarch->getRelativeConstraint(fixed, oPort)); } void GateMatePacker::pack_misc() { + log_info("Packing misc..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; if (!ci.type.in(id_CC_USR_RSTN)) @@ -251,7 +83,7 @@ void GateMatePacker::pack_misc() } } -void GateMatePacker::remove_not_used() +void GateMatePacker::disconnect_not_used() { for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -283,6 +115,269 @@ void GateMatePacker::copy_constraint(NetInfo *in_net, NetInfo *out_net) } } +void GateMatePacker::move_connections(NetInfo *from_net, NetInfo *to_net) +{ + for (const auto &usr : from_net->users) { + IdString port = usr.port; + usr.cell->disconnectPort(port); + usr.cell->connectPort(port, to_net); + } +} + +void GateMatePacker::count_cell(CellInfo &ci) +{ + packed_cells.insert(ci.name); + count_per_type[ci.type]++; + count++; +} + +void GateMatePacker::optimize_lut() +{ + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_LUT1, id_CC_LUT2)) + continue; + NetInfo *o_net = ci.getPort(id_O); + if (!o_net) { + count_cell(ci); + continue; + } + + uint8_t val = int_or_default(ci.params, id_INIT, 0); + if (ci.type == id_CC_LUT1) + val = val << 2 | val; + switch (val) { + case LUT_ZERO: // constant 0 + move_connections(o_net, net_PACKER_GND); + count_cell(ci); + break; + case LUT_D0: // propagate + move_connections(o_net, ci.getPort(id_I0)); + count_cell(ci); + break; + case LUT_D1: // propagate + move_connections(o_net, ci.getPort(id_I1)); + count_cell(ci); + break; + case LUT_ONE: // constant 1 + move_connections(o_net, net_PACKER_VCC); + count_cell(ci); + break; + default: + break; + } + } + flush_cells(); +} + +void GateMatePacker::optimize_mx() +{ + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_MX2, id_CC_MX4)) + continue; + NetInfo *y_net = ci.getPort(id_Y); + if (!y_net) { + count_cell(ci); + continue; + } + if (ci.type == id_CC_MX2) { + if (ci.getPort(id_S0) == net_PACKER_GND) { + move_connections(y_net, ci.getPort(id_D0)); + count_cell(ci); + continue; + } else if (ci.getPort(id_S0) == net_PACKER_VCC) { + move_connections(y_net, ci.getPort(id_D1)); + count_cell(ci); + continue; + } + } else { + if ((ci.getPort(id_S1) == net_PACKER_GND) && (ci.getPort(id_S0) == net_PACKER_GND)) { + move_connections(y_net, ci.getPort(id_D0)); + count_cell(ci); + continue; + } else if ((ci.getPort(id_S1) == net_PACKER_GND) && (ci.getPort(id_S0) == net_PACKER_VCC)) { + move_connections(y_net, ci.getPort(id_D1)); + count_cell(ci); + continue; + } else if ((ci.getPort(id_S1) == net_PACKER_VCC) && (ci.getPort(id_S0) == net_PACKER_GND)) { + move_connections(y_net, ci.getPort(id_D2)); + count_cell(ci); + continue; + } else if ((ci.getPort(id_S1) == net_PACKER_VCC) && (ci.getPort(id_S0) == net_PACKER_VCC)) { + move_connections(y_net, ci.getPort(id_D3)); + count_cell(ci); + continue; + } + } + } + flush_cells(); +} + +void GateMatePacker::optimize_ff() +{ + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_DFF, id_CC_DLT)) + continue; + + NetInfo *q_net = ci.getPort(id_Q); + if (!q_net) { + count_cell(ci); + continue; + } + + int cpe_clk = int_or_default(ci.params, id_C_CPE_CLK, 0); + int cpe_en = int_or_default(ci.params, id_C_CPE_EN, 0); + int cpe_res = int_or_default(ci.params, id_C_CPE_RES, 0); + int cpe_set = int_or_default(ci.params, id_C_CPE_SET, 0); + int ff_init = int_or_default(ci.params, id_FF_INIT, 0); + bool ff_has_init = (ff_init >> 1) & 1; + bool ff_init_value = ff_init & 1; + + if (cpe_res == 0) { // RES is always ON + move_connections(q_net, net_PACKER_GND); + count_cell(ci); + continue; + } + if (cpe_set == 0) { // SET is always ON + move_connections(q_net, net_PACKER_VCC); + count_cell(ci); + continue; + } + + if (ci.type == id_CC_DFF) { + if ((cpe_en == 0 || cpe_clk == 0) && ci.getPort(id_SR) == nullptr) { + // Only when there is no SR signal + // EN always OFF (never loads) or CLK never triggers + move_connections(q_net, + ff_has_init ? (ff_init_value ? net_PACKER_VCC : net_PACKER_GND) : net_PACKER_GND); + count_cell(ci); + continue; + } + } else { + if (cpe_clk == 3 && ci.getPort(id_SR) == nullptr && cpe_res == 3 && cpe_set == 3) { + // Clamp G if there is no set or reset + move_connections(q_net, ci.getPort(id_D)); + count_cell(ci); + continue; + } + } + } + flush_cells(); +} + +void GateMatePacker::cleanup() +{ + log_info("Running cleanups..\n"); + dff_update_params(); + int i = 1; + do { + count = 0; + disconnect_not_used(); + optimize_lut(); + optimize_mx(); + optimize_ff(); + for (auto c : count_per_type) + log_info(" %6d %s cells removed (iteration %d)\n", c.second, c.first.c_str(ctx), i); + count_per_type.clear(); + i++; + } while (count != 0); +} + +void GateMatePacker::rename_param(CellInfo *cell, IdString name, IdString new_name, int width) +{ + if (cell->params.count(name)) { + cell->params[new_name] = Property(int_or_default(cell->params, name, 0), width); + cell->unsetParam(name); + } +} + +void GateMatePacker::repack() +{ + log_info("Repacking CPEs..\n"); + for (auto &cell : ctx->cells) { + if (cell.second->type.in(id_CPE_L2T4)) { + Loc l = ctx->getBelLocation(cell.second->bel); + if (l.z == CPE_LT_L_Z) { + if (!cell.second->params.count(id_INIT_L20)) + cell.second->params[id_INIT_L20] = Property(LUT_D1, 4); + } + cell.second->params[id_L2T4_UPPER] = Property((l.z == CPE_LT_U_Z) ? 1 : 0, 1); + } else if (cell.second->type.in(id_CPE_LT_L)) { + BelId bel = cell.second->bel; + PlaceStrength strength = cell.second->belStrength; + uint8_t func = int_or_default(cell.second->params, id_C_FUNCTION, 0); + Loc loc = ctx->getBelLocation(bel); + loc.z = CPE_LT_FULL_Z; + ctx->unbindBel(bel); + ctx->bindBel(ctx->getBelByLocation(loc), cell.second.get(), strength); + cell.second->renamePort(id_IN1, id_IN5); + cell.second->renamePort(id_IN2, id_IN6); + cell.second->renamePort(id_IN3, id_IN7); + cell.second->renamePort(id_IN4, id_IN8); + cell.second->renamePort(id_OUT, id_OUT1); + cell.second->renamePort(id_CPOUT, id_CPOUT1); + if (!cell.second->params.count(id_INIT_L20)) + cell.second->params[id_INIT_L20] = Property(LUT_D1, 4); + rename_param(cell.second.get(), id_INIT_L00, id_INIT_L02, 4); + rename_param(cell.second.get(), id_INIT_L01, id_INIT_L03, 4); + rename_param(cell.second.get(), id_INIT_L10, id_INIT_L11, 4); + + switch (func) { + case C_ADDF: + cell.second->type = id_CPE_ADDF; + break; + case C_ADDF2: + cell.second->type = id_CPE_ADDF2; + break; + case C_MULT: + cell.second->type = id_CPE_MULT; + break; + case C_MX4: + cell.second->type = id_CPE_MX4; + break; + case C_EN_CIN: + log_error("EN_CIN should be using L2T4.\n"); + break; + case C_CONCAT: + cell.second->type = id_CPE_CONCAT; + break; + case C_ADDCIN: + log_error("ADDCIN should be using L2T4.\n"); + break; + default: + break; + } + + loc.z = CPE_LT_U_Z; + CellInfo *upper = ctx->getBoundBelCell(ctx->getBelByLocation(loc)); + if (upper->params.count(id_INIT_L00)) + cell.second->params[id_INIT_L00] = Property(int_or_default(upper->params, id_INIT_L00, 0), 4); + if (upper->params.count(id_INIT_L01)) + cell.second->params[id_INIT_L01] = Property(int_or_default(upper->params, id_INIT_L01, 0), 4); + if (upper->params.count(id_INIT_L10)) + cell.second->params[id_INIT_L10] = Property(int_or_default(upper->params, id_INIT_L10, 0), 4); + if (upper->params.count(id_C_I1)) + cell.second->params[id_C_I1] = Property(int_or_default(upper->params, id_C_I1, 0), 1); + if (upper->params.count(id_C_I2)) + cell.second->params[id_C_I2] = Property(int_or_default(upper->params, id_C_I2, 0), 1); + upper->movePortTo(id_IN1, cell.second.get(), id_IN1); + upper->movePortTo(id_IN2, cell.second.get(), id_IN2); + upper->movePortTo(id_IN3, cell.second.get(), id_IN3); + upper->movePortTo(id_IN4, cell.second.get(), id_IN4); + upper->movePortTo(id_OUT, cell.second.get(), id_OUT2); + upper->movePortTo(id_CPOUT, cell.second.get(), id_CPOUT2); + + } + // Mark for deletion + else if (cell.second->type.in(id_CPE_LT_U, id_CPE_DUMMY)) { + packed_cells.insert(cell.second->name); + } + } + flush_cells(); +} + void GateMateImpl::pack() { const ArchArgs &args = ctx->args; @@ -292,7 +387,7 @@ void GateMateImpl::pack() GateMatePacker packer(ctx, this); packer.pack_constants(); - packer.remove_not_used(); + packer.cleanup(); packer.pack_io(); packer.insert_pll_bufg(); packer.sort_bufg(); @@ -309,4 +404,10 @@ void GateMateImpl::pack() packer.remove_clocking(); } +void GateMateImpl::repack() +{ + GateMatePacker packer(ctx, this); + packer.repack(); +} + NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index 0e870256..b589563e 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -64,14 +64,25 @@ struct GateMatePacker void remove_constants(); void remove_clocking(); - void remove_not_used(); + + void cleanup(); + void repack(); private: + void rename_param(CellInfo *cell, IdString name, IdString new_name, int width); void dff_to_cpe(CellInfo *dff); + void dff_update_params(); void insert_bufg(CellInfo *cell, IdString port); void disconnect_if_gnd(CellInfo *cell, IdString input); void pll_out(CellInfo *cell, IdString origPort, Loc fixed); + void disconnect_not_used(); + void optimize_lut(); + void optimize_mx(); + void optimize_ff(); + void count_cell(CellInfo &ci); + void move_connections(NetInfo *from_net, NetInfo *to_net); + PllCfgRecord get_pll_settings(double f_ref, double f_core, int mode, int low_jitter, bool pdiv0_mux, bool feedback); std::pair move_ram_i(CellInfo *cell, IdString origPort, bool place = true, @@ -86,6 +97,8 @@ struct GateMatePacker uint8_t ram_ctrl_signal(CellInfo *cell, IdString port, bool alt); uint8_t ram_clk_signal(CellInfo *cell, IdString port); bool is_gpio_valid_dff(CellInfo *dff); + bool are_ffs_compatible(CellInfo *dff, CellInfo *other); + // Cell creating CellInfo *create_cell_ptr(IdString type, IdString name); void flush_cells(); @@ -101,6 +114,10 @@ struct GateMatePacker GateMateImpl *uarch; HimbaechelHelpers h; + NetInfo *net_PACKER_VCC; + NetInfo *net_PACKER_GND; + int count; + std::map count_per_type; }; NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack_bram.cc b/himbaechel/uarch/gatemate/pack_bram.cc index da4a3781..0c398b59 100644 --- a/himbaechel/uarch/gatemate/pack_bram.cc +++ b/himbaechel/uarch/gatemate/pack_bram.cc @@ -31,10 +31,10 @@ uint8_t GateMatePacker::ram_ctrl_signal(CellInfo *cell, IdString port, bool alt) { NetInfo *net = cell->getPort(port); if (net) { - if (net->name == ctx->id("$PACKER_GND")) { + if (net == net_PACKER_GND) { cell->disconnectPort(port); return 0b00000011; - } else if (net->name == ctx->id("$PACKER_VCC")) { + } else if (net == net_PACKER_VCC) { cell->disconnectPort(port); return 0b00010011; } else { @@ -242,6 +242,7 @@ void GateMatePacker::pack_ram() std::vector> rams; std::vector> rams_merged[2]; std::map ram_cascade; + log_info("Packing RAMs..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; if (!ci.type.in(id_CC_BRAM_20K, id_CC_BRAM_40K, id_CC_FIFO_40K)) diff --git a/himbaechel/uarch/gatemate/pack_clocking.cc b/himbaechel/uarch/gatemate/pack_clocking.cc index 8e6d8eae..c655cb25 100644 --- a/himbaechel/uarch/gatemate/pack_clocking.cc +++ b/himbaechel/uarch/gatemate/pack_clocking.cc @@ -39,6 +39,7 @@ void GateMatePacker::sort_bufg() ItemBufG(CellInfo *cell, int32_t fan_out) : cell(cell), fan_out(fan_out) {} }; + log_info("Sort BUFGs..\n"); std::vector bufg; for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -281,6 +282,7 @@ void GateMatePacker::insert_bufg(CellInfo *cell, IdString port) void GateMatePacker::insert_pll_bufg() { + log_info("Insert BUFGs for PLLs..\n"); for (int i = 0; i < uarch->dies; i++) { Loc fixed_loc = uarch->locations[std::make_pair(id_CLKIN, i)]; clkin.push_back(create_cell_ptr(id_CLKIN, ctx->idf("CLKIN%d", i))); @@ -308,6 +310,7 @@ void GateMatePacker::insert_pll_bufg() void GateMatePacker::remove_clocking() { + log_info("Remove unused clocking cells..\n"); auto remove_unused_cells = [&](std::vector &cells, const char *type) { for (auto cell : cells) { bool used = false; @@ -333,7 +336,7 @@ void GateMatePacker::remove_clocking() void GateMatePacker::pack_pll() { std::vector pll_index(uarch->dies); - log_info("Packing PLLss..\n"); + log_info("Packing PLLs..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; if (!ci.type.in(id_CC_PLL, id_CC_PLL_ADV)) @@ -572,11 +575,11 @@ void GateMatePacker::pack_pll() out_clk_max = out_clk; } NetInfo *select_net = ci.getPort(id_USR_SEL_A_B); - if (select_net == nullptr || select_net->name == ctx->id("$PACKER_GND")) { + if (select_net == nullptr || select_net == net_PACKER_GND) { ci.params[ctx->id("SET_SEL")] = Property(0b0, 1); ci.params[ctx->id("USR_SET")] = Property(0b0, 1); ci.disconnectPort(id_USR_SEL_A_B); - } else if (select_net->name == ctx->id("$PACKER_VCC")) { + } else if (select_net == net_PACKER_VCC) { ci.params[ctx->id("SET_SEL")] = Property(0b1, 1); ci.params[ctx->id("USR_SET")] = Property(0b0, 1); ci.disconnectPort(id_USR_SEL_A_B); diff --git a/himbaechel/uarch/gatemate/pack_cpe.cc b/himbaechel/uarch/gatemate/pack_cpe.cc index bd360f43..fc02b232 100644 --- a/himbaechel/uarch/gatemate/pack_cpe.cc +++ b/himbaechel/uarch/gatemate/pack_cpe.cc @@ -29,6 +29,21 @@ NEXTPNR_NAMESPACE_BEGIN // Return true if a cell is a flipflop inline bool is_dff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type.in(id_CC_DFF, id_CC_DLT); } +bool GateMatePacker::are_ffs_compatible(CellInfo *dff, CellInfo *other) +{ + if (!other) + return true; + if (dff->getPort(id_CLK) != other->getPort(id_CLK)) + return false; + if (dff->getPort(id_EN) != other->getPort(id_EN)) + return false; + if (dff->getPort(id_SR) != other->getPort(id_SR)) + return false; + if (uarch->get_dff_config(dff) != uarch->get_dff_config(other)) + return false; + return true; +} + void GateMatePacker::dff_to_cpe(CellInfo *dff) { bool invert; @@ -37,10 +52,10 @@ void GateMatePacker::dff_to_cpe(CellInfo *dff) NetInfo *g_net = dff->getPort(id_G); invert = bool_or_default(dff->params, id_G_INV, 0); if (g_net) { - if (g_net->name == ctx->id("$PACKER_GND")) { + if (g_net == net_PACKER_GND) { dff->params[id_C_CPE_CLK] = Property(invert ? 0b11 : 0b00, 2); dff->disconnectPort(id_G); - } else if (g_net->name == ctx->id("$PACKER_VCC")) { + } else if (g_net == net_PACKER_VCC) { dff->params[id_C_CPE_CLK] = Property(invert ? 0b00 : 0b11, 2); dff->disconnectPort(id_G); } else { @@ -58,10 +73,10 @@ void GateMatePacker::dff_to_cpe(CellInfo *dff) NetInfo *en_net = dff->getPort(id_EN); bool invert = bool_or_default(dff->params, id_EN_INV, 0); if (en_net) { - if (en_net->name == ctx->id("$PACKER_GND")) { + if (en_net == net_PACKER_GND) { dff->params[id_C_CPE_EN] = Property(invert ? 0b11 : 0b00, 2); dff->disconnectPort(id_EN); - } else if (en_net->name == ctx->id("$PACKER_VCC")) { + } else if (en_net == net_PACKER_VCC) { dff->params[id_C_CPE_EN] = Property(invert ? 0b00 : 0b11, 2); dff->disconnectPort(id_EN); } else { @@ -75,10 +90,10 @@ void GateMatePacker::dff_to_cpe(CellInfo *dff) NetInfo *clk_net = dff->getPort(id_CLK); invert = bool_or_default(dff->params, id_CLK_INV, 0); if (clk_net) { - if (clk_net->name == ctx->id("$PACKER_GND")) { + if (clk_net == net_PACKER_GND) { dff->params[id_C_CPE_CLK] = Property(invert ? 0b11 : 0b00, 2); dff->disconnectPort(id_CLK); - } else if (clk_net->name == ctx->id("$PACKER_VCC")) { + } else if (clk_net == net_PACKER_VCC) { dff->params[id_C_CPE_CLK] = Property(invert ? 0b00 : 0b11, 2); dff->disconnectPort(id_CLK); } else { @@ -94,8 +109,8 @@ void GateMatePacker::dff_to_cpe(CellInfo *dff) invert = bool_or_default(dff->params, id_SR_INV, 0); bool sr_val = bool_or_default(dff->params, id_SR_VAL, 0); if (sr_net) { - if (sr_net->name.in(ctx->id("$PACKER_GND"), ctx->id("$PACKER_VCC"))) { - bool sr_signal = sr_net->name == ctx->id("$PACKER_VCC"); + if (sr_net == net_PACKER_VCC || sr_net == net_PACKER_GND) { + bool sr_signal = sr_net == net_PACKER_VCC; if (sr_signal ^ invert) { if (sr_val) { dff->params[id_C_CPE_RES] = Property(0b11, 2); @@ -141,14 +156,37 @@ void GateMatePacker::dff_to_cpe(CellInfo *dff) } } +void GateMatePacker::dff_update_params() +{ + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_CC_DFF, id_CC_DLT)) + continue; + dff_to_cpe(&ci); + } +} + void GateMatePacker::pack_cpe() { log_info("Packing CPEs..\n"); std::vector l2t5_list; + + auto merge_dff = [&](CellInfo &ci, CellInfo *dff) { + dff->cluster = ci.name; + dff->constr_abs_z = false; + dff->constr_z = +2; + ci.cluster = ci.name; + ci.constr_children.push_back(dff); + dff->renamePort(id_D, id_DIN); + dff->renamePort(id_Q, id_DOUT); + dff->type = (dff->type == id_CC_DLT) ? id_CPE_LATCH : id_CPE_FF; + }; + for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; if (!ci.type.in(id_CC_L2T4, id_CC_L2T5, id_CC_LUT2, id_CC_LUT1, id_CC_MX2)) continue; + bool is_l2t5 = false; if (ci.type == id_CC_L2T5) { l2t5_list.push_back(&ci); ci.renamePort(id_I0, id_IN1); @@ -157,13 +195,14 @@ void GateMatePacker::pack_cpe() ci.renamePort(id_I3, id_IN4); ci.renamePort(id_O, id_OUT); - uarch->rename_param(&ci, id_INIT_L02, id_INIT_L00, 4); - uarch->rename_param(&ci, id_INIT_L03, id_INIT_L01, 4); - uarch->rename_param(&ci, id_INIT_L11, id_INIT_L10, 4); + rename_param(&ci, id_INIT_L02, id_INIT_L00, 4); + rename_param(&ci, id_INIT_L03, id_INIT_L01, 4); + rename_param(&ci, id_INIT_L11, id_INIT_L10, 4); ci.cluster = ci.name; ci.constr_abs_z = true; ci.constr_z = CPE_LT_L_Z; ci.type = id_CPE_L2T4; + is_l2t5 = true; } else if (ci.type == id_CC_MX2) { ci.renamePort(id_D1, id_IN1); NetInfo *sel = ci.getPort(id_S0); @@ -173,9 +212,9 @@ void GateMatePacker::pack_cpe() ci.connectPort(id_IN3, sel); ci.renamePort(id_D0, id_IN4); ci.disconnectPort(id_D1); - ci.params[id_INIT_L00] = Property(0b1000, 4); // AND - ci.params[id_INIT_L01] = Property(0b0100, 4); // AND inv D0 - ci.params[id_INIT_L10] = Property(0b1110, 4); // OR + ci.params[id_INIT_L00] = Property(LUT_AND, 4); + ci.params[id_INIT_L01] = Property(LUT_AND_INV_D0, 4); + ci.params[id_INIT_L10] = Property(LUT_OR, 4); ci.renamePort(id_Y, id_OUT); ci.type = id_CPE_L2T4; } else { @@ -190,35 +229,64 @@ void GateMatePacker::pack_cpe() val = val << 2 | val; ci.params[id_INIT_L00] = Property(val, 4); ci.unsetParam(id_INIT); - ci.params[id_INIT_L10] = Property(0b1010, 4); + ci.params[id_INIT_L10] = Property(LUT_D0, 4); } ci.type = id_CPE_L2T4; } NetInfo *o = ci.getPort(id_OUT); if (o) { - CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, true); - if (dff) { - dff->cluster = ci.name; - dff->constr_abs_z = false; - dff->constr_z = +2; - ci.cluster = ci.name; - ci.constr_children.push_back(dff); - dff->renamePort(id_D, id_DIN); - dff->renamePort(id_Q, id_DOUT); - dff_to_cpe(dff); - dff->type = (dff->type == id_CC_DLT) ? id_CPE_LATCH : id_CPE_FF; + if (o->users.entries() == 1) { + // When only it is driving FF + CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, true); + if (dff) + merge_dff(ci, dff); + } else if (!is_l2t5) { + CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, false); + // When driving FF + other logic + if (dff) { + // Make sure main logic is in upper half + ci.constr_abs_z = true; + ci.constr_z = CPE_LT_U_Z; + + merge_dff(ci, dff); + + // Lower half propagate output from upper one + CellInfo *lower = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$lower", ci.name.c_str(ctx))); + ci.constr_children.push_back(lower); + lower->cluster = ci.name; + lower->constr_abs_z = true; + lower->constr_z = CPE_LT_L_Z; + lower->params[id_INIT_L20] = Property(LUT_D0, 4); + ci.movePortTo(id_OUT, lower, id_OUT); + + // Reconnect net + NetInfo *ci_out_conn = ctx->createNet(ctx->idf("%s$out", ci.name.c_str(ctx))); + ci.connectPort(id_OUT, ci_out_conn); + lower->ports[id_COMBIN].name = id_COMBIN; + lower->ports[id_COMBIN].type = PORT_IN; + lower->connectPort(id_COMBIN, ci_out_conn); + dff->disconnectPort(id_DIN); + dff->connectPort(id_DIN, ci_out_conn); + + // Attach if only remaining cell is FF + CellInfo *other = net_only_drives(ctx, o, is_dff, id_D, true); + if (other && are_ffs_compatible(dff, other)) { + merge_dff(ci, other); + other->constr_abs_z = true; + other->constr_z = 3; + } + } } } } - for (auto ci : l2t5_list) { CellInfo *upper = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$upper", ci->name.c_str(ctx))); upper->cluster = ci->name; upper->constr_abs_z = true; upper->constr_z = CPE_LT_U_Z; ci->movePortTo(id_I4, upper, id_IN1); - upper->params[id_INIT_L00] = Property(0b1010, 4); - upper->params[id_INIT_L10] = Property(0b1010, 4); + upper->params[id_INIT_L00] = Property(LUT_D0, 4); + upper->params[id_INIT_L10] = Property(LUT_D0, 4); ci->constr_children.push_back(upper); NetInfo *ci_out_conn = ctx->createNet(ctx->idf("%s$combin", ci->name.c_str(ctx))); @@ -228,7 +296,6 @@ void GateMatePacker::pack_cpe() ci->connectPort(id_COMBIN, ci_out_conn); } l2t5_list.clear(); - flush_cells(); std::vector mux_list; @@ -251,9 +318,10 @@ void GateMatePacker::pack_cpe() for (int i = 0; i < 4; i++) { NetInfo *net = ci.getPort(ctx->idf("D%d", i)); if (net) { - if (net->name.in(ctx->id("$PACKER_GND"), ctx->id("$PACKER_VCC"))) { - if (net->name == ctx->id("$PACKER_VCC")) - invert |= 1 << i; + if (net == net_PACKER_GND) { + ci.disconnectPort(ctx->idf("D%d", i)); + } else if (net == net_PACKER_VCC) { + invert |= 1 << i; ci.disconnectPort(ctx->idf("D%d", i)); } else { select |= 1 << i; @@ -261,10 +329,10 @@ void GateMatePacker::pack_cpe() } } ci.params[id_C_FUNCTION] = Property(C_MX4, 3); - ci.params[id_INIT_L02] = Property(0b1100, 4); // IN6 - ci.params[id_INIT_L03] = Property(0b1100, 4); // IN8 + ci.params[id_INIT_L02] = Property(LUT_D1, 4); // IN6 + ci.params[id_INIT_L03] = Property(LUT_D1, 4); // IN8 ci.params[id_INIT_L11] = Property(invert, 4); // Inversion bits - // ci.params[id_INIT_L20] = Property(0b1100, 4); // Always D1 + ci.params[id_INIT_L20] = Property(LUT_D1, 4); // Always D1 ci.type = id_CPE_LT_L; CellInfo *upper = create_cell_ptr(id_CPE_LT_U, ctx->idf("%s$upper", ci.name.c_str(ctx))); @@ -279,6 +347,13 @@ void GateMatePacker::pack_cpe() ci.movePortTo(id_D2, upper, id_IN3); ci.movePortTo(id_D3, upper, id_IN4); ci.constr_children.push_back(upper); + + NetInfo *o = ci.getPort(id_OUT); + if (o) { + CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, true); + if (dff) + merge_dff(ci, dff); + } } mux_list.clear(); @@ -299,18 +374,17 @@ void GateMatePacker::pack_cpe() ci.constr_children.push_back(lt); ci.renamePort(id_Q, id_DOUT); NetInfo *d_net = ci.getPort(id_D); - if (d_net->name == ctx->id("$PACKER_GND")) { - lt->params[id_INIT_L00] = Property(0b0000, 4); + if (d_net == net_PACKER_GND) { + lt->params[id_INIT_L00] = Property(LUT_ZERO, 4); ci.disconnectPort(id_D); - } else if (d_net->name == ctx->id("$PACKER_VCC")) { - lt->params[id_INIT_L00] = Property(0b1111, 4); + } else if (d_net == net_PACKER_VCC) { + lt->params[id_INIT_L00] = Property(LUT_ONE, 4); ci.disconnectPort(id_D); } else { - lt->params[id_INIT_L00] = Property(0b1010, 4); + lt->params[id_INIT_L00] = Property(LUT_D0, 4); } - lt->params[id_INIT_L10] = Property(0b1010, 4); + lt->params[id_INIT_L10] = Property(LUT_D0, 4); ci.movePortTo(id_D, lt, id_IN1); - dff_to_cpe(&ci); ci.type = (ci.type == id_CC_DLT) ? id_CPE_LATCH : id_CPE_FF; NetInfo *conn = ctx->createNet(ctx->idf("%s$di", ci.name.c_str(ctx))); lt->connectPort(id_OUT, conn); @@ -407,6 +481,56 @@ void GateMatePacker::pack_addf() } flush_cells(); + auto merge_input = [&](CellInfo *cell, CellInfo *target, IdString port, IdString config, IdString in1, + IdString in2) { + NetInfo *net = cell->getPort(port); + if (net == net_PACKER_GND) { + target->params[config] = Property(LUT_ZERO, 4); + cell->disconnectPort(port); + } else if (net == net_PACKER_VCC) { + target->params[config] = Property(LUT_ONE, 4); + cell->disconnectPort(port); + } else { + if (net && net->driver.cell && net->driver.cell->type.in(id_CC_LUT1, id_CC_LUT2) && + (net->users.entries() == 1)) { + CellInfo *lut2 = net->driver.cell; + uint8_t val = int_or_default(lut2->params, id_INIT, 0); + if (lut2->type == id_CC_LUT1) + val = val << 2 | val; + + target->params[config] = Property(val, 4); + lut2->movePortTo(id_I0, target, in1); + lut2->movePortTo(id_I1, target, in2); + cell->disconnectPort(port); + packed_cells.insert(lut2->name); + } else { + if (cell == target) + cell->renamePort(port, in1); + else + cell->movePortTo(port, target, in1); + target->params[config] = Property(LUT_D0, 4); + } + } + }; + + auto merge_dff = [&](CellInfo *cell, IdString port, CellInfo *other) -> CellInfo * { + NetInfo *o = cell->getPort(port); + if (o) { + CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, true); + if (dff && are_ffs_compatible(dff, other)) { + dff->cluster = cell->cluster; + dff->constr_abs_z = false; + dff->constr_z = +2; + cell->constr_children.push_back(dff); + dff->renamePort(id_D, id_DIN); + dff->renamePort(id_Q, id_DOUT); + dff->type = (dff->type == id_CC_DLT) ? id_CPE_LATCH : id_CPE_FF; + return dff; + } + } + return nullptr; + }; + for (auto &grp : splitNestedVector(groups)) { CellInfo *root = grp.front(); root->cluster = root->name; @@ -423,8 +547,8 @@ void GateMatePacker::pack_addf() ci_lower->cluster = root->name; ci_lower->constr_abs_z = false; ci_lower->constr_y = -1; - ci_lower->params[id_INIT_L00] = Property(0b0000, 4); // zero - ci_lower->params[id_INIT_L10] = Property(0b1010, 4); // D0 + ci_lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); + ci_lower->params[id_INIT_L10] = Property(LUT_D0, 4); CellInfo *ci_cplines = create_cell_ptr(id_CPE_CPLINES, ctx->idf("%s$ci_cplines", root->name.c_str(ctx))); ci_cplines->params[id_C_SELY1] = Property(1, 1); @@ -439,15 +563,15 @@ void GateMatePacker::pack_addf() ci_cplines->connectPort(id_OUT1, ci_out_conn); NetInfo *ci_net = root->getPort(id_CI); - if (ci_net->name == ctx->id("$PACKER_GND")) { - ci_lower->params[id_INIT_L00] = Property(0b0000, 4); + if (ci_net == net_PACKER_GND) { + ci_lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); root->disconnectPort(id_CI); - } else if (ci_net->name == ctx->id("$PACKER_VCC")) { - ci_lower->params[id_INIT_L00] = Property(0b1111, 4); + } else if (ci_net == net_PACKER_VCC) { + ci_lower->params[id_INIT_L00] = Property(LUT_ONE, 4); root->disconnectPort(id_CI); } else { - root->movePortTo(id_CI, ci_lower, id_IN1); - ci_lower->params[id_INIT_L00] = Property(0b1010, 4); // IN5 + root->movePortTo(id_CI, ci_lower, id_IN1); // IN5 + ci_lower->params[id_INIT_L00] = Property(LUT_D0, 4); } NetInfo *ci_conn = ctx->createNet(ctx->idf("%s$ci_net", root->name.c_str(ctx))); @@ -469,35 +593,14 @@ void GateMatePacker::pack_addf() bool merged = cy->type != id_CC_ADDF; if (merged) { - NetInfo *a_net = cy->getPort(id_A2); - if (a_net->name == ctx->id("$PACKER_GND")) { - cy->params[id_INIT_L02] = Property(0b0000, 4); - cy->disconnectPort(id_A2); - } else if (a_net->name == ctx->id("$PACKER_VCC")) { - cy->params[id_INIT_L02] = Property(0b1111, 4); - cy->disconnectPort(id_A2); - } else { - cy->renamePort(id_A2, id_IN1); - cy->params[id_INIT_L02] = Property(0b1010, 4); // IN1 - } - NetInfo *b_net = cy->getPort(id_B2); - if (b_net->name == ctx->id("$PACKER_GND")) { - cy->params[id_INIT_L03] = Property(0b0000, 4); - cy->disconnectPort(id_B2); - } else if (b_net->name == ctx->id("$PACKER_VCC")) { - cy->params[id_INIT_L03] = Property(0b1111, 4); - cy->disconnectPort(id_B2); - } else { - cy->renamePort(id_B2, id_IN3); - cy->params[id_INIT_L03] = Property(0b1010, 4); // IN3 - } - cy->params[id_INIT_L11] = Property(0b0110, 4); // XOR - cy->renamePort(id_S2, id_OUT); + merge_input(cy, cy, id_A2, id_INIT_L02, id_IN1, id_IN2); // IN5,IN6 + merge_input(cy, cy, id_B2, id_INIT_L03, id_IN3, id_IN4); // IN7,IN8 + cy->params[id_INIT_L11] = Property(LUT_XOR, 4); } else { - cy->params[id_INIT_L02] = Property(0b0000, 4); // 0 - cy->params[id_INIT_L03] = Property(0b0000, 4); // 0 - cy->params[id_INIT_L11] = Property(0b0110, 4); // XOR - cy->params[id_INIT_L20] = Property(0b0110, 4); // XOR + cy->params[id_INIT_L02] = Property(LUT_ZERO, 4); + cy->params[id_INIT_L03] = Property(LUT_ZERO, 4); + cy->params[id_INIT_L11] = Property(LUT_XOR, 4); + cy->params[id_INIT_L20] = Property(LUT_XOR, 4); } cy->params[id_C_FUNCTION] = Property(merged ? C_ADDF2 : C_ADDF, 3); cy->type = id_CPE_LT_L; @@ -508,36 +611,18 @@ void GateMatePacker::pack_addf() upper->constr_abs_z = false; upper->constr_y = +i; upper->constr_z = -1; + CellInfo *other_dff = nullptr; if (merged) { cy->movePortTo(id_S, upper, id_OUT); + cy->renamePort(id_S2, id_OUT); + other_dff = merge_dff(upper, id_OUT, other_dff); } else { cy->renamePort(id_S, id_OUT); } - - NetInfo *a_net = cy->getPort(id_A); - if (a_net->name == ctx->id("$PACKER_GND")) { - upper->params[id_INIT_L00] = Property(0b0000, 4); - cy->disconnectPort(id_A); - } else if (a_net->name == ctx->id("$PACKER_VCC")) { - upper->params[id_INIT_L00] = Property(0b1111, 4); - cy->disconnectPort(id_A); - } else { - cy->movePortTo(id_A, upper, id_IN1); - upper->params[id_INIT_L00] = Property(0b1010, 4); // IN1 - } - NetInfo *b_net = cy->getPort(id_B); - if (b_net->name == ctx->id("$PACKER_GND")) { - upper->params[id_INIT_L01] = Property(0b0000, 4); - cy->disconnectPort(id_B); - } else if (b_net->name == ctx->id("$PACKER_VCC")) { - upper->params[id_INIT_L01] = Property(0b1111, 4); - cy->disconnectPort(id_B); - } else { - cy->movePortTo(id_B, upper, id_IN3); - upper->params[id_INIT_L01] = Property(0b1010, 4); // IN3 - } - - upper->params[id_INIT_L10] = Property(0b0110, 4); // XOR + merge_dff(cy, id_OUT, other_dff); + merge_input(cy, upper, id_A, id_INIT_L00, id_IN1, id_IN2); + merge_input(cy, upper, id_B, id_INIT_L01, id_IN3, id_IN4); + upper->params[id_INIT_L10] = Property(LUT_XOR, 4); upper->params[id_C_FUNCTION] = Property(merged ? C_ADDF2 : C_ADDF, 3); if (i == grp.size() - 1) { @@ -555,8 +640,8 @@ void GateMatePacker::pack_addf() co_lower->constr_abs_z = false; co_lower->constr_y = +i + 1; co_lower->params[id_C_FUNCTION] = Property(C_EN_CIN, 3); - co_lower->params[id_INIT_L10] = Property(0b1100, 4); - co_lower->params[id_INIT_L20] = Property(0b1100, 4); + co_lower->params[id_INIT_L10] = Property(LUT_D1, 4); + co_lower->params[id_INIT_L20] = Property(LUT_D1, 4); NetInfo *co_conn = ctx->createNet(ctx->idf("%s$co_net", cy->name.c_str(ctx))); @@ -587,21 +672,24 @@ void GateMatePacker::pack_addf() } } } + flush_cells(); } void GateMatePacker::pack_constants() { log_info("Packing constants..\n"); // Replace constants with LUTs - const dict vcc_params = {{id_INIT_L10, Property(0b1111, 4)}}; - const dict gnd_params = {{id_INIT_L10, Property(0b0000, 4)}}; + const dict vcc_params = {{id_INIT_L10, Property(LUT_ONE, 4)}}; + const dict gnd_params = {{id_INIT_L10, Property(LUT_ZERO, 4)}}; h.replace_constants(CellTypePort(id_CPE_L2T4, id_OUT), CellTypePort(id_CPE_L2T4, id_OUT), vcc_params, gnd_params); + net_PACKER_VCC = ctx->nets.at(ctx->id("$PACKER_VCC")).get(); + net_PACKER_GND = ctx->nets.at(ctx->id("$PACKER_GND")).get(); } void GateMatePacker::remove_constants() { - log_info("Removing constants..\n"); + log_info("Removing unused constants..\n"); auto fnd_cell = ctx->cells.find(ctx->id("$PACKER_VCC_DRV")); if (fnd_cell != ctx->cells.end()) { auto fnd_net = ctx->nets.find(ctx->id("$PACKER_VCC")); @@ -628,4 +716,171 @@ void GateMatePacker::remove_constants() } } +std::pair GateMatePacker::move_ram_i(CellInfo *cell, IdString origPort, bool place, Loc cpe_loc) +{ + CellInfo *cpe_half = nullptr; + CellInfo *cpe_ramio = nullptr; + NetInfo *net = cell->getPort(origPort); + if (net) { + cpe_ramio = create_cell_ptr(id_CPE_RAMI, ctx->idf("%s$%s_rami", cell->name.c_str(ctx), origPort.c_str(ctx))); + if (place) { + cell->constr_children.push_back(cpe_ramio); + cpe_ramio->cluster = cell->cluster; + cpe_ramio->constr_abs_z = false; + cpe_ramio->constr_z = PLACE_DB_CONSTR + origPort.index; + } else { + BelId b = ctx->getBelByLocation(cpe_loc); + ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); + } + CellInfo *cpe_half = + create_cell_ptr(id_CPE_DUMMY, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), origPort.c_str(ctx))); + if (place) { + cpe_ramio->constr_children.push_back(cpe_half); + cpe_half->cluster = cell->cluster; + cpe_half->constr_abs_z = false; + cpe_half->constr_z = -4; + } else { + BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); + ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); + } + + cpe_ramio->params[id_C_RAM_I] = Property(1, 1); + + NetInfo *ram_i = ctx->createNet(ctx->idf("%s$ram_i", cpe_ramio->name.c_str(ctx))); + cell->movePortTo(origPort, cpe_ramio, id_OUT); + cell->connectPort(origPort, ram_i); + cpe_ramio->connectPort(id_RAM_I, ram_i); + } + return std::make_pair(cpe_half, cpe_ramio); +} + +std::pair GateMatePacker::move_ram_o(CellInfo *cell, IdString origPort, bool place, Loc cpe_loc) +{ + CellInfo *cpe_half = nullptr; + CellInfo *cpe_ramio = nullptr; + NetInfo *net = cell->getPort(origPort); + if (net) { + cpe_ramio = create_cell_ptr(id_CPE_RAMO, ctx->idf("%s$%s_ramo", cell->name.c_str(ctx), origPort.c_str(ctx))); + if (place) { + cell->constr_children.push_back(cpe_ramio); + cpe_ramio->cluster = cell->cluster; + cpe_ramio->constr_abs_z = false; + cpe_ramio->constr_z = PLACE_DB_CONSTR + origPort.index; + } else { + BelId b = ctx->getBelByLocation(cpe_loc); + ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); + } + cpe_half = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), origPort.c_str(ctx))); + if (place) { + cpe_ramio->constr_children.push_back(cpe_half); + cpe_half->cluster = cell->cluster; + cpe_half->constr_abs_z = false; + cpe_half->constr_z = -4; + } else { + BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); + ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); + } + if (net == net_PACKER_GND) { + cpe_half->params[id_INIT_L00] = Property(LUT_ZERO, 4); + cell->disconnectPort(origPort); + } else if (net == net_PACKER_VCC) { + cpe_half->params[id_INIT_L00] = Property(LUT_ONE, 4); + cell->disconnectPort(origPort); + } else { + cpe_half->params[id_INIT_L00] = Property(LUT_D0, 4); + cell->movePortTo(origPort, cpe_half, id_IN1); + } + cpe_half->params[id_INIT_L10] = Property(LUT_D0, 4); + + cpe_ramio->params[id_C_RAM_O] = Property(1, 1); + NetInfo *ram_o = ctx->createNet(ctx->idf("%s$ram_o", cpe_half->name.c_str(ctx))); + cell->connectPort(origPort, ram_o); + cpe_ramio->connectPort(id_RAM_O, ram_o); + + NetInfo *out = ctx->createNet(ctx->idf("%s$out", cpe_half->name.c_str(ctx))); + cpe_half->connectPort(id_OUT, out); + cpe_ramio->connectPort(id_I, out); + } + return std::make_pair(cpe_half, cpe_ramio); +} + +std::pair GateMatePacker::move_ram_io(CellInfo *cell, IdString iPort, IdString oPort, + bool place, Loc cpe_loc) +{ + NetInfo *i_net = cell->getPort(iPort); + NetInfo *o_net = cell->getPort(oPort); + if (!i_net && !o_net) + return std::make_pair(nullptr, nullptr); + + CellInfo *cpe_ramio = + create_cell_ptr(id_CPE_RAMIO, ctx->idf("%s$%s_ramio", cell->name.c_str(ctx), oPort.c_str(ctx))); + if (place) { + cell->constr_children.push_back(cpe_ramio); + cpe_ramio->cluster = cell->cluster; + cpe_ramio->constr_abs_z = false; + cpe_ramio->constr_z = PLACE_DB_CONSTR + oPort.index; + } else { + BelId b = ctx->getBelByLocation(cpe_loc); + ctx->bindBel(b, cpe_ramio, PlaceStrength::STRENGTH_FIXED); + } + CellInfo *cpe_half = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$%s_cpe", cell->name.c_str(ctx), oPort.c_str(ctx))); + if (place) { + cpe_ramio->constr_children.push_back(cpe_half); + cpe_half->cluster = cell->cluster; + cpe_half->constr_abs_z = false; + cpe_half->constr_z = -4; + } else { + BelId b = ctx->getBelByLocation(Loc(cpe_loc.x, cpe_loc.y, cpe_loc.z - 4)); + ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED); + } + + if (o_net) { + if (o_net == net_PACKER_GND) { + cpe_half->params[id_INIT_L00] = Property(LUT_ZERO, 4); + cell->disconnectPort(oPort); + } else if (o_net == net_PACKER_VCC) { + cpe_half->params[id_INIT_L00] = Property(LUT_ONE, 4); + cell->disconnectPort(oPort); + } else { + cpe_half->params[id_INIT_L00] = Property(LUT_D0, 4); + cell->movePortTo(oPort, cpe_half, id_IN1); + } + cpe_half->params[id_INIT_L10] = Property(LUT_D0, 4); + cpe_ramio->params[id_C_RAM_O] = Property(1, 1); + + NetInfo *ram_o = ctx->createNet(ctx->idf("%s$ram_o", cpe_half->name.c_str(ctx))); + cell->connectPort(oPort, ram_o); + cpe_ramio->connectPort(id_RAM_O, ram_o); + + NetInfo *out = ctx->createNet(ctx->idf("%s$out", cpe_half->name.c_str(ctx))); + cpe_half->connectPort(id_OUT, out); + cpe_ramio->connectPort(id_I, out); + } + if (i_net) { + cpe_ramio->params[id_C_RAM_I] = Property(1, 1); + + NetInfo *ram_i = ctx->createNet(ctx->idf("%s$ram_i", cpe_half->name.c_str(ctx))); + cell->movePortTo(iPort, cpe_ramio, id_OUT); + cell->connectPort(iPort, ram_i); + cpe_ramio->connectPort(id_RAM_I, ram_i); + } + return std::make_pair(cpe_half, cpe_ramio); +} + +std::pair GateMatePacker::move_ram_i_fixed(CellInfo *cell, IdString origPort, Loc fixed) +{ + return move_ram_i(cell, origPort, false, uarch->getRelativeConstraint(fixed, origPort)); +} + +std::pair GateMatePacker::move_ram_o_fixed(CellInfo *cell, IdString origPort, Loc fixed) +{ + return move_ram_o(cell, origPort, false, uarch->getRelativeConstraint(fixed, origPort)); +} + +std::pair GateMatePacker::move_ram_io_fixed(CellInfo *cell, IdString iPort, IdString oPort, + Loc fixed) +{ + return move_ram_io(cell, iPort, oPort, false, uarch->getRelativeConstraint(fixed, oPort)); +} + NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack_io.cc b/himbaechel/uarch/gatemate/pack_io.cc index 8875614f..1f1556b6 100644 --- a/himbaechel/uarch/gatemate/pack_io.cc +++ b/himbaechel/uarch/gatemate/pack_io.cc @@ -33,6 +33,7 @@ std::string get_die_name(int total_dies, int die) void GateMatePacker::pack_io() { + log_info("Packing IOs..\n"); // Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis for (auto &port : ctx->ports) { if (!ctx->cells.count(port.first)) @@ -317,6 +318,7 @@ void GateMatePacker::pack_io() void GateMatePacker::pack_io_sel() { + log_info("Packing IO SELs..\n"); std::vector cells; for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -331,9 +333,9 @@ void GateMatePacker::pack_io_sel() auto set_out_clk = [&](CellInfo *cell, CellInfo *target) -> bool { NetInfo *clk_net = cell->getPort(id_CLK); if (clk_net) { - if (clk_net->name == ctx->id("$PACKER_GND")) { + if (clk_net == net_PACKER_GND) { cell->disconnectPort(id_CLK); - } else if (clk_net->name == ctx->id("$PACKER_VCC")) { + } else if (clk_net == net_PACKER_VCC) { cell->disconnectPort(id_CLK); } else { if (!global_signals.count(clk_net)) { @@ -352,9 +354,9 @@ void GateMatePacker::pack_io_sel() auto set_in_clk = [&](CellInfo *cell, CellInfo *target) { NetInfo *clk_net = cell->getPort(id_CLK); if (clk_net) { - if (clk_net->name == ctx->id("$PACKER_GND")) { + if (clk_net == net_PACKER_GND) { cell->disconnectPort(id_CLK); - } else if (clk_net->name == ctx->id("$PACKER_VCC")) { + } else if (clk_net == net_PACKER_VCC) { cell->disconnectPort(id_CLK); } else { if (!global_signals.count(clk_net)) { @@ -439,9 +441,11 @@ void GateMatePacker::pack_io_sel() NetInfo *do_net = ci.getPort(id_A); bool use_custom_clock = false; if (do_net) { - if (do_net->name.in(ctx->id("$PACKER_GND"), ctx->id("$PACKER_VCC"))) { - ci.params[id_OUT23_14_SEL] = - Property(do_net->name == ctx->id("$PACKER_VCC") ? Property::State::S1 : Property::State::S0); + if (do_net == net_PACKER_GND) { + ci.params[id_OUT23_14_SEL] = Property(Property::State::S0); + ci.disconnectPort(id_A); + } else if (do_net == net_PACKER_VCC) { + ci.params[id_OUT23_14_SEL] = Property(Property::State::S1); ci.disconnectPort(id_A); } else { ci.params[id_OUT_SIGNAL] = Property(Property::State::S1); @@ -522,7 +526,7 @@ void GateMatePacker::pack_io_sel() for (int i = 0; i < 4; i++) { CellInfo *cpe = move_ram_o_fixed(&ci, ctx->idf("OUT%d", i + 1), root_loc).first; if (cpe && i == 2) - cpe->params[id_INIT_L10] = Property(0b0101, 4); // Invert CPE out for output enable (OUT3) + cpe->params[id_INIT_L10] = Property(LUT_INV_D0, 4); // Invert CPE out for output enable (OUT3) } } flush_cells(); @@ -533,11 +537,11 @@ bool GateMatePacker::is_gpio_valid_dff(CellInfo *dff) NetInfo *en_net = dff->getPort(id_EN); bool invert = bool_or_default(dff->params, id_EN_INV, 0); if (en_net) { - if (en_net->name == ctx->id("$PACKER_GND")) { + if (en_net == net_PACKER_GND) { if (!invert) return false; dff->disconnectPort(id_EN); - } else if (en_net->name == ctx->id("$PACKER_VCC")) { + } else if (en_net == net_PACKER_VCC) { if (invert) return false; dff->disconnectPort(id_EN); @@ -550,8 +554,8 @@ bool GateMatePacker::is_gpio_valid_dff(CellInfo *dff) NetInfo *sr_net = dff->getPort(id_SR); invert = bool_or_default(dff->params, id_SR_INV, 0); if (sr_net) { - if (sr_net->name.in(ctx->id("$PACKER_GND"), ctx->id("$PACKER_VCC"))) { - bool sr_signal = sr_net->name == ctx->id("$PACKER_VCC"); + if ((sr_net == net_PACKER_GND) || (sr_net == net_PACKER_VCC)) { + bool sr_signal = sr_net == net_PACKER_VCC; if (sr_signal ^ invert) log_error("Currently unsupported DFF configuration for '%s'\n.", dff->name.c_str(ctx)); dff->disconnectPort(id_SR); @@ -565,9 +569,9 @@ bool GateMatePacker::is_gpio_valid_dff(CellInfo *dff) // Sanity check for CLK signal, that it must exist NetInfo *clk_net = dff->getPort(id_CLK); if (clk_net) { - if (clk_net->name == ctx->id("$PACKER_GND")) { + if (clk_net == net_PACKER_GND) { return false; - } else if (clk_net->name == ctx->id("$PACKER_VCC")) { + } else if (clk_net == net_PACKER_VCC) { return false; } } else { diff --git a/himbaechel/uarch/gatemate/pack_serdes.cc b/himbaechel/uarch/gatemate/pack_serdes.cc index 03946805..866c9b83 100644 --- a/himbaechel/uarch/gatemate/pack_serdes.cc +++ b/himbaechel/uarch/gatemate/pack_serdes.cc @@ -293,6 +293,7 @@ static const DefaultParam serdes_defaults[] = { void GateMatePacker::pack_serdes() { + log_info("Packing SERDES..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; if (!ci.type.in(id_CC_SERDES)) diff --git a/himbaechel/uarch/gatemate/tests/lut.cc b/himbaechel/uarch/gatemate/tests/lut.cc index 7f3c75a8..053b0556 100644 --- a/himbaechel/uarch/gatemate/tests/lut.cc +++ b/himbaechel/uarch/gatemate/tests/lut.cc @@ -49,9 +49,9 @@ TEST_F(GateMateTest, remove_lut1_zero) CellInfo *obuf = create_cell_ptr(id_CC_OBUF, "obuf"); - direct_connect(lut1, id_O, obuf, id_A); + lut1->connectPorts(id_O, obuf, id_A); - ASSERT_EQ(ctx->cells.size(), 1LU); + ASSERT_EQ(ctx->cells.size(), 2LU); ctx->uarch->pack(); ASSERT_EQ(ctx->cells.size(), 1LU); } @@ -63,7 +63,7 @@ TEST_F(GateMateTest, remove_lut1_one) CellInfo *obuf = create_cell_ptr(id_CC_OBUF, "obuf"); - direct_connect(lut1, id_O, obuf, id_A); + lut1->connectPorts(id_O, obuf, id_A); ASSERT_EQ(ctx->cells.size(), 2LU); ctx->uarch->pack(); @@ -78,14 +78,14 @@ TEST_F(GateMateTest, remove_lut1_pass) CellInfo *obuf = create_cell_ptr(id_CC_OBUF, "obuf"); CellInfo *ibuf = create_cell_ptr(id_CC_IBUF, "ibuf"); - direct_connect(ibuf, id_Y, lut1, id_I0); - direct_connect(lut1, id_O, obuf, id_A); + ibuf->connectPorts(id_Y, lut1, id_I0); + lut1->connectPorts(id_O, obuf, id_A); ASSERT_EQ(ctx->cells.size(), 3LU); ctx->uarch->pack(); // Expect IBUF -> CPE -> OBUF // LUT removed, but CPE for driving OBUF added - ASSERT_EQ(ctx->cells.size(), 3LU); + ASSERT_EQ(ctx->cells.size(), 4LU); } TEST_F(GateMateTest, remove_lut1_inv) @@ -96,14 +96,14 @@ TEST_F(GateMateTest, remove_lut1_inv) CellInfo *obuf = create_cell_ptr(id_CC_OBUF, "obuf"); CellInfo *ibuf = create_cell_ptr(id_CC_IBUF, "ibuf"); - direct_connect(ibuf, id_Y, lut1, id_I0); - direct_connect(lut1, id_O, obuf, id_A); + ibuf->connectPorts(id_Y, lut1, id_I0); + lut1->connectPorts(id_O, obuf, id_A); ASSERT_EQ(ctx->cells.size(), 3LU); ctx->uarch->pack(); // Expect IBUF -> CPE -> OBUF // LUT merged, but CPE for driving OBUF added - ASSERT_EQ(ctx->cells.size(), 3LU); + ASSERT_EQ(ctx->cells.size(), 5LU); } TEST_F(GateMateTest, remove_lut1_not_driven) @@ -123,5 +123,5 @@ TEST_F(GateMateTest, remove_lut1_not_driven) ctx->uarch->pack(); // Expect IBUF -> CPE -> OBUF // LUT1 removed as not used, but CPE for driving OBUF added - ASSERT_EQ(ctx->cells.size(), 3LU); + ASSERT_EQ(ctx->cells.size(), 4LU); } diff --git a/himbaechel/uarch/gatemate/tests/testing.cc b/himbaechel/uarch/gatemate/tests/testing.cc index 4306e657..190e19e8 100644 --- a/himbaechel/uarch/gatemate/tests/testing.cc +++ b/himbaechel/uarch/gatemate/tests/testing.cc @@ -201,11 +201,4 @@ CellInfo *GateMateTest::create_cell_ptr(IdString type, std::string name) return cell; } -void GateMateTest::direct_connect(CellInfo *o_cell, IdString o_port, CellInfo *i_cell, IdString i_port) -{ - NetInfo *net = ctx->createNet(ctx->idf("%s_%s", o_cell->name.c_str(ctx), o_port.c_str(ctx))); - o_cell->connectPort(o_port, net); - i_cell->connectPort(i_port, net); -} - NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/tests/testing.h b/himbaechel/uarch/gatemate/tests/testing.h index 576729cd..73c1110e 100644 --- a/himbaechel/uarch/gatemate/tests/testing.h +++ b/himbaechel/uarch/gatemate/tests/testing.h @@ -34,7 +34,6 @@ class GateMateTest : public ::testing::Test virtual void TearDown() override; CellInfo *create_cell_ptr(IdString type, std::string name); - void direct_connect(CellInfo *o_cell, IdString o_port, CellInfo *i_cell, IdString i_port); ArchArgs chipArgs; Context *ctx;