aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-09-24 19:20:36 +0100
committerGitHub <noreply@github.com>2021-09-24 19:20:36 +0100
commitd44b6acaa9f724694081139b2e88266af8acbb02 (patch)
treeadfb3dde2e6a46f5a9907f7aee66b017c8608a1f
parentd9a71083e1a081f89e1aa4c357bc3b828eea6709 (diff)
parent718ee441a0dcf7328692c67d143f2b26b8ebc61c (diff)
downloadnextpnr-d44b6acaa9f724694081139b2e88266af8acbb02.tar.gz
nextpnr-d44b6acaa9f724694081139b2e88266af8acbb02.tar.bz2
nextpnr-d44b6acaa9f724694081139b2e88266af8acbb02.zip
Merge pull request #826 from YosysHQ/gatecat/nexus-lutperm
nexus: Add LUT permutation support
-rw-r--r--common/router2.cc3
-rw-r--r--common/router2.h8
-rw-r--r--nexus/arch.cc19
-rw-r--r--nexus/arch.h33
-rw-r--r--nexus/bba_version.inc2
-rw-r--r--nexus/fasm.cc41
6 files changed, 100 insertions, 6 deletions
diff --git a/common/router2.cc b/common/router2.cc
index 1f9196ab..813249b4 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -355,8 +355,7 @@ struct Router2
{
auto &wd = wire_data(wire);
auto &nd = nets.at(net->udata);
- float base_cost = ctx->getDelayNS(ctx->getPipDelay(pip).maxDelay() + ctx->getWireDelay(wire).maxDelay() +
- ctx->getDelayEpsilon());
+ float base_cost = cfg.get_base_cost(ctx, wire, pip, crit_weight);
int overuse = wd.curr_cong;
float hist_cost = 1.0f + crit_weight * (wd.hist_cong_cost - 1.0f);
float bias_cost = 0;
diff --git a/common/router2.h b/common/router2.h
index 34102f44..629453c6 100644
--- a/common/router2.h
+++ b/common/router2.h
@@ -21,6 +21,13 @@
NEXTPNR_NAMESPACE_BEGIN
+inline float default_base_cost(Context *ctx, WireId wire, PipId pip, float crit_weight)
+{
+ (void)crit_weight; // unused
+ return ctx->getDelayNS(ctx->getPipDelay(pip).maxDelay() + ctx->getWireDelay(wire).maxDelay() +
+ ctx->getDelayEpsilon());
+}
+
struct Router2Cfg
{
Router2Cfg(Context *ctx);
@@ -51,6 +58,7 @@ struct Router2Cfg
bool perf_profile = false;
std::string heatmap;
+ std::function<float(Context *ctx, WireId wire, PipId pip, float crit_weight)> get_base_cost = default_base_cost;
};
void router2(Context *ctx, const Router2Cfg &cfg);
diff --git a/nexus/arch.cc b/nexus/arch.cc
index fa81485a..ee7f6304 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -705,6 +705,21 @@ void Arch::pre_routing()
}
}
}
+namespace {
+float router2_base_cost(Context *ctx, WireId wire, PipId pip, float crit_weight)
+{
+ (void)crit_weight; // unused
+ if (pip != PipId()) {
+ auto &data = ctx->pip_data(pip);
+ if (data.flags & PIP_ZERO_RR_COST)
+ return 1e-12;
+ if (data.flags & PIP_DRMUX_C)
+ return 1e15;
+ }
+ return ctx->getDelayNS(ctx->getPipDelay(pip).maxDelay() + ctx->getWireDelay(wire).maxDelay() +
+ ctx->getDelayEpsilon());
+}
+} // namespace
bool Arch::route()
{
@@ -719,7 +734,9 @@ bool Arch::route()
if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx()));
} else if (router == "router2") {
- router2(getCtx(), Router2Cfg(getCtx()));
+ Router2Cfg cfg(getCtx());
+ cfg.get_base_cost = router2_base_cost;
+ router2(getCtx(), cfg);
result = true;
} else {
log_error("Nexus architecture does not support router '%s'\n", router.c_str());
diff --git a/nexus/arch.h b/nexus/arch.h
index deb9b6db..3e718e78 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -86,6 +86,9 @@ NPNR_PACKED_STRUCT(struct LocWireInfoPOD {
enum PipFlags
{
PIP_FIXED_CONN = 0x8000,
+ PIP_LUT_PERM = 0x4000,
+ PIP_ZERO_RR_COST = 0x2000,
+ PIP_DRMUX_C = 0x1000,
};
NPNR_PACKED_STRUCT(struct PipInfoPOD {
@@ -979,10 +982,38 @@ struct Arch : BaseArch<ArchRanges>
return tileStatus[bel.tile].boundcells[bel.index] == nullptr;
}
+ bool is_pseudo_pip_disabled(PipId pip) const
+ {
+ const auto &data = pip_data(pip);
+ if (data.flags & PIP_LUT_PERM) {
+ int lut_idx = (data.flags >> 8) & 0xF;
+ int from_pin = (data.flags >> 4) & 0xF;
+ int to_pin = (data.flags >> 0) & 0xF;
+ auto &ts = tileStatus.at(pip.tile);
+ if (!ts.lts)
+ return false;
+ const CellInfo *lut = ts.lts->cells[((lut_idx / 2) << 3) | (BEL_LUT0 + (lut_idx % 2))];
+ if (lut) {
+ if (lut->lutInfo.is_memory)
+ return true;
+ if (lut->lutInfo.is_carry && (from_pin == 3 || to_pin == 3))
+ return true; // Upper pin is special for carries
+ }
+ if (lut_idx == 4 || lut_idx == 5) {
+ const CellInfo *ramw = ts.lts->cells[((lut_idx / 2) << 3) | BEL_RAMW];
+ if (ramw)
+ return true; // Don't permute RAM write address
+ }
+ }
+ return false;
+ }
+
bool checkPipAvail(PipId pip) const override
{
if (disabled_pips.count(pip))
return false;
+ if (is_pseudo_pip_disabled(pip))
+ return false;
return BaseArch::checkPipAvail(pip);
}
@@ -990,6 +1021,8 @@ struct Arch : BaseArch<ArchRanges>
{
if (disabled_pips.count(pip))
return false;
+ if (is_pseudo_pip_disabled(pip))
+ return false;
return BaseArch::checkPipAvailForNet(pip, net);
}
diff --git a/nexus/bba_version.inc b/nexus/bba_version.inc
index f599e28b..b4de3947 100644
--- a/nexus/bba_version.inc
+++ b/nexus/bba_version.inc
@@ -1 +1 @@
-10
+11
diff --git a/nexus/fasm.cc b/nexus/fasm.cc
index 964828cb..bb0a7941 100644
--- a/nexus/fasm.cc
+++ b/nexus/fasm.cc
@@ -207,7 +207,7 @@ struct NexusFasmWriter
void write_pip(PipId pip)
{
auto &pd = ctx->pip_data(pip);
- if (pd.flags & PIP_FIXED_CONN)
+ if ((pd.flags & PIP_FIXED_CONN) || (pd.flags & PIP_LUT_PERM))
return;
std::string tile = tile_name(pip.tile, tile_by_type_and_loc(pip.tile, IdString(pd.tile_type)));
std::string source_wire = escape_name(ctx->pip_src_wire_name(pip).str(ctx));
@@ -317,6 +317,43 @@ struct NexusFasmWriter
}
}
+ unsigned permute_init(const CellInfo *cell)
+ {
+ unsigned orig_init = int_or_default(cell->params, id_INIT, 0);
+ std::array<std::vector<unsigned>, 4> phys_to_log;
+ const std::array<IdString, 4> ports{id_A, id_B, id_C, id_D};
+ for (unsigned i = 0; i < 4; i++) {
+ WireId pin_wire = ctx->getBelPinWire(cell->bel, ports[i]);
+ for (PipId pip : ctx->getPipsUphill(pin_wire)) {
+ if (!ctx->getBoundPipNet(pip))
+ continue;
+ const auto &data = ctx->pip_data(pip);
+ if (data.flags & PIP_FIXED_CONN) { // non-permuting
+ phys_to_log[i].push_back(i);
+ } else { // permuting
+ NPNR_ASSERT(data.flags & PIP_LUT_PERM);
+ unsigned from_pin = (data.flags >> 4) & 0xF;
+ unsigned to_pin = (data.flags >> 0) & 0xF;
+ NPNR_ASSERT(to_pin == i);
+ phys_to_log[from_pin].push_back(i);
+ }
+ }
+ }
+ unsigned permuted_init = 0;
+ for (unsigned i = 0; i < 16; i++) {
+ unsigned log_idx = 0;
+ for (unsigned j = 0; j < 4; j++) {
+ if ((i >> j) & 0x1) {
+ for (auto log_pin : phys_to_log[j])
+ log_idx |= (1 << log_pin);
+ }
+ }
+ if ((orig_init >> log_idx) & 0x1)
+ permuted_init |= (1 << i);
+ }
+ return permuted_init;
+ }
+
// Write config for an OXIDE_COMB cell
void write_comb(const CellInfo *cell)
{
@@ -327,7 +364,7 @@ struct NexusFasmWriter
push_tile(bel.tile, id_PLC);
push(stringf("SLICE%c", slice));
if (cell->params.count(id_INIT))
- write_int_vector(stringf("K%d.INIT[15:0]", k), int_or_default(cell->params, id_INIT, 0), 16);
+ write_int_vector(stringf("K%d.INIT[15:0]", k), permute_init(cell), 16);
if (cell->lutInfo.is_carry) {
write_bit("MODE.CCU2");
write_enum(cell, "CCU2.INJECT", "NO");