/* * Copyright (C) 2017-2020 The Project X-Ray Authors. * * Use of this source code is governed by a ISC-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/ISC * * SPDX-License-Identifier: ISC */ #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, "", "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"); DEFINE_string(architecture, "Series7", "Architecture of the provided bitstream"); namespace xilinx = prjxray::xilinx; template int patch_frames( const std::string& frm_file_str, std::map>* frames) { xilinx::Frames frames_from_file; if (frames_from_file.readFrames(frm_file_str)) { std::cerr << "Failed to read frames" << std::endl; return 1; } // 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 << static_cast(frame.first) << " because it was not found in frames." << std::endl; return 1; } auto& frame_data = iter->second; frame_data = frame.second; } return 0; } struct BitstreamPatcher { template int operator()(T& arg) { using ArchType = std::decay_t; auto part = ArchType::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 = xilinx::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 = xilinx::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)); } if (!FLAGS_frm_file.empty()) { int ret = patch_frames(FLAGS_frm_file, &frames); if (ret != 0) { return ret; } } // Create data for the type 2 configuration packet with // information about all frames typename xilinx::Configuration::PacketData configuration_packet_data( xilinx::Configuration:: createType2ConfigurationPacketData(frames, part)); // Put together a configuration package typename ArchType::ConfigurationPackage configuration_package; xilinx::Configuration::createConfigurationPackage( configuration_package, configuration_packet_data, part); // Write bitstream. auto bitstream_writer = xilinx::BitstreamWriter(configuration_package); if (bitstream_writer.writeBitstream( configuration_package, FLAGS_part_name, FLAGS_frm_file, "xc7patch", FLAGS_output_file)) { std::cerr << "Failed to write bitstream" << std::endl << "Exitting" << std::endl; } return 0; } }; int main(int argc, char* argv[]) { gflags::SetUsageMessage(argv[0]); gflags::ParseCommandLineFlags(&argc, &argv, true); xilinx::Architecture::Container arch_container = xilinx::ArchitectureFactory::create_architecture( FLAGS_architecture); return absl::visit(BitstreamPatcher(), arch_container); }