#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 import subprocess import tempfile import argparse import os import string import sys quartus_cpf_template = """ ${OUTPUT_FILENAME} 1 1 14 Page_0 1 ${SOF_FILENAME}1 10 0 0 0 1 1 0 1 0 0 0 0 2 ${KERNEL_FILENAME} 2 2 0 -1 -1 1 """ # XXX Do we care about FileRevision, DefaultMfr, PartName? Do they need # to be parameters? So far seems to work across 2 different boards, leave # this alone for now. quartus_pgm_template = """/* Quartus Prime Version 16.0.0 Build 211 04/27/2016 SJ Lite Edition */ JedecChain; FileRevision(JESD32A); DefaultMfr(6E); P ActionCode(Cfg) Device PartName(10M50DAF484ES) Path("${POF_DIR}/") File("${POF_FILE}") MfrSpec(OpMask(1)); ChainEnd; AlteraBegin; ChainType(JTAG); AlteraEnd;""" def create_pof(input_sof, kernel_hex): """given an input CPU .sof file and a kernel binary, return a file-like object containing .pof data suitable for flashing onto the device""" t = string.Template(quartus_cpf_template) output_pof = tempfile.NamedTemporaryFile(suffix=".pof") input_sof = os.path.abspath(input_sof) kernel_hex = os.path.abspath(kernel_hex) # These tools are very stupid and freak out if the desired filename # extensions are used. The kernel image must have extension .hex with tempfile.NamedTemporaryFile(suffix=".cof") as temp_xml: xml = t.substitute(SOF_FILENAME=input_sof, OUTPUT_FILENAME=output_pof.name, KERNEL_FILENAME=kernel_hex) temp_xml.write(bytes(xml, 'UTF-8')) temp_xml.flush() cmd = ["quartus_cpf", "-c", temp_xml.name] try: subprocess.check_output(cmd) except subprocess.CalledProcessError as cpe: sys.exit(cpe.output.decode("utf-8") + "\nFailed to create POF file") return output_pof def flash_kernel(device_id, input_sof, kernel_hex): pof_file = create_pof(input_sof, kernel_hex) with tempfile.NamedTemporaryFile(suffix=".cdf") as temp_cdf: dname, fname = os.path.split(pof_file.name) t = string.Template(quartus_pgm_template) cdf = t.substitute(POF_DIR=dname, POF_FILE=fname) temp_cdf.write(bytes(cdf, 'UTF-8')) temp_cdf.flush() cmd = ["quartus_pgm", "-c", device_id, temp_cdf.name] try: subprocess.check_output(cmd) except subprocess.CalledProcessError as cpe: sys.exit(cpe.output.decode("utf-8") + "\nFailed to flash image") pof_file.close() def main(): parser = argparse.ArgumentParser(description="Flash zephyr onto Altera boards", allow_abbrev=False) parser.add_argument("-s", "--sof", help=".sof file with Nios II CPU configuration") parser.add_argument("-k", "--kernel", help="Zephyr kernel image to place into UFM in Intel HEX format") parser.add_argument("-d", "--device", help="Remote device identifier / cable name. Default is " "USB-BlasterII. Run jtagconfig -n if unsure.", default="USB-BlasterII") args = parser.parse_args() flash_kernel(args.device, args.sof, args.kernel) if __name__ == "__main__": main()