From 3d33f101bc850a17a2b8540fc70d5ed772d9be83 Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Thu, 1 Feb 2018 12:32:19 -0800 Subject: [PATCH] xc7patch: Generate Xilinx BIT header in output bitstream Xilinx tools generate and expect an additional header to be added to the bitstream. This header is the only difference between .bit and .bin files and is not required by the part in any way. OpenOCD only supports reading .bit files so the easiest path to a using FOSS tools from FASM down is to generate a .bit header in xc7patch's output. To distinguish xc7patch-generated files from Xilinx-generated files, the source file field includes a Generator tag indicating that the bitstream was produced by xc7patch. Vivado uses the same technique to record the Vivado version in a Version tag. Signed-off-by: Rick Altherr --- tools/CMakeLists.txt | 1 + tools/xc7patch.cc | 67 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 06dc18c0..85023a91 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -21,6 +21,7 @@ target_link_libraries(gen_part_base_yaml add_executable(xc7patch xc7patch.cc) target_link_libraries(xc7patch absl::strings + absl::time gflags libprjxray ) diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc index 245d6e65..9ea3962d 100644 --- a/tools/xc7patch.cc +++ b/tools/xc7patch.cc @@ -5,7 +5,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -18,6 +21,7 @@ #include #include +DEFINE_string(part_name, "", ""); DEFINE_string(part_file, "", "Definition file for target 7-series part"); DEFINE_string(bitstream_file, "", @@ -315,6 +319,61 @@ int main(int argc, char* argv[]) { return 1; } + // Xilinx BIT header. + // Sync header + std::vector bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f, + 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, + 0x00, 0x00, 0x01, 'a'}; + auto build_source = absl::StrCat(FLAGS_frm_file, ";Generator=xc7patch"); + bit_header.push_back( + static_cast((build_source.size() + 1) >> 8)); + bit_header.push_back(static_cast(build_source.size() + 1)); + bit_header.insert(bit_header.end(), build_source.begin(), + build_source.end()); + bit_header.push_back(0x0); + + // Source file. + bit_header.push_back('b'); + bit_header.push_back( + static_cast((FLAGS_part_name.size() + 1) >> 8)); + bit_header.push_back(static_cast(FLAGS_part_name.size() + 1)); + bit_header.insert(bit_header.end(), FLAGS_part_name.begin(), + FLAGS_part_name.end()); + bit_header.push_back(0x0); + + // Build timestamp. + auto build_time = absl::Now(); + auto build_date_string = + absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone()); + auto build_time_string = + absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone()); + + bit_header.push_back('c'); + bit_header.push_back( + static_cast((build_date_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(build_date_string.size() + 1)); + bit_header.insert(bit_header.end(), build_date_string.begin(), + build_date_string.end()); + bit_header.push_back(0x0); + + bit_header.push_back('d'); + bit_header.push_back( + static_cast((build_time_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(build_time_string.size() + 1)); + bit_header.insert(bit_header.end(), build_time_string.begin(), + build_time_string.end()); + bit_header.push_back(0x0); + + bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0}); + out_file.write(reinterpret_cast(bit_header.data()), + bit_header.size()); + + auto end_of_header_pos = out_file.tellp(); + auto header_data_length_pos = + end_of_header_pos - static_cast(4); + for (uint32_t word : out_bitstream_writer) { out_file.put((word >> 24) & 0xFF); out_file.put((word >> 16) & 0xFF); @@ -322,5 +381,13 @@ int main(int argc, char* argv[]) { out_file.put((word)&0xFF); } + uint32_t length_of_data = out_file.tellp() - end_of_header_pos; + + out_file.seekp(header_data_length_pos); + out_file.put((length_of_data >> 24) & 0xFF); + out_file.put((length_of_data >> 16) & 0xFF); + out_file.put((length_of_data >> 8) & 0xFF); + out_file.put((length_of_data)&0xFF); + return 0; }