| /* | |
| * 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 <iostream> | |
| #include <gflags/gflags.h> | |
| #include <prjxray/memory_mapped_file.h> | |
| #include <prjxray/xilinx/architectures.h> | |
| #include <prjxray/xilinx/bitstream_reader.h> | |
| #include <prjxray/xilinx/bitstream_writer.h> | |
| #include <prjxray/xilinx/configuration.h> | |
| 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: " | |
| "<frame_address> <word1>,...,<word101>."); | |
| DEFINE_string(output_file, "", "Write patched bitsteam to file"); | |
| DEFINE_string(architecture, | |
| "Series7", | |
| "Architecture of the provided bitstream"); | |
| namespace xilinx = prjxray::xilinx; | |
| template <typename ArchType> | |
| int patch_frames( | |
| const std::string& frm_file_str, | |
| std::map<typename ArchType::FrameAddress, std::vector<uint32_t>>* frames) { | |
| xilinx::Frames<ArchType> 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<uint32_t>(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 <typename T> | |
| int operator()(T& arg) { | |
| using ArchType = std::decay_t<decltype(arg)>; | |
| 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<ArchType>::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<ArchType>::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<typename ArchType::FrameAddress, std::vector<uint32_t>> | |
| 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<ArchType>(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<ArchType>::PacketData | |
| configuration_packet_data( | |
| xilinx::Configuration<ArchType>:: | |
| createType2ConfigurationPacketData(frames, part)); | |
| // Put together a configuration package | |
| typename ArchType::ConfigurationPackage configuration_package; | |
| xilinx::Configuration<ArchType>::createConfigurationPackage( | |
| configuration_package, configuration_packet_data, part); | |
| // Write bitstream. | |
| auto bitstream_writer = | |
| xilinx::BitstreamWriter<ArchType>(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); | |
| } |