aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/arch.h
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-12-13 16:04:45 +0000
committergatecat <gatecat@ds0.me>2021-12-13 20:22:06 +0000
commitf36188f2e18783ea692f8b6132712a0d1da6b6b7 (patch)
treed63db5e03f36e4f8598d1bcff0b475660ea57d6b /ecp5/arch.h
parent8720d79f21ac052138426b3268981ccd1926342a (diff)
downloadnextpnr-f36188f2e18783ea692f8b6132712a0d1da6b6b7.tar.gz
nextpnr-f36188f2e18783ea692f8b6132712a0d1da6b6b7.tar.bz2
nextpnr-f36188f2e18783ea692f8b6132712a0d1da6b6b7.zip
ecp5: LUT permutation support
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'ecp5/arch.h')
-rw-r--r--ecp5/arch.h50
1 files changed, 48 insertions, 2 deletions
diff --git a/ecp5/arch.h b/ecp5/arch.h
index e7bf64fe..51a919bb 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -58,8 +58,15 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD {
int16_t timing_class;
int8_t tile_type;
int8_t pip_type;
+ int16_t lutperm_flags;
+ int16_t padding;
});
+inline bool is_lutperm_pip(int16_t flags) { return flags & 0x4000; }
+inline uint8_t lutperm_lut(int16_t flags) { return (flags >> 4) & 0x7; }
+inline uint8_t lutperm_out(int16_t flags) { return (flags >> 2) & 0x3; }
+inline uint8_t lutperm_in(int16_t flags) { return flags & 0x3; }
+
NPNR_PACKED_STRUCT(struct PipLocatorPOD {
LocationPOD rel_loc;
int32_t index;
@@ -446,6 +453,14 @@ struct Arch : BaseArch<ArchRanges>
mutable dict<IdStringList, PipId> pip_by_name;
std::vector<CellInfo *> bel_to_cell;
+ enum class LutPermRule
+ {
+ NONE,
+ CARRY,
+ ALL,
+ };
+ std::vector<LutPermRule> lutperm_allowed;
+ bool disable_router_lutperm = false;
// faster replacements for base_pip2net, base_wire2net
// indexed by get_pip_vecidx()
@@ -509,6 +524,12 @@ struct Arch : BaseArch<ArchRanges>
return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index;
}
+ int get_slice_index(int x, int y, int slice) const
+ {
+ NPNR_ASSERT(slice >= 0 && slice < 4);
+ return (y * chip_info->width + x) * 4 + slice;
+ }
+
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override
{
NPNR_ASSERT(bel != BelId());
@@ -517,6 +538,11 @@ struct Arch : BaseArch<ArchRanges>
bel_to_cell[idx] = cell;
cell->bel = bel;
cell->belStrength = strength;
+ if (getBelType(bel) == id_TRELLIS_SLICE) {
+ lutperm_allowed.at(get_slice_index(bel.location.x, bel.location.y, getBelLocation(bel).z)) =
+ (cell->sliceInfo.is_memory ? LutPermRule::NONE
+ : (cell->sliceInfo.is_carry ? LutPermRule::CARRY : LutPermRule::ALL));
+ }
refreshUiBel(bel);
}
@@ -744,11 +770,31 @@ struct Arch : BaseArch<ArchRanges>
p2n_entry->wires.erase(dst);
p2n_entry = nullptr;
}
- bool checkPipAvail(PipId pip) const override { return getBoundPipNet(pip) == nullptr; }
+ bool is_pip_blocked(PipId pip) const
+ {
+ auto &pip_data = loc_info(pip)->pip_data[pip.index];
+ int lp = pip_data.lutperm_flags;
+ if (is_lutperm_pip(lp)) {
+ if (disable_router_lutperm)
+ return true;
+ auto rule = lutperm_allowed.at(get_slice_index(pip.location.x, pip.location.y, lutperm_lut(lp) / 2));
+ if (rule == LutPermRule::NONE) {
+ // Permutation not allowed
+ return true;
+ } else if (rule == LutPermRule::CARRY) {
+ // Can swap A/B and C/D only
+ int i = lutperm_out(lp), j = lutperm_in(lp);
+ if ((i / 2) != (j / 2))
+ return true;
+ }
+ }
+ return false;
+ }
+ bool checkPipAvail(PipId pip) const override { return (getBoundPipNet(pip) == nullptr) && !is_pip_blocked(pip); }
bool checkPipAvailForNet(PipId pip, NetInfo *net) const override
{
NetInfo *bound_net = getBoundPipNet(pip);
- return bound_net == nullptr || bound_net == net;
+ return (bound_net == nullptr || bound_net == net) && !is_pip_blocked(pip);
}
NetInfo *getBoundPipNet(PipId pip) const override { return pip2net.at(get_pip_vecidx(pip)); }