mirror of https://github.com/openXC7/prjxray.git
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 <kc8apf@kc8apf.net>
This commit is contained in:
parent
b7d01aa9f6
commit
3d33f101bc
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/strings/str_cat.h>
|
||||
#include <absl/strings/str_split.h>
|
||||
#include <absl/time/clock.h>
|
||||
#include <absl/time/time.h>
|
||||
#include <gflags/gflags.h>
|
||||
#include <prjxray/memory_mapped_file.h>
|
||||
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
|
||||
|
|
@ -18,6 +21,7 @@
|
|||
#include <prjxray/xilinx/xc7series/nop_packet.h>
|
||||
#include <prjxray/xilinx/xc7series/part.h>
|
||||
|
||||
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<uint8_t> 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<uint8_t>((build_source.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(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<uint8_t>((FLAGS_part_name.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(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<uint8_t>((build_date_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(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<uint8_t>((build_time_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(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<const char*>(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<std::ofstream::off_type>(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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue