116 lines
2.9 KiB
Python
Executable File
116 lines
2.9 KiB
Python
Executable File
#!/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', 250000, 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 is None:
|
|
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)
|