diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index bc53f61c..331798d8 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,9 +14,11 @@ add_library(libprjxray xilinx/xc7series/global_clock_region.cc xilinx/xc7series/part.cc xilinx/xc7series/row.cc + xilinx/xc7series/frames.cc + xilinx/xc7series/utils.cc ) target_include_directories(libprjxray PUBLIC "include") -target_link_libraries(libprjxray absl::optional absl::strings absl::span yaml-cpp) +target_link_libraries(libprjxray absl::optional absl::strings absl::span absl::time yaml-cpp) if (PRJXRAY_BUILD_TESTING) add_executable(big_endian_span_test big_endian_span_test.cc) diff --git a/lib/include/prjxray/xilinx/xc7series/frames.h b/lib/include/prjxray/xilinx/xc7series/frames.h new file mode 100644 index 00000000..77f0e976 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/frames.h @@ -0,0 +1,46 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H +#define PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H + +#include +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +// Contains frame information which is used for the generation +// of the configuration package that is used in bitstream generation. +class Frames { + public: + typedef std::vector FrameData; + typedef std::map Frames2Data; + + // Reads the contents of the frames file and populates + // the Frames container. + int readFrames(const std::string& frm_file_str); + + // Adds empty frames that are present in the tilegrid of a specific part + // but are missing in the current frames container. + void addMissingFrames(const absl::optional& part); + + // Returns the map with frame addresses and corresponding data + Frames2Data& getFrames(); + + private: + Frames2Data frames_data_; + + // Updates the ECC information in the frame. + void updateECC(FrameData& data); + uint32_t calculateECC(const FrameData& data); +}; + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H diff --git a/lib/include/prjxray/xilinx/xc7series/utils.h b/lib/include/prjxray/xilinx/xc7series/utils.h new file mode 100644 index 00000000..36767544 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/utils.h @@ -0,0 +1,51 @@ + +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_ + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { +using PacketData = std::vector; +using BitstreamHeader = std::vector; +using ConfigurationPackage = std::vector>; + +// Returns the payload for a type 2 packet. +// Type 2 packets can have the payload length of more than the 11 bits available +// for type 1 packets. +PacketData createType2ConfigurationPacketData(const Frames::Frames2Data& frames, + absl::optional& part); + +// Creates the complete configuration package that is +// then used by the bitstream writer to generate the bitstream file. The package +// forms a sequence suitable for xilinx 7-series devices. The programming +// sequence is taken from +// https://www.kc8apf.net/2018/05/unpacking-xilinx-7-series-bitstreams-part-2/ +void createConfigurationPackage(ConfigurationPackage& out_packets, + const PacketData& packet_data, + absl::optional& part); + +// Creates a Xilinx bit header which is mostly a +// Tag-Length-Value(TLV) format documented here: +// http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm +BitstreamHeader createBitistreamHeader(const std::string& part_name, + const std::string& frames_file_name, + const std::string& generator_name); + +// Writies out the complete bitstream for a 7-series +// Xilinx FPGA based on the Configuration Package which holds the complete +// programming sequence. +int writeBitstream(const ConfigurationPackage& packets, + const std::string& part_name, + const std::string& frames_file, + const std::string& generator_name, + const std::string& output_file); +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_ diff --git a/lib/xilinx/xc7series/frames.cc b/lib/xilinx/xc7series/frames.cc new file mode 100644 index 00000000..f6accecb --- /dev/null +++ b/lib/xilinx/xc7series/frames.cc @@ -0,0 +1,101 @@ +#include +#include + +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +Frames::Frames2Data& Frames::getFrames() { + return frames_data_; +} + +int Frames::readFrames(const std::string& frm_file_str) { + assert(!frm_file_str.empty()); + + std::ifstream frm_file(frm_file_str); + if (!frm_file) { + std::cerr << "Unable to open frm file: " << frm_file_str + << std::endl; + return 1; + } + std::string frm_line; + + while (std::getline(frm_file, frm_line)) { + if (frm_line[0] == '#') + continue; + + std::pair frame_delta = + absl::StrSplit(frm_line, ' '); + + uint32_t frame_address = + std::stoul(frame_delta.first, nullptr, 16); + + std::vector frame_data_strings = + absl::StrSplit(frame_delta.second, ','); + if (frame_data_strings.size() != 101) { + std::cerr << "Frame " << std::hex << frame_address + << ": found " << std::dec + << frame_data_strings.size() + << "words instead of 101"; + continue; + } + + FrameData frame_data(101, 0); + std::transform(frame_data_strings.begin(), + frame_data_strings.end(), frame_data.begin(), + [](const std::string& val) -> uint32_t { + return std::stoul(val, nullptr, 16); + }); + + // TODO make sure if this is needed + updateECC(frame_data); + + // Insert the frame address and corresponding frame data to the + // map + FrameAddress frm_addr(frame_address); + frames_data_.insert( + std::pair(frm_addr, frame_data)); + } + return 0; +} + +void Frames::addMissingFrames(const absl::optional& part) { + auto current_frame_address = frames_data_.begin()->first; + auto next_frame_address = + part->GetNextFrameAddress(current_frame_address); + while (next_frame_address) { + current_frame_address = *next_frame_address; + auto iter = frames_data_.find(current_frame_address); + if (iter == frames_data_.end()) { + FrameData frame_data(101, 0); + // TODO make sure if this is needed + updateECC(frame_data); + frames_data_.insert(std::pair( + current_frame_address, frame_data)); + } + next_frame_address = + part->GetNextFrameAddress(current_frame_address); + } +} + +void Frames::updateECC(FrameData& data) { + assert(data.size() != 0); + // Replace the old ECC with the new. + data[0x32] &= 0xFFFFE000; + data[0x32] |= (calculateECC(data) & 0x1FFF); +} + +uint32_t Frames::calculateECC(const FrameData& data) { + uint32_t ecc = 0; + for (size_t ii = 0; ii < data.size(); ++ii) { + ecc = icap_ecc(ii, data[ii], ecc); + } + return ecc; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray diff --git a/lib/xilinx/xc7series/utils.cc b/lib/xilinx/xc7series/utils.cc new file mode 100644 index 00000000..c8fae481 --- /dev/null +++ b/lib/xilinx/xc7series/utils.cc @@ -0,0 +1,263 @@ +#include +#include + +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +PacketData createType2ConfigurationPacketData(const Frames::Frames2Data& frames, + absl::optional& part) { + // Generate a single type 2 packet that writes everything at once. + 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(), 202, 0); + } + } + packet_data.insert(packet_data.end(), 202, 0); + return packet_data; +} + +void createConfigurationPackage(ConfigurationPackage& out_packets, + const PacketData& packet_data, + absl::optional& part) { + // Initialization sequence + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::TIMER, + {0x0})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::WBSTAR, + {0x0})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::NOP)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::UNKNOWN, + {0x0})); + + // Configuration Options 0 + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::COR0, + {ConfigurationOptions0Value() + .SetAddPipelineStageForDoneIn(true) + .SetReleaseDonePinAtStartupCycle( + ConfigurationOptions0Value::SignalReleaseCycle::Phase4) + .SetStallAtStartupCycleUntilDciMatch( + ConfigurationOptions0Value::StallCycle::NoWait) + .SetStallAtStartupCycleUntilMmcmLock( + ConfigurationOptions0Value::StallCycle::NoWait) + .SetReleaseGtsSignalAtStartupCycle( + ConfigurationOptions0Value::SignalReleaseCycle::Phase5) + .SetReleaseGweSignalAtStartupCycle( + ConfigurationOptions0Value::SignalReleaseCycle::Phase6)})); + + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::COR1, + {0x0})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::IDCODE, + {part->idcode()})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::SWITCH)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK, + {0x401})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL0, + {0x501})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK, + {0x0})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL1, + {0x0})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::FAR, + {0x0})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::WCFG)})); + out_packets.emplace_back(new NopPacket()); + + // Frame data write + out_packets.emplace_back( + new ConfigurationPacket(1, ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FDRI, {})); + out_packets.emplace_back( + new ConfigurationPacket(2, ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FDRI, packet_data)); + + // Finalization sequence + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::GRESTORE)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::LFRM)})); + for (int ii = 0; ii < 100; ++ii) { + out_packets.emplace_back(new NopPacket()); + } + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::START)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::FAR, + {0x3be0000})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK, + {0x501})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL0, + {0x501})); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( + ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, + {static_cast(Command::DESYNC)})); + for (int ii = 0; ii < 400; ++ii) { + out_packets.emplace_back(new NopPacket()); + } +} + +BitstreamHeader createBitstreamHeader(const std::string& part_name, + const std::string& frames_file_name, + const std::string& generator_name) { + // Sync header + BitstreamHeader bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, + 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 'a'}; + auto build_source = + absl::StrCat(frames_file_name, ";Generator=" + generator_name); + 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((part_name.size() + 1) >> 8)); + bit_header.push_back(static_cast(part_name.size() + 1)); + bit_header.insert(bit_header.end(), part_name.begin(), 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}); + + return bit_header; +} + +int writeBitstream(const ConfigurationPackage& packets, + const std::string& part_name, + const std::string& frames_file, + const std::string& generator_name, + const std::string& output_file) { + std::ofstream out_file(output_file, std::ofstream::binary); + if (!out_file) { + std::cerr << "Unable to open file for writting: " << output_file + << std::endl; + return 1; + } + + BitstreamHeader bit_header( + createBitstreamHeader(part_name, frames_file, generator_name)); + 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); + + BitstreamWriter out_bitstream_writer(packets); + for (uint32_t word : out_bitstream_writer) { + out_file.put((word >> 24) & 0xFF); + out_file.put((word >> 16) & 0xFF); + out_file.put((word >> 8) & 0xFF); + 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; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1a0bec1b..2fc35558 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -25,3 +25,10 @@ target_link_libraries(xc7patch gflags libprjxray ) +add_executable(xc7frames2bit xc7frames2bit.cc) +target_link_libraries(xc7frames2bit + absl::strings + absl::time + gflags + libprjxray +) diff --git a/tools/xc7frames2bit.cc b/tools/xc7frames2bit.cc new file mode 100644 index 00000000..554ca197 --- /dev/null +++ b/tools/xc7frames2bit.cc @@ -0,0 +1,61 @@ +#include + +#include +#include + +DEFINE_string(part_name, "", "Name of the 7-series part"); +DEFINE_string(part_file, "", "Definition file for target 7-series part"); +DEFINE_string( + frm_file, + "", + "File containing a list of frame deltas to be applied to the base " + "bitstream. Each line in the file is of the form: " + " ,...,."); +DEFINE_string(output_file, "", "Write bitsteam to file"); + +namespace xc7series = prjxray::xilinx::xc7series; + +int main(int argc, char* argv[]) { + gflags::SetUsageMessage(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + auto part = xc7series::Part::FromFile(FLAGS_part_file); + if (!part) { + std::cerr << "Part file " << FLAGS_part_file + << " not found or invalid" << std::endl; + return 1; + } + + // Read the frames from the input file + xc7series::Frames frames; + if (frames.readFrames(FLAGS_frm_file)) { + std::cerr << "Frames file " << FLAGS_frm_file + << " not found or invalid" << std::endl; + return 1; + } + + // In case the frames input file is missing some frames that are in the + // tilegrid + frames.addMissingFrames(part); + + // Create data for the type 2 configuration packet with information + // about all frames + xc7series::PacketData configuration_packet_data( + xc7series::createType2ConfigurationPacketData(frames.getFrames(), + part)); + + // Put together a configuration package + xc7series::ConfigurationPackage configuration_package; + xc7series::createConfigurationPackage(configuration_package, + configuration_packet_data, part); + + // Write bitstream + if (xc7series::writeBitstream(configuration_package, FLAGS_part_name, + FLAGS_frm_file, "xc7frames2bit", + FLAGS_output_file)) { + std::cerr << "Failed to write bitstream" << std::endl + << "Exitting" << std::endl; + } + + return 0; +} diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc index d82b2869..9d030cb5 100644 --- a/tools/xc7patch.cc +++ b/tools/xc7patch.cc @@ -1,25 +1,8 @@ -#include -#include #include -#include -#include -#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"); @@ -39,61 +22,25 @@ namespace xc7series = prjxray::xilinx::xc7series; int patch_frames( const std::string& frm_file_str, std::map>* frames) { - // Apply the deltas. - std::ifstream frm_file(frm_file_str); - if (!frm_file) { - std::cerr << "Unable to open frm file: " << frm_file_str - << std::endl; + xc7series::Frames frames_from_file; + if (frames_from_file.readFrames(frm_file_str)) { + std::cerr << "Failed to read frames" << std::endl; return 1; } - std::string frm_line; - while (std::getline(frm_file, frm_line)) { - if (frm_line[0] == '#') - continue; - - std::pair frame_delta = - absl::StrSplit(frm_line, ' '); - - uint32_t frame_address = - std::stoul(frame_delta.first, nullptr, 16); - - auto iter = frames->find(frame_address); + // Apply the deltas. + for (auto& frame : frames_from_file.getFrames()) { + auto iter = frames->find(frame.first); if (iter == frames->end()) { std::cerr << "frame address 0x" << std::hex - << frame_address + << static_cast(frame.first) << " because it was not found in frames." << std::endl; return 1; } auto& frame_data = iter->second; - frame_data.resize(101); - - std::vector frame_data_strings = - absl::StrSplit(frame_delta.second, ','); - if (frame_data_strings.size() != 101) { - std::cerr << "Frame " << std::hex << frame_address - << ": found " << std::dec - << frame_data_strings.size() - << "words instead of 101"; - continue; - }; - - std::transform(frame_data_strings.begin(), - frame_data_strings.end(), frame_data.begin(), - [](const std::string& val) -> uint32_t { - return std::stoul(val, nullptr, 16); - }); - - uint32_t ecc = 0; - for (size_t ii = 0; ii < frame_data.size(); ++ii) { - ecc = xc7series::icap_ecc(ii, frame_data[ii], ecc); - } - - // Replace the old ECC with the new. - frame_data[0x32] &= 0xFFFFE000; - frame_data[0x32] |= (ecc & 0x1FFF); + frame_data = frame.second; } return 0; @@ -150,266 +97,22 @@ int main(int argc, char* argv[]) { } } - std::vector> - out_packets; + // Create data for the type 2 configuration packet with information + // about all frames + xc7series::PacketData configuration_packet_data( + xc7series::createType2ConfigurationPacketData(frames, part)); - // Generate a single type 2 packet that writes everything at once. - std::vector 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(), 202, 0); - } - } - packet_data.insert(packet_data.end(), 202, 0); - - // 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.emplace_back(new xc7series::ConfigurationPacket( - 2, xc7series::ConfigurationPacket::Opcode::Write, - xc7series::ConfigurationRegister::FDRI, packet_data)); - - // 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()); - } + // Put together a configuration package + xc7series::ConfigurationPackage configuration_package; + xc7series::createConfigurationPackage(configuration_package, + configuration_packet_data, part); // Write bitstream. - xc7series::BitstreamWriter out_bitstream_writer(out_packets); - std::ofstream out_file(FLAGS_output_file); - if (!out_file) { - std::cerr << "Unable to open file for writting: " - << FLAGS_output_file << std::endl; - return 1; + if (xc7series::writeBitstream(configuration_package, FLAGS_part_name, + FLAGS_frm_file, "xc7patch", + FLAGS_output_file)) { + std::cerr << "Failed to write bitstream" << std::endl + << "Exitting" << std::endl; } - - // 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); - out_file.put((word >> 8) & 0xFF); - 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; }