gatemate: Add LUT permutation support (#1619)

Adds LUT permutation support
This commit is contained in:
Miodrag Milanović 2025-12-22 15:10:53 +01:00 committed by GitHub
parent 210e6c8158
commit c30f810ee0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 395 additions and 56 deletions

View File

@ -906,6 +906,12 @@ X(USR_RSTN)
// hardware primitive CPE_LT_U
X(CPE_LT_U)
// CPE_LT_U pins
X(D0_00)
X(D1_00)
X(D0_01)
X(D1_01)
X(D0_10)
X(D1_10)
X(IN1)
X(IN2)
X(IN3)
@ -935,11 +941,17 @@ X(RAM_O)
// hardware primitive CPE_LT_L
X(CPE_LT_L)
// CPE_LT_L pins
//X(D0_00)
//X(D1_00)
//X(D0_01)
//X(D1_01)
//X(D0_10)
//X(D1_10)
X(COMBIN)
//X(IN1)
//X(IN2)
//X(IN3)
//X(IN4)
X(COMBIN)
//X(OUT)
//X(CPOUT)
//X(CINX)
@ -988,6 +1000,18 @@ X(MUXOUT)
// hardware primitive CPE_LT_FULL
X(CPE_LT_FULL)
// CPE_LT_FULL pins
//X(D0_00)
//X(D1_00)
//X(D0_01)
//X(D1_01)
X(D0_02)
X(D1_02)
X(D0_03)
X(D1_03)
//X(D0_10)
//X(D1_10)
X(D0_11)
X(D1_11)
//X(IN1)
//X(IN2)
//X(IN3)
@ -2476,6 +2500,14 @@ X(2B)
X(DIE)
X(GATEMATE_DIE)
// LUT permutation
X(LUT2_00)
X(LUT2_01)
X(LUT2_02)
X(LUT2_03)
X(LUT2_10)
X(LUT2_11)
// Timing
X(timing_ADDF2x_IN5_8_comb2)
X(timing_CIN_C_CINI)

View File

@ -90,14 +90,20 @@ bool GateMateImpl::getCellDelay(const CellInfo *cell, IdString fromPort, IdStrin
{
delay = DelayQuad{0};
static dict<IdString, IdString> map_upper = {
{id_OUT, id_OUT2},
{id_RAM_O, id_RAM_O2},
{id_RAM_I, id_RAM_I2},
{id_CPOUT, id_CPOUT2},
{id_D0_00, id_IN1}, {id_D1_00, id_IN2}, {id_D0_01, id_IN3}, {id_D1_01, id_IN4}, {id_D0_10, id_IN1},
{id_D1_10, id_IN3}, {id_OUT, id_OUT2}, {id_RAM_O, id_RAM_O2}, {id_RAM_I, id_RAM_I2}, {id_CPOUT, id_CPOUT2},
};
static dict<IdString, IdString> map_lower = {
{id_OUT, id_OUT1}, {id_RAM_O, id_RAM_O1}, {id_RAM_I, id_RAM_I1}, {id_CPOUT, id_CPOUT1},
{id_IN1, id_IN5}, {id_IN2, id_IN6}, {id_IN3, id_IN7}, {id_IN4, id_IN8},
{id_D0_00, id_IN5}, {id_D1_00, id_IN6}, {id_D0_01, id_IN7}, {id_D1_01, id_IN8}, {id_D0_10, id_IN5},
{id_D1_10, id_IN7}, {id_D0_02, id_IN5}, {id_D1_02, id_IN6}, {id_D0_03, id_IN7}, {id_D1_03, id_IN8},
{id_D0_11, id_IN5}, {id_D1_11, id_IN7}, {id_OUT, id_OUT1}, {id_RAM_O, id_RAM_O1}, {id_RAM_I, id_RAM_I1},
{id_CPOUT, id_CPOUT1}, {id_IN1, id_IN5}, {id_IN2, id_IN6}, {id_IN3, id_IN7}, {id_IN4, id_IN8},
};
static dict<IdString, IdString> map_both = {
{id_D0_00, id_IN1}, {id_D1_00, id_IN2}, {id_D0_01, id_IN3}, {id_D1_01, id_IN4},
{id_D0_10, id_IN1}, {id_D1_10, id_IN3}, {id_D0_02, id_IN5}, {id_D1_02, id_IN6},
{id_D0_03, id_IN7}, {id_D1_03, id_IN8}, {id_D0_11, id_IN5}, {id_D1_11, id_IN7},
};
int z = (cell->bel != BelId()) ? (ctx->getBelLocation(cell->bel).z % 2) : 0;
@ -116,9 +122,19 @@ bool GateMateImpl::getCellDelay(const CellInfo *cell, IdString fromPort, IdStrin
}
return get_delay_from_tmg_db(ctx->idf("timing__ARBLUT_%s_%s", fp.c_str(ctx), tp.c_str(ctx)), delay);
} else if (cell->type.in(id_CPE_ADDF, id_CPE_ADDF2)) {
return get_delay_from_tmg_db(ctx->idf("timing__ADDF2Y1_%s_%s", fromPort.c_str(ctx), toPort.c_str(ctx)), delay);
IdString fp = fromPort, tp = toPort;
if (map_both.count(fp))
fp = map_both[fp];
if (map_both.count(tp))
tp = map_both[tp];
return get_delay_from_tmg_db(ctx->idf("timing__ADDF2Y1_%s_%s", fp.c_str(ctx), tp.c_str(ctx)), delay);
} else if (cell->type.in(id_CPE_MX4)) {
return get_delay_from_tmg_db(ctx->idf("timing__MX4A_%s_%s", fromPort.c_str(ctx), toPort.c_str(ctx)), delay);
IdString fp = fromPort, tp = toPort;
if (map_both.count(fp))
fp = map_both[fp];
if (map_both.count(tp))
tp = map_both[tp];
return get_delay_from_tmg_db(ctx->idf("timing__MX4A_%s_%s", fp.c_str(ctx), tp.c_str(ctx)), delay);
} else if (cell->type.in(id_CPE_MULT)) {
if (toPort == id_CPOUT1)
return get_delay_from_tmg_db(ctx->id("timing_cpout_OUT1"), delay);
@ -187,22 +203,29 @@ TimingPortClass GateMateImpl::getPortTimingClass(const CellInfo *cell, IdString
auto disconnected = [cell](IdString p) { return !cell->ports.count(p) || cell->ports.at(p).net == nullptr; };
clockInfoCount = 0;
if (cell->type.in(id_CPE_L2T4, id_CPE_LT_L, id_CPE_LT_U)) {
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_COMBIN, id_CINY1, id_CINY2, id_CINX, id_PINX))
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_COMBIN, id_CINY1, id_CINY2, id_CINX, id_PINX, id_D0_00, id_D1_00,
id_D0_01, id_D1_01, id_D0_10, id_D1_10, id_D0_02, id_D1_02, id_D0_03, id_D1_03, id_D0_11, id_D1_11))
return TMG_COMB_INPUT;
if (port == id_OUT && disconnected(id_IN1) && disconnected(id_IN2) && disconnected(id_IN3) &&
disconnected(id_IN4))
disconnected(id_IN4) && disconnected(id_D0_00) && disconnected(id_D1_00) && disconnected(id_D0_01) &&
disconnected(id_D1_01) && disconnected(id_D0_10) && disconnected(id_D1_10) && disconnected(id_D0_02) &&
disconnected(id_D1_02) && disconnected(id_D0_03) && disconnected(id_D1_03) && disconnected(id_D0_11) &&
disconnected(id_D1_11))
return TMG_IGNORE; // LUT with no inputs is a constant
if (port.in(id_OUT))
return TMG_COMB_OUTPUT;
return TMG_IGNORE;
} else if (cell->type.in(id_CPE_ADDF, id_CPE_ADDF2)) {
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_IN5, id_IN6, id_IN7, id_IN8, id_CINX, id_CINY1))
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_IN5, id_IN6, id_IN7, id_IN8, id_CINX, id_CINY1, id_D0_00,
id_D1_00, id_D0_01, id_D1_01, id_D0_10, id_D1_10, id_D0_02, id_D1_02, id_D0_03, id_D1_03, id_D0_11,
id_D1_11))
return TMG_COMB_INPUT;
if (port.in(id_OUT1, id_OUT2, id_COUTY1))
return TMG_COMB_OUTPUT;
return TMG_IGNORE;
} else if (cell->type.in(id_CPE_MX4)) {
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_IN5, id_IN6, id_IN7, id_IN8))
if (port.in(id_IN1, id_IN2, id_IN3, id_IN4, id_IN5, id_IN6, id_IN7, id_IN8, id_D0_00, id_D1_00, id_D0_01,
id_D1_01, id_D0_10, id_D1_10, id_D0_02, id_D1_02, id_D0_03, id_D1_03, id_D0_11, id_D1_11))
return TMG_COMB_INPUT;
if (port.in(id_OUT1))
return TMG_COMB_OUTPUT;

View File

@ -447,6 +447,201 @@ void GateMateImpl::postRoute()
}
}
dict<IdString, int> cfg;
dict<IdString, IdString> port_mapping;
auto add_input = [&](IdString orig_port, IdString port, bool merged) -> bool {
static dict<IdString, IdString> convert_port = {
{ctx->id("CPE.IN1"), id_IN1}, {ctx->id("CPE.IN2"), id_IN2}, {ctx->id("CPE.IN3"), id_IN3},
{ctx->id("CPE.IN4"), id_IN4}, {ctx->id("CPE.IN5"), id_IN1}, {ctx->id("CPE.IN6"), id_IN2},
{ctx->id("CPE.IN7"), id_IN3}, {ctx->id("CPE.IN8"), id_IN4}, {ctx->id("CPE.PINY1"), id_PINY1},
{ctx->id("CPE.CINX"), id_CINX}, {ctx->id("CPE.PINX"), id_PINX}};
static dict<IdString, IdString> convert_port_merged = {
{ctx->id("CPE.IN1"), id_IN1}, {ctx->id("CPE.IN2"), id_IN2}, {ctx->id("CPE.IN3"), id_IN3},
{ctx->id("CPE.IN4"), id_IN4}, {ctx->id("CPE.IN5"), id_IN5}, {ctx->id("CPE.IN6"), id_IN6},
{ctx->id("CPE.IN7"), id_IN7}, {ctx->id("CPE.IN8"), id_IN8}, {ctx->id("CPE.PINY1"), id_PINY1},
{ctx->id("CPE.CINX"), id_CINX}, {ctx->id("CPE.PINX"), id_PINX}};
if (convert_port.count(port)) {
port_mapping.emplace(orig_port, merged ? convert_port_merged[port] : convert_port[port]);
return true;
};
return false;
};
auto check_input = [&](CellInfo *cell, IdString port, bool merged) {
if (cell->getPort(port)) {
NetInfo *net = cell->getPort(port);
WireId src = ctx->getBelPinWire(cell->bel, port);
// In current chip db real CPE input is max 4 pips away
for (int i = 0; i < 4; i++) {
if (net->wires.count(src)) {
auto &p = net->wires.at(src);
src = ctx->getPipSrcWire(p.pip);
const auto &extra_data = *pip_extra_data(p.pip);
if (extra_data.type == PipExtra::PIP_EXTRA_MUX) {
cfg.emplace(IdString(extra_data.name), extra_data.value);
if (add_input(port, ctx->getWireName(src)[1], merged))
break;
}
}
}
}
};
auto swap_lut2_inputs = [&](int lut) -> int {
// bit permutation: [3,1,2,0]
return ((lut & 0b1000)) | // b3 -> bit 3
((lut & 0b0010) << 1) | // b1 -> bit 2
((lut & 0b0100) >> 1) | // b2 -> bit 1
((lut & 0b0001)); // b0 -> bit 0
};
log_info("Update configuration based on routing..\n");
for (auto &cell : ctx->cells) {
if (cell.second->type.in(id_CPE_L2T4)) {
cfg.clear();
port_mapping.clear();
int l00 = int_or_default(cell.second->params, id_INIT_L00, 0);
int l01 = int_or_default(cell.second->params, id_INIT_L01, 0);
int l10 = int_or_default(cell.second->params, id_INIT_L10, 0);
check_input(cell.second.get(), id_D0_00, false);
check_input(cell.second.get(), id_D1_00, false);
check_input(cell.second.get(), id_D0_01, false);
check_input(cell.second.get(), id_D1_01, false);
check_input(cell.second.get(), id_D0_10, false);
check_input(cell.second.get(), id_D1_10, false);
if (cfg.count(id_LUT2_11) || cfg.count(id_LUT2_10)) {
if (cfg.count(id_LUT2_11)) { // lower
if (cfg.count(id_LUT2_02) && !cfg.count(id_LUT2_03)) {
// both inputs on 02
l00 = l10; // config is now in 02
l10 = 0b1010; // LUT_D0 - we propagate only
} else if (!cfg.count(id_LUT2_02) && cfg.count(id_LUT2_03)) {
// both inputs on 03
l01 = l10; // config is now in 03
l10 = 0b1010; // LUT_D0 - we propagate only
} else {
// one input on 02, other on 03 (or LUT1)
if (cfg.count(id_LUT2_02))
l00 = 0b1010; // LUT_D0 - we propagate only
if (cfg.count(id_LUT2_03))
l01 = 0b1010; // LUT_D0 - we propagate only
}
if (cfg.at(id_LUT2_11) == 1)
l10 = swap_lut2_inputs(l10);
if (cfg.count(id_LUT2_02) && (cfg.at(id_LUT2_02) == 1))
l00 = swap_lut2_inputs(l00);
if (cfg.count(id_LUT2_03) && (cfg.at(id_LUT2_03) == 1))
l01 = swap_lut2_inputs(l01);
} else { // upper part
if (cfg.count(id_LUT2_00) && !cfg.count(id_LUT2_01)) {
// both inputs on 02
l00 = l10; // config is now in 02
l10 = 0b1010; // LUT_D0 - we propagate only
} else if (!cfg.count(id_LUT2_00) && cfg.count(id_LUT2_01)) {
// both inputs on 03
l01 = l10; // config is now in 03
l10 = 0b1010; // LUT_D0 - we propagate only
} else {
// one input on 02, other on 03 (or LUT1)
if (cfg.count(id_LUT2_00))
l00 = 0b1010; // LUT_D0 - we propagate only
if (cfg.count(id_LUT2_01))
l01 = 0b1010; // LUT_D0 - we propagate only
}
if (cfg.at(id_LUT2_10) == 1)
l10 = swap_lut2_inputs(l10);
if (cfg.count(id_LUT2_00) && (cfg.at(id_LUT2_00) == 1))
l00 = swap_lut2_inputs(l00);
if (cfg.count(id_LUT2_01) && (cfg.at(id_LUT2_01) == 1))
l01 = swap_lut2_inputs(l01);
}
cell.second->params[id_INIT_L00] = Property(l00, 4);
cell.second->params[id_INIT_L01] = Property(l01, 4);
cell.second->params[id_INIT_L10] = Property(l10, 4);
cell.second->renamePort(id_D0_10, port_mapping[id_D0_10]);
cell.second->renamePort(id_D1_10, port_mapping[id_D1_10]);
} else {
if (cfg.count(id_LUT2_00) && cfg.at(id_LUT2_00) == 1)
l00 = swap_lut2_inputs(l00);
if (cfg.count(id_LUT2_01) && cfg.at(id_LUT2_01) == 1)
l01 = swap_lut2_inputs(l01);
if (cfg.count(id_LUT2_02) && cfg.at(id_LUT2_02) == 1)
l00 = swap_lut2_inputs(l00);
if (cfg.count(id_LUT2_03) && cfg.at(id_LUT2_03) == 1)
l01 = swap_lut2_inputs(l01);
cell.second->params[id_INIT_L00] = Property(l00, 4);
cell.second->params[id_INIT_L01] = Property(l01, 4);
cell.second->params[id_INIT_L10] = Property(l10, 4);
cell.second->renamePort(id_D0_00, port_mapping[id_D0_00]);
cell.second->renamePort(id_D1_00, port_mapping[id_D1_00]);
cell.second->renamePort(id_D0_01, port_mapping[id_D0_01]);
cell.second->renamePort(id_D1_01, port_mapping[id_D1_01]);
}
if (cfg.count(id_C_I1) && cfg.at(id_C_I1) == 1)
cell.second->params[id_C_I1] = Property(1, 1);
if (cfg.count(id_C_I2) && cfg.at(id_C_I2) == 1)
cell.second->params[id_C_I2] = Property(1, 1);
if (cfg.count(id_C_I3) && cfg.at(id_C_I3) == 1)
cell.second->params[id_C_I3] = Property(1, 1);
if (cfg.count(id_C_I4) && cfg.at(id_C_I4) == 1)
cell.second->params[id_C_I4] = Property(1, 1);
}
if (cell.second->type.in(id_CPE_MX4, id_CPE_ADDF, id_CPE_ADDF2)) {
cfg.clear();
port_mapping.clear();
int l00 = int_or_default(cell.second->params, id_INIT_L00, 0);
int l01 = int_or_default(cell.second->params, id_INIT_L01, 0);
int l02 = int_or_default(cell.second->params, id_INIT_L02, 0);
int l03 = int_or_default(cell.second->params, id_INIT_L03, 0);
check_input(cell.second.get(), id_D0_00, true);
check_input(cell.second.get(), id_D1_00, true);
check_input(cell.second.get(), id_D0_01, true);
check_input(cell.second.get(), id_D1_01, true);
check_input(cell.second.get(), id_D0_02, true);
check_input(cell.second.get(), id_D1_02, true);
check_input(cell.second.get(), id_D0_03, true);
check_input(cell.second.get(), id_D1_03, true);
if (cfg.count(id_LUT2_00) && cfg.at(id_LUT2_00) == 1)
l00 = swap_lut2_inputs(l00);
if (cfg.count(id_LUT2_01) && cfg.at(id_LUT2_01) == 1)
l01 = swap_lut2_inputs(l01);
if (cfg.count(id_LUT2_02) && cfg.at(id_LUT2_02) == 1)
l02 = swap_lut2_inputs(l02);
if (cfg.count(id_LUT2_03) && cfg.at(id_LUT2_03) == 1)
l03 = swap_lut2_inputs(l03);
cell.second->params[id_INIT_L00] = Property(l00, 4);
cell.second->params[id_INIT_L01] = Property(l01, 4);
cell.second->params[id_INIT_L02] = Property(l02, 4);
cell.second->params[id_INIT_L03] = Property(l03, 4);
cell.second->renamePort(id_D0_00, port_mapping[id_D0_00]);
cell.second->renamePort(id_D1_00, port_mapping[id_D1_00]);
cell.second->renamePort(id_D0_01, port_mapping[id_D0_01]);
cell.second->renamePort(id_D1_01, port_mapping[id_D1_01]);
cell.second->renamePort(id_D0_02, port_mapping[id_D0_02]);
cell.second->renamePort(id_D1_02, port_mapping[id_D1_02]);
cell.second->renamePort(id_D0_03, port_mapping[id_D0_03]);
cell.second->renamePort(id_D1_03, port_mapping[id_D1_03]);
if (cfg.count(id_C_I1) && cfg.at(id_C_I1) == 1)
cell.second->params[id_C_I1] = Property(1, 1);
if (cfg.count(id_C_I2) && cfg.at(id_C_I2) == 1)
cell.second->params[id_C_I2] = Property(1, 1);
if (cfg.count(id_C_I3) && cfg.at(id_C_I3) == 1)
cell.second->params[id_C_I3] = Property(1, 1);
if (cfg.count(id_C_I4) && cfg.at(id_C_I4) == 1)
cell.second->params[id_C_I4] = Property(1, 1);
}
}
ctx->assignArchInfo();
const ArchArgs &args = ctx->args;

View File

@ -224,7 +224,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.10
EXPECTED_VERSION = 1.11
def main():
# Range needs to be +1, but we are adding +2 more to coordinates, since

View File

@ -131,10 +131,83 @@ void GateMatePacker::count_cell(CellInfo &ci)
count++;
}
inline int lut2_apply_constant_inputs(int init, int d0_const, int d1_const)
{
int b0 = (init >> 0) & 1;
int b1 = (init >> 1) & 1;
int b2 = (init >> 2) & 1;
int b3 = (init >> 3) & 1;
int out[4];
for (int i = 0; i < 4; i++) {
int D1 = (i >> 1) & 1;
int D0 = (i >> 0) & 1;
// Apply constants if present
if (d0_const != -1)
D0 = d0_const;
if (d1_const != -1)
D1 = d1_const;
int src = (D1 << 1) | D0;
out[i] = (src == 0) ? b0 : (src == 1) ? b1 : (src == 2) ? b2 : b3;
}
return (out[3] << 3) | (out[2] << 2) | (out[1] << 1) | out[0];
}
void GateMatePacker::optimize_lut2(CellInfo &ci, IdString i0, IdString i1, IdString init)
{
auto lut2_same_inputs = [&](int lut) -> int {
int b0 = lut & 1; // bit 0
int b3 = (lut >> 3) & 1; // bit 3
return (b3 << 3) | (b3 << 2) | (b0 << 1) | b0;
};
uint8_t val = int_or_default(ci.params, init, 0);
int d0_const = -1;
int d1_const = -1;
if (ci.getPort(i0) && ci.getPort(i0) == net_PACKER_GND) {
d0_const = 0;
ci.disconnectPort(i0);
}
if (ci.getPort(i0) && ci.getPort(i0) == net_PACKER_VCC) {
d0_const = 1;
ci.disconnectPort(i0);
}
if (ci.getPort(i1) && ci.getPort(i1) == net_PACKER_GND) {
d1_const = 0;
ci.disconnectPort(i1);
}
if (ci.getPort(i1) && ci.getPort(i1) == net_PACKER_VCC) {
d1_const = 1;
ci.disconnectPort(i1);
}
val = lut2_apply_constant_inputs(val, d0_const, d1_const);
if (ci.getPort(i0) == ci.getPort(i1)) {
val = lut2_same_inputs(val);
ci.params[init] = Property(val, 4);
ci.disconnectPort(i1);
}
}
void GateMatePacker::optimize_lut()
{
for (auto &cell : ctx->cells) {
CellInfo &ci = *cell.second;
if (ci.type == id_CC_LUT2) {
optimize_lut2(ci, id_I0, id_I1, id_INIT);
} else if (ci.type == id_CC_L2T4) {
optimize_lut2(ci, id_I0, id_I1, id_INIT_L00);
optimize_lut2(ci, id_I2, id_I3, id_INIT_L01);
} else if (ci.type == id_CC_L2T5) {
optimize_lut2(ci, id_I0, id_I1, id_INIT_L02);
optimize_lut2(ci, id_I2, id_I3, id_INIT_L03);
}
if (!ci.type.in(id_CC_LUT1, id_CC_LUT2))
continue;
if (ci.attrs.count(ctx->id("keep")))
@ -308,6 +381,8 @@ void GateMatePacker::repack_cpe()
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);
if (cell.second->getPort(id_D0_10)) {
}
}
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)) {
@ -318,6 +393,13 @@ void GateMatePacker::repack_cpe()
loc.z = CPE_LT_FULL_Z;
ctx->unbindBel(bel);
ctx->bindBel(ctx->getBelByLocation(loc), cell.second.get(), strength);
cell.second->renamePort(id_D0_00, id_D0_02);
cell.second->renamePort(id_D1_00, id_D1_02);
cell.second->renamePort(id_D0_01, id_D0_03);
cell.second->renamePort(id_D1_01, id_D1_03);
cell.second->renamePort(id_D0_10, id_D0_11);
cell.second->renamePort(id_D1_10, id_D1_11);
cell.second->renamePort(id_IN1, id_IN5);
cell.second->renamePort(id_IN2, id_IN6);
cell.second->renamePort(id_IN3, id_IN7);
@ -368,6 +450,14 @@ void GateMatePacker::repack_cpe()
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_D0_00, cell.second.get(), id_D0_00);
upper->movePortTo(id_D1_00, cell.second.get(), id_D1_00);
upper->movePortTo(id_D0_01, cell.second.get(), id_D0_01);
upper->movePortTo(id_D1_01, cell.second.get(), id_D1_01);
upper->movePortTo(id_D0_10, cell.second.get(), id_D0_10);
upper->movePortTo(id_D1_10, cell.second.get(), id_D1_10);
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);

View File

@ -85,6 +85,7 @@ struct GateMatePacker
void disconnect_not_used();
void optimize_lut();
void optimize_lut2(CellInfo &ci, IdString i0, IdString i1, IdString init);
void optimize_mx();
void optimize_ff();
void count_cell(CellInfo &ci);

View File

@ -202,10 +202,10 @@ void GateMatePacker::pack_cpe()
bool is_l2t5 = false;
if (ci.type == id_CC_L2T5) {
l2t5_list.push_back(&ci);
ci.renamePort(id_I0, id_IN1);
ci.renamePort(id_I1, id_IN2);
ci.renamePort(id_I2, id_IN3);
ci.renamePort(id_I3, id_IN4);
ci.renamePort(id_I0, id_D0_00);
ci.renamePort(id_I1, id_D1_00);
ci.renamePort(id_I2, id_D0_01);
ci.renamePort(id_I3, id_D1_01);
ci.renamePort(id_O, id_OUT);
rename_param(&ci, id_INIT_L02, id_INIT_L00, 4);
@ -217,12 +217,12 @@ void GateMatePacker::pack_cpe()
ci.type = id_CPE_L2T4;
is_l2t5 = true;
} else if (ci.type == id_CC_MX2) {
ci.renamePort(id_D1, id_IN1);
ci.renamePort(id_D1, id_D0_00);
NetInfo *sel = ci.getPort(id_S0);
ci.renamePort(id_S0, id_IN2);
ci.addInput(id_IN3);
ci.connectPort(id_IN3, sel);
ci.renamePort(id_D0, id_IN4);
ci.renamePort(id_S0, id_D1_00);
ci.addInput(id_D0_01);
ci.connectPort(id_D0_01, sel);
ci.renamePort(id_D0, id_D1_01);
ci.disconnectPort(id_D1);
ci.params[id_INIT_L00] = Property(LUT_AND, 4);
ci.params[id_INIT_L01] = Property(LUT_AND_INV_D0, 4);
@ -230,18 +230,20 @@ void GateMatePacker::pack_cpe()
ci.renamePort(id_Y, id_OUT);
ci.type = id_CPE_L2T4;
} else {
ci.renamePort(id_I0, id_IN1);
ci.renamePort(id_I1, id_IN2);
ci.renamePort(id_I2, id_IN3);
ci.renamePort(id_I3, id_IN4);
ci.renamePort(id_O, id_OUT);
if (ci.type.in(id_CC_LUT1, id_CC_LUT2)) {
ci.renamePort(id_I0, id_D0_10);
ci.renamePort(id_I1, id_D1_10);
uint8_t val = int_or_default(ci.params, id_INIT, 0);
if (ci.type == id_CC_LUT1)
val = val << 2 | val;
ci.params[id_INIT_L00] = Property(val, 4);
ci.params[id_INIT_L10] = Property(val, 4);
ci.unsetParam(id_INIT);
ci.params[id_INIT_L10] = Property(LUT_D0, 4);
} else {
ci.renamePort(id_I0, id_D0_00);
ci.renamePort(id_I1, id_D1_00);
ci.renamePort(id_I2, id_D0_01);
ci.renamePort(id_I3, id_D1_01);
}
ci.type = id_CPE_L2T4;
}
@ -297,8 +299,7 @@ void GateMatePacker::pack_cpe()
upper->region = ci->region;
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(LUT_D0, 4);
ci->movePortTo(id_I4, upper, id_D0_10);
upper->params[id_INIT_L10] = Property(LUT_D0, 4);
ci->constr_children.push_back(upper);
@ -322,8 +323,8 @@ void GateMatePacker::pack_cpe()
ci.cluster = ci.name;
ci.renamePort(id_Y, id_OUT);
ci.renamePort(id_S0, id_IN2); // IN6
ci.renamePort(id_S1, id_IN4); // IN8
ci.renamePort(id_S0, id_D0_00); // IN5
ci.renamePort(id_S1, id_D0_01); // IN7
uint8_t select = 0;
uint8_t invert = 0;
@ -341,8 +342,8 @@ void GateMatePacker::pack_cpe()
}
}
ci.params[id_C_FUNCTION] = Property(C_MX4, 3);
ci.params[id_INIT_L02] = Property(LUT_D1, 4); // IN6
ci.params[id_INIT_L03] = Property(LUT_D1, 4); // IN8
ci.params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
ci.params[id_INIT_L03] = Property(LUT_D0, 4); // IN7
ci.params[id_INIT_L11] = Property(invert, 4); // Inversion bits
ci.params[id_INIT_L20] = Property(LUT_D1, 4); // Always D1
ci.type = id_CPE_LT_L;
@ -389,16 +390,15 @@ void GateMatePacker::pack_cpe()
ci.renamePort(id_Q, id_DOUT);
NetInfo *d_net = ci.getPort(id_D);
if (d_net == net_PACKER_GND) {
lt->params[id_INIT_L00] = Property(LUT_ZERO, 4);
lt->params[id_INIT_L10] = Property(LUT_ZERO, 4);
ci.disconnectPort(id_D);
} else if (d_net == net_PACKER_VCC) {
lt->params[id_INIT_L00] = Property(LUT_ONE, 4);
lt->params[id_INIT_L10] = Property(LUT_ONE, 4);
ci.disconnectPort(id_D);
} else {
lt->params[id_INIT_L00] = Property(LUT_D0, 4);
}
lt->params[id_INIT_L10] = Property(LUT_D0, 4);
ci.movePortTo(id_D, lt, id_IN1);
ci.movePortTo(id_D, lt, id_D0_10);
}
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);
@ -610,8 +610,8 @@ void GateMatePacker::pack_addf()
bool merged = cy->type != id_CC_ADDF;
if (merged) {
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
merge_input(cy, cy, id_A2, id_INIT_L02, id_D0_02, id_D1_02); // IN5,IN6
merge_input(cy, cy, id_B2, id_INIT_L03, id_D0_03, id_D1_03); // IN7,IN8
cy->params[id_INIT_L11] = Property(LUT_XOR, 4);
} else {
cy->params[id_INIT_L02] = Property(LUT_ZERO, 4);
@ -638,8 +638,8 @@ void GateMatePacker::pack_addf()
cy->renamePort(id_S, id_OUT);
}
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);
merge_input(cy, upper, id_A, id_INIT_L00, id_D0_00, id_D1_00);
merge_input(cy, upper, id_B, id_INIT_L01, id_D0_01, id_D1_01);
upper->params[id_INIT_L10] = Property(LUT_XOR, 4);
upper->params[id_C_FUNCTION] = Property(merged ? C_ADDF2 : C_ADDF, 3);
@ -804,16 +804,15 @@ std::pair<CellInfo *, CellInfo *> GateMatePacker::move_ram_o(CellInfo *cell, IdS
ctx->bindBel(b, cpe_half, PlaceStrength::STRENGTH_FIXED);
}
if (net == net_PACKER_GND) {
cpe_half->params[id_INIT_L00] = Property(LUT_ZERO, 4);
cpe_half->params[id_INIT_L10] = Property(LUT_ZERO, 4);
cell->disconnectPort(origPort);
} else if (net == net_PACKER_VCC) {
cpe_half->params[id_INIT_L00] = Property(LUT_ONE, 4);
cpe_half->params[id_INIT_L10] = 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);
cell->movePortTo(origPort, cpe_half, id_D0_10);
}
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)));
@ -867,16 +866,15 @@ std::pair<CellInfo *, CellInfo *> GateMatePacker::move_ram_io(CellInfo *cell, Id
if (o_net) {
if (o_net == net_PACKER_GND) {
cpe_half->params[id_INIT_L00] = Property(LUT_ZERO, 4);
cpe_half->params[id_INIT_L10] = Property(LUT_ZERO, 4);
cell->disconnectPort(oPort);
} else if (o_net == net_PACKER_VCC) {
cpe_half->params[id_INIT_L00] = Property(LUT_ONE, 4);
cpe_half->params[id_INIT_L10] = 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);
cell->movePortTo(oPort, cpe_half, id_D0_10);
}
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)));

View File

@ -560,7 +560,7 @@ void GateMatePacker::pack_io_sel()
int die = uarch->tile_extra_data(ci.bel.tile)->die;
auto [cpe_half, cpe_ramio] = ddr[die][pad->pad_bank];
if (cpe_half) {
if (cpe_half->getPort(id_IN1) != oddr->getPort(id_DDR))
if (cpe_half->getPort(id_D0_10) != oddr->getPort(id_DDR))
log_error("DDR port use signal different than already occupied DDR source.\n");
ci.addInput(id_DDR);
ci.connectPort(id_DDR, cpe_ramio->getPort(id_RAM_O));
@ -568,7 +568,7 @@ void GateMatePacker::pack_io_sel()
auto l = reinterpret_cast<const GateMatePadExtraDataPOD *>(pad->extra_data.get());
oddr->movePortTo(id_DDR, &ci, id_DDR);
ddr[die][pad->pad_bank] = move_ram_o(&ci, id_DDR, false, Loc(l->x, l->y, l->z));
uarch->ddr_nets.insert(ddr[die][pad->pad_bank].first->getPort(id_IN1)->name);
uarch->ddr_nets.insert(ddr[die][pad->pad_bank].first->getPort(id_D0_10)->name);
}
use_custom_clock = set_out_clk(oddr, &ci);
bool invert = bool_or_default(oddr->params, id_CLK_INV, 0);