mirror of https://github.com/openXC7/prjxray.git
Add initial support for UltraScale devices
Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
This commit is contained in:
parent
baab49c7da
commit
3f574743cf
|
|
@ -14,13 +14,18 @@ namespace prjxray {
|
|||
namespace xilinx {
|
||||
|
||||
class Series7;
|
||||
class UltraScale;
|
||||
class UltraScalePlus;
|
||||
|
||||
class Architecture {
|
||||
public:
|
||||
using Container = absl::variant<Series7, UltraScalePlus>;
|
||||
virtual const std::string& name() const = 0;
|
||||
using Container = absl::variant<Series7, UltraScale, UltraScalePlus>;
|
||||
Architecture(const std::string& name) : name_(name) {}
|
||||
const std::string& name() const { return name_; }
|
||||
virtual ~Architecture() {}
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
};
|
||||
|
||||
class Series7 : public Architecture {
|
||||
|
|
@ -31,22 +36,21 @@ class Series7 : public Architecture {
|
|||
std::vector<std::unique_ptr<ConfigurationPacket<ConfRegType>>>;
|
||||
using FrameAddress = xc7series::FrameAddress;
|
||||
using WordType = uint32_t;
|
||||
Series7() : name_("Series7") {}
|
||||
const std::string& name() const override { return name_; }
|
||||
Series7() : Architecture("Series7") {}
|
||||
Series7(const std::string& name) : Architecture(name) {}
|
||||
static constexpr int words_per_frame = 101;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
class UltraScalePlus : public Series7 {
|
||||
public:
|
||||
UltraScalePlus() : name_("UltraScalePlus") {}
|
||||
const std::string& name() const override { return name_; }
|
||||
UltraScalePlus() : Series7("UltraScalePlus") {}
|
||||
static constexpr int words_per_frame = 93;
|
||||
};
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
class UltraScale : public Series7 {
|
||||
public:
|
||||
UltraScale() : Series7("UltraScale") {}
|
||||
static constexpr int words_per_frame = 123;
|
||||
};
|
||||
|
||||
class ArchitectureFactory {
|
||||
|
|
@ -55,6 +59,8 @@ class ArchitectureFactory {
|
|||
const std::string& arch) {
|
||||
if (arch == "Series7") {
|
||||
return Series7();
|
||||
} else if (arch == "UltraScale") {
|
||||
return UltraScale();
|
||||
} else if (arch == "UltraScalePlus") {
|
||||
return UltraScalePlus();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,32 @@ BitstreamReader<Series7>::InitWithBytes(T bitstream) {
|
|||
return BitstreamReader<Series7>(std::move(words));
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
absl::optional<BitstreamReader<UltraScale>>
|
||||
BitstreamReader<UltraScale>::InitWithBytes(T bitstream) {
|
||||
// If this is really a Xilinx bitstream, there will be a sync
|
||||
// word somewhere toward the beginning.
|
||||
auto sync_pos = std::search(bitstream.begin(), bitstream.end(),
|
||||
kSyncWord.begin(), kSyncWord.end());
|
||||
if (sync_pos == bitstream.end()) {
|
||||
return absl::optional<BitstreamReader<UltraScale>>();
|
||||
}
|
||||
sync_pos += kSyncWord.size();
|
||||
|
||||
// Wrap the provided container in a span that strips off the preamble.
|
||||
absl::Span<typename T::value_type> bitstream_span(bitstream);
|
||||
auto config_packets =
|
||||
bitstream_span.subspan(sync_pos - bitstream.begin());
|
||||
|
||||
// Convert the bytes into 32-bit, big-endian words.
|
||||
auto big_endian_reader = make_big_endian_span<uint32_t>(config_packets);
|
||||
std::vector<uint32_t> words{big_endian_reader.begin(),
|
||||
big_endian_reader.end()};
|
||||
|
||||
return BitstreamReader<UltraScale>(std::move(words));
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
absl::optional<BitstreamReader<UltraScalePlus>>
|
||||
|
|
|
|||
|
|
@ -196,11 +196,143 @@ absl::optional<Configuration<Series7>> Configuration<Series7>::InitWithPackets(
|
|||
return Configuration(part, frames);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename Collection>
|
||||
absl::optional<Configuration<UltraScale>>
|
||||
Configuration<UltraScale>::InitWithPackets(
|
||||
const typename UltraScale::Part& part,
|
||||
Collection& packets) {
|
||||
using ArchType = UltraScale;
|
||||
// Registers that can be directly written to.
|
||||
uint32_t command_register = 0;
|
||||
uint32_t frame_address_register = 0;
|
||||
uint32_t mask_register = 0;
|
||||
uint32_t ctl1_register = 0;
|
||||
|
||||
// Internal state machine for writes.
|
||||
bool start_new_write = false;
|
||||
typename ArchType::FrameAddress current_frame_address = 0;
|
||||
|
||||
Configuration<ArchType>::FrameMap frames;
|
||||
for (auto packet : packets) {
|
||||
if (packet.opcode() !=
|
||||
ConfigurationPacket<
|
||||
typename ArchType::ConfRegType>::Opcode::Write) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (packet.address()) {
|
||||
case ArchType::ConfRegType::MASK:
|
||||
if (packet.data().size() < 1)
|
||||
continue;
|
||||
mask_register = packet.data()[0];
|
||||
break;
|
||||
case ArchType::ConfRegType::CTL1:
|
||||
if (packet.data().size() < 1)
|
||||
continue;
|
||||
ctl1_register =
|
||||
packet.data()[0] & mask_register;
|
||||
break;
|
||||
case ArchType::ConfRegType::CMD:
|
||||
if (packet.data().size() < 1)
|
||||
continue;
|
||||
command_register = packet.data()[0];
|
||||
// Writes to CMD trigger an immediate action. In
|
||||
// the case of WCFG, that is just setting a flag
|
||||
// for the next FDIR.
|
||||
if (command_register == 0x1) {
|
||||
start_new_write = true;
|
||||
}
|
||||
break;
|
||||
case ArchType::ConfRegType::IDCODE:
|
||||
// This really should be a one-word write.
|
||||
if (packet.data().size() < 1)
|
||||
continue;
|
||||
|
||||
// If the IDCODE doesn't match our expected
|
||||
// part, consider the bitstream invalid.
|
||||
if (packet.data()[0] != part.idcode()) {
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
case ArchType::ConfRegType::FAR:
|
||||
// This really should be a one-word write.
|
||||
if (packet.data().size() < 1)
|
||||
continue;
|
||||
frame_address_register = packet.data()[0];
|
||||
|
||||
// Per UG470, the command present in the CMD
|
||||
// register is executed each time the FAR
|
||||
// register is laoded with a new value. As we
|
||||
// only care about WCFG commands, just check
|
||||
// that here. CTRL1 is completely undocumented
|
||||
// but looking at generated bitstreams, bit 21
|
||||
// is used when per-frame CRC is enabled.
|
||||
// Setting this bit seems to inhibit the
|
||||
// re-execution of CMD during a FAR write. In
|
||||
// practice, this is used so FAR writes can be
|
||||
// added in the bitstream to show progress
|
||||
// markers without impacting the actual write
|
||||
// operation.
|
||||
if (bit_field_get(ctl1_register, 21, 21) == 0 &&
|
||||
command_register == 0x1) {
|
||||
start_new_write = true;
|
||||
}
|
||||
break;
|
||||
case ArchType::ConfRegType::FDRI: {
|
||||
if (start_new_write) {
|
||||
current_frame_address =
|
||||
frame_address_register;
|
||||
start_new_write = false;
|
||||
}
|
||||
|
||||
// UltraScale frames are 123-words long. Writes
|
||||
// to this register can be multiples of that to
|
||||
// do auto-incrementing block writes.
|
||||
for (size_t ii = 0; ii < packet.data().size();
|
||||
ii += ArchType::words_per_frame) {
|
||||
frames[current_frame_address] =
|
||||
packet.data().subspan(
|
||||
ii, ArchType::words_per_frame);
|
||||
|
||||
auto next_address =
|
||||
part.GetNextFrameAddress(
|
||||
current_frame_address);
|
||||
if (!next_address)
|
||||
break;
|
||||
|
||||
// Bitstreams appear to have 2 frames of
|
||||
// padding between rows.
|
||||
if (next_address &&
|
||||
(next_address->block_type() !=
|
||||
current_frame_address
|
||||
.block_type() ||
|
||||
next_address
|
||||
->is_bottom_half_rows() !=
|
||||
current_frame_address
|
||||
.is_bottom_half_rows() ||
|
||||
next_address->row() !=
|
||||
current_frame_address.row())) {
|
||||
ii += 2 *
|
||||
ArchType::words_per_frame;
|
||||
}
|
||||
current_frame_address = *next_address;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Configuration(part, frames);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename Collection>
|
||||
absl::optional<Configuration<UltraScalePlus>>
|
||||
Configuration<UltraScalePlus>::InitWithPackets(
|
||||
const typename UltraScalePlus::Part& part,
|
||||
const typename UltraScale::Part& part,
|
||||
Collection& packets) {
|
||||
using ArchType = UltraScalePlus;
|
||||
// Registers that can be directly written to.
|
||||
|
|
@ -327,7 +459,6 @@ Configuration<UltraScalePlus>::InitWithPackets(
|
|||
|
||||
return Configuration(part, frames);
|
||||
}
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ template <>
|
|||
typename BitstreamWriter<Series7>::header_t BitstreamWriter<Series7>::header_{
|
||||
0xFFFFFFFF, 0x000000BB, 0x11220044, 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566};
|
||||
|
||||
template <>
|
||||
typename BitstreamWriter<UltraScale>::header_t
|
||||
BitstreamWriter<UltraScale>::header_{0xFFFFFFFF, 0x000000BB, 0x11220044,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566};
|
||||
|
||||
template <>
|
||||
typename BitstreamWriter<UltraScalePlus>::header_t
|
||||
BitstreamWriter<UltraScalePlus>::header_{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,31 @@ Configuration<Series7>::createType2ConfigurationPacketData(
|
|||
return packet_data;
|
||||
}
|
||||
|
||||
template <>
|
||||
Configuration<UltraScale>::PacketData
|
||||
Configuration<UltraScale>::createType2ConfigurationPacketData(
|
||||
const Frames<UltraScale>::Frames2Data& frames,
|
||||
absl::optional<UltraScale::Part>& part) {
|
||||
PacketData packet_data;
|
||||
for (auto& frame : frames) {
|
||||
std::copy(frame.second.begin(), frame.second.end(),
|
||||
std::back_inserter(packet_data));
|
||||
|
||||
auto next_address = part->GetNextFrameAddress(frame.first);
|
||||
if (next_address &&
|
||||
(next_address->block_type() != frame.first.block_type() ||
|
||||
next_address->is_bottom_half_rows() !=
|
||||
frame.first.is_bottom_half_rows() ||
|
||||
next_address->row() != frame.first.row())) {
|
||||
packet_data.insert(packet_data.end(),
|
||||
UltraScale::words_per_frame * 2, 0);
|
||||
}
|
||||
}
|
||||
packet_data.insert(packet_data.end(), UltraScale::words_per_frame * 2,
|
||||
0);
|
||||
return packet_data;
|
||||
}
|
||||
|
||||
template <>
|
||||
Configuration<UltraScalePlus>::PacketData
|
||||
Configuration<UltraScalePlus>::createType2ConfigurationPacketData(
|
||||
|
|
@ -239,6 +264,167 @@ void Configuration<Series7>::createConfigurationPackage(
|
|||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Configuration<UltraScale>::createConfigurationPackage(
|
||||
UltraScale::ConfigurationPackage& out_packets,
|
||||
const PacketData& packet_data,
|
||||
absl::optional<UltraScale::Part>& part) {
|
||||
using ArchType = UltraScale;
|
||||
using ConfigurationRegister = ArchType::ConfRegType;
|
||||
// Initialization sequence
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::TIMER, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::WBSTAR, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::NOP)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::FAR, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::UNKNOWN, {0x0}));
|
||||
|
||||
// Configuration Options 0
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::COR0, {0x38003fe5}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::COR1, {0x400000}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::IDCODE, {part->idcode()}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::SWITCH)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::MASK, {0x1}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CTL0, {0x101}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::MASK, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CTL1, {0x0}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::FAR, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::WCFG)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
|
||||
// Frame data write
|
||||
out_packets.emplace_back(new ConfigurationPacket<ConfigurationRegister>(
|
||||
TYPE1, ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::FDRI, {}));
|
||||
out_packets.emplace_back(new ConfigurationPacket<ConfigurationRegister>(
|
||||
TYPE2, ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::FDRI, packet_data));
|
||||
|
||||
// Finalization sequence
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::GRESTORE)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::LFRM)}));
|
||||
for (int ii = 0; ii < 100; ++ii) {
|
||||
out_packets.emplace_back(
|
||||
new NopPacket<ConfigurationRegister>());
|
||||
}
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::START)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::FAR, {0x3be0000}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::MASK, {0x101}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CTL0, {0x101}));
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
|
||||
out_packets.emplace_back(
|
||||
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
|
||||
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
|
||||
ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::DESYNC)}));
|
||||
for (int ii = 0; ii < 400; ++ii) {
|
||||
out_packets.emplace_back(
|
||||
new NopPacket<ConfigurationRegister>());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Configuration<UltraScalePlus>::createConfigurationPackage(
|
||||
UltraScalePlus::ConfigurationPackage& out_packets,
|
||||
|
|
@ -399,6 +585,5 @@ void Configuration<UltraScalePlus>::createConfigurationPackage(
|
|||
new NopPacket<ConfigurationRegister>());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
|
|||
|
|
@ -8,10 +8,17 @@ void Frames<Series7>::updateECC(typename Frames<Series7>::FrameData& data) {
|
|||
xc7series::updateECC(data);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Frames<UltraScale>::updateECC(
|
||||
typename Frames<UltraScale>::FrameData& data) {
|
||||
xc7series::updateECC(data);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Frames<UltraScalePlus>::updateECC(
|
||||
typename Frames<UltraScalePlus>::FrameData& data) {
|
||||
xc7series::updateECC(data);
|
||||
}
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ struct Frames2BitWriter {
|
|||
}
|
||||
|
||||
if (std::is_same<ArchType, xilinx::Series7>::value ||
|
||||
std::is_same<ArchType, xilinx::UltraScale>::value ||
|
||||
std::is_same<ArchType, xilinx::UltraScalePlus>::value) {
|
||||
// In case the frames input file is missing some frames
|
||||
// that are in the tilegrid
|
||||
|
|
|
|||
Loading…
Reference in New Issue