gatemate: BRAM cascade mode support (#1487)

* BRAM cascade mode support

* Removed unused connections

* Exclusive connection
This commit is contained in:
Miodrag Milanović 2025-05-19 09:55:11 +02:00 committed by GitHub
parent 23a99989d1
commit 6c3956c3b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 197 deletions

View File

@ -1593,198 +1593,6 @@ X(F_RSTN)
//X(FRD_ADDRX[14])
//X(FRD_ADDR[15])
//X(FRD_ADDRX[15])
X(FORW_CAS_WRAO)
X(FORW_CAS_WRAI)
X(FORW_CAS_WRBO)
X(FORW_CAS_WRBI)
X(FORW_CAS_BMAO)
X(FORW_CAS_BMAI)
X(FORW_CAS_BMBO)
X(FORW_CAS_BMBI)
X(FORW_CAS_RDAO)
X(FORW_CAS_RDAI)
X(FORW_CAS_RDBO)
X(FORW_CAS_RDBI)
//X(FORW_UADDRAO[0])
//X(FORW_UADDRAO[1])
//X(FORW_UADDRAO[2])
//X(FORW_UADDRAO[3])
//X(FORW_UADDRAO[4])
//X(FORW_UADDRAO[5])
//X(FORW_UADDRAO[6])
//X(FORW_UADDRAO[7])
//X(FORW_UADDRAO[8])
//X(FORW_UADDRAO[9])
//X(FORW_UADDRAO[10])
//X(FORW_UADDRAO[11])
//X(FORW_UADDRAO[12])
//X(FORW_UADDRAO[13])
//X(FORW_UADDRAO[14])
//X(FORW_UADDRAO[15])
//X(FORW_LADDRAI[0])
//X(FORW_LADDRAI[1])
//X(FORW_LADDRAI[2])
//X(FORW_LADDRAI[3])
//X(FORW_LADDRAI[4])
//X(FORW_LADDRAI[5])
//X(FORW_LADDRAI[6])
//X(FORW_LADDRAI[7])
//X(FORW_LADDRAI[8])
//X(FORW_LADDRAI[9])
//X(FORW_LADDRAI[10])
//X(FORW_LADDRAI[11])
//X(FORW_LADDRAI[12])
//X(FORW_LADDRAI[13])
//X(FORW_LADDRAI[14])
//X(FORW_LADDRAI[15])
//X(FORW_LADDRAO[0])
//X(FORW_LADDRAO[1])
//X(FORW_LADDRAO[2])
//X(FORW_LADDRAO[3])
//X(FORW_LADDRAO[4])
//X(FORW_LADDRAO[5])
//X(FORW_LADDRAO[6])
//X(FORW_LADDRAO[7])
//X(FORW_LADDRAO[8])
//X(FORW_LADDRAO[9])
//X(FORW_LADDRAO[10])
//X(FORW_LADDRAO[11])
//X(FORW_LADDRAO[12])
//X(FORW_LADDRAO[13])
//X(FORW_LADDRAO[14])
//X(FORW_LADDRAO[15])
//X(FORW_UADDRAI[0])
//X(FORW_UADDRAI[1])
//X(FORW_UADDRAI[2])
//X(FORW_UADDRAI[3])
//X(FORW_UADDRAI[4])
//X(FORW_UADDRAI[5])
//X(FORW_UADDRAI[6])
//X(FORW_UADDRAI[7])
//X(FORW_UADDRAI[8])
//X(FORW_UADDRAI[9])
//X(FORW_UADDRAI[10])
//X(FORW_UADDRAI[11])
//X(FORW_UADDRAI[12])
//X(FORW_UADDRAI[13])
//X(FORW_UADDRAI[14])
//X(FORW_UADDRAI[15])
//X(FORW_UADDRBO[0])
//X(FORW_UADDRBO[1])
//X(FORW_UADDRBO[2])
//X(FORW_UADDRBO[3])
//X(FORW_UADDRBO[4])
//X(FORW_UADDRBO[5])
//X(FORW_UADDRBO[6])
//X(FORW_UADDRBO[7])
//X(FORW_UADDRBO[8])
//X(FORW_UADDRBO[9])
//X(FORW_UADDRBO[10])
//X(FORW_UADDRBO[11])
//X(FORW_UADDRBO[12])
//X(FORW_UADDRBO[13])
//X(FORW_UADDRBO[14])
//X(FORW_UADDRBO[15])
//X(FORW_LADDRBI[0])
//X(FORW_LADDRBI[1])
//X(FORW_LADDRBI[2])
//X(FORW_LADDRBI[3])
//X(FORW_LADDRBI[4])
//X(FORW_LADDRBI[5])
//X(FORW_LADDRBI[6])
//X(FORW_LADDRBI[7])
//X(FORW_LADDRBI[8])
//X(FORW_LADDRBI[9])
//X(FORW_LADDRBI[10])
//X(FORW_LADDRBI[11])
//X(FORW_LADDRBI[12])
//X(FORW_LADDRBI[13])
//X(FORW_LADDRBI[14])
//X(FORW_LADDRBI[15])
//X(FORW_LADDRBO[0])
//X(FORW_LADDRBO[1])
//X(FORW_LADDRBO[2])
//X(FORW_LADDRBO[3])
//X(FORW_LADDRBO[4])
//X(FORW_LADDRBO[5])
//X(FORW_LADDRBO[6])
//X(FORW_LADDRBO[7])
//X(FORW_LADDRBO[8])
//X(FORW_LADDRBO[9])
//X(FORW_LADDRBO[10])
//X(FORW_LADDRBO[11])
//X(FORW_LADDRBO[12])
//X(FORW_LADDRBO[13])
//X(FORW_LADDRBO[14])
//X(FORW_LADDRBO[15])
//X(FORW_UADDRBI[0])
//X(FORW_UADDRBI[1])
//X(FORW_UADDRBI[2])
//X(FORW_UADDRBI[3])
//X(FORW_UADDRBI[4])
//X(FORW_UADDRBI[5])
//X(FORW_UADDRBI[6])
//X(FORW_UADDRBI[7])
//X(FORW_UADDRBI[8])
//X(FORW_UADDRBI[9])
//X(FORW_UADDRBI[10])
//X(FORW_UADDRBI[11])
//X(FORW_UADDRBI[12])
//X(FORW_UADDRBI[13])
//X(FORW_UADDRBI[14])
//X(FORW_UADDRBI[15])
X(FORW_UA0CLKO)
X(FORW_LA0CLKI)
X(FORW_UA0ENO)
X(FORW_LA0ENI)
X(FORW_UA0WEO)
X(FORW_LA0WEI)
X(FORW_LA0CLKO)
X(FORW_UA0CLKI)
X(FORW_LA0ENO)
X(FORW_UA0ENI)
X(FORW_LA0WEO)
X(FORW_UA0WEI)
X(FORW_UA1CLKO)
X(FORW_LA1CLKI)
X(FORW_UA1ENO)
X(FORW_LA1ENI)
X(FORW_UA1WEO)
X(FORW_LA1WEI)
X(FORW_LA1CLKO)
X(FORW_UA1CLKI)
X(FORW_LA1ENO)
X(FORW_UA1ENI)
X(FORW_LA1WEO)
X(FORW_UA1WEI)
X(FORW_UB0CLKO)
X(FORW_LB0CLKI)
X(FORW_UB0ENO)
X(FORW_LB0ENI)
X(FORW_UB0WEO)
X(FORW_LB0WEI)
X(FORW_LB0CLKO)
X(FORW_UB0CLKI)
X(FORW_LB0ENO)
X(FORW_UB0ENI)
X(FORW_LB0WEO)
X(FORW_UB0WEI)
X(FORW_UB1CLKO)
X(FORW_LB1CLKI)
X(FORW_UB1ENO)
X(FORW_LB1ENI)
X(FORW_UB1WEO)
X(FORW_LB1WEI)
X(FORW_LB1CLKO)
X(FORW_UB1CLKI)
X(FORW_LB1ENO)
X(FORW_UB1ENI)
X(FORW_LB1WEO)
X(FORW_UB1WEI)
//X(CLOCK1)
//X(CLOCK2)
//X(CLOCK3)
//X(CLOCK4)
// hardware primitive SERDES
X(SERDES)

View File

@ -128,6 +128,10 @@ bool GateMateImpl::getChildPlacement(const BaseClusterInfo *cluster, Loc root_lo
child_loc.y = root_loc.y + child->constr_y;
child_loc.z = child->constr_abs_z ? child->constr_z : (root_loc.z + child->constr_z);
}
if (child_loc.x < 0 || child_loc.x >= ctx->getGridDimX())
return false;
if (child_loc.y < 0 || child_loc.y >= ctx->getGridDimY())
return false;
BelId child_bel = ctx->getBelByLocation(child_loc);
if (child_bel == BelId() || !this->isValidBelForCellType(child->type, child_bel))
return false;

View File

@ -55,7 +55,7 @@ CellInfo *GateMatePacker::move_ram_i(CellInfo *cell, IdString origPort, bool pla
cpe_half = create_cell_ptr(id_CPE_HALF, ctx->idf("%s$%s_cpe_half", cell->name.c_str(ctx), origPort.c_str(ctx)));
if (place) {
cell->constr_children.push_back(cpe_half);
cpe_half->cluster = cell->name;
cpe_half->cluster = cell->cluster;
cpe_half->constr_abs_z = false;
cpe_half->constr_z = PLACE_DB_CONSTR + origPort.index;
}
@ -77,7 +77,7 @@ CellInfo *GateMatePacker::move_ram_o(CellInfo *cell, IdString origPort, bool pla
cpe_half = create_cell_ptr(id_CPE_HALF, ctx->idf("%s$%s_cpe_half", cell->name.c_str(ctx), origPort.c_str(ctx)));
if (place) {
cell->constr_children.push_back(cpe_half);
cpe_half->cluster = cell->name;
cpe_half->cluster = cell->cluster;
cpe_half->constr_abs_z = false;
cpe_half->constr_z = PLACE_DB_CONSTR + origPort.index;
}
@ -133,7 +133,7 @@ CellInfo *GateMatePacker::move_ram_io(CellInfo *cell, IdString iPort, IdString o
cpe_half = create_cell_ptr(id_CPE_HALF, ctx->idf("%s$%s_cpe_half", cell->name.c_str(ctx), oPort.c_str(ctx)));
if (place) {
cell->constr_children.push_back(cpe_half);
cpe_half->cluster = cell->name;
cpe_half->cluster = cell->cluster;
cpe_half->constr_abs_z = false;
cpe_half->constr_z = PLACE_DB_CONSTR + oPort.index;
}

View File

@ -17,6 +17,7 @@
*
*/
#include "design_utils.h"
#include "pack.h"
#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc"
@ -24,6 +25,8 @@
NEXTPNR_NAMESPACE_BEGIN
inline bool is_bram_40k(const BaseCtx *ctx, const CellInfo *cell) { return cell->type.in(id_CC_BRAM_40K); }
uint8_t GateMatePacker::ram_ctrl_signal(CellInfo *cell, IdString port, bool alt)
{
NetInfo *net = cell->getPort(port);
@ -223,6 +226,7 @@ void GateMatePacker::pack_ram()
{
std::vector<std::pair<CellInfo *, CellInfo *>> rams;
std::vector<std::pair<CellInfo *, CellInfo *>> rams_merged[2];
std::map<CellInfo *, CellInfo *> ram_cascade;
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))
@ -232,6 +236,9 @@ void GateMatePacker::pack_ram()
if (ram_mode_str != "SDP" && ram_mode_str != "TDP")
log_error("Unknown RAM_MODE parameter value '%s' for cell %s.\n", ram_mode_str.c_str(), ci.name.c_str(ctx));
int ram_mode = ram_mode_str == "SDP" ? 1 : 0;
std::string cas = str_or_default(ci.params, id_CAS, "NONE");
if (cas != "NONE" && !ci.type.in(id_CC_BRAM_40K))
log_error("Cascade feature only supported for CC_BRAM_40K.\n");
if (split) {
bool added = false;
if (!rams_merged[ram_mode].empty()) {
@ -245,6 +252,33 @@ void GateMatePacker::pack_ram()
if (!added)
rams_merged[ram_mode].push_back(std::make_pair(&ci, nullptr));
} else {
CellInfo *upper = nullptr;
CellInfo *lower = nullptr;
if (cas != "NONE" && ram_mode_str != "TDP")
log_error("Cascade feature only supported in TDP mode.\n");
int a_rd_width = int_or_default(ci.params, id_A_WIDTH, 0);
int b_wr_width = int_or_default(ci.params, id_B_WIDTH, 0);
if (cas != "NONE" && (a_rd_width > 1 || b_wr_width > 1))
log_error("Cascade feature only supported in 1 bit data width mode.\n");
if (cas == "UPPER") {
if (!net_driven_by(ctx, ci.getPort(id_A_CI), is_bram_40k, id_A_CO))
log_error("Port A_CI of '%s' must be driven by other CC_BRAM_40K.", ci.name.c_str(ctx));
if (!net_driven_by(ctx, ci.getPort(id_B_CI), is_bram_40k, id_B_CO))
log_error("Port B_CI of '%s' must be driven by other CC_BRAM_40K.", ci.name.c_str(ctx));
upper = &ci;
lower = ci.getPort(id_A_CI)->driver.cell;
} else if (cas == "LOWER") {
if (!net_only_drives(ctx, ci.getPort(id_A_CO), is_bram_40k, id_A_CI, true))
log_error("Port A_CO of '%s' must be driving one other CC_BRAM_40K.", ci.name.c_str(ctx));
if (!net_only_drives(ctx, ci.getPort(id_B_CO), is_bram_40k, id_B_CI, true))
log_error("Port B_CO of '%s' must be driving one other CC_BRAM_40K.", ci.name.c_str(ctx));
upper = (*ci.getPort(id_A_CO)->users.begin()).cell;
lower = &ci;
}
if (ram_cascade.count(lower) && ram_cascade[lower] != upper)
log_error("RAM cell '%s' already cascaded to different RAM block.\n", ci.name.c_str(ctx));
ram_cascade[lower] = upper;
rams.push_back(std::make_pair(&ci, nullptr));
}
}
@ -264,12 +298,25 @@ void GateMatePacker::pack_ram()
std::string cas = str_or_default(ci.params, id_CAS, "NONE");
int cascade = 0;
// Concepts of UPPER and LOWER are different in documentation
if (cas == "NONE") {
cascade = 0;
} else if (cas == "UPPER") {
cascade = 1;
} else if (cas == "LOWER") {
cascade = 2;
ci.disconnectPort(id_A_CI);
ci.disconnectPort(id_B_CI);
} else if (cas == "LOWER") {
cascade = 1;
ci.disconnectPort(id_A_CO);
ci.disconnectPort(id_B_CO);
if (!ram_cascade.count(&ci))
log_error("Unable to find cascaded RAM for '%s'.\n", ci.name.c_str(ctx));
CellInfo *upper = ram_cascade[&ci];
ci.cluster = upper->name;
upper->constr_children.push_back(&ci);
ci.constr_abs_z = false;
ci.constr_y = -16;
ci.constr_z = 0;
} else {
log_error("Unknown CAS parameter value '%s' for cell %s.\n", cas.c_str(), ci.name.c_str(ctx));
}