diff --git a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h b/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h index ae0634d7..806cc9a2 100644 --- a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h +++ b/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h @@ -23,7 +23,7 @@ namespace xc7series { class BitstreamWriter { public: typedef std::array header_t; - typedef std::vector packets_t; + typedef std::vector> packets_t; // Only defined if a packet exists typedef absl::optional> op_data_t; typedef absl::Span::iterator data_iterator_t; diff --git a/lib/include/prjxray/xilinx/xc7series/command.h b/lib/include/prjxray/xilinx/xc7series/command.h new file mode 100644 index 00000000..2ff16e86 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/command.h @@ -0,0 +1,34 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_ + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +enum class Command : uint32_t { + NOP = 0x0, + WCFG = 0x1, + MFW = 0x2, + LFRM = 0x3, + RCFG = 0x4, + START = 0x5, + RCAP = 0x6, + RCRC = 0x7, + AGHIGH = 0x8, + SWITCH = 0x9, + GRESTORE = 0xA, + SHUTDOWN = 0xB, + GCAPTURE = 0xC, + DESYNC = 0xD, + IPROG = 0xF, + CRCC = 0x10, + LTIMER = 0x11, + BSPI_READ = 0x12, + FALL_EDGE = 0x13, +}; + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h new file mode 100644 index 00000000..1b7c1c13 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h @@ -0,0 +1,122 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H +#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H + +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +class ConfigurationOptions0Value { + public: + enum class StartupClockSource : uint32_t { + CCLK = 0x0, + User = 0x1, + JTAG = 0x2, + }; + + enum class SignalReleaseCycle : uint32_t { + Phase1 = 0x0, + Phase2 = 0x1, + Phase3 = 0x2, + Phase4 = 0x3, + Phase5 = 0x4, + Phase6 = 0x5, + TrackDone = 0x6, + Keep = 0x7, + }; + + enum class StallCycle : uint32_t { + Phase0 = 0x0, + Phase1 = 0x1, + Phase2 = 0x2, + Phase3 = 0x3, + Phase4 = 0x4, + Phase5 = 0x5, + Phase6 = 0x6, + NoWait = 0x7, + }; + + ConfigurationOptions0Value() : value_(0) {} + + operator uint32_t() const { return value_; } + + ConfigurationOptions0Value& SetUseDonePinAsPowerdownStatus( + bool enabled) { + value_ = bit_field_set(value_, 27, 27, enabled ? 1 : 0); + return *this; + } + + ConfigurationOptions0Value& SetAddPipelineStageForDoneIn(bool enabled) { + value_ = bit_field_set(value_, 25, 25, enabled ? 1 : 0); + return *this; + } + + ConfigurationOptions0Value& SetDriveDoneHigh(bool enabled) { + value_ = bit_field_set(value_, 24, 24, enabled); + return *this; + } + + ConfigurationOptions0Value& SetReadbackIsSingleShot(bool enabled) { + value_ = bit_field_set(value_, 23, 23, enabled); + return *this; + } + + ConfigurationOptions0Value& SetCclkFrequency(uint32_t mhz) { + value_ = bit_field_set(value_, 22, 17, mhz); + return *this; + } + + ConfigurationOptions0Value& SetStartupClockSource( + StartupClockSource source) { + value_ = bit_field_set(value_, 16, 15, + static_cast(source)); + return *this; + } + + ConfigurationOptions0Value& SetReleaseDonePinAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 14, 12, static_cast(cycle)); + return *this; + } + + ConfigurationOptions0Value& SetStallAtStartupCycleUntilDciMatch( + StallCycle cycle) { + value_ = + bit_field_set(value_, 11, 9, static_cast(cycle)); + return *this; + }; + + ConfigurationOptions0Value& SetStallAtStartupCycleUntilMmcmLock( + StallCycle cycle) { + value_ = + bit_field_set(value_, 8, 6, static_cast(cycle)); + return *this; + }; + + ConfigurationOptions0Value& SetReleaseGtsSignalAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 5, 3, static_cast(cycle)); + return *this; + } + + ConfigurationOptions0Value& SetReleaseGweSignalAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 2, 0, static_cast(cycle)); + return *this; + } + + private: + uint32_t value_; +}; // namespace xc7series + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h b/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h new file mode 100644 index 00000000..bdcdc3c3 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h @@ -0,0 +1,33 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H +#define PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H + +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +template +class ConfigurationPacketWithPayload : public ConfigurationPacket { + public: + ConfigurationPacketWithPayload( + Opcode op, + ConfigurationRegister reg, + const std::array& payload) + : ConfigurationPacket(1, op, reg, absl::Span(payload_)), + payload_(std::move(payload)) {} + + private: + std::array payload_; +}; // namespace xc7series + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_register.h b/lib/include/prjxray/xilinx/xc7series/configuration_register.h index 9f75a090..4fbc5d4c 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration_register.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration_register.h @@ -25,6 +25,7 @@ enum class ConfigurationRegister : unsigned int { COR1 = 0x0e, WBSTAR = 0x10, TIMER = 0x11, + UNKNOWN = 0x13, BOOTSTS = 0x16, CTL1 = 0x18, BSPI = 0x1F, diff --git a/lib/include/prjxray/xilinx/xc7series/nop_packet.h b/lib/include/prjxray/xilinx/xc7series/nop_packet.h new file mode 100644 index 00000000..65339883 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/nop_packet.h @@ -0,0 +1,24 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H +#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H + +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +class NopPacket : public ConfigurationPacket { + public: + NopPacket() + : ConfigurationPacket(1, + Opcode::NOP, + ConfigurationRegister::CRC, + {}) {} +}; + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H diff --git a/lib/xilinx/xc7series/bitstream_writer.cc b/lib/xilinx/xc7series/bitstream_writer.cc index 3a7da30d..eb388ca5 100644 --- a/lib/xilinx/xc7series/bitstream_writer.cc +++ b/lib/xilinx/xc7series/bitstream_writer.cc @@ -28,7 +28,7 @@ BitstreamWriter::BitstreamWriter(const packets_t& packets) BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() { // itr_packets = packets.begin(); - const ConfigurationPacket& packet = *itr_packets_; + const ConfigurationPacket& packet = **itr_packets_; return BitstreamWriter::packet_iterator( &packet, BitstreamWriter::packet_iterator::STATE_HEADER, @@ -36,7 +36,7 @@ BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() { } BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_end() { - const ConfigurationPacket& packet = *itr_packets_; + const ConfigurationPacket& packet = **itr_packets_; return BitstreamWriter::packet_iterator( &packet, BitstreamWriter::packet_iterator::STATE_END, @@ -138,7 +138,7 @@ BitstreamWriter::iterator BitstreamWriter::begin() { if (itr_packets != packets_.end()) { // op_packet_itr = packet_begin(); // FIXME: de-duplicate this - const ConfigurationPacket& packet = *itr_packets; + const ConfigurationPacket& packet = **itr_packets; packet_iterator packet_itr = packet_iterator(&packet, packet_iterator::STATE_HEADER, packet.data().begin()); diff --git a/lib/xilinx/xc7series/bitstream_writer_test.cc b/lib/xilinx/xc7series/bitstream_writer_test.cc index 752fa4c9..be2d41ec 100644 --- a/lib/xilinx/xc7series/bitstream_writer_test.cc +++ b/lib/xilinx/xc7series/bitstream_writer_test.cc @@ -50,7 +50,8 @@ void dump_packets(xc7series::BitstreamWriter writer, bool nl = true) { } // Special all 0's -void AddType0(std::vector& packets) { +void AddType0( + std::vector>& packets) { // InitWithWords doesn't like type 0 /* static std::vector words{0x00000000}; @@ -61,27 +62,32 @@ void AddType0(std::vector& packets) { static std::vector words{}; absl::Span word_span(words); // CRC is config value 0 - packets.push_back(xc7series::ConfigurationPacket( + packets.emplace_back(new xc7series::ConfigurationPacket( 0, xc7series::ConfigurationPacket::NOP, xc7series::ConfigurationRegister::CRC, word_span)); } -void AddType1(std::vector& packets) { +void AddType1( + std::vector>& packets) { static std::vector words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB}; absl::Span word_span(words); auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span); - packets.push_back(*(packet.second)); + packets.emplace_back( + new xc7series::ConfigurationPacket(*(packet.second))); } // Empty -void AddType1E(std::vector& packets) { +void AddType1E( + std::vector>& packets) { static std::vector words{MakeType1(0x2, 0x3, 0)}; absl::Span word_span(words); auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span); - packets.push_back(*(packet.second)); + packets.emplace_back( + new xc7series::ConfigurationPacket(*(packet.second))); } -void AddType2(std::vector& packets) { +void AddType2( + std::vector>& packets) { // Type 1 packet with address // Without this InitWithWords will fail on type 2 xc7series::ConfigurationPacket* packet1; @@ -90,8 +96,9 @@ void AddType2(std::vector& packets) { absl::Span word_span(words); auto packet1_pair = xc7series::ConfigurationPacket::InitWithWords(word_span); - packets.push_back(*(packet1_pair.second)); - packet1 = &packets[0]; + packets.emplace_back( + new xc7series::ConfigurationPacket(*(packet1_pair.second))); + packet1 = packets[0].get(); } // Type 2 packet with data { @@ -100,13 +107,14 @@ void AddType2(std::vector& packets) { absl::Span word_span(words); auto packet = xc7series::ConfigurationPacket::InitWithWords( word_span, packet1); - packets.push_back(*(packet.second)); + packets.emplace_back( + new xc7series::ConfigurationPacket(*(packet.second))); } } // Empty packets should produce just the header TEST(BitstreamWriterTest, WriteHeader) { - std::vector packets; + std::vector> packets; xc7series::BitstreamWriter writer(packets); std::vector words(writer.begin(), writer.end()); @@ -120,7 +128,7 @@ TEST(BitstreamWriterTest, WriteHeader) { } TEST(BitstreamWriterTest, WriteType0) { - std::vector packets; + std::vector> packets; AddType0(packets); xc7series::BitstreamWriter writer(packets); // dump_packets(writer, false); @@ -133,7 +141,7 @@ TEST(BitstreamWriterTest, WriteType0) { EXPECT_EQ(words, ref); } TEST(BitstreamWriterTest, WriteType1) { - std::vector packets; + std::vector> packets; AddType1(packets); xc7series::BitstreamWriter writer(packets); // dump_packets(writer, false); @@ -147,7 +155,7 @@ TEST(BitstreamWriterTest, WriteType1) { } TEST(BitstreamWriterTest, WriteType2) { - std::vector packets; + std::vector> packets; AddType2(packets); xc7series::BitstreamWriter writer(packets); // dump_packets(writer, false); @@ -164,7 +172,7 @@ TEST(BitstreamWriterTest, WriteType2) { } TEST(BitstreamWriterTest, WriteMulti) { - std::vector packets; + std::vector> packets; AddType1(packets); AddType1E(packets); AddType2(packets); diff --git a/minitests/partial_reconfig_flow/Makefile b/minitests/partial_reconfig_flow/Makefile index f451f815..239cac4f 100644 --- a/minitests/partial_reconfig_flow/Makefile +++ b/minitests/partial_reconfig_flow/Makefile @@ -1,4 +1,4 @@ -.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit +.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit %_roi_partial.bit # Top-level target for generating a programmable bitstream. Given a .fasm # file, calling make with the .fasm extension replaced with _hand_crafted.bit @@ -6,49 +6,14 @@ # ready for programming to a board. For example, # 'make inv_hand_crafted.bit' will generate a bitstream that includes the # design from roi_noninv.fasm. -%_hand_crafted.bit: init_sequence.bit %_no_headers.bin final_sequence.bin - cat $^ > $@ - -%_no_headers.bin: %_patched.bin - # WARNING: these values need to be tweaked if anything about the - # Vivado-generated design changes. - xxd -p -s 0x18 $< | xxd -r -p - $@ - -%_patched.bin: %_roi_partial.frm harness.bit +%_hand_crafted.bit: %_roi_partial.frm harness.bit ${XRAY_TOOLS_DIR}/xc7patch \ - --part_file ${XRAY_PART_YAML} \ + --part_name "${XRAY_PART}" \ + --part_file "${XRAY_PART_YAML}" \ --bitstream_file harness.bit \ --frm_file $< \ --output_file $@ -# xc7patch currently only generates the actual frame writes which is -# insufficient to program a device. Grab the initialization and finalization -# sequences from the harness bitstream so they can be tacked on to the -# xc7patch-generated bitstream to create a programmable bitstream. -# -# The offsets used below were determined by manually inspecting -# harness.bit with a hex editor. init_sequence.bit is the beginning of -# the file until just before the actual frame data is sent via a write to FDRI. -# final_sequence.bin is from just after the frame data write to the end of the -# file. Note that final_sequence.bin normally includes at least one CRC check. -# The sed command replaces any CRC checks with a Reset CRC command which is the -# same behavior as setting BITSTREAM.GENERAL.CRC to Disabled. These offset -# should not change unless you alter the bitstream format used (i.e. setting -# BITSTREAM.GENERAL.DEBUGBITSTREAM or BITSTREAM.GENERAL.PERFRAMECRC to YES). -init_sequence.bit: harness.bit - # WARNING: these values need to be tweaked if anything about the - # Vivado-generated design changes. - xxd -p -l 0x147 $< | xxd -r -p - $@ - -final_sequence.bin: harness.bit - # WARNING: these values need to be tweaked if anything about the - # Vivado-generated design changes. - xxd -p -s 0x216abf $< | \ - tr -d '\n' | \ - sed -e 's/30000001.\{8\}/3000800100000007/g' | \ - fold -w 40 | \ - xxd -r -p - $@ - # Generate a suitable harness by using Vivado's partial reconfiguration # feature. inv.v is used as a sample reconfiguration design as one is # required to generate a partial reconfiguration design. diff --git a/minitests/roi_harness/fasm2bit.sh b/minitests/roi_harness/fasm2bit.sh index 3e7798c9..5beb90f5 100755 --- a/minitests/roi_harness/fasm2bit.sh +++ b/minitests/roi_harness/fasm2bit.sh @@ -30,28 +30,11 @@ echo "Out .bit: $bit_out" ${XRAY_DIR}/tools/fasm2frame.py $fasm_in roi_partial.frm ${XRAY_TOOLS_DIR}/xc7patch \ + --part_name ${XRAY_PART} \ --part_file ${XRAY_PART_YAML} \ --bitstream_file $bit_in \ --frm_file roi_partial.frm \ - --output_file patched.bin - -# WARNING: these values need to be tweaked if anything about the -# Vivado-generated design changes. -xxd -p -l 0x147 $bit_in | xxd -r -p - init_sequence.bit - -# WARNING: these values need to be tweaked if anything about the -# Vivado-generated design changes. -xxd -p -s 0x18 patched.bin | xxd -r -p - no_headers.bin - -# WARNING: these values need to be tweaked if anything about the -# Vivado-generated design changes. -xxd -p -s 0x216abf $bit_in | \ - tr -d '\n' | \ - sed -e 's/30000001.\{8\}/3000800100000007/g' | \ - fold -w 40 | \ - xxd -r -p - final_sequence.bin - -cat init_sequence.bit no_headers.bin final_sequence.bin >$bit_out + --output_file $bit_out #openocd -f $XRAY_DIR/utils/openocd/board-digilent-basys3.cfg -c "init; pld load 0 $bit_out; exit" diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 06dc18c0..85023a91 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -21,6 +21,7 @@ target_link_libraries(gen_part_base_yaml add_executable(xc7patch xc7patch.cc) target_link_libraries(xc7patch absl::strings + absl::time gflags libprjxray ) diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc index 3e0c549f..9ea3962d 100644 --- a/tools/xc7patch.cc +++ b/tools/xc7patch.cc @@ -5,14 +5,23 @@ #include #include +#include #include +#include +#include #include #include #include #include +#include #include +#include +#include +#include +#include #include +DEFINE_string(part_name, "", ""); DEFINE_string(part_file, "", "Definition file for target 7-series part"); DEFINE_string(bitstream_file, "", @@ -111,54 +120,16 @@ int main(int argc, char* argv[]) { uint32_t ecc = 0; for (size_t ii = 0; ii < frame_data.size(); ++ii) { - uint32_t word = frame_data[ii]; - uint32_t offset = ii * 32; - if (ii > 0x25) { - offset += 0x1360; - } else if (ii > 0x6) { - offset += 0x1340; - } else { - offset += 0x1320; - } - - // Mask out where the ECC should be. - if (ii == 0x32) { - word &= 0xFFFFE000; - } - - for (int jj = 0; jj < 32; ++jj) { - if ((word & 1) == 1) { - ecc ^= offset + jj; - } - word >>= 1; - } + ecc = xc7series::icap_ecc(ii, frame_data[ii], ecc); } - uint32_t v = ecc & 0xFFF; - v ^= v >> 8; - v ^= v >> 4; - v ^= v >> 2; - v ^= v >> 1; - ecc ^= (v & 1) << 12; - // Replace the old ECC with the new. frame_data[0x32] &= 0xFFFFE000; frame_data[0x32] |= (ecc & 0x1FFF); } -#if 0 - for (auto& frame : frames) { - std::cout << "0x" << std::hex - << static_cast(frame.first) << " "; - - for (auto& word : frame.second) { - std::cout << "0x" << std::hex << word << ","; - } - - std::cout << std::endl; - } -#endif - std::vector out_packets; + std::vector> + out_packets; // Generate a single type 2 packet that writes everything at once. std::vector packet_data; @@ -177,18 +148,167 @@ int main(int argc, char* argv[]) { } packet_data.insert(packet_data.end(), 202, 0); - out_packets.push_back(xc7series::ConfigurationPacket( + // Initialization sequence + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::TIMER, {0x0})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::WBSTAR, {0x0})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::NOP)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::UNKNOWN, {0x0})); + + // Configuration Options 0 + out_packets.emplace_back(new xc7series::ConfigurationPacketWithPayload< + 1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::COR0, + {xc7series::ConfigurationOptions0Value() + .SetAddPipelineStageForDoneIn(true) + .SetReleaseDonePinAtStartupCycle( + xc7series::ConfigurationOptions0Value::SignalReleaseCycle:: + Phase4) + .SetStallAtStartupCycleUntilDciMatch( + xc7series::ConfigurationOptions0Value::StallCycle::NoWait) + .SetStallAtStartupCycleUntilMmcmLock( + xc7series::ConfigurationOptions0Value::StallCycle::NoWait) + .SetReleaseGtsSignalAtStartupCycle( + xc7series::ConfigurationOptions0Value::SignalReleaseCycle:: + Phase5) + .SetReleaseGweSignalAtStartupCycle( + xc7series::ConfigurationOptions0Value::SignalReleaseCycle:: + Phase6)})); + + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::COR1, {0x0})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::IDCODE, {part->idcode()})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::SWITCH)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::MASK, {0x401})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CTL0, {0x501})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::MASK, {0x0})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CTL1, {0x0})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::FAR, {0x0})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::WCFG)})); + out_packets.emplace_back(new xc7series::NopPacket()); + + // Frame data write + out_packets.emplace_back(new xc7series::ConfigurationPacket( 1, xc7series::ConfigurationPacket::Opcode::Write, xc7series::ConfigurationRegister::FDRI, {})); - out_packets.push_back(xc7series::ConfigurationPacket( + out_packets.emplace_back(new xc7series::ConfigurationPacket( 2, xc7series::ConfigurationPacket::Opcode::Write, xc7series::ConfigurationRegister::FDRI, packet_data)); -#if 0 - for (auto& packet : out_packets) { - std::cout << packet << std::endl; + // Finalization sequence + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::GRESTORE)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::LFRM)})); + for (int ii = 0; ii < 100; ++ii) { + out_packets.emplace_back(new xc7series::NopPacket()); + } + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::START)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::FAR, {0x3be0000})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::MASK, {0x501})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CTL0, {0x501})); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back(new xc7series::NopPacket()); + out_packets.emplace_back( + new xc7series::ConfigurationPacketWithPayload<1>( + xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::CMD, + {static_cast(xc7series::Command::DESYNC)})); + for (int ii = 0; ii < 400; ++ii) { + out_packets.emplace_back(new xc7series::NopPacket()); } -#endif // Write bitstream. xc7series::BitstreamWriter out_bitstream_writer(out_packets); @@ -199,6 +319,61 @@ int main(int argc, char* argv[]) { return 1; } + // Xilinx BIT header. + // Sync header + std::vector bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f, + 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, + 0x00, 0x00, 0x01, 'a'}; + auto build_source = absl::StrCat(FLAGS_frm_file, ";Generator=xc7patch"); + bit_header.push_back( + static_cast((build_source.size() + 1) >> 8)); + bit_header.push_back(static_cast(build_source.size() + 1)); + bit_header.insert(bit_header.end(), build_source.begin(), + build_source.end()); + bit_header.push_back(0x0); + + // Source file. + bit_header.push_back('b'); + bit_header.push_back( + static_cast((FLAGS_part_name.size() + 1) >> 8)); + bit_header.push_back(static_cast(FLAGS_part_name.size() + 1)); + bit_header.insert(bit_header.end(), FLAGS_part_name.begin(), + FLAGS_part_name.end()); + bit_header.push_back(0x0); + + // Build timestamp. + auto build_time = absl::Now(); + auto build_date_string = + absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone()); + auto build_time_string = + absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone()); + + bit_header.push_back('c'); + bit_header.push_back( + static_cast((build_date_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(build_date_string.size() + 1)); + bit_header.insert(bit_header.end(), build_date_string.begin(), + build_date_string.end()); + bit_header.push_back(0x0); + + bit_header.push_back('d'); + bit_header.push_back( + static_cast((build_time_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(build_time_string.size() + 1)); + bit_header.insert(bit_header.end(), build_time_string.begin(), + build_time_string.end()); + bit_header.push_back(0x0); + + bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0}); + out_file.write(reinterpret_cast(bit_header.data()), + bit_header.size()); + + auto end_of_header_pos = out_file.tellp(); + auto header_data_length_pos = + end_of_header_pos - static_cast(4); + for (uint32_t word : out_bitstream_writer) { out_file.put((word >> 24) & 0xFF); out_file.put((word >> 16) & 0xFF); @@ -206,5 +381,13 @@ int main(int argc, char* argv[]) { out_file.put((word)&0xFF); } + uint32_t length_of_data = out_file.tellp() - end_of_header_pos; + + out_file.seekp(header_data_length_pos); + out_file.put((length_of_data >> 24) & 0xFF); + out_file.put((length_of_data >> 16) & 0xFF); + out_file.put((length_of_data >> 8) & 0xFF); + out_file.put((length_of_data)&0xFF); + return 0; }