diff --git a/tools/flash.py b/tools/flash.py new file mode 100755 index 0000000..755b75a --- /dev/null +++ b/tools/flash.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +# -------------------------------------------------------------------------- -- +# TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- +# -------------------------------------------------------------------------- -- +# Interface program for the bootrom. Basically a serial-to-wishbone bridge. +# -------------------------------------------------------------------------- -- +# Author : Markus Koch +# Contributors : None +# License : Mozilla Public License (MPL) Version 2 +# -------------------------------------------------------------------------- -- + +import serial +import sys +from ast import literal_eval + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +ser = serial.Serial('/dev/ttyUSB0', 19200, timeout=2) + +def sread(address, length, quiet = False): + if not quiet: + eprint(f'Reading {length} bytes from 0x{address:08x}...') + ser.write(b'\x02' + address.to_bytes(4, byteorder='big') + length.to_bytes(4, byteorder='big')) + data = bytes() + while length > 0: + maxpkg = min(length, 128) + rd = ser.read(maxpkg) + if len(rd) == 0: + eprint("ERROR: Receive timeout") + return None + data += rd + length -= len(rd) + return data + +def swrite(address, data, quiet = False): + if not quiet: + eprint('Writing {} bytes to 0x{:08x}...'.format(len(data), address)) + ser.write(b'\x01' + address.to_bytes(4, byteorder='big') + len(data).to_bytes(4, byteorder='big') + data) + return 0 + +def sjump(address, quiet = False): + if not quiet: + eprint(f'Jumping to 0x{address:08x}...') + ser.write(b'\x03' + address.to_bytes(4, byteorder='big')) + return 0 + +def get_diff(a, b): + diff = 0 + for i in range(0, len(a)): + if a[i] != b[i]: + print('[0x{:08x}] 0x{:02x} => 0x{:02x}'.format(i, a[i], b[i])) + diff += 1 + return diff + +def probe(): + r = sread(0, 4, quiet = True); + if r != b'7\x03\x00\x81': + eprint("ERROR: Probe failed! Check that the device is in bootloader mode.") + return 1 + return 0 + +def program(filename, addr=0, check=True): + f = open(filename, "rb") + d = bytes(f.read()) + swrite(addr, d) + if check: + r = sread(addr, len(d)) + if r is None: + eprint("Programming failed") + return 1 + diff_cnt = get_diff(d, r) + if diff_cnt == 0: + eprint("Programming OK.") + return 0 + else: + print(f"Programming failed, {diff_cnt} bytes differ.") + return 2 + else: + return 0 + +def monitor(): + print("Monitoring serial, press Ctrl+C to stop.") + while 1: + rd = ser.read(1) + if len(rd) > 0: + sys.stdout.buffer.write(bytes(rd)) + sys.stdout.buffer.flush() + +if len(sys.argv) < 3: + eprint("usage: " + sys.argv[0] + " [write|dump|jump] [address] [file]") + exit() + +command = sys.argv[1] +addr = literal_eval(sys.argv[2]) + +if probe(): + exit(-1) + +ret = 0 +if command == "write": + file = sys.argv[3] + ret = program(file, addr) +elif command == "dump": + length = literal_eval(sys.argv[3]) + sys.stdout.buffer.write(sread(addr, length)) +elif command == "jump": + ret = sjump(addr) + monitor() +else: + ret = -2 + eprint("Unknown command") + +exit(ret)