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);
|
y_ids.push_back(y_id);
|
||||||
id_to_y[y_id] = i;
|
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()
|
void Arch::list_devices()
|
||||||
@ -395,6 +418,9 @@ bool Arch::place()
|
|||||||
bool Arch::route()
|
bool Arch::route()
|
||||||
{
|
{
|
||||||
std::string router = str_or_default(settings, id_router, defaultRouter);
|
std::string router = str_or_default(settings, id_router, defaultRouter);
|
||||||
|
|
||||||
|
disable_router_lutperm = getCtx()->setting<bool>("arch.disable_router_lutperm", false);
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
if (router == "router1") {
|
if (router == "router1") {
|
||||||
result = router1(getCtx(), Router1Cfg(getCtx()));
|
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;
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
233
machxo2/arch.h
233
machxo2/arch.h
@ -66,6 +66,11 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
|||||||
int16_t padding2;
|
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 {
|
NPNR_PACKED_STRUCT(struct PipLocatorPOD {
|
||||||
LocationPOD rel_loc;
|
LocationPOD rel_loc;
|
||||||
int32_t index;
|
int32_t index;
|
||||||
@ -383,6 +388,15 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// inverse of the above for name->object mapping
|
// inverse of the above for name->object mapping
|
||||||
dict<IdString, int> id_to_x, id_to_y;
|
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
|
enum LogicBELType
|
||||||
{
|
{
|
||||||
BEL_COMB = 0,
|
BEL_COMB = 0,
|
||||||
@ -415,6 +429,17 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
mutable std::vector<TileStatus> tile_status;
|
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
|
// Helpers
|
||||||
template <typename Id> const TileTypePOD *tile_info(Id &id) const
|
template <typename Id> const TileTypePOD *tile_info(Id &id) const
|
||||||
{
|
{
|
||||||
@ -470,6 +495,62 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return IdStringList(ids);
|
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
|
Loc getBelLocation(BelId bel) const override
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
@ -484,6 +565,27 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
BelRange getBelsByTile(int x, int y) const override;
|
BelRange getBelsByTile(int x, int y) const override;
|
||||||
bool getBelGlobalBuf(BelId bel) 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 getBels() const override
|
||||||
{
|
{
|
||||||
BelRange range;
|
BelRange range;
|
||||||
@ -523,6 +625,60 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return IdStringList(ids);
|
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); }
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0.01); }
|
||||||
|
|
||||||
WireRange getWires() const override
|
WireRange getWires() const override
|
||||||
@ -568,6 +724,78 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
PipId getPipByName(IdStringList name) const override;
|
PipId getPipByName(IdStringList name) const override;
|
||||||
IdStringList getPipName(PipId pip) 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 getPips() const override
|
||||||
{
|
{
|
||||||
AllPipRange range;
|
AllPipRange range;
|
||||||
@ -648,6 +876,11 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
NPNR_ASSERT_FALSE("failed to find Pip tile");
|
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
|
||||||
delay_t estimateDelay(WireId src, WireId dst) const override;
|
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;
|
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)
|
static std::vector<bool> int_to_bitvector(int val, int size)
|
||||||
{
|
{
|
||||||
std::vector<bool> bv;
|
std::vector<bool> bv;
|
||||||
@ -526,7 +575,8 @@ void write_bitstream(Context *ctx, std::string text_config_file)
|
|||||||
return;
|
return;
|
||||||
int lut_init = int_or_default(ci->params, id_INITVAL);
|
int lut_init = int_or_default(ci->params, id_INITVAL);
|
||||||
cc.tiles[tname].add_enum(slice + ".MODE", mode);
|
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") {
|
if (mode == "CCU2") {
|
||||||
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, str_or_default(ci->params, id_CCU2_INJECT1, "YES"));
|
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, str_or_default(ci->params, id_CCU2_INJECT1, "YES"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,6 +126,7 @@ X(NOM_FREQ)
|
|||||||
X(VCC)
|
X(VCC)
|
||||||
|
|
||||||
X(WIRE_TYPE_NONE)
|
X(WIRE_TYPE_NONE)
|
||||||
|
X(TILE_WIRE_ID)
|
||||||
|
|
||||||
X(machxo2)
|
X(machxo2)
|
||||||
X(pack)
|
X(pack)
|
||||||
|
@ -51,6 +51,7 @@ po::options_description MachXO2CommandHandler::getArchOptions()
|
|||||||
specific.add_options()("list-devices", "list all supported device names");
|
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()("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()("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;
|
return specific;
|
||||||
}
|
}
|
||||||
@ -76,6 +77,8 @@ std::unique_ptr<Context> MachXO2CommandHandler::createContext(dict<std::string,
|
|||||||
}
|
}
|
||||||
chipArgs.device = vm["device"].as<std::string>();
|
chipArgs.device = vm["device"].as<std::string>();
|
||||||
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
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;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user