tools: Add flash.py

This commit is contained in:
Markus Koch 2024-07-07 15:35:09 +02:00
parent e1672bb712
commit 07bac62438

115
tools/flash.py Executable file
View File

@ -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 <markus@notsyncing.net>
# 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)