Andrew Boie | 9280e71 | 2016-05-26 14:45:52 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
Anas Nashif | 3ae5262 | 2019-04-06 09:08:09 -0400 | [diff] [blame] | 3 | # SPDX-License-Identifier: Apache-2.0 |
Andrew Boie | 9280e71 | 2016-05-26 14:45:52 -0700 | [diff] [blame] | 4 | import subprocess |
| 5 | import tempfile |
| 6 | import argparse |
| 7 | import os |
| 8 | import string |
| 9 | import sys |
Andrew Boie | 9280e71 | 2016-05-26 14:45:52 -0700 | [diff] [blame] | 10 | |
| 11 | quartus_cpf_template = """<?xml version="1.0" encoding="US-ASCII" standalone="yes"?> |
| 12 | <cof> |
| 13 | <output_filename>${OUTPUT_FILENAME}</output_filename> |
| 14 | <n_pages>1</n_pages> |
| 15 | <width>1</width> |
| 16 | <mode>14</mode> |
| 17 | <sof_data> |
| 18 | <user_name>Page_0</user_name> |
| 19 | <page_flags>1</page_flags> |
| 20 | <bit0> |
| 21 | <sof_filename>${SOF_FILENAME}<compress_bitstream>1</compress_bitstream></sof_filename> |
| 22 | </bit0> |
| 23 | </sof_data> |
| 24 | <version>10</version> |
| 25 | <create_cvp_file>0</create_cvp_file> |
| 26 | <create_hps_iocsr>0</create_hps_iocsr> |
| 27 | <auto_create_rpd>0</auto_create_rpd> |
| 28 | <rpd_little_endian>1</rpd_little_endian> |
| 29 | <options> |
| 30 | <map_file>1</map_file> |
| 31 | </options> |
| 32 | <MAX10_device_options> |
| 33 | <por>0</por> |
| 34 | <io_pullup>1</io_pullup> |
| 35 | <config_from_cfm0_only>0</config_from_cfm0_only> |
| 36 | <isp_source>0</isp_source> |
| 37 | <verify_protect>0</verify_protect> |
| 38 | <epof>0</epof> |
| 39 | <ufm_source>2</ufm_source> |
| 40 | <ufm_filepath>${KERNEL_FILENAME}</ufm_filepath> |
| 41 | </MAX10_device_options> |
| 42 | <advanced_options> |
| 43 | <ignore_epcs_id_check>2</ignore_epcs_id_check> |
| 44 | <ignore_condone_check>2</ignore_condone_check> |
| 45 | <plc_adjustment>0</plc_adjustment> |
| 46 | <post_chain_bitstream_pad_bytes>-1</post_chain_bitstream_pad_bytes> |
| 47 | <post_device_bitstream_pad_bytes>-1</post_device_bitstream_pad_bytes> |
| 48 | <bitslice_pre_padding>1</bitslice_pre_padding> |
| 49 | </advanced_options> |
| 50 | </cof> |
| 51 | """ |
| 52 | |
| 53 | # XXX Do we care about FileRevision, DefaultMfr, PartName? Do they need |
| 54 | # to be parameters? So far seems to work across 2 different boards, leave |
| 55 | # this alone for now. |
| 56 | quartus_pgm_template = """/* Quartus Prime Version 16.0.0 Build 211 04/27/2016 SJ Lite Edition */ |
| 57 | JedecChain; |
| 58 | FileRevision(JESD32A); |
| 59 | DefaultMfr(6E); |
| 60 | |
| 61 | P ActionCode(Cfg) |
| 62 | Device PartName(10M50DAF484ES) Path("${POF_DIR}/") File("${POF_FILE}") MfrSpec(OpMask(1)); |
| 63 | |
| 64 | ChainEnd; |
| 65 | |
| 66 | AlteraBegin; |
| 67 | ChainType(JTAG); |
| 68 | AlteraEnd;""" |
| 69 | |
| 70 | |
| 71 | def create_pof(input_sof, kernel_hex): |
| 72 | """given an input CPU .sof file and a kernel binary, return a file-like |
| 73 | object containing .pof data suitable for flashing onto the device""" |
| 74 | |
| 75 | t = string.Template(quartus_cpf_template) |
| 76 | output_pof = tempfile.NamedTemporaryFile(suffix=".pof") |
| 77 | |
| 78 | input_sof = os.path.abspath(input_sof) |
| 79 | kernel_hex = os.path.abspath(kernel_hex) |
| 80 | |
| 81 | # These tools are very stupid and freak out if the desired filename |
| 82 | # extensions are used. The kernel image must have extension .hex |
| 83 | |
| 84 | with tempfile.NamedTemporaryFile(suffix=".cof") as temp_xml: |
| 85 | |
| 86 | xml = t.substitute(SOF_FILENAME=input_sof, |
| 87 | OUTPUT_FILENAME=output_pof.name, |
| 88 | KERNEL_FILENAME=kernel_hex) |
| 89 | |
| 90 | temp_xml.write(bytes(xml, 'UTF-8')) |
| 91 | temp_xml.flush() |
| 92 | |
| 93 | cmd = ["quartus_cpf", "-c", temp_xml.name] |
| 94 | try: |
| 95 | subprocess.check_output(cmd) |
| 96 | except subprocess.CalledProcessError as cpe: |
| 97 | print(cpe.output.decode("UTF-8")) |
| 98 | print("Failed to create POF file") |
| 99 | sys.exit(1) |
| 100 | |
| 101 | return output_pof |
| 102 | |
| 103 | |
| 104 | def flash_kernel(device_id, input_sof, kernel_hex): |
| 105 | pof_file = create_pof(input_sof, kernel_hex) |
| 106 | |
| 107 | with tempfile.NamedTemporaryFile(suffix=".cdf") as temp_cdf: |
| 108 | dname, fname = os.path.split(pof_file.name) |
| 109 | t = string.Template(quartus_pgm_template) |
| 110 | cdf = t.substitute(POF_DIR=dname, POF_FILE=fname) |
| 111 | temp_cdf.write(bytes(cdf, 'UTF-8')) |
| 112 | temp_cdf.flush() |
| 113 | cmd = ["quartus_pgm", "-c", device_id, temp_cdf.name] |
| 114 | try: |
| 115 | subprocess.check_output(cmd) |
| 116 | except subprocess.CalledProcessError as cpe: |
| 117 | print(cpe.output.decode("UTF-8")) |
| 118 | print("Failed to flash image") |
| 119 | sys.exit(1) |
| 120 | pof_file.close() |
| 121 | |
| 122 | def main(): |
| 123 | parser = argparse.ArgumentParser(description="Flash zephyr onto Altera boards") |
| 124 | parser.add_argument("-s", "--sof", |
| 125 | help=".sof file with Nios II CPU configuration") |
| 126 | parser.add_argument("-k", "--kernel", |
| 127 | help="Zephyr kernel image to place into UFM in Intel HEX format") |
| 128 | parser.add_argument("-d", "--device", |
| 129 | help="Remote device identifier / cable name. Default is " |
| 130 | "USB-BlasterII. Run jtagconfig -n if unsure.", |
| 131 | default="USB-BlasterII") |
| 132 | |
| 133 | args = parser.parse_args() |
| 134 | |
| 135 | flash_kernel(args.device, args.sof, args.kernel) |
| 136 | |
| 137 | |
| 138 | if __name__ == "__main__": |
| 139 | main() |