From 86db6b6724fd229e6426651bb064b044c0593f4b Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Mon, 22 Jan 2018 13:33:36 -0800 Subject: [PATCH] Tool to patch a 7-series bitstream Applies a .frm file (lines of frame address: frame words) to a bitstream and writes the result as a new bitstream. Note that the new bitstream will not include the initialization and finalization sequences required for programming. Signed-off-by: Rick Altherr --- tools/CMakeLists.txt | 7 ++ tools/xc7patch.cc | 210 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 tools/xc7patch.cc diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 558c7d83..06dc18c0 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -17,3 +17,10 @@ target_link_libraries(gen_part_base_yaml libprjxray yaml-cpp ) + +add_executable(xc7patch xc7patch.cc) +target_link_libraries(xc7patch + absl::strings + gflags + libprjxray +) diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc new file mode 100644 index 00000000..3e0c549f --- /dev/null +++ b/tools/xc7patch.cc @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +DEFINE_string(part_file, "", "Definition file for target 7-series part"); +DEFINE_string(bitstream_file, + "", + "Initial bitstream to which the deltas are applied."); +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 patched 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 not found or invalid" << std::endl; + return 1; + } + + auto bitstream_file = + prjxray::MemoryMappedFile::InitWithFile(FLAGS_bitstream_file); + if (!bitstream_file) { + std::cerr << "Can't open base bitstream file: " + << FLAGS_bitstream_file << std::endl; + return 1; + } + + auto bitstream_reader = xc7series::BitstreamReader::InitWithBytes( + bitstream_file->as_bytes()); + if (!bitstream_reader) { + std::cout + << "Bitstream does not appear to be a 7-series bitstream!" + << std::endl; + return 1; + } + + auto bitstream_config = + xc7series::Configuration::InitWithPackets(*part, *bitstream_reader); + if (!bitstream_config) { + std::cerr << "Bitstream does not appear to be for this part" + << std::endl; + return 1; + } + + // Copy the base frames to a mutable collection + std::map> frames; + for (auto& frame_val : bitstream_config->frames()) { + auto& cur_frame = frames[frame_val.first]; + + std::copy(frame_val.second.begin(), frame_val.second.end(), + std::back_inserter(cur_frame)); + } + + // Apply the deltas. + std::ifstream frm_file(FLAGS_frm_file); + if (!frm_file) { + std::cerr << "Unable to open frm file: " << FLAGS_frm_file + << 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& frame_data = frames[frame_address]; + 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) { + 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; + } + } + + 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; + + // 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); + + out_packets.push_back(xc7series::ConfigurationPacket( + 1, xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::FDRI, {})); + out_packets.push_back(xc7series::ConfigurationPacket( + 2, xc7series::ConfigurationPacket::Opcode::Write, + xc7series::ConfigurationRegister::FDRI, packet_data)); + +#if 0 + for (auto& packet : out_packets) { + std::cout << packet << std::endl; + } +#endif + + // 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; + } + + 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); + } + + return 0; +}