artiq/artiq/frontend/artiq_flash.py

273 lines
9.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
2016-01-05 07:50:59 +08:00
import argparse
import os
import subprocess
import tempfile
import shutil
from functools import partial
2016-01-05 07:50:59 +08:00
from artiq import __artiq_dir__ as artiq_dir
2016-01-05 07:50:59 +08:00
from artiq.frontend.bit2bin import bit2bin
2016-01-19 12:41:42 +08:00
def get_argparser():
2016-01-05 07:50:59 +08:00
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="ARTIQ flashing/deployment tool",
epilog="""\
Valid actions:
2016-03-01 03:45:41 +08:00
* proxy: load the flash proxy gateware bitstream
* gateware: write gateware bitstream to flash
2016-01-05 07:50:59 +08:00
* bios: write bios to flash
* runtime: write runtime to flash
* storage: write storage image to flash
2016-03-01 03:45:41 +08:00
* load: load gateware bitstream into device (volatile but fast)
* start: trigger the target to (re)load its gateware bitstream from flash
2016-01-05 07:50:59 +08:00
Prerequisites:
* Connect the board through its/a JTAG adapter.
* Have OpenOCD installed and in your $PATH.
* Have access to the JTAG adapter's devices. Udev rules from OpenOCD:
'sudo cp openocd/contrib/99-openocd.rules /etc/udev/rules.d'
and replug the device. Ensure you are member of the
plugdev group: 'sudo adduser $USER plugdev' and re-login.
""")
parser.add_argument("-t", "--target", default="kc705",
help="target board, default: %(default)s")
2017-08-21 05:23:56 +08:00
parser.add_argument("-m", "--adapter", default=None,
help="target adapter, default: board-dependent")
parser.add_argument("--preinit-command", default=[], action="append",
help="add a pre-initialization OpenOCD command. "
"Useful for selecting a development board "
"when several are connected.")
2016-01-05 07:50:59 +08:00
parser.add_argument("-f", "--storage", help="write file to storage area")
parser.add_argument("-d", "--dir", help="look for files in this directory")
parser.add_argument("action", metavar="ACTION", nargs="*",
2016-03-01 03:45:41 +08:00
default="proxy gateware bios runtime start".split(),
2016-01-05 07:50:59 +08:00
help="actions to perform, default: %(default)s")
2016-01-19 12:41:42 +08:00
return parser
2017-08-21 05:23:56 +08:00
def scripts_path():
p = ["share", "openocd", "scripts"]
if os.name == "nt":
p.insert(0, "Library")
p = os.path.abspath(os.path.join(
os.path.dirname(shutil.which("openocd")),
"..", *p))
return p
def proxy_path():
p = ["share", "bscan-spi-bitstreams"]
p = os.path.abspath(os.path.join(
os.path.dirname(shutil.which("openocd")),
"..", *p))
return p
2017-08-21 05:23:56 +08:00
class Programmer:
def __init__(self, target_file, preinit_commands):
2017-08-21 05:23:56 +08:00
self.target_file = target_file
self.preinit_commands = preinit_commands
2017-08-21 05:23:56 +08:00
self.prog = []
def init(self):
self.prog.extend(self.preinit_commands)
self.prog.append("init")
2017-08-21 05:23:56 +08:00
def load(self, bitfile):
raise NotImplementedError
def proxy(self, proxy_bitfile):
raise NotImplementedError
def flash_binary(self, flashno, address, filename):
raise NotImplementedError
def start(self):
raise NotImplementedError
def do(self):
self.prog.append("exit")
cmdline = [
"openocd",
"-s", scripts_path()
]
if self.target_file is not None:
2017-08-31 12:16:52 +08:00
cmdline += ["-f", self.target_file]
2017-08-21 05:23:56 +08:00
cmdline += ["-c", "; ".join(self.prog)]
subprocess.check_call(cmdline)
class ProgrammerJtagSpi7(Programmer):
def __init__(self, target, preinit_commands):
Programmer.__init__(self, os.path.join("board", target + ".cfg"),
preinit_commands)
self.init()
2017-08-21 05:23:56 +08:00
def load(self, bitfile):
self.prog.append("pld load 0 " + bitfile)
def proxy(self, proxy_bitfile):
self.prog.append("jtagspi_init 0 {{{}}}".format(proxy_bitfile))
def flash_binary(self, flashno, address, filename):
# jtagspi_program supports only one flash
assert flashno == 0
self.prog.append("jtagspi_program {{{}}} 0x{:x}".format(
filename, address))
def start(self):
self.prog.append("xc7_program xc7.tap")
class ProgrammerSayma(Programmer):
def __init__(self, preinit_commands):
2017-08-21 05:23:56 +08:00
# TODO: support Sayma RTM
Programmer.__init__(self, None, preinit_commands)
2017-08-21 05:23:56 +08:00
self.proxy_loaded = False
self.prog += [
"interface ftdi",
"ftdi_device_desc \"Quad RS232-HS\"",
"ftdi_vid_pid 0x0403 0x6011",
"ftdi_channel 0",
# EN_USB_JTAG on ADBUS7: out, high
# nTRST on ADBUS4: out, high, but R46 is DNP
"ftdi_layout_init 0x0098 0x008b",
"ftdi_tdo_sample_edge falling",
"ftdi_layout_signal nSRST -data 0x0080",
"reset_config srst_only srst_pulls_trst srst_gates_jtag srst_push_pull",
"adapter_khz 25000",
"transport select jtag",
"jtag newtap amc_xcu tap -irlen 6 -ignore-version -expected-id 0x03822093",
"pld device virtex2 amc_xcu.tap 1",
"set XILINX_USER1 0x02",
"set XILINX_USER2 0x03",
2017-08-21 06:20:51 +08:00
"set AMC_DR_LEN 1",
2017-08-21 05:23:56 +08:00
"target create amc_xcu.proxy testee -chain-position amc_xcu.tap",
"flash bank amc_xcu.spi0 jtagspi 0 0 0 0 amc_xcu.proxy $XILINX_USER1 $AMC_DR_LEN",
"flash bank amc_xcu.spi1 jtagspi 0 0 0 0 amc_xcu.proxy $XILINX_USER2 $AMC_DR_LEN",
]
self.init()
2017-08-21 05:23:56 +08:00
def load(self, bitfile):
self.prog.append("pld load 0 " + bitfile)
def proxy(self, proxy_bitfile):
self.prog += [
"pld load 0 " + proxy_bitfile,
"reset halt"
]
def flash_binary(self, flashno, address, filename):
self.prog += [
"flash probe amc_xcu.spi{}".format(flashno),
"irscan amc_xcu.tap $XILINX_USER{}".format(flashno+1),
"flash write_bank {} {} 0x{:x}".format(flashno, filename, address)
]
def start(self):
self.proxy_loaded = False
self.prog.append("xcu_program xcu.tap")
2016-01-19 12:41:42 +08:00
def main():
parser = get_argparser()
2016-01-05 07:50:59 +08:00
opts = parser.parse_args()
config = {
"kc705": {
"programmer_factory": partial(ProgrammerJtagSpi7, "kc705"),
2017-08-21 05:23:56 +08:00
"proxy_bitfile": "bscan_spi_xc7k325t.bit",
"adapters": ["nist_clock", "nist_qc2"],
"gateware": (0, 0x000000),
"bios": (0, 0xaf0000),
"runtime": (0, 0xb00000),
"storage": (0, 0xb80000),
},
"sayma": {
"programmer_factory": ProgrammerSayma,
"proxy_bitfile": "bscan_spi_xcku040-sayma.bit",
2017-08-21 05:23:56 +08:00
"adapters": [],
"gateware": (0, 0x000000),
2017-08-21 06:21:36 +08:00
"bios": (1, 0x000000),
"runtime": (1, 0x010000),
"storage": (1, 0x090000),
2016-01-05 07:50:59 +08:00
},
}[opts.target]
2017-08-21 05:23:56 +08:00
adapter = opts.adapter
if adapter is not None and adapter not in config["adapters"]:
raise SystemExit("Invalid adapter for this board")
if adapter is None and config["adapters"]:
adapter = config["adapters"][0]
bin_dir = opts.dir
if bin_dir is None:
if adapter is None:
bin_dir = os.path.join(artiq_dir, "binaries",
"{}".format(opts.target))
else:
bin_dir = os.path.join(artiq_dir, "binaries",
"{}-{}".format(opts.target, adapter))
if not os.path.exists(bin_dir) and opts.action != ["start"]:
raise SystemExit("Binaries directory '{}' does not exist"
2017-08-21 05:23:56 +08:00
.format(bin_dir))
2016-01-05 07:50:59 +08:00
programmer = config["programmer_factory"](opts.preinit_command)
2016-01-05 07:50:59 +08:00
2017-08-21 05:23:56 +08:00
conv = False
for action in opts.action:
2016-01-05 07:50:59 +08:00
if action == "proxy":
2017-08-21 05:23:56 +08:00
proxy_found = False
for p in [bin_dir, proxy_path(), os.path.expanduser("~/.migen"),
2016-03-01 03:45:41 +08:00
"/usr/local/share/migen", "/usr/share/migen"]:
2017-08-21 05:23:56 +08:00
proxy_bitfile = os.path.join(p, config["proxy_bitfile"])
if os.access(proxy_bitfile, os.R_OK):
programmer.proxy(proxy_bitfile)
proxy_found = True
2016-01-05 07:50:59 +08:00
break
2017-08-21 05:23:56 +08:00
if not proxy_found:
2016-01-05 07:50:59 +08:00
raise SystemExit(
2017-08-21 05:23:56 +08:00
"proxy gateware bitstream {} not found".format(config["proxy_bitfile"]))
2016-03-01 03:45:41 +08:00
elif action == "gateware":
2017-08-21 05:23:56 +08:00
bin = os.path.join(bin_dir, "top.bin")
2016-01-05 07:50:59 +08:00
if not os.access(bin, os.R_OK):
2016-05-17 03:30:16 +08:00
bin_handle, bin = tempfile.mkstemp()
2017-08-21 05:23:56 +08:00
bit = os.path.join(bin_dir, "top.bit")
2016-01-05 07:50:59 +08:00
conv = True
2017-08-21 05:23:56 +08:00
programmer.flash_binary(*config["gateware"], bin)
2016-01-05 07:50:59 +08:00
elif action == "bios":
2017-08-21 05:23:56 +08:00
programmer.flash_binary(*config["bios"], os.path.join(bin_dir, "bios.bin"))
2016-01-05 07:50:59 +08:00
elif action == "runtime":
2017-08-21 05:23:56 +08:00
programmer.flash_binary(*config["runtime"], os.path.join(bin_dir, "runtime.fbi"))
2016-01-05 07:50:59 +08:00
elif action == "storage":
2017-08-21 05:23:56 +08:00
programmer.flash_binary(*config["storage"], opts.storage)
2016-01-05 07:50:59 +08:00
elif action == "load":
2017-08-21 05:23:56 +08:00
programmer.load(os.path.join(bin_dir, "top.bit"))
2016-01-05 07:50:59 +08:00
elif action == "start":
2017-08-21 05:23:56 +08:00
programmer.start()
2016-01-05 07:50:59 +08:00
else:
raise ValueError("invalid action", action)
2017-08-21 05:23:56 +08:00
if conv:
bit2bin(bit, bin_handle)
2016-01-05 07:50:59 +08:00
try:
2017-08-21 05:23:56 +08:00
programmer.do()
2016-01-05 07:50:59 +08:00
finally:
if conv:
os.unlink(bin)
if __name__ == "__main__":
main()