mirror of https://github.com/YosysHQ/nextpnr.git
Merge 840311b5ac into a3938de734
This commit is contained in:
commit
240a75da6e
|
|
@ -1442,6 +1442,28 @@ struct FasmBackend
|
|||
write_bit("CASCOUT_ARD_ACTIVE", !used_rdaddrcasc.empty());
|
||||
write_bit("CASCOUT_BWR_ACTIVE", !used_wraddrcasc.empty());
|
||||
}
|
||||
// A RAMB36E1 with a width-1 port needs the RAMB36-level BRAM36_*_WIDTH_*_1
|
||||
// feature in addition to the per-half RAMB18_Yx width bits. Without it the
|
||||
// two 16K halves (which interleave even/odd bit addresses in true 32K x 1
|
||||
// mode) both respond at addr>>1: every write hits bit pairs 2k/2k+1 and
|
||||
// the address LSB is ignored.
|
||||
if (half == 0 && ci != nullptr && ci->type == id_RAMB36E1_RAMB36E1) {
|
||||
push("RAMB36");
|
||||
for (const char *port : {"READ_WIDTH_A", "READ_WIDTH_B", "WRITE_WIDTH_A", "WRITE_WIDTH_B"})
|
||||
if (int_or_default(ci->params, ctx->id(port), 0) == 1)
|
||||
write_bit(std::string("BRAM36_") + port + "_1");
|
||||
// Depth-cascaded pairs (64K x 1): the LOWER cell needs its
|
||||
// RAM_EXTENSION bit set; UPPER shares the NONE encoding (bit
|
||||
// clear), so only LOWER is written. Was never emitted, which
|
||||
// breaks true width-1 cascaded memories.
|
||||
for (const char *port : {"A", "B"}) {
|
||||
std::string ext =
|
||||
str_or_default(ci->params, ctx->id(std::string("RAM_EXTENSION_") + port), "NONE");
|
||||
if (ext == "LOWER")
|
||||
write_bit(std::string("RAM_EXTENSION_") + port + "_LOWER");
|
||||
}
|
||||
pop();
|
||||
}
|
||||
pop();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -754,14 +754,19 @@ void XC7Packer::pack_bram()
|
|||
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
|
||||
}
|
||||
} else if (ci->type == id_RAMB36E1_RAMB36E1) {
|
||||
// ADDRARDADDRL15/ADDRBWRADDRL15 must be tied high in non-cascaded
|
||||
// modes, but in a depth-cascaded pair (RAM_EXTENSION_A/B = LOWER/
|
||||
// UPPER) they carry the address MSB that selects the half; the
|
||||
// multixform has already wired ADDRARDADDR[15] onto them, and
|
||||
// overriding that with VCC pins both reads and writes to the upper
|
||||
// 32K half. Only tie when not driven.
|
||||
for (auto p : {id_ADDRARDADDRL15, id_ADDRBWRADDRL15}) {
|
||||
if (!ci->ports.count(p)) {
|
||||
ci->ports[p].name = p;
|
||||
ci->ports[p].type = PORT_IN;
|
||||
} else {
|
||||
ci->disconnectPort(p);
|
||||
}
|
||||
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
|
||||
if (ci->getPort(p) == nullptr)
|
||||
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
|
||||
}
|
||||
if (int_or_default(ci->params, id_WRITE_WIDTH_A, 0) == 1) {
|
||||
ci->disconnectPort(id_DIADI1);
|
||||
|
|
@ -803,6 +808,42 @@ void XC7Packer::pack_bram()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cluster cascaded RAMB36 pairs: CASCADEOUT->CASCADEIN are dedicated
|
||||
// wires that only reach the vertically adjacent RAMB36 site, so the
|
||||
// pair must be placed together (cf. carry chains). BRAM tiles are 5
|
||||
// grid rows apart within a column.
|
||||
int cascade_pairs = 0;
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *lower = cell.second.get();
|
||||
if (lower->type != id_RAMB36E1_RAMB36E1)
|
||||
continue;
|
||||
for (auto pn : {ctx->id("CASCADEOUTA"), ctx->id("CASCADEOUTB")}) {
|
||||
NetInfo *cn = lower->getPort(pn);
|
||||
if (cn == nullptr)
|
||||
continue;
|
||||
for (auto &usr : cn->users) {
|
||||
CellInfo *upper = usr.cell;
|
||||
if (upper == lower || upper->type != id_RAMB36E1_RAMB36E1)
|
||||
continue;
|
||||
if (upper->cluster != ClusterId())
|
||||
continue; // already clustered (e.g. via the A cascade)
|
||||
if (lower->cluster == ClusterId())
|
||||
lower->cluster = lower->name;
|
||||
else if (lower->cluster != lower->name)
|
||||
continue; // lower is a child of another cluster; unsupported
|
||||
upper->cluster = lower->name;
|
||||
lower->constr_children.push_back(upper);
|
||||
upper->constr_x = 0;
|
||||
upper->constr_y = 5;
|
||||
upper->constr_z = 0;
|
||||
upper->constr_abs_z = false;
|
||||
++cascade_pairs;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cascade_pairs > 0)
|
||||
log_info(" Clustered %d cascaded BRAM pairs\n", cascade_pairs);
|
||||
}
|
||||
|
||||
void XilinxPacker::pack_inverters()
|
||||
|
|
|
|||
|
|
@ -101,6 +101,49 @@ void XilinxImpl::init(Context *ctx)
|
|||
auto extra_data = tile_extra_data(i);
|
||||
tile_status.at(i).site_variant.resize(extra_data->sites.ssize());
|
||||
}
|
||||
|
||||
// Build the next-RAMB36-up-the-column map for cascade placement
|
||||
std::map<int, std::map<int, BelId>> bram36_by_col; // x -> y -> bel
|
||||
for (BelId bel : ctx->getBels()) {
|
||||
if (ctx->getBelType(bel) != id_RAMB36E1_RAMB36E1)
|
||||
continue;
|
||||
Loc l = ctx->getBelLocation(bel);
|
||||
bram36_by_col[l.x][l.y] = bel;
|
||||
}
|
||||
for (auto &col : bram36_by_col) {
|
||||
BelId prev;
|
||||
int prev_y = 0;
|
||||
for (auto &entry : col.second) {
|
||||
if (prev != BelId() && (entry.first - prev_y) <= 6)
|
||||
next_bram36_up[entry.second] = prev; // grid Y increases downwards: 'up' = smaller y
|
||||
prev = entry.second;
|
||||
prev_y = entry.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool XilinxImpl::getClusterPlacement(ClusterId cluster, BelId root_bel,
|
||||
std::vector<std::pair<CellInfo *, BelId>> &placement) const
|
||||
{
|
||||
CellInfo *root_cell = ctx->getClusterRootCell(cluster);
|
||||
if (root_cell->type == id_RAMB36E1_RAMB36E1) {
|
||||
if (ctx->getBelType(root_bel) != id_RAMB36E1_RAMB36E1)
|
||||
return false;
|
||||
placement.clear();
|
||||
placement.emplace_back(root_cell, root_bel);
|
||||
BelId cursor = root_bel;
|
||||
for (auto child : root_cell->constr_children) {
|
||||
auto fnd = next_bram36_up.find(cursor);
|
||||
if (fnd == next_bram36_up.end())
|
||||
return false;
|
||||
cursor = fnd->second;
|
||||
if (ctx->getBelType(cursor) != id_RAMB36E1_RAMB36E1)
|
||||
return false;
|
||||
placement.emplace_back(child, cursor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return HimbaechelAPI::getClusterPlacement(cluster, root_bel, placement);
|
||||
}
|
||||
|
||||
SiteIndex XilinxImpl::get_bel_site(BelId bel) const
|
||||
|
|
@ -397,7 +440,7 @@ void XilinxImpl::configurePlacerStatic(PlacerStaticCfg &cfg)
|
|||
comb.cell_area[id_RAMB18E1_RAMB18E1] = StaticRect(1.0f, 3.0f);
|
||||
comb.bel_area[id_RAMB18E1_RAMB18E1] = StaticRect(1.0f, 3.0f);
|
||||
comb.cell_area[id_RAMB36E1_RAMB36E1] = StaticRect(1.0f, 6.0f);
|
||||
comb.bel_area[id_RAMB36E1_RAMB36E1] = StaticRect(0.0f, 0.0f);
|
||||
comb.bel_area[id_RAMB36E1_RAMB36E1] = StaticRect(1.0f, 6.0f);
|
||||
comb.spacer_rect = StaticRect(1.0f, 3.0f);
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -123,6 +123,14 @@ struct XilinxImpl : HimbaechelAPI
|
|||
bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override;
|
||||
bool xc7_logic_tile_valid(IdString tileType, const LogicTileStatus <s) const;
|
||||
|
||||
// BRAM cascade support: CASCADEOUT->CASCADEIN only reaches the next
|
||||
// RAMB36 site up the column; bel z indices are not uniform across BRAM
|
||||
// tiles, so relative (x,y,z) constraints cannot express this. Precompute
|
||||
// the next-RAMB36-in-column map and use it in getClusterPlacement.
|
||||
dict<BelId, BelId> next_bram36_up;
|
||||
bool getClusterPlacement(ClusterId cluster, BelId root_bel,
|
||||
std::vector<std::pair<CellInfo *, BelId>> &placement) const override;
|
||||
|
||||
// Pips
|
||||
bool is_pip_unavail(PipId pip) const;
|
||||
bool checkPipAvail(PipId pip) const override { return !is_pip_unavail(pip); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue