Add initial support for UltraScale devices

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
This commit is contained in:
Tomasz Michalak 2019-10-09 13:03:11 +02:00
parent baab49c7da
commit 3f574743cf
7 changed files with 375 additions and 14 deletions

View File

@ -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 {

View File

@ -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>>

View File

@ -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

View File

@ -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_{

View File

@ -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

View File

@ -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

View File

@ -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