#!/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)