add missing bind and lutperm
This commit is contained in:
parent
7f8518d938
commit
62ace58204
@ -127,6 +127,29 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
y_ids.push_back(y_id);
|
||||
id_to_y[y_id] = i;
|
||||
}
|
||||
|
||||
wire_tile_vecidx.resize(chip_info->num_tiles, -1);
|
||||
int n_wires = 0;
|
||||
for (auto e : getWires()) {
|
||||
if (e.index == 0) {
|
||||
wire_tile_vecidx.at(e.location.y * chip_info->width + e.location.x) = n_wires;
|
||||
}
|
||||
n_wires++;
|
||||
}
|
||||
wire2net.resize(n_wires, nullptr);
|
||||
wire_fanout.resize(n_wires, 0);
|
||||
|
||||
pip_tile_vecidx.resize(chip_info->num_tiles, -1);
|
||||
int n_pips = 0;
|
||||
for (auto e : getPips()) {
|
||||
if (e.index == 0) {
|
||||
pip_tile_vecidx.at(e.location.y * chip_info->width + e.location.x) = n_pips;
|
||||
}
|
||||
n_pips++;
|
||||
}
|
||||
pip2net.resize(n_pips, nullptr);
|
||||
|
||||
lutperm_allowed.resize(chip_info->width * chip_info->height * 4);
|
||||
}
|
||||
|
||||
void Arch::list_devices()
|
||||
@ -395,6 +418,9 @@ bool Arch::place()
|
||||
bool Arch::route()
|
||||
{
|
||||
std::string router = str_or_default(settings, id_router, defaultRouter);
|
||||
|
||||
disable_router_lutperm = getCtx()->setting<bool>("arch.disable_router_lutperm", false);
|
||||
|
||||
bool result;
|
||||
if (router == "router1") {
|
||||
result = router1(getCtx(), Router1Cfg(getCtx()));
|
||||
@ -503,4 +529,16 @@ std::vector<std::pair<std::string, std::string>> Arch::get_tiles_at_loc(int row,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
std::vector<std::pair<IdString, std::string>> Arch::getWireAttrs(WireId wire) const
|
||||
{
|
||||
std::vector<std::pair<IdString, std::string>> ret;
|
||||
auto &wi = tile_info(wire)->wire_data[wire.index];
|
||||
|
||||
ret.push_back(std::make_pair(id_TILE_WIRE_ID, stringf("%d", wi.tile_wire)));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
233
machxo2/arch.h
233
machxo2/arch.h
@ -66,6 +66,11 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
||||
int16_t padding2;
|
||||
});
|
||||
|
||||
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;
|
||||
@ -383,6 +388,15 @@ struct Arch : BaseArch<ArchRanges>
|
||||
// inverse of the above for name->object mapping
|
||||
dict<IdString, int> id_to_x, id_to_y;
|
||||
|
||||
enum class LutPermRule
|
||||
{
|
||||
NONE,
|
||||
CARRY,
|
||||
ALL,
|
||||
};
|
||||
std::vector<LutPermRule> lutperm_allowed;
|
||||
bool disable_router_lutperm = false;
|
||||
|
||||
enum LogicBELType
|
||||
{
|
||||
BEL_COMB = 0,
|
||||
@ -415,6 +429,17 @@ struct Arch : BaseArch<ArchRanges>
|
||||
|
||||
mutable std::vector<TileStatus> tile_status;
|
||||
|
||||
// faster replacements for base_pip2net, base_wire2net
|
||||
// indexed by get_pip_vecidx()
|
||||
std::vector<NetInfo *> pip2net;
|
||||
// indexed by get_wire_vecidx()
|
||||
std::vector<NetInfo *> wire2net;
|
||||
std::vector<int> wire_fanout;
|
||||
// We record the index=0 offset into pip2net for each tile, allowing us to
|
||||
// calculate any PipId's offset from pip.index and pip.location
|
||||
std::vector<int32_t> pip_tile_vecidx;
|
||||
std::vector<int32_t> wire_tile_vecidx;
|
||||
|
||||
// Helpers
|
||||
template <typename Id> const TileTypePOD *tile_info(Id &id) const
|
||||
{
|
||||
@ -470,6 +495,62 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return IdStringList(ids);
|
||||
}
|
||||
|
||||
uint32_t getBelChecksum(BelId bel) const override { return 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 update_bel(BelId bel, CellInfo *old_cell, CellInfo *new_cell)
|
||||
{
|
||||
CellInfo *act_cell = (old_cell == nullptr) ? new_cell : old_cell;
|
||||
if (act_cell->type.in(id_TRELLIS_FF, id_TRELLIS_COMB, id_TRELLIS_RAMW)) {
|
||||
LogicTileStatus *lts = tile_status.at(tile_index(bel)).lts;
|
||||
NPNR_ASSERT(lts != nullptr);
|
||||
int z = tile_info(bel)->bel_data[bel.index].z;
|
||||
lts->slices[(z >> lc_idx_shift) / 2].dirty = true;
|
||||
if (act_cell->type == id_TRELLIS_FF)
|
||||
lts->tile_dirty = true; // because FF CLK/LSR signals are tile-wide
|
||||
if (act_cell->type == id_TRELLIS_COMB && (act_cell->combInfo.flags & ArchCellInfo::COMB_LUTRAM))
|
||||
lts->tile_dirty = true; // because RAM shares CLK/LSR signals with FFs
|
||||
lts->cells[z] = new_cell;
|
||||
}
|
||||
}
|
||||
|
||||
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
auto &slot = tile_status.at(tile_index(bel)).boundcells.at(bel.index);
|
||||
NPNR_ASSERT(slot == nullptr);
|
||||
slot = cell;
|
||||
cell->bel = bel;
|
||||
cell->belStrength = strength;
|
||||
if (getBelType(bel) == id_TRELLIS_COMB) {
|
||||
int flags = cell->combInfo.flags;
|
||||
lutperm_allowed.at(
|
||||
get_slice_index(bel.location.x, bel.location.y, (getBelLocation(bel).z >> lc_idx_shift) / 2)) =
|
||||
(((flags & ArchCellInfo::COMB_LUTRAM) || (flags & ArchCellInfo::COMB_RAMW_BLOCK))
|
||||
? LutPermRule::NONE
|
||||
: ((flags & ArchCellInfo::COMB_CARRY) ? LutPermRule::CARRY : LutPermRule::ALL));
|
||||
}
|
||||
update_bel(bel, nullptr, cell);
|
||||
refreshUiBel(bel);
|
||||
}
|
||||
|
||||
void unbindBel(BelId bel) override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
auto &slot = tile_status.at(tile_index(bel)).boundcells.at(bel.index);
|
||||
NPNR_ASSERT(slot != nullptr);
|
||||
update_bel(bel, slot, nullptr);
|
||||
slot->bel = BelId();
|
||||
slot->belStrength = STRENGTH_NONE;
|
||||
slot = nullptr;
|
||||
refreshUiBel(bel);
|
||||
}
|
||||
|
||||
Loc getBelLocation(BelId bel) const override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
@ -484,6 +565,27 @@ struct Arch : BaseArch<ArchRanges>
|
||||
BelRange getBelsByTile(int x, int y) const override;
|
||||
bool getBelGlobalBuf(BelId bel) const override;
|
||||
|
||||
bool checkBelAvail(BelId bel) const override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
const CellInfo *slot = tile_status.at(tile_index(bel)).boundcells.at(bel.index);
|
||||
return slot == nullptr;
|
||||
}
|
||||
|
||||
CellInfo *getBoundBelCell(BelId bel) const override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
CellInfo *slot = tile_status.at(tile_index(bel)).boundcells.at(bel.index);
|
||||
return slot;
|
||||
}
|
||||
|
||||
CellInfo *getConflictingBelCell(BelId bel) const override
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
CellInfo *slot = tile_status.at(tile_index(bel)).boundcells.at(bel.index);
|
||||
return slot;
|
||||
}
|
||||
|
||||
BelRange getBels() const override
|
||||
{
|
||||
BelRange range;
|
||||
@ -523,6 +625,60 @@ struct Arch : BaseArch<ArchRanges>
|
||||
return IdStringList(ids);
|
||||
}
|
||||
|
||||
IdString getWireType(WireId wire) const override
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
IdString id;
|
||||
id.index = tile_info(wire)->wire_data[wire.index].type;
|
||||
return id;
|
||||
}
|
||||
|
||||
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId) const override;
|
||||
|
||||
uint32_t getWireChecksum(WireId wire) const override { return wire.index; }
|
||||
|
||||
uint32_t get_wire_vecidx(const WireId &e) const
|
||||
{
|
||||
uint32_t tile = e.location.y * chip_info->width + e.location.x;
|
||||
int32_t base = wire_tile_vecidx.at(tile);
|
||||
NPNR_ASSERT(base != -1);
|
||||
int32_t i = base + e.index;
|
||||
return i;
|
||||
}
|
||||
|
||||
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
auto &w2n_entry = wire2net.at(get_wire_vecidx(wire));
|
||||
NPNR_ASSERT(w2n_entry == nullptr);
|
||||
net->wires[wire].pip = PipId();
|
||||
net->wires[wire].strength = strength;
|
||||
w2n_entry = net;
|
||||
this->refreshUiWire(wire);
|
||||
}
|
||||
void unbindWire(WireId wire) override
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
auto &w2n_entry = wire2net.at(get_wire_vecidx(wire));
|
||||
NPNR_ASSERT(w2n_entry != nullptr);
|
||||
|
||||
auto &net_wires = w2n_entry->wires;
|
||||
auto it = net_wires.find(wire);
|
||||
NPNR_ASSERT(it != net_wires.end());
|
||||
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
pip2net.at(get_pip_vecidx(pip)) = nullptr;
|
||||
wire_fanout[get_wire_vecidx(getPipSrcWire(pip))]--;
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
w2n_entry = nullptr;
|
||||
this->refreshUiWire(wire);
|
||||
}
|
||||
virtual bool checkWireAvail(WireId wire) const override { return getBoundWireNet(wire) == nullptr; }
|
||||
NetInfo *getBoundWireNet(WireId wire) const override { return wire2net.at(get_wire_vecidx(wire)); }
|
||||
|
||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0.01); }
|
||||
|
||||
WireRange getWires() const override
|
||||
@ -568,6 +724,78 @@ struct Arch : BaseArch<ArchRanges>
|
||||
PipId getPipByName(IdStringList name) const override;
|
||||
IdStringList getPipName(PipId pip) const override;
|
||||
|
||||
uint32_t getPipChecksum(PipId pip) const override { return pip.index; }
|
||||
|
||||
uint32_t get_pip_vecidx(const PipId &e) const
|
||||
{
|
||||
uint32_t tile = e.location.y * chip_info->width + e.location.x;
|
||||
int32_t base = pip_tile_vecidx.at(tile);
|
||||
NPNR_ASSERT(base != -1);
|
||||
int32_t i = base + e.index;
|
||||
return i;
|
||||
}
|
||||
|
||||
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
wire_fanout[get_wire_vecidx(getPipSrcWire(pip))]++;
|
||||
|
||||
auto &p2n_entry = pip2net.at(get_pip_vecidx(pip));
|
||||
NPNR_ASSERT(p2n_entry == nullptr);
|
||||
p2n_entry = net;
|
||||
|
||||
WireId dst = this->getPipDstWire(pip);
|
||||
auto &w2n_entry = wire2net.at(get_wire_vecidx(dst));
|
||||
NPNR_ASSERT(w2n_entry == nullptr);
|
||||
w2n_entry = net;
|
||||
net->wires[dst].pip = pip;
|
||||
net->wires[dst].strength = strength;
|
||||
}
|
||||
|
||||
void unbindPip(PipId pip) override
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
wire_fanout[get_wire_vecidx(getPipSrcWire(pip))]--;
|
||||
|
||||
auto &p2n_entry = pip2net.at(get_pip_vecidx(pip));
|
||||
NPNR_ASSERT(p2n_entry != nullptr);
|
||||
WireId dst = this->getPipDstWire(pip);
|
||||
|
||||
auto &w2n_entry = wire2net.at(get_wire_vecidx(dst));
|
||||
NPNR_ASSERT(w2n_entry != nullptr);
|
||||
w2n_entry = nullptr;
|
||||
|
||||
p2n_entry->wires.erase(dst);
|
||||
p2n_entry = nullptr;
|
||||
}
|
||||
bool is_pip_blocked(PipId pip) const
|
||||
{
|
||||
auto &pip_data = tile_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, const NetInfo *net) const override
|
||||
{
|
||||
NetInfo *bound_net = getBoundPipNet(pip);
|
||||
return (bound_net == nullptr || bound_net == net) && !is_pip_blocked(pip);
|
||||
}
|
||||
NetInfo *getBoundPipNet(PipId pip) const override { return pip2net.at(get_pip_vecidx(pip)); }
|
||||
|
||||
AllPipRange getPips() const override
|
||||
{
|
||||
AllPipRange range;
|
||||
@ -648,6 +876,11 @@ struct Arch : BaseArch<ArchRanges>
|
||||
NPNR_ASSERT_FALSE("failed to find Pip tile");
|
||||
}
|
||||
|
||||
std::string get_pip_tiletype(PipId pip) const
|
||||
{
|
||||
return chip_info->tiletype_names[tile_info(pip)->pip_data[pip.index].tile_type].get();
|
||||
}
|
||||
|
||||
// Delay
|
||||
delay_t estimateDelay(WireId src, WireId dst) const override;
|
||||
delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const override;
|
||||
|
@ -404,6 +404,55 @@ static void set_pip(Context *ctx, ChipConfig &cc, PipId pip)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned permute_lut(Context *ctx, CellInfo *cell, pool<IdString> &used_phys_pins, unsigned orig_init)
|
||||
{
|
||||
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;
|
||||
unsigned lp = ctx->tile_info(pip)->pip_data[pip.index].lutperm_flags;
|
||||
if (!is_lutperm_pip(lp)) { // non-permuting
|
||||
phys_to_log[i].push_back(i);
|
||||
} else { // permuting
|
||||
unsigned from_pin = lutperm_in(lp);
|
||||
unsigned to_pin = lutperm_out(lp);
|
||||
NPNR_ASSERT(to_pin == i);
|
||||
phys_to_log[from_pin].push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
if (!phys_to_log.at(i).empty())
|
||||
used_phys_pins.insert(ports.at(i));
|
||||
if (cell->combInfo.flags & ArchCellInfo::COMB_CARRY) {
|
||||
// Insert dummy entries to ensure we keep the split between the two halves of a CCU2
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
if (!phys_to_log.at(i).empty())
|
||||
continue;
|
||||
for (unsigned j = 2 * (i / 2); j < 2 * ((i / 2) + 1); j++) {
|
||||
if (!ctx->getBoundWireNet(ctx->getBelPinWire(cell->bel, ports[j])))
|
||||
phys_to_log.at(i).push_back(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static std::vector<bool> int_to_bitvector(int val, int size)
|
||||
{
|
||||
std::vector<bool> bv;
|
||||
@ -526,7 +575,8 @@ void write_bitstream(Context *ctx, std::string text_config_file)
|
||||
return;
|
||||
int lut_init = int_or_default(ci->params, id_INITVAL);
|
||||
cc.tiles[tname].add_enum(slice + ".MODE", mode);
|
||||
cc.tiles[tname].add_word(slice + ".K" + lc + ".INIT", int_to_bitvector(lut_init, 16));
|
||||
cc.tiles[tname].add_word(slice + ".K" + lc + ".INIT",
|
||||
int_to_bitvector(permute_lut(ctx, ci, used_phys_pins, lut_init), 16));
|
||||
if (mode == "CCU2") {
|
||||
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, str_or_default(ci->params, id_CCU2_INJECT1, "YES"));
|
||||
} else {
|
||||
|
@ -126,6 +126,7 @@ X(NOM_FREQ)
|
||||
X(VCC)
|
||||
|
||||
X(WIRE_TYPE_NONE)
|
||||
X(TILE_WIRE_ID)
|
||||
|
||||
X(machxo2)
|
||||
X(pack)
|
||||
|
@ -51,6 +51,7 @@ po::options_description MachXO2CommandHandler::getArchOptions()
|
||||
specific.add_options()("list-devices", "list all supported device names");
|
||||
specific.add_options()("textcfg", po::value<std::string>(), "textual configuration in Trellis format to write");
|
||||
// specific.add_options()("lpf", po::value<std::vector<std::string>>(), "LPF pin constraint file(s)");
|
||||
specific.add_options()("disable-router-lutperm", "don't allow the router to permute LUT inputs");
|
||||
|
||||
return specific;
|
||||
}
|
||||
@ -76,6 +77,8 @@ std::unique_ptr<Context> MachXO2CommandHandler::createContext(dict<std::string,
|
||||
}
|
||||
chipArgs.device = vm["device"].as<std::string>();
|
||||
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
if (vm.count("disable-router-lutperm"))
|
||||
ctx->settings[ctx->id("arch.disable_router_lutperm")] = 1;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user