From 5eb7e15ad3baf0cf2c15e9a82e9f23604829f434 Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Thu, 14 Dec 2017 13:35:42 -0800 Subject: [PATCH] tools: Tool to generate part YAML from a debug bitstream Signed-off-by: Rick Altherr Signed-off-by: Tim 'mithro' Ansell --- tools/CMakeLists.txt | 8 +++ tools/gen_part_base_yaml.cc | 117 ++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 tools/gen_part_base_yaml.cc diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 652d73e2..596babbf 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -9,3 +9,11 @@ target_link_libraries(bittool libprjxray gflags absl::strings absl::span) add_executable(frame_address_decoder frame_address_decoder.cc) target_link_libraries(frame_address_decoder libprjxray) + +add_executable(gen_part_base_yaml gen_part_base_yaml.cc) +target_link_libraries(gen_part_base_yaml + absl::optional + absl::span + libprjxray + yaml-cpp +) diff --git a/tools/gen_part_base_yaml.cc b/tools/gen_part_base_yaml.cc new file mode 100644 index 00000000..2e1ec762 --- /dev/null +++ b/tools/gen_part_base_yaml.cc @@ -0,0 +1,117 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace xc7series = prjxray::xilinx::xc7series; + +template +std::string HexString(T value) { + std::ostringstream out; + out << "0x" << std::hex << value; + return out.str(); +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + std::cerr << "ERROR: no input specified" << std::endl; + std::cerr << "Usage: " << basename(argv[0]) + << " " + << std::endl; + return 1; + } + + auto in_file_name = argv[1]; + 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()); + auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes); + if (!reader) { + std::cerr << "Input doesn't look like a bitstream" + << std::endl; + return 1; + } + + bool found_fdri_write = false; + std::vector frame_addresses; + absl::optional idcode; + for (auto packet : *reader) { + if (packet.opcode() != + xc7series::ConfigurationPacket::Opcode::Write) { + continue; + } + + if (packet.address() == + xc7series::ConfigurationRegister::FDRI) { + found_fdri_write = true; + } else if ((packet.address() == + xc7series::ConfigurationRegister::IDCODE) && + packet.data().size() == 1) { + idcode = packet.data()[0]; + } else if (found_fdri_write && + (packet.address() == + xc7series::ConfigurationRegister::LOUT) && + packet.data().size() == 1) { + frame_addresses.push_back(packet.data()[0]); + } + } + + if (!idcode) { + std::cerr << "No IDCODE found." << std::endl; + return 1; + } + + if (frame_addresses.empty()) { + std::cerr << "No LOUT writes found. Was " + << "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?" + << std::endl; + return 1; + } + + YAML::Node config_yaml; + config_yaml.SetTag("xilinx/xc7series/part"); + config_yaml["idcode"] = HexString(*idcode); + + // So far, the addresses appear to be written in increasing order but + // there is no guarantee. Sort them just in case. + std::sort(frame_addresses.begin(), frame_addresses.end()); + + YAML::Node regions = config_yaml["configuration_regions"]; + for (auto start_of_range = frame_addresses.begin(); + start_of_range != frame_addresses.end(); + ) { + auto end_of_range = start_of_range; + while (end_of_range + 1 != frame_addresses.end() && + *(end_of_range + 1) == *end_of_range + 1) { + ++end_of_range; + } + + YAML::Node region; + region["start"] = + xc7series::ConfigurationFrameAddress(*start_of_range); + region["end"] = + xc7series::ConfigurationFrameAddress(*end_of_range); + regions.push_back(region); + + start_of_range = ++end_of_range; + } + + std::cout << config_yaml << std::endl; + + return 0; +}