/* * 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 #include #include namespace xilinx = prjxray::xilinx; struct Action { std::string name; std::function handler; }; struct ConfigPacketsLister { ConfigPacketsLister(const absl::Span& bytes) : bytes_(bytes) {} const absl::Span& bytes_; template int operator()(T& arg) { using ArchType = std::decay_t; auto reader = xilinx::BitstreamReader::InitWithBytes(bytes_); if (!reader) { std::cerr << "Input doesn't look like a bitstream" << std::endl; return 1; } for (auto packet : *reader) { std::cout << packet; } return 0; } }; int ListConfigPackets(int argc, char* argv[]) { std::string architecture("Series7"); if (argc < 1) { std::cerr << "ERROR: no input specified" << std::endl; std::cerr << "Usage: " << argv[0] << "list_config_packets " << std::endl; return 1; } if (argc == 2) { architecture = argv[1]; } auto in_file_name = argv[0]; auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name); if (!in_file) { std::cerr << "Unable to open bit file: " << in_file_name << std::endl; return 1; } auto in_bytes = absl::Span( static_cast(in_file->data()), in_file->size()); xilinx::Architecture::Container arch_container = xilinx::ArchitectureFactory::create_architecture(architecture); return absl::visit(ConfigPacketsLister(in_bytes), arch_container); } struct DebugFrameAddressesDumper { DebugFrameAddressesDumper(const absl::Span& bytes) : bytes_(bytes) {} const absl::Span& bytes_; template int operator()(T& arg) { using ArchType = std::decay_t; auto reader = xilinx::BitstreamReader::InitWithBytes(bytes_); if (!reader) { std::cerr << "Input doesn't look like a bitstream" << std::endl; return 1; } bool found_one_lout = false; for (auto packet : *reader) { if ((packet.opcode() != xilinx::ConfigurationPacket< typename ArchType::ConfRegType>::Opcode:: Write) || (packet.address() != ArchType::ConfRegType::LOUT)) { continue; } if (packet.data().size() != 1) { std::cerr << "Write to FAR with word_count != 1" << std::endl; continue; } found_one_lout = true; std::cout << std::dec << packet.data()[0] << std::endl; } if (!found_one_lout) { std::cerr << "No LOUT writes found. Was " << "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?" << std::endl; return 1; } return 0; } }; int DumpDebugbitstreamFrameAddresses(int argc, char* argv[]) { std::string architecture("Series7"); if (argc < 1) { std::cerr << "ERROR: no input specified" << std::endl; std::cerr << "Usage: " << argv[0] << "dump_debugbitstream_frame_addresses " << std::endl; return 1; } if (argc == 2) { architecture = argv[1]; } auto in_file_name = argv[0]; auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name); if (!in_file) { std::cerr << "Unable to open bit file: " << in_file_name << std::endl; return 1; } auto in_bytes = absl::Span( static_cast(in_file->data()), in_file->size()); xilinx::Architecture::Container arch_container = xilinx::ArchitectureFactory::create_architecture(architecture); return absl::visit(DebugFrameAddressesDumper(in_bytes), arch_container); } struct DeviceIdGetter { DeviceIdGetter(const absl::Span& bytes) : bytes_(bytes) {} const absl::Span& bytes_; template int operator()(T& arg) { using ArchType = std::decay_t; auto reader = xilinx::BitstreamReader::InitWithBytes(bytes_); if (!reader) { std::cerr << "Input doesn't look like a bitstream" << std::endl; return 1; } auto idcode_packet = std::find_if( reader->begin(), reader->end(), [](const xilinx::ConfigurationPacket< typename ArchType::ConfRegType>& packet) { return (packet.opcode() == xilinx::ConfigurationPacket< typename ArchType::ConfRegType>:: Opcode::Write) && (packet.address() == ArchType::ConfRegType::IDCODE); }); if (idcode_packet != reader->end()) { if (std::is_same::value) { if (idcode_packet->data().size() != 2) { std::cerr << "Write to IDCODE with " "word_count != 2" << std::endl; return 1; } std::cout << "0x" << std::hex << ((idcode_packet->data()[0] << 16) | idcode_packet->data()[1]) << std::endl; } else { if (idcode_packet->data().size() != 1) { std::cerr << "Write to IDCODE with " "word_count != 1" << std::endl; return 1; } std::cout << "0x" << std::hex << idcode_packet->data()[0] << std::endl; } } return 0; } }; int GetDeviceId(int argc, char* argv[]) { std::string architecture("Series7"); if (argc < 1) { std::cerr << "ERROR: no input specified" << std::endl; std::cerr << "Usage: " << argv[0] << "get_device_id []" << std::endl; return 1; } if (argc == 2) { architecture = argv[1]; } auto in_file_name = argv[0]; auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name); if (!in_file) { std::cerr << "Unable to open bit file: " << in_file_name << std::endl; return 1; } auto in_bytes = absl::Span( static_cast(in_file->data()), in_file->size()); xilinx::Architecture::Container arch_container = xilinx::ArchitectureFactory::create_architecture(architecture); return absl::visit(DeviceIdGetter(in_bytes), arch_container); } int main(int argc, char* argv[]) { Action actions[] = { {"list_config_packets", ListConfigPackets}, {"dump_debugbitstream_frame_addresses", DumpDebugbitstreamFrameAddresses}, {"get_device_id", GetDeviceId}, }; gflags::SetUsageMessage( absl::StrCat("Usage: ", argv[0], " [options] [bitfile]")); gflags::ParseCommandLineFlags(&argc, &argv, true); if (argc < 2) { std::cerr << "ERROR: no command specified" << std::endl; std::cerr << "Usage: " << argv[0] << " " << std::endl; return 1; } auto requested_action_str = argv[1]; auto requested_action = std::find_if( std::begin(actions), std::end(actions), [&](const Action& t) { return t.name == requested_action_str; }); if (requested_action == std::end(actions)) { std::cerr << "Unknown action: " << requested_action_str << std::endl; return 1; } return requested_action->handler(argc - 2, argv + 2); }