strix/tools/vidor_image.py

69 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Turn a Quartus .ttf bitstream into the app image embedded in a MKR Vidor 4000 sketch.
The Vidor bootloader expects the bitstream bytes bit-reversed relative to Quartus' .ttf
output, written as a C initializer list (bitstream.h), plus a signature block (signature.h)
describing where the image goes in the FPGA's flash. The app image slot starts at 512 KB.
"""
import argparse
import hashlib
from pathlib import Path
APP_OFFSET_KB = 512
IMAGE_TYPE_APP = 1
def reverse_bits(byte: int) -> int:
return int(f"{byte:08b}"[::-1], 2)
def read_ttf(path: Path) -> bytes:
values = (field.strip() for field in path.read_text().split(","))
return bytes(reverse_bits(int(v)) for v in values if v)
def format_initializer(data: bytes) -> str:
lines = []
for start in range(0, len(data), 16):
chunk = data[start:start + 16]
if len(chunk) == 16:
lines.append(", ".join(f"{b:3d}" for b in chunk) + ",")
else:
lines.append("".join(f"{b:3d}, " for b in chunk))
return "\n".join(lines) + "\n"
def hex_bytes(data: bytes) -> str:
return ", ".join(f"0x{b:02x}" for b in data) + ","
def format_signature(image_text: str, length: int) -> str:
digest = hashlib.sha256(image_text.encode()).digest()
return "\n".join([
"NO_BOOTLOADER,",
hex_bytes((APP_OFFSET_KB * 1024).to_bytes(4, "little")),
hex_bytes(length.to_bytes(4, "little")),
hex_bytes(digest),
hex_bytes(IMAGE_TYPE_APP.to_bytes(4, "little")),
"0x00, 0x00, 0x00, 0x00, // force flag",
"NO_USER_DATA,",
]) + "\n"
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("ttf", type=Path, help="Quartus .ttf bitstream")
parser.add_argument("out_dir", type=Path, help="directory for bitstream.h and signature.h")
args = parser.parse_args()
data = read_ttf(args.ttf)
image_text = format_initializer(data)
args.out_dir.mkdir(parents=True, exist_ok=True)
(args.out_dir / "bitstream.h").write_text(image_text)
(args.out_dir / "signature.h").write_text(format_signature(image_text, len(data)))
print(f"{len(data)} bytes -> {args.out_dir}/bitstream.h, signature.h")
if __name__ == "__main__":
main()