324 lines
11 KiB
Python
324 lines
11 KiB
Python
import intelhex
|
|
import wdc
|
|
import foenix
|
|
import srec
|
|
import configparser
|
|
import re
|
|
import sys
|
|
import argparse
|
|
import os
|
|
|
|
from serial.tools import list_ports
|
|
|
|
FLASH_SIZE = 524288 # Required size of flash file: 512 KB
|
|
CHUNK_SIZE = 4096 # Size of block of binary data to transfer
|
|
|
|
label_file = ""
|
|
to_send = ""
|
|
port = ""
|
|
start_address = ""
|
|
count = ""
|
|
label = ""
|
|
|
|
def confirm(question):
|
|
return input(question).lower().strip()[:1] == "y"
|
|
|
|
def revision(port):
|
|
"""Get the version code for the debug port."""
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
c256.enter_debug()
|
|
try:
|
|
data = c256.get_revision()
|
|
return "%X" % data
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
c256.close()
|
|
|
|
def upload_binary(port, filename, address):
|
|
"""Upload a binary file into the C256 memory."""
|
|
with open(filename, "rb") as f:
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
c256.enter_debug()
|
|
try:
|
|
current_addr = int(address, 16)
|
|
block = f.read(CHUNK_SIZE)
|
|
while block:
|
|
c256.write_block(current_addr, block)
|
|
current_addr += len(block)
|
|
block = f.read(CHUNK_SIZE)
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
c256.close()
|
|
|
|
def program_flash(port, filename, hex_address):
|
|
"""Program the flash memory using the contents of the C256's RAM."""
|
|
|
|
base_address = int(hex_address, 16)
|
|
address = base_address
|
|
print("About to upload image to address 0x{:X}".format(address), flush=True)
|
|
|
|
#if os.path.getsize(filename) == FLASH_SIZE:
|
|
if confirm("Are you sure you want to reprogram the flash memory? (y/n): "):
|
|
with open(filename, "rb") as f:
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
c256.enter_debug()
|
|
try:
|
|
block = f.read(CHUNK_SIZE)
|
|
while block:
|
|
c256.write_block(address, block)
|
|
address += len(block)
|
|
block = f.read(CHUNK_SIZE)
|
|
|
|
print("Binary file uploaded...", flush=True)
|
|
c256.erase_flash()
|
|
print("Flash memory erased...", flush=True)
|
|
c256.program_flash(base_address)
|
|
print("Flash memory programmed...")
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
c256.close()
|
|
# else:
|
|
# print("The provided flash file is not the right size.")
|
|
|
|
def dereference(port, file, label):
|
|
"""Get the address contained in the pointer with the label in the label file."""
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
address = lookup(file, label)
|
|
c256.open(port)
|
|
c256.enter_debug()
|
|
try:
|
|
data = c256.read_block(int(address, 16), 3)
|
|
deref = data[2] << 16 | data[1] << 8 | data[0]
|
|
return "%X" % deref
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
c256.close()
|
|
|
|
def lookup(file, label):
|
|
"""Return the hex address linked to the passed label in the label file."""
|
|
with open(file) as f:
|
|
for line in f:
|
|
match = re.match('^(\S+)\s*\=\s*\$(\S+)', line)
|
|
if match:
|
|
if match.group(1) == label:
|
|
return match.group(2)
|
|
sys.stderr.write("Could not find a definition for that label.\n")
|
|
sys.exit(2)
|
|
|
|
def display(base_address, data):
|
|
"""Write a block of data to the console in a nice, hexadecimal format."""
|
|
|
|
text_buff = ""
|
|
for i in range(0, len(data)):
|
|
if (i % 16) == 0:
|
|
if text_buff != "":
|
|
sys.stdout.write(" {}\n".format(text_buff))
|
|
text_buff = ""
|
|
sys.stdout.write("{:06X}: ".format(base_address + i))
|
|
elif (i % 8) == 0:
|
|
sys.stdout.write(" ")
|
|
sys.stdout.write("{:02X}".format(data[i]))
|
|
|
|
b = bytearray(1)
|
|
b[0] = data[i]
|
|
if (b[0] & 0x80 == 0):
|
|
c = b.decode('ascii')
|
|
if c.isprintable():
|
|
text_buff = text_buff + c
|
|
else:
|
|
text_buff = text_buff + "."
|
|
else:
|
|
text_buff = text_buff + "."
|
|
|
|
sys.stdout.write(' {}\n'.format(text_buff))
|
|
|
|
def send_wdc(port, filename):
|
|
"""Send the data in the hex file 'filename' to the C256 on the given serial port."""
|
|
infile = wdc.WdcBinFile()
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
infile.open(filename)
|
|
try:
|
|
infile.set_handler(lambda address, data: c256.write_block(address, data))
|
|
c256.enter_debug()
|
|
try:
|
|
# Process the lines in the hex file
|
|
infile.read_blocks()
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
infile.close()
|
|
finally:
|
|
c256.close()
|
|
|
|
def send_srec(port, filename):
|
|
"""Send the data in the SREC hex file 'filename' to the C256 on the given serial port."""
|
|
infile = srec.SRECFile()
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
infile.open(filename)
|
|
try:
|
|
infile.set_handler(lambda address, data: c256.write_block(address, bytes.fromhex(data)))
|
|
c256.enter_debug()
|
|
try:
|
|
# Process the lines in the hex file
|
|
infile.read_lines()
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
infile.close()
|
|
finally:
|
|
c256.close()
|
|
|
|
def send(port, filename):
|
|
"""Send the data in the hex file 'filename' to the C256 on the given serial port."""
|
|
infile = intelhex.HexFile()
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
infile.open(filename)
|
|
try:
|
|
infile.set_handler(lambda address, data: c256.write_block(address, bytes.fromhex(data)))
|
|
c256.enter_debug()
|
|
try:
|
|
# Process the lines in the hex file
|
|
infile.read_lines()
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
infile.close()
|
|
finally:
|
|
c256.close()
|
|
|
|
def get(port, address, length):
|
|
"""Read a block of data from the C256."""
|
|
c256 = foenix.FoenixDebugPort()
|
|
try:
|
|
c256.open(port)
|
|
c256.enter_debug()
|
|
try:
|
|
data = c256.read_block(int(address, 16), int(length, 16))
|
|
|
|
display(int(address, 16), data)
|
|
finally:
|
|
c256.exit_debug()
|
|
finally:
|
|
c256.close()
|
|
|
|
def list_serial_ports():
|
|
serial_ports = list_ports.comports()
|
|
|
|
if len(serial_ports) == 0:
|
|
print("No serial ports found")
|
|
|
|
for serial_port in serial_ports:
|
|
print(f"{serial_port.device}")
|
|
print(f" Description: {serial_port.description}")
|
|
print(f" Manufacturer: {serial_port.manufacturer}")
|
|
print(f" Product: {serial_port.product}")
|
|
print()
|
|
|
|
|
|
config = configparser.ConfigParser()
|
|
config.read('c256.ini')
|
|
|
|
parser = argparse.ArgumentParser(description='Manage the C256 Foenix through its debug port.')
|
|
parser.add_argument("--port", dest="port", default=config['DEFAULT'].get('port', 'COM3'),
|
|
help="Specify the serial port to use to access the C256 debug port.")
|
|
|
|
parser.add_argument("--list-ports", dest="list_ports", action="store_true",
|
|
help="List available serial ports.")
|
|
|
|
parser.add_argument("--label-file", dest="label_file", default=config['DEFAULT'].get('labels', 'basic8'),
|
|
help="Specify the label file to use for dereference and lookup")
|
|
|
|
parser.add_argument("--count", dest="count", default="10", help="the number of bytes to read")
|
|
|
|
parser.add_argument("--dump", metavar="ADDRESS", dest="dump_address",
|
|
help="Read memory from the C256's memory and display it.")
|
|
|
|
parser.add_argument("--deref", metavar="LABEL", dest="deref_name",
|
|
help="Lookup the address stored at LABEL and display the memory there.")
|
|
|
|
parser.add_argument("--lookup", metavar="LABEL", dest="lookup_name",
|
|
help="Display the memory starting at the address indicated by the label.")
|
|
|
|
parser.add_argument("--revision", action="store_true", dest="revision",
|
|
help="Display the revision code of the debug interface.")
|
|
|
|
parser.add_argument("--flash", metavar="BINARY FILE", dest="flash_file",
|
|
help="Attempt to reprogram the flash using the binary file provided.")
|
|
|
|
parser.add_argument("--binary", metavar="BINARY FILE", dest="binary_file",
|
|
help="Upload a binary file to the C256's RAM.")
|
|
|
|
parser.add_argument("--address", metavar="ADDRESS", dest="address",
|
|
default=config['DEFAULT'].get('flash_address', '380000'),
|
|
help="Provide the starting address of the memory block to use in flashing memory.")
|
|
|
|
parser.add_argument("--upload", metavar="HEX FILE", dest="hex_file",
|
|
help="Attempt to reprogram the flash using the binary file provided.")
|
|
|
|
parser.add_argument("--upload-wdc", metavar="BINARY FILE", dest="wdc_file",
|
|
help="Upload a WDCTools binary hex file. (WDCLN.EXE -HZ)")
|
|
|
|
parser.add_argument("--upload-srec", metavar="SREC FILE", dest="srec_file",
|
|
help="Upload a Motorola SREC hex file.")
|
|
|
|
options = parser.parse_args()
|
|
|
|
try:
|
|
if options.port != "":
|
|
if options.hex_file:
|
|
send(options.port, options.hex_file)
|
|
|
|
elif options.wdc_file:
|
|
send_wdc(options.port, options.wdc_file)
|
|
|
|
elif options.srec_file:
|
|
send_srec(options.port, options.srec_file)
|
|
|
|
elif options.deref_name and options.label_file:
|
|
address = dereference(options.port, options.label_file, options.deref_name)
|
|
get(options.port, address, options.count)
|
|
|
|
elif options.lookup_name and options.label_file:
|
|
address = lookup(options.label_file, options.lookup_name)
|
|
get(options.port, address, options.count)
|
|
|
|
elif options.dump_address:
|
|
get(options.port, options.dump_address, options.count)
|
|
|
|
elif options.revision:
|
|
rev = revision(options.port)
|
|
print(rev)
|
|
|
|
elif options.address and options.binary_file:
|
|
upload_binary(options.port, options.binary_file, options.address)
|
|
|
|
elif options.address and options.flash_file:
|
|
program_flash(options.port, options.flash_file, options.address)
|
|
|
|
elif options.list_ports:
|
|
list_serial_ports()
|
|
|
|
else:
|
|
parser.print_help()
|
|
else:
|
|
parser.print_help()
|
|
finally:
|
|
print
|