mirror of https://github.com/YosysHQ/nextpnr.git
gatemate: Enable placing RAM halfs (#1544)
* gatemate: Split BRAMs into halfs * Cleanups * move code arround * optmize remapping halfs * Name RAM cells * fix cluster setting for cascade mode * attach ECC pins * rewire global clocks * bump chip database version * Fix KEEPER setting * Fix conflict check * cleanup
This commit is contained in:
parent
a18bd2e055
commit
0399b8865e
|
|
@ -1751,6 +1751,346 @@ X(F_RSTN)
|
|||
//X(CLOCK3)
|
||||
//X(CLOCK4)
|
||||
|
||||
// hardware primitive RAM_HALF_U
|
||||
X(RAM_HALF_U)
|
||||
// RAM_HALF_U pins
|
||||
//X(CLKA[0])
|
||||
//X(ENA[0])
|
||||
//X(GLWEA[0])
|
||||
//X(CLKB[0])
|
||||
//X(ENB[0])
|
||||
//X(GLWEB[0])
|
||||
//X(WEA[0])
|
||||
//X(WEA[1])
|
||||
//X(WEA[2])
|
||||
//X(WEA[3])
|
||||
//X(WEA[4])
|
||||
//X(WEA[5])
|
||||
//X(WEA[6])
|
||||
//X(WEA[7])
|
||||
//X(WEA[8])
|
||||
//X(WEA[9])
|
||||
//X(WEA[10])
|
||||
//X(WEA[11])
|
||||
//X(WEA[12])
|
||||
//X(WEA[13])
|
||||
//X(WEA[14])
|
||||
//X(WEA[15])
|
||||
//X(WEA[16])
|
||||
//X(WEA[17])
|
||||
//X(WEA[18])
|
||||
//X(WEA[19])
|
||||
//X(WEB[0])
|
||||
//X(WEB[1])
|
||||
//X(WEB[2])
|
||||
//X(WEB[3])
|
||||
//X(WEB[4])
|
||||
//X(WEB[5])
|
||||
//X(WEB[6])
|
||||
//X(WEB[7])
|
||||
//X(WEB[8])
|
||||
//X(WEB[9])
|
||||
//X(WEB[10])
|
||||
//X(WEB[11])
|
||||
//X(WEB[12])
|
||||
//X(WEB[13])
|
||||
//X(WEB[14])
|
||||
//X(WEB[15])
|
||||
//X(WEB[16])
|
||||
//X(WEB[17])
|
||||
//X(WEB[18])
|
||||
//X(WEB[19])
|
||||
//X(ADDRA0[0])
|
||||
//X(ADDRA0[1])
|
||||
//X(ADDRA0[2])
|
||||
//X(ADDRA0[3])
|
||||
//X(ADDRA0[4])
|
||||
//X(ADDRA0[5])
|
||||
//X(ADDRA0[6])
|
||||
//X(ADDRA0[7])
|
||||
//X(ADDRA0[8])
|
||||
//X(ADDRA0[9])
|
||||
//X(ADDRA0[10])
|
||||
//X(ADDRA0[11])
|
||||
//X(ADDRA0[12])
|
||||
//X(ADDRA0[13])
|
||||
//X(ADDRA0[14])
|
||||
//X(ADDRA0[15])
|
||||
//X(ADDRB0[0])
|
||||
//X(ADDRB0[1])
|
||||
//X(ADDRB0[2])
|
||||
//X(ADDRB0[3])
|
||||
//X(ADDRB0[4])
|
||||
//X(ADDRB0[5])
|
||||
//X(ADDRB0[6])
|
||||
//X(ADDRB0[7])
|
||||
//X(ADDRB0[8])
|
||||
//X(ADDRB0[9])
|
||||
//X(ADDRB0[10])
|
||||
//X(ADDRB0[11])
|
||||
//X(ADDRB0[12])
|
||||
//X(ADDRB0[13])
|
||||
//X(ADDRB0[14])
|
||||
//X(ADDRB0[15])
|
||||
//X(DIA[0])
|
||||
//X(DIA[1])
|
||||
//X(DIA[2])
|
||||
//X(DIA[3])
|
||||
//X(DIA[4])
|
||||
//X(DIA[5])
|
||||
//X(DIA[6])
|
||||
//X(DIA[7])
|
||||
//X(DIA[8])
|
||||
//X(DIA[9])
|
||||
//X(DIA[10])
|
||||
//X(DIA[11])
|
||||
//X(DIA[12])
|
||||
//X(DIA[13])
|
||||
//X(DIA[14])
|
||||
//X(DIA[15])
|
||||
//X(DIA[16])
|
||||
//X(DIA[17])
|
||||
//X(DIA[18])
|
||||
//X(DIA[19])
|
||||
//X(DIB[0])
|
||||
//X(DIB[1])
|
||||
//X(DIB[2])
|
||||
//X(DIB[3])
|
||||
//X(DIB[4])
|
||||
//X(DIB[5])
|
||||
//X(DIB[6])
|
||||
//X(DIB[7])
|
||||
//X(DIB[8])
|
||||
//X(DIB[9])
|
||||
//X(DIB[10])
|
||||
//X(DIB[11])
|
||||
//X(DIB[12])
|
||||
//X(DIB[13])
|
||||
//X(DIB[14])
|
||||
//X(DIB[15])
|
||||
//X(DIB[16])
|
||||
//X(DIB[17])
|
||||
//X(DIB[18])
|
||||
//X(DIB[19])
|
||||
//X(DOA[0])
|
||||
//X(DOA[1])
|
||||
//X(DOA[2])
|
||||
//X(DOA[3])
|
||||
//X(DOA[4])
|
||||
//X(DOA[5])
|
||||
//X(DOA[6])
|
||||
//X(DOA[7])
|
||||
//X(DOA[8])
|
||||
//X(DOA[9])
|
||||
//X(DOA[10])
|
||||
//X(DOA[11])
|
||||
//X(DOA[12])
|
||||
//X(DOA[13])
|
||||
//X(DOA[14])
|
||||
//X(DOA[15])
|
||||
//X(DOA[16])
|
||||
//X(DOA[17])
|
||||
//X(DOA[18])
|
||||
//X(DOA[19])
|
||||
//X(DOB[0])
|
||||
//X(DOB[1])
|
||||
//X(DOB[2])
|
||||
//X(DOB[3])
|
||||
//X(DOB[4])
|
||||
//X(DOB[5])
|
||||
//X(DOB[6])
|
||||
//X(DOB[7])
|
||||
//X(DOB[8])
|
||||
//X(DOB[9])
|
||||
//X(DOB[10])
|
||||
//X(DOB[11])
|
||||
//X(DOB[12])
|
||||
//X(DOB[13])
|
||||
//X(DOB[14])
|
||||
//X(DOB[15])
|
||||
//X(DOB[16])
|
||||
//X(DOB[17])
|
||||
//X(DOB[18])
|
||||
//X(DOB[19])
|
||||
//X(ECC1B_ERRA[0])
|
||||
//X(ECC1B_ERRB[0])
|
||||
//X(ECC2B_ERRA[0])
|
||||
//X(ECC2B_ERRB[0])
|
||||
//X(CLOCK1)
|
||||
//X(CLOCK2)
|
||||
//X(CLOCK3)
|
||||
//X(CLOCK4)
|
||||
|
||||
// hardware primitive RAM_HALF_L
|
||||
X(RAM_HALF_L)
|
||||
// RAM_HALF_L pins
|
||||
//X(CLKA[0])
|
||||
//X(ENA[0])
|
||||
//X(GLWEA[0])
|
||||
//X(CLKB[0])
|
||||
//X(ENB[0])
|
||||
//X(GLWEB[0])
|
||||
//X(WEA[0])
|
||||
//X(WEA[1])
|
||||
//X(WEA[2])
|
||||
//X(WEA[3])
|
||||
//X(WEA[4])
|
||||
//X(WEA[5])
|
||||
//X(WEA[6])
|
||||
//X(WEA[7])
|
||||
//X(WEA[8])
|
||||
//X(WEA[9])
|
||||
//X(WEA[10])
|
||||
//X(WEA[11])
|
||||
//X(WEA[12])
|
||||
//X(WEA[13])
|
||||
//X(WEA[14])
|
||||
//X(WEA[15])
|
||||
//X(WEA[16])
|
||||
//X(WEA[17])
|
||||
//X(WEA[18])
|
||||
//X(WEA[19])
|
||||
//X(WEB[0])
|
||||
//X(WEB[1])
|
||||
//X(WEB[2])
|
||||
//X(WEB[3])
|
||||
//X(WEB[4])
|
||||
//X(WEB[5])
|
||||
//X(WEB[6])
|
||||
//X(WEB[7])
|
||||
//X(WEB[8])
|
||||
//X(WEB[9])
|
||||
//X(WEB[10])
|
||||
//X(WEB[11])
|
||||
//X(WEB[12])
|
||||
//X(WEB[13])
|
||||
//X(WEB[14])
|
||||
//X(WEB[15])
|
||||
//X(WEB[16])
|
||||
//X(WEB[17])
|
||||
//X(WEB[18])
|
||||
//X(WEB[19])
|
||||
//X(ADDRA0[0])
|
||||
//X(ADDRA0[1])
|
||||
//X(ADDRA0[2])
|
||||
//X(ADDRA0[3])
|
||||
//X(ADDRA0[4])
|
||||
//X(ADDRA0[5])
|
||||
//X(ADDRA0[6])
|
||||
//X(ADDRA0[7])
|
||||
//X(ADDRA0[8])
|
||||
//X(ADDRA0[9])
|
||||
//X(ADDRA0[10])
|
||||
//X(ADDRA0[11])
|
||||
//X(ADDRA0[12])
|
||||
//X(ADDRA0[13])
|
||||
//X(ADDRA0[14])
|
||||
//X(ADDRA0[15])
|
||||
//X(ADDRB0[0])
|
||||
//X(ADDRB0[1])
|
||||
//X(ADDRB0[2])
|
||||
//X(ADDRB0[3])
|
||||
//X(ADDRB0[4])
|
||||
//X(ADDRB0[5])
|
||||
//X(ADDRB0[6])
|
||||
//X(ADDRB0[7])
|
||||
//X(ADDRB0[8])
|
||||
//X(ADDRB0[9])
|
||||
//X(ADDRB0[10])
|
||||
//X(ADDRB0[11])
|
||||
//X(ADDRB0[12])
|
||||
//X(ADDRB0[13])
|
||||
//X(ADDRB0[14])
|
||||
//X(ADDRB0[15])
|
||||
//X(DIA[0])
|
||||
//X(DIA[1])
|
||||
//X(DIA[2])
|
||||
//X(DIA[3])
|
||||
//X(DIA[4])
|
||||
//X(DIA[5])
|
||||
//X(DIA[6])
|
||||
//X(DIA[7])
|
||||
//X(DIA[8])
|
||||
//X(DIA[9])
|
||||
//X(DIA[10])
|
||||
//X(DIA[11])
|
||||
//X(DIA[12])
|
||||
//X(DIA[13])
|
||||
//X(DIA[14])
|
||||
//X(DIA[15])
|
||||
//X(DIA[16])
|
||||
//X(DIA[17])
|
||||
//X(DIA[18])
|
||||
//X(DIA[19])
|
||||
//X(DIB[0])
|
||||
//X(DIB[1])
|
||||
//X(DIB[2])
|
||||
//X(DIB[3])
|
||||
//X(DIB[4])
|
||||
//X(DIB[5])
|
||||
//X(DIB[6])
|
||||
//X(DIB[7])
|
||||
//X(DIB[8])
|
||||
//X(DIB[9])
|
||||
//X(DIB[10])
|
||||
//X(DIB[11])
|
||||
//X(DIB[12])
|
||||
//X(DIB[13])
|
||||
//X(DIB[14])
|
||||
//X(DIB[15])
|
||||
//X(DIB[16])
|
||||
//X(DIB[17])
|
||||
//X(DIB[18])
|
||||
//X(DIB[19])
|
||||
//X(DOA[0])
|
||||
//X(DOA[1])
|
||||
//X(DOA[2])
|
||||
//X(DOA[3])
|
||||
//X(DOA[4])
|
||||
//X(DOA[5])
|
||||
//X(DOA[6])
|
||||
//X(DOA[7])
|
||||
//X(DOA[8])
|
||||
//X(DOA[9])
|
||||
//X(DOA[10])
|
||||
//X(DOA[11])
|
||||
//X(DOA[12])
|
||||
//X(DOA[13])
|
||||
//X(DOA[14])
|
||||
//X(DOA[15])
|
||||
//X(DOA[16])
|
||||
//X(DOA[17])
|
||||
//X(DOA[18])
|
||||
//X(DOA[19])
|
||||
//X(DOB[0])
|
||||
//X(DOB[1])
|
||||
//X(DOB[2])
|
||||
//X(DOB[3])
|
||||
//X(DOB[4])
|
||||
//X(DOB[5])
|
||||
//X(DOB[6])
|
||||
//X(DOB[7])
|
||||
//X(DOB[8])
|
||||
//X(DOB[9])
|
||||
//X(DOB[10])
|
||||
//X(DOB[11])
|
||||
//X(DOB[12])
|
||||
//X(DOB[13])
|
||||
//X(DOB[14])
|
||||
//X(DOB[15])
|
||||
//X(DOB[16])
|
||||
//X(DOB[17])
|
||||
//X(DOB[18])
|
||||
//X(DOB[19])
|
||||
//X(ECC1B_ERRA[0])
|
||||
//X(ECC1B_ERRB[0])
|
||||
//X(ECC2B_ERRA[0])
|
||||
//X(ECC2B_ERRB[0])
|
||||
//X(CLOCK1)
|
||||
//X(CLOCK2)
|
||||
//X(CLOCK3)
|
||||
//X(CLOCK4)
|
||||
|
||||
// hardware primitive SERDES
|
||||
X(SERDES)
|
||||
// SERDES pins
|
||||
|
|
@ -2283,6 +2623,8 @@ X(L2T4_UPPER)
|
|||
X(CPE_MX8)
|
||||
X(CPE_BRIDGE)
|
||||
X(MULT_INVERT)
|
||||
X(RAM_HALF)
|
||||
X(RAM_HALF_DUMMY)
|
||||
|
||||
// Timing
|
||||
X(timing_ADDF2x_IN5_8_comb2)
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ bool GateMateImpl::getCellDelay(const CellInfo *cell, IdString fromPort, IdStrin
|
|||
return get_delay_from_tmg_db(ctx->idf("timing_clkin_%s_%s", fromPort.c_str(ctx), toPort.c_str(ctx)), delay);
|
||||
} else if (cell->type.in(id_GLBOUT)) {
|
||||
return get_delay_from_tmg_db(ctx->idf("timing_glbout_%s_%s", fromPort.c_str(ctx), toPort.c_str(ctx)), delay);
|
||||
} else if (cell->type.in(id_RAM)) {
|
||||
} else if (cell->type.in(id_RAM, id_RAM_HALF)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -257,7 +257,7 @@ TimingPortClass GateMateImpl::getPortTimingClass(const CellInfo *cell, IdString
|
|||
if (port.in(id_CLK))
|
||||
return TMG_CLOCK_INPUT;
|
||||
return TMG_IGNORE;
|
||||
} else if (cell->type == id_RAM) {
|
||||
} else if (cell->type.in(id_RAM, id_RAM_HALF)) {
|
||||
std::string name = port.str(ctx);
|
||||
if (boost::starts_with(name, "CLKA[") || boost::starts_with(name, "CLKB[") || boost::starts_with(name, "CLOCK"))
|
||||
return TMG_CLOCK_INPUT;
|
||||
|
|
@ -326,7 +326,7 @@ TimingClockingInfo GateMateImpl::getPortClockingInfo(const CellInfo *cell, IdStr
|
|||
get_delay_from_tmg_db(id_timing_del_CPE_CP_Q, delay);
|
||||
info.clockToQ += delay;
|
||||
}
|
||||
} else if (cell->type == id_RAM) {
|
||||
} else if (cell->type.in(id_RAM, id_RAM_HALF)) {
|
||||
std::string name = port.str(ctx);
|
||||
if (boost::starts_with(name, "CLOCK"))
|
||||
get_delay_from_tmg_db(id_timing_RAM_NOECC_IOPATH_1, info.clockToQ);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ enum CPE_Z
|
|||
CPE_COMP_Z = 6,
|
||||
CPE_CPLINES_Z = 7,
|
||||
CPE_LT_FULL_Z = 8,
|
||||
|
||||
RAM_FULL_Z = 10,
|
||||
RAM_HALF_U_Z = 11,
|
||||
RAM_HALF_L_Z = 12,
|
||||
};
|
||||
|
||||
enum ClusterPlacement
|
||||
|
|
|
|||
|
|
@ -172,10 +172,10 @@ bool GateMateImpl::isBelLocationValid(BelId bel, bool explain_invalid) const
|
|||
ctx->getBelByLocation(Loc(loc.x, loc.y, loc.z == CPE_FF_L_Z ? CPE_FF_U_Z : CPE_FF_L_Z)));
|
||||
if (adj_half) {
|
||||
const auto &half_data = fast_cell_info.at(cell->flat_index);
|
||||
if (half_data.dff_used) {
|
||||
if (half_data.used) {
|
||||
const auto &adj_data = fast_cell_info.at(adj_half->flat_index);
|
||||
if (adj_data.dff_used) {
|
||||
if (adj_data.ff_config != half_data.ff_config)
|
||||
if (adj_data.used) {
|
||||
if (adj_data.config != half_data.config)
|
||||
return false;
|
||||
if (adj_data.ff_en != half_data.ff_en)
|
||||
return false;
|
||||
|
|
@ -187,7 +187,24 @@ bool GateMateImpl::isBelLocationValid(BelId bel, bool explain_invalid) const
|
|||
}
|
||||
}
|
||||
return true;
|
||||
} else if (ctx->getBelBucketForBel(bel) == id_RAM_HALF) {
|
||||
Loc loc = ctx->getBelLocation(bel);
|
||||
const CellInfo *adj_half =
|
||||
ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.z == RAM_HALF_L_Z ? loc.y - 8 : loc.y + 8,
|
||||
loc.z == RAM_HALF_L_Z ? RAM_HALF_U_Z : RAM_HALF_L_Z)));
|
||||
if (adj_half) {
|
||||
const auto &half_data = fast_cell_info.at(cell->flat_index);
|
||||
if (half_data.used) {
|
||||
const auto &adj_data = fast_cell_info.at(adj_half->flat_index);
|
||||
if (adj_data.used) {
|
||||
if (adj_data.config != half_data.config)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +316,15 @@ int GateMateImpl::get_dff_config(CellInfo *dff) const
|
|||
return val;
|
||||
}
|
||||
|
||||
int GateMateImpl::get_ram_config(CellInfo *ram) const
|
||||
{
|
||||
int val = 0;
|
||||
val |= int_or_default(ram->params, id_RAM_cfg_ecc_enable, 0);
|
||||
val <<= 2;
|
||||
val |= int_or_default(ram->params, id_RAM_cfg_sram_mode, 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
void GateMateImpl::assign_cell_info()
|
||||
{
|
||||
fast_cell_info.resize(ctx->cells.size());
|
||||
|
|
@ -309,8 +335,12 @@ 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 = get_dff_config(ci);
|
||||
fc.dff_used = true;
|
||||
fc.config = get_dff_config(ci);
|
||||
fc.used = true;
|
||||
}
|
||||
if (ci->type == id_RAM_HALF) {
|
||||
fc.config = get_ram_config(ci);
|
||||
fc.used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -327,6 +357,8 @@ IdString GateMateImpl::getBelBucketForCellType(IdString cell_type) const
|
|||
return id_CPE_FF;
|
||||
else if (cell_type.in(id_CPE_RAMIO, id_CPE_RAMI, id_CPE_RAMO))
|
||||
return id_CPE_RAMIO;
|
||||
else if (cell_type.in(id_RAM_HALF, id_RAM_HALF_DUMMY))
|
||||
return id_RAM_HALF;
|
||||
else
|
||||
return cell_type;
|
||||
}
|
||||
|
|
@ -340,6 +372,8 @@ BelBucketId GateMateImpl::getBelBucketForBel(BelId bel) const
|
|||
return id_CPE_FF;
|
||||
else if (bel_type.in(id_CPE_RAMIO_U, id_CPE_RAMIO_L))
|
||||
return id_CPE_RAMIO;
|
||||
else if (bel_type.in(id_RAM_HALF_U, id_RAM_HALF_L))
|
||||
return id_RAM_HALF;
|
||||
return bel_type;
|
||||
}
|
||||
|
||||
|
|
@ -359,6 +393,10 @@ bool GateMateImpl::isValidBelForCellType(IdString cell_type, BelId bel) const
|
|||
return cell_type.in(id_CPE_FF_L, id_CPE_FF, id_CPE_LATCH);
|
||||
else if (bel_type.in(id_CPE_RAMIO_U, id_CPE_RAMIO_L))
|
||||
return cell_type.in(id_CPE_RAMIO, id_CPE_RAMI, id_CPE_RAMO);
|
||||
else if (bel_type == id_RAM_HALF_U)
|
||||
return cell_type.in(id_RAM_HALF, id_RAM_HALF_DUMMY);
|
||||
else if (bel_type == id_RAM_HALF_L)
|
||||
return cell_type.in(id_RAM_HALF, id_RAM_HALF_DUMMY);
|
||||
else
|
||||
return (bel_type == cell_type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct GateMateImpl : HimbaechelAPI
|
|||
const GateMateTileExtraDataPOD *tile_extra_data(int tile) const;
|
||||
|
||||
int get_dff_config(CellInfo *dff) const;
|
||||
int get_ram_config(CellInfo *ram) const;
|
||||
|
||||
std::set<IdString> available_pads;
|
||||
std::map<BelId, const PadInfoPOD *> bel_to_pad;
|
||||
|
|
@ -105,9 +106,9 @@ struct GateMateImpl : HimbaechelAPI
|
|||
{
|
||||
// slice info
|
||||
const NetInfo *ff_en = nullptr, *ff_clk = nullptr, *ff_sr = nullptr;
|
||||
int ff_config = 0;
|
||||
int config = 0;
|
||||
int signal_used = -1;
|
||||
bool dff_used = false;
|
||||
bool used = false;
|
||||
};
|
||||
std::vector<GateMateCellInfo> fast_cell_info;
|
||||
std::map<BelId, std::map<IdString, const GateMateBelPinConstraintPOD *>> pin_to_constr;
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ def set_timings(ch):
|
|||
# assert k in timing, f"pip class {k} not found in timing data"
|
||||
# tmg.set_pip_class(grade=speed, name=k, delay=convert_timing(timing[k]))
|
||||
|
||||
EXPECTED_VERSION = 1.4
|
||||
EXPECTED_VERSION = 1.5
|
||||
|
||||
def main():
|
||||
# Range needs to be +1, but we are adding +2 more to coordinates, since
|
||||
|
|
@ -233,7 +233,7 @@ def main():
|
|||
tt.create_wire(wire.name, wire.type)
|
||||
for prim in sorted(die.get_primitives_for_type(type_name)):
|
||||
bel = tt.create_bel(prim.name, prim.type, prim.z)
|
||||
if (prim.name in ["CPE_LT_FULL"]):
|
||||
if (prim.name in ["CPE_LT_FULL", "RAM"]):
|
||||
bel.flags |= BEL_FLAG_HIDDEN
|
||||
extra = BelExtraData()
|
||||
for constr in sorted(die.get_pins_constraint(type_name, prim.name, prim.type)):
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ void GateMatePacker::rename_param(CellInfo *cell, IdString name, IdString new_na
|
|||
}
|
||||
}
|
||||
|
||||
void GateMatePacker::repack()
|
||||
void GateMatePacker::repack_cpe()
|
||||
{
|
||||
log_info("Repacking CPEs..\n");
|
||||
for (auto &cell : ctx->cells) {
|
||||
|
|
@ -407,7 +407,8 @@ void GateMateImpl::pack()
|
|||
void GateMateImpl::repack()
|
||||
{
|
||||
GateMatePacker packer(ctx, this);
|
||||
packer.repack();
|
||||
packer.repack_ram();
|
||||
packer.repack_cpe();
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ struct GateMatePacker
|
|||
void remove_clocking();
|
||||
|
||||
void cleanup();
|
||||
void repack();
|
||||
void repack_cpe();
|
||||
void repack_ram();
|
||||
|
||||
private:
|
||||
void rename_param(CellInfo *cell, IdString name, IdString new_name, int width);
|
||||
|
|
@ -82,6 +83,7 @@ struct GateMatePacker
|
|||
void optimize_ff();
|
||||
void count_cell(CellInfo &ci);
|
||||
void move_connections(NetInfo *from_net, NetInfo *to_net);
|
||||
void remap_ram_half(CellInfo *half, CellInfo *cell, int num);
|
||||
|
||||
PllCfgRecord get_pll_settings(double f_ref, double f_core, int mode, int low_jitter, bool pdiv0_mux, bool feedback);
|
||||
|
||||
|
|
@ -102,7 +104,7 @@ struct GateMatePacker
|
|||
// Cell creating
|
||||
CellInfo *create_cell_ptr(IdString type, IdString name);
|
||||
void flush_cells();
|
||||
void pack_ram_cell(CellInfo &ci, CellInfo *cell, int num, bool is_split);
|
||||
void pack_ram_cell(CellInfo &ci, CellInfo *cell, bool is_split);
|
||||
void copy_constraint(NetInfo *in_net, NetInfo *out_net);
|
||||
|
||||
pool<IdString> packed_cells;
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ static void rename_or_move(CellInfo *main, CellInfo *other, IdString port, IdStr
|
|||
main->movePortTo(port, other, other_port);
|
||||
}
|
||||
|
||||
void GateMatePacker::pack_ram_cell(CellInfo &ci, CellInfo *cell, int num, bool is_split)
|
||||
void GateMatePacker::pack_ram_cell(CellInfo &ci, CellInfo *cell, bool is_split)
|
||||
{
|
||||
// Port Widths
|
||||
int a_rd_width = int_or_default(cell->params, id_A_RD_WIDTH, 0);
|
||||
|
|
@ -161,98 +161,71 @@ void GateMatePacker::pack_ram_cell(CellInfo &ci, CellInfo *cell, int num, bool i
|
|||
uint8_t a_we = ram_ctrl_signal(cell, id_A_WE, false);
|
||||
uint8_t b_we = ram_ctrl_signal(cell, id_B_WE, false);
|
||||
|
||||
if (num) {
|
||||
ci.params[id_RAM_cfg_forward_a0_clk] = Property(cfg_a, 8);
|
||||
if (!is_split)
|
||||
ci.params[id_RAM_cfg_forward_a1_clk] = Property(cfg_a, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_b0_clk] = Property(cfg_b, 8);
|
||||
if (!is_split)
|
||||
ci.params[id_RAM_cfg_forward_b1_clk] = Property(cfg_b, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_a1_en] = Property(a_en, 8);
|
||||
ci.params[id_RAM_cfg_forward_b1_en] = Property(b_en, 8);
|
||||
ci.params[id_RAM_cfg_forward_a0_en] = Property(a_en, 8);
|
||||
ci.params[id_RAM_cfg_forward_b0_en] = Property(b_en, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_a1_we] = Property(a_we, 8);
|
||||
ci.params[id_RAM_cfg_forward_b1_we] = Property(b_we, 8);
|
||||
ci.params[id_RAM_cfg_forward_a0_we] = Property(a_we, 8);
|
||||
ci.params[id_RAM_cfg_forward_b0_we] = Property(b_we, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_input_config_a1] = Property(width_to_config(a_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_input_config_b1] = Property(width_to_config(b_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_a1] = Property(width_to_config(a_rd_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_b1] = Property(width_to_config(b_rd_width), 3);
|
||||
ci.params[id_RAM_cfg_input_config_a0] = Property(width_to_config(a_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_input_config_b0] = Property(width_to_config(b_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_a0] = Property(width_to_config(a_rd_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_b0] = Property(width_to_config(b_rd_width), 3);
|
||||
|
||||
ci.params[id_RAM_cfg_a1_writemode] = Property(a_wr_mode, 1);
|
||||
ci.params[id_RAM_cfg_b1_writemode] = Property(b_wr_mode, 1);
|
||||
ci.params[id_RAM_cfg_a0_writemode] = Property(a_wr_mode, 1);
|
||||
ci.params[id_RAM_cfg_b0_writemode] = Property(b_wr_mode, 1);
|
||||
|
||||
ci.params[id_RAM_cfg_a1_set_outputreg] = Property(a_do_reg, 1);
|
||||
ci.params[id_RAM_cfg_b1_set_outputreg] = Property(b_do_reg, 1);
|
||||
ci.params[id_RAM_cfg_a0_set_outputreg] = Property(a_do_reg, 1);
|
||||
ci.params[id_RAM_cfg_b0_set_outputreg] = Property(b_do_reg, 1);
|
||||
|
||||
ci.params[id_RAM_cfg_inversion_a1] = Property(a_inv, 3);
|
||||
ci.params[id_RAM_cfg_inversion_b1] = Property(b_inv, 3);
|
||||
} else {
|
||||
ci.params[id_RAM_cfg_forward_a0_clk] = Property(cfg_a, 8);
|
||||
if (!is_split)
|
||||
ci.params[id_RAM_cfg_forward_a1_clk] = Property(cfg_a, 8);
|
||||
ci.params[id_RAM_cfg_inversion_a0] = Property(a_inv, 3);
|
||||
ci.params[id_RAM_cfg_inversion_b0] = Property(b_inv, 3);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_b0_clk] = Property(cfg_b, 8);
|
||||
if (!is_split)
|
||||
ci.params[id_RAM_cfg_forward_b1_clk] = Property(cfg_b, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_a0_en] = Property(a_en, 8);
|
||||
ci.params[id_RAM_cfg_forward_b0_en] = Property(b_en, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_a0_we] = Property(a_we, 8);
|
||||
ci.params[id_RAM_cfg_forward_b0_we] = Property(b_we, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_input_config_a0] = Property(width_to_config(a_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_input_config_b0] = Property(width_to_config(b_wr_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_a0] = Property(width_to_config(a_rd_width), 3);
|
||||
ci.params[id_RAM_cfg_output_config_b0] = Property(width_to_config(b_rd_width), 3);
|
||||
|
||||
ci.params[id_RAM_cfg_a0_writemode] = Property(a_wr_mode, 1);
|
||||
ci.params[id_RAM_cfg_b0_writemode] = Property(b_wr_mode, 1);
|
||||
|
||||
ci.params[id_RAM_cfg_a0_set_outputreg] = Property(a_do_reg, 1);
|
||||
ci.params[id_RAM_cfg_b0_set_outputreg] = Property(b_do_reg, 1);
|
||||
|
||||
ci.params[id_RAM_cfg_inversion_a0] = Property(a_inv, 3);
|
||||
ci.params[id_RAM_cfg_inversion_b0] = Property(b_inv, 3);
|
||||
}
|
||||
|
||||
int index = (num == 0) ? 0 : 2;
|
||||
rename_or_move(cell, &ci, id_A_CLK, ctx->idf("CLKA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_B_CLK, ctx->idf("CLKB[%d]", index));
|
||||
rename_or_move(cell, &ci, id_A_EN, ctx->idf("ENA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_B_EN, ctx->idf("ENB[%d]", index));
|
||||
rename_or_move(cell, &ci, id_A_WE, ctx->idf("GLWEA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_B_WE, ctx->idf("GLWEB[%d]", index));
|
||||
rename_or_move(cell, &ci, id_A_CLK, ctx->id("CLKA[0]"));
|
||||
rename_or_move(cell, &ci, id_B_CLK, ctx->id("CLKB[0]"));
|
||||
rename_or_move(cell, &ci, id_A_EN, ctx->id("ENA[0]"));
|
||||
rename_or_move(cell, &ci, id_B_EN, ctx->id("ENB[0]"));
|
||||
rename_or_move(cell, &ci, id_A_WE, ctx->id("GLWEA[0]"));
|
||||
rename_or_move(cell, &ci, id_B_WE, ctx->id("GLWEB[0]"));
|
||||
if (is_split) {
|
||||
rename_or_move(cell, &ci, id_ECC_1B_ERR, ctx->idf("ECC1B_ERRA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_ECC_2B_ERR, ctx->idf("ECC2B_ERRA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_ECC_1B_ERR, ctx->id("ECC1B_ERRA[0]"));
|
||||
rename_or_move(cell, &ci, id_ECC_2B_ERR, ctx->id("ECC2B_ERRA[0]"));
|
||||
} else {
|
||||
rename_or_move(cell, &ci, id_A_ECC_1B_ERR, ctx->idf("ECC1B_ERRA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_B_ECC_1B_ERR, ctx->idf("ECC1B_ERRB[%d]", index));
|
||||
rename_or_move(cell, &ci, id_A_ECC_2B_ERR, ctx->idf("ECC2B_ERRA[%d]", index));
|
||||
rename_or_move(cell, &ci, id_B_ECC_2B_ERR, ctx->idf("ECC2B_ERRB[%d]", index));
|
||||
rename_or_move(cell, &ci, id_A_ECC_1B_ERR, ctx->id("ECC1B_ERRA[0]"));
|
||||
rename_or_move(cell, &ci, id_B_ECC_1B_ERR, ctx->id("ECC1B_ERRB[0]"));
|
||||
rename_or_move(cell, &ci, id_A_ECC_2B_ERR, ctx->id("ECC2B_ERRA[0]"));
|
||||
rename_or_move(cell, &ci, id_B_ECC_2B_ERR, ctx->id("ECC2B_ERRB[0]"));
|
||||
}
|
||||
int items = is_split ? 20 : 40;
|
||||
for (int i = 0; i < items; i++) {
|
||||
rename_or_move(cell, &ci, ctx->idf("A_BM[%d]", i), ctx->idf("WEA[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_BM[%d]", i), ctx->idf("WEB[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("A_BM[%d]", i), ctx->idf("WEA[%d]", i));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_BM[%d]", i), ctx->idf("WEB[%d]", i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
rename_or_move(cell, &ci, ctx->idf("A_ADDR[%d]", i), ctx->idf("ADDRA%d[%d]", num, i));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_ADDR[%d]", i), ctx->idf("ADDRB%d[%d]", num, i));
|
||||
rename_or_move(cell, &ci, ctx->idf("A_ADDR[%d]", i), ctx->idf("ADDRA0[%d]", i));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_ADDR[%d]", i), ctx->idf("ADDRB0[%d]", i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < items; i++) {
|
||||
rename_or_move(cell, &ci, ctx->idf("A_DI[%d]", i), ctx->idf("DIA[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("A_DO[%d]", i), ctx->idf("DOA[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_DI[%d]", i), ctx->idf("DIB[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_DO[%d]", i), ctx->idf("DOB[%d]", i + num * 20));
|
||||
rename_or_move(cell, &ci, ctx->idf("A_DI[%d]", i), ctx->idf("DIA[%d]", i));
|
||||
rename_or_move(cell, &ci, ctx->idf("A_DO[%d]", i), ctx->idf("DOA[%d]", i));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_DI[%d]", i), ctx->idf("DIB[%d]", i));
|
||||
rename_or_move(cell, &ci, ctx->idf("B_DO[%d]", i), ctx->idf("DOB[%d]", i));
|
||||
}
|
||||
}
|
||||
|
||||
void GateMatePacker::pack_ram()
|
||||
{
|
||||
std::vector<std::pair<CellInfo *, CellInfo *>> rams;
|
||||
std::vector<std::pair<CellInfo *, CellInfo *>> rams_merged[2];
|
||||
std::vector<CellInfo *> rams;
|
||||
std::map<CellInfo *, CellInfo *> ram_cascade;
|
||||
log_info("Packing RAMs..\n");
|
||||
for (auto &cell : ctx->cells) {
|
||||
|
|
@ -263,7 +236,6 @@ void GateMatePacker::pack_ram()
|
|||
std::string ram_mode_str = str_or_default(ci.params, id_RAM_MODE, "SDP");
|
||||
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");
|
||||
|
|
@ -277,17 +249,7 @@ void GateMatePacker::pack_ram()
|
|||
}
|
||||
|
||||
if (split) {
|
||||
bool added = false;
|
||||
if (!rams_merged[ram_mode].empty()) {
|
||||
auto &last = rams_merged[ram_mode].back();
|
||||
if (last.second == nullptr) {
|
||||
last.second = &ci;
|
||||
packed_cells.insert(ci.name);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
if (!added)
|
||||
rams_merged[ram_mode].push_back(std::make_pair(&ci, nullptr));
|
||||
rams.push_back(&ci);
|
||||
} else {
|
||||
CellInfo *upper = nullptr;
|
||||
CellInfo *lower = nullptr;
|
||||
|
|
@ -316,18 +278,16 @@ void GateMatePacker::pack_ram()
|
|||
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));
|
||||
rams.push_back(&ci);
|
||||
}
|
||||
}
|
||||
rams.insert(rams.end(), rams_merged[0].begin(), rams_merged[0].end());
|
||||
rams.insert(rams.end(), rams_merged[1].begin(), rams_merged[1].end());
|
||||
|
||||
for (auto item : rams) {
|
||||
CellInfo &ci = *item.first;
|
||||
CellInfo &ci = *item;
|
||||
int split = ci.type.in(id_CC_BRAM_20K) ? 1 : 0;
|
||||
bool is_fifo = ci.type.in(id_CC_FIFO_40K);
|
||||
|
||||
ci.type = id_RAM;
|
||||
ci.type = split ? id_RAM_HALF : id_RAM;
|
||||
ci.cluster = ci.name;
|
||||
|
||||
// Location format: D(0..N-1)X(0..3)Y(0..7) or UNPLACED
|
||||
|
|
@ -358,6 +318,21 @@ void GateMatePacker::pack_ram()
|
|||
log_error("Unknown CAS parameter value '%s' for cell %s.\n", cas.c_str(), ci.name.c_str(ctx));
|
||||
}
|
||||
|
||||
if (!split) {
|
||||
CellInfo *cell = ctx->createCell(ctx->idf("%s$dummy$u", ci.name.c_str(ctx)), id_RAM_HALF_DUMMY);
|
||||
ci.constr_children.push_back(cell);
|
||||
cell->constr_abs_z = true;
|
||||
cell->constr_z = RAM_HALF_U_Z;
|
||||
cell->cluster = ci.cluster;
|
||||
|
||||
cell = ctx->createCell(ctx->idf("%s$dummy$l", ci.name.c_str(ctx)), id_RAM_HALF_DUMMY);
|
||||
ci.constr_children.push_back(cell);
|
||||
cell->constr_abs_z = true;
|
||||
cell->constr_y = +8;
|
||||
cell->constr_z = RAM_HALF_L_Z;
|
||||
cell->cluster = ci.cluster;
|
||||
}
|
||||
|
||||
// RAM and Write Modes
|
||||
std::string ram_mode_str = str_or_default(ci.params, id_RAM_MODE, "SDP");
|
||||
if (ram_mode_str != "SDP" && ram_mode_str != "TDP")
|
||||
|
|
@ -367,42 +342,21 @@ void GateMatePacker::pack_ram()
|
|||
// Error Checking and Correction
|
||||
int a_ecc_en = int_or_default(ci.params, id_A_ECC_EN, 0);
|
||||
int b_ecc_en = int_or_default(ci.params, id_B_ECC_EN, 0);
|
||||
if (ci.params.count(id_ECC_EN)) {
|
||||
a_ecc_en = int_or_default(ci.params, id_ECC_EN, 0);
|
||||
}
|
||||
ci.params[id_RAM_cfg_ecc_enable] = Property(b_ecc_en << 1 | a_ecc_en, 2);
|
||||
|
||||
ci.params[id_RAM_cfg_forward_a_addr] = Property(0b00000000, 8);
|
||||
ci.params[id_RAM_cfg_forward_b_addr] = Property(0b00000000, 8);
|
||||
|
||||
ci.params[id_RAM_cfg_sram_mode] = Property(ram_mode << 1 | split, 2);
|
||||
|
||||
pack_ram_cell(ci, item.first, 0, split);
|
||||
if (item.second) {
|
||||
pack_ram_cell(ci, item.second, 1, split);
|
||||
}
|
||||
if (split) {
|
||||
for (int i = 63; i >= 0; i--) {
|
||||
std::vector<bool> orig_first =
|
||||
item.first->params.at(ctx->idf("INIT_%02X", i)).extract(0, 320).as_bits();
|
||||
std::vector<bool> orig_second;
|
||||
if (item.second)
|
||||
orig_second = item.second->params.at(ctx->idf("INIT_%02X", i)).extract(0, 320).as_bits();
|
||||
std::string init[2];
|
||||
ci.params[id_RAM_cfg_sram_delay] = Property(0b000101, 6); // Always set to default
|
||||
// id_RAM_cfg_datbm_sel
|
||||
ci.params[id_RAM_cfg_cascade_enable] = Property(cascade, 2);
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
for (int l = 0; l < 40; l++) {
|
||||
if (item.second)
|
||||
init[j].push_back(orig_second.at(319 - (l + k * 40 + j * 160)) ? '1' : '0');
|
||||
else
|
||||
init[j].push_back('0');
|
||||
}
|
||||
for (int l = 0; l < 40; l++) {
|
||||
init[j].push_back(orig_first.at(319 - (l + k * 40 + j * 160)) ? '1' : '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
ci.params[ctx->idf("INIT_%02X", i * 2 + 1)] = Property::from_string(init[0]);
|
||||
ci.params[ctx->idf("INIT_%02X", i * 2 + 0)] = Property::from_string(init[1]);
|
||||
}
|
||||
}
|
||||
pack_ram_cell(ci, item, split);
|
||||
|
||||
if (is_fifo) {
|
||||
int a_rd_width = int_or_default(ci.params, id_A_WIDTH, 0);
|
||||
|
|
@ -442,11 +396,6 @@ void GateMatePacker::pack_ram()
|
|||
Property(int_or_default(ci.params, id_F_ALMOST_FULL_OFFSET, 0), 15);
|
||||
}
|
||||
|
||||
ci.params[id_RAM_cfg_ecc_enable] = Property(b_ecc_en << 1 | a_ecc_en, 2);
|
||||
ci.params[id_RAM_cfg_sram_delay] = Property(0b000101, 6); // Always set to default
|
||||
// id_RAM_cfg_datbm_sel
|
||||
ci.params[id_RAM_cfg_cascade_enable] = Property(cascade, 2);
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
move_ram_o(&ci, ctx->idf("WEA[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("WEB[%d]", i));
|
||||
|
|
@ -470,6 +419,10 @@ void GateMatePacker::pack_ram()
|
|||
move_ram_o(&ci, ctx->idf("ENB[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("GLWEA[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("GLWEB[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("ECC1B_ERRA[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("ECC1B_ERRB[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("ECC2B_ERRA[%d]", i));
|
||||
move_ram_o(&ci, ctx->idf("ECC2B_ERRB[%d]", i));
|
||||
}
|
||||
|
||||
if (is_fifo) {
|
||||
|
|
@ -509,4 +462,148 @@ void GateMatePacker::pack_ram()
|
|||
flush_cells();
|
||||
}
|
||||
|
||||
void GateMatePacker::remap_ram_half(CellInfo *half, CellInfo *cell, int num)
|
||||
{
|
||||
int index = num ? 2 : 0;
|
||||
|
||||
rename_or_move(half, cell, ctx->id("CLKA[0]"), ctx->idf("CLKA[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("CLKB[0]"), ctx->idf("CLKB[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("ENA[0]"), ctx->idf("ENA[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("ENB[0]"), ctx->idf("ENB[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("GLWEA[0]"), ctx->idf("GLWEA[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("GLWEB[0]"), ctx->idf("GLWEB[%d]", index));
|
||||
for (int i = 0; i < 20; i++) {
|
||||
rename_or_move(half, cell, ctx->idf("WEA[%d]", i), ctx->idf("WEA[%d]", i + 20 * num));
|
||||
rename_or_move(half, cell, ctx->idf("WEB[%d]", i), ctx->idf("WEB[%d]", i + 20 * num));
|
||||
rename_or_move(half, cell, ctx->idf("DIA[%d]", i), ctx->idf("DIA[%d]", i + 20 * num));
|
||||
rename_or_move(half, cell, ctx->idf("DIB[%d]", i), ctx->idf("DIB[%d]", i + 20 * num));
|
||||
rename_or_move(half, cell, ctx->idf("DOA[%d]", i), ctx->idf("DOA[%d]", i + 20 * num));
|
||||
rename_or_move(half, cell, ctx->idf("DOB[%d]", i), ctx->idf("DOB[%d]", i + 20 * num));
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
rename_or_move(half, cell, ctx->idf("ADDRA0[%d]", i), ctx->idf("ADDRA%d[%d]", num, i));
|
||||
rename_or_move(half, cell, ctx->idf("ADDRB0[%d]", i), ctx->idf("ADDRB%d[%d]", num, i));
|
||||
}
|
||||
|
||||
index = num ? 1 : 0;
|
||||
rename_or_move(half, cell, ctx->id("ECC1B_ERRA[0]"), ctx->idf("ECC1B_ERRA[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("ECC1B_ERRB[0]"), ctx->idf("ECC1B_ERRB[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("ECC2B_ERRA[0]"), ctx->idf("ECC2B_ERRA[%d]", index));
|
||||
rename_or_move(half, cell, ctx->id("ECC2B_ERRB[0]"), ctx->idf("ECC2B_ERRB[%d]", index));
|
||||
|
||||
for (int i = 1; i < 5; i++)
|
||||
if (!cell->getPort(ctx->idf("CLOCK%d", i)))
|
||||
rename_or_move(half, cell, ctx->idf("CLOCK%d", i), ctx->idf("CLOCK%d", i));
|
||||
|
||||
static dict<IdString, IdString> map_params = {
|
||||
{id_RAM_cfg_forward_a0_clk, id_RAM_cfg_forward_a1_clk},
|
||||
{id_RAM_cfg_forward_b0_clk, id_RAM_cfg_forward_b1_clk},
|
||||
|
||||
{id_RAM_cfg_forward_a0_en, id_RAM_cfg_forward_a1_en},
|
||||
{id_RAM_cfg_forward_b0_en, id_RAM_cfg_forward_b1_en},
|
||||
|
||||
{id_RAM_cfg_forward_a0_we, id_RAM_cfg_forward_a1_we},
|
||||
{id_RAM_cfg_forward_b0_we, id_RAM_cfg_forward_b1_we},
|
||||
|
||||
{id_RAM_cfg_input_config_a0, id_RAM_cfg_input_config_a1},
|
||||
{id_RAM_cfg_input_config_b0, id_RAM_cfg_input_config_b1},
|
||||
{id_RAM_cfg_output_config_a0, id_RAM_cfg_output_config_a1},
|
||||
{id_RAM_cfg_output_config_b0, id_RAM_cfg_output_config_b1},
|
||||
|
||||
{id_RAM_cfg_a0_writemode, id_RAM_cfg_a1_writemode},
|
||||
{id_RAM_cfg_b0_writemode, id_RAM_cfg_b1_writemode},
|
||||
|
||||
{id_RAM_cfg_a0_set_outputreg, id_RAM_cfg_a1_set_outputreg},
|
||||
{id_RAM_cfg_b0_set_outputreg, id_RAM_cfg_b1_set_outputreg},
|
||||
|
||||
{id_RAM_cfg_inversion_a0, id_RAM_cfg_inversion_a1},
|
||||
{id_RAM_cfg_inversion_b0, id_RAM_cfg_inversion_b1},
|
||||
|
||||
// This is for both halfs and it is same
|
||||
{id_RAM_cfg_forward_a_addr, id_RAM_cfg_forward_a_addr},
|
||||
{id_RAM_cfg_forward_b_addr, id_RAM_cfg_forward_b_addr},
|
||||
{id_RAM_cfg_sram_mode, id_RAM_cfg_sram_mode},
|
||||
{id_RAM_cfg_ecc_enable, id_RAM_cfg_ecc_enable},
|
||||
{id_RAM_cfg_sram_delay, id_RAM_cfg_sram_delay},
|
||||
{id_RAM_cfg_cascade_enable, id_RAM_cfg_cascade_enable},
|
||||
};
|
||||
|
||||
for (auto &p : map_params) {
|
||||
if (map_params.count(p.first)) {
|
||||
cell->params[num ? p.second : p.first] = half->params[p.first];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GateMatePacker::repack_ram()
|
||||
{
|
||||
log_info("Repacking RAMs..\n");
|
||||
dict<Loc, std::pair<CellInfo *, CellInfo *>> rams;
|
||||
for (auto &cell : ctx->cells) {
|
||||
if (cell.second->type.in(id_RAM_HALF)) {
|
||||
Loc l = ctx->getBelLocation(cell.second->bel);
|
||||
if (l.z == RAM_HALF_U_Z) {
|
||||
rams[Loc(l.x, l.y, 0)].first = cell.second.get();
|
||||
} else {
|
||||
rams[Loc(l.x, l.y - 8, 0)].second = cell.second.get();
|
||||
}
|
||||
} else if (cell.second->type.in(id_RAM_HALF_DUMMY))
|
||||
packed_cells.insert(cell.second->name);
|
||||
}
|
||||
int id = 0;
|
||||
for (auto &ram : rams) {
|
||||
IdString name = ctx->idf("$ram$merged$id%d", id);
|
||||
if (!ram.second.first)
|
||||
name = ctx->idf("%s$full", ram.second.second->name.c_str(ctx));
|
||||
if (!ram.second.second)
|
||||
name = ctx->idf("%s$full", ram.second.first->name.c_str(ctx));
|
||||
|
||||
CellInfo *cell = ctx->createCell(name, id_RAM);
|
||||
BelId bel = ctx->getBelByLocation({ram.first.x, ram.first.y, RAM_FULL_Z});
|
||||
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_FIXED);
|
||||
|
||||
if (ram.second.first) {
|
||||
remap_ram_half(ram.second.first, cell, 0);
|
||||
packed_cells.insert(ram.second.first->name);
|
||||
}
|
||||
if (ram.second.second) {
|
||||
remap_ram_half(ram.second.second, cell, 1);
|
||||
packed_cells.insert(ram.second.second->name);
|
||||
}
|
||||
|
||||
for (int i = 63; i >= 0; i--) {
|
||||
std::vector<bool> orig_first;
|
||||
if (ram.second.first)
|
||||
orig_first = ram.second.first->params.at(ctx->idf("INIT_%02X", i)).extract(0, 320).as_bits();
|
||||
std::vector<bool> orig_second;
|
||||
if (ram.second.second)
|
||||
orig_second = ram.second.second->params.at(ctx->idf("INIT_%02X", i)).extract(0, 320).as_bits();
|
||||
std::string init[2];
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
for (int l = 0; l < 40; l++) {
|
||||
if (ram.second.second)
|
||||
init[j].push_back(orig_second.at(319 - (l + k * 40 + j * 160)) ? '1' : '0');
|
||||
else
|
||||
init[j].push_back('0');
|
||||
}
|
||||
for (int l = 0; l < 40; l++) {
|
||||
if (ram.second.first)
|
||||
init[j].push_back(orig_first.at(319 - (l + k * 40 + j * 160)) ? '1' : '0');
|
||||
else
|
||||
init[j].push_back('0');
|
||||
}
|
||||
}
|
||||
}
|
||||
cell->params[ctx->idf("INIT_%02X", i * 2 + 1)] = Property::from_string(init[0]);
|
||||
cell->params[ctx->idf("INIT_%02X", i * 2 + 0)] = Property::from_string(init[1]);
|
||||
}
|
||||
|
||||
id++;
|
||||
}
|
||||
flush_cells();
|
||||
ctx->assignArchInfo();
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -233,11 +233,11 @@ void GateMatePacker::pack_io()
|
|||
ci.params[id_SLEW] = Property(Property::State::S1);
|
||||
|
||||
int keeper = int_or_default(ci.params, id_KEEPER, 0);
|
||||
ci.unsetParam(id_KEEPER);
|
||||
if (keeper && (int_or_default(ci.params, id_PULLUP, 0) + int_or_default(ci.params, id_PULLDOWN, 0) > 1))
|
||||
log_error("PULLUP/PULLDOWN and KEEPER are mutually exclusive parameters, issue for '%s' cell.\n",
|
||||
ci.name.c_str(ctx));
|
||||
if (keeper) {
|
||||
ci.unsetParam(id_KEEPER);
|
||||
ci.params[id_PULLUP] = Property(Property::State::S1);
|
||||
ci.params[id_PULLDOWN] = Property(Property::State::S1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue