1
0
mirror of https://github.com/mnaberez/py65.git synced 2024-06-18 08:29:32 +00:00
py65/py65/monitor.py

760 lines
25 KiB
Python
Raw Normal View History

2008-09-07 06:07:58 +00:00
#!/usr/bin/env python -u
2012-01-01 23:56:56 +00:00
"""py65mon -- interact with a simulated 6502-based system
Usage: %s [options]
Options:
-h, --help : Show this message
-m, --mpu <device> : Choose which MPU device (default is 6502)
-l, --load <file> : Load a file at address 0
-r, --rom <file> : Load a rom at the top of address space and reset into it
-g, --goto <address> : Perform a goto command after loading any files
"""
2008-09-07 06:07:58 +00:00
import cmd
2012-01-02 00:56:28 +00:00
import getopt
2008-09-07 06:07:58 +00:00
import os
import re
import shlex
2008-11-17 05:59:59 +00:00
import sys
2013-10-26 22:15:51 +00:00
from asyncore import compact_traceback
from py65.devices.mpu6502 import MPU as NMOS6502
from py65.devices.mpu65c02 import MPU as CMOS65C02
from py65.devices.mpu65org16 import MPU as V65Org16
2008-11-18 06:57:17 +00:00
from py65.disassembler import Disassembler
2008-11-21 05:44:25 +00:00
from py65.assembler import Assembler
from py65.utils.addressing import AddressParser
from py65.utils import console
from py65.utils.conversions import itoa
2008-09-10 02:34:04 +00:00
from py65.memory import ObservableMemory
2008-09-07 06:07:58 +00:00
2013-10-26 22:15:51 +00:00
try:
from urllib2 import urlopen
except ImportError: # Python 3
from urllib.request import urlopen
2012-11-19 20:44:30 +00:00
2008-09-07 06:07:58 +00:00
class Monitor(cmd.Cmd):
2012-11-19 20:44:30 +00:00
Microprocessors = {'6502': NMOS6502, '65C02': CMOS65C02,
'65Org16': V65Org16}
2012-11-19 20:44:30 +00:00
def __init__(self, mpu_type=NMOS6502, completekey='tab', stdin=None,
stdout=None, argv=None):
self.mpu_type = mpu_type
if argv is None:
argv = sys.argv
self._reset(self.mpu_type)
2008-11-29 23:32:46 +00:00
self._width = 78
self.prompt = "."
2008-11-29 07:06:38 +00:00
self._add_shortcuts()
2008-09-07 06:07:58 +00:00
cmd.Cmd.__init__(self, completekey, stdin, stdout)
self._parse_args(argv)
2008-09-07 06:07:58 +00:00
def _parse_args(self, argv):
try:
2012-11-19 20:44:30 +00:00
shortopts = 'hm:l:r:g:'
longopts = ['help', 'mpu=', 'load=', 'rom=', 'goto=']
options, args = getopt.getopt(argv[1:], shortopts, longopts)
2013-10-26 20:39:35 +00:00
except getopt.GetoptError as exc:
2013-10-26 22:48:13 +00:00
self._output(exc.args[0])
2012-01-05 05:22:56 +00:00
self._usage()
self._exit(1)
for opt, value in options:
2012-11-19 20:44:30 +00:00
if opt in ('-l', '--load'):
cmd = "load %s" % value
self.onecmd(cmd)
2012-11-19 20:44:30 +00:00
if opt in ('-r', '--rom'):
# load a ROM and run from the reset vector
cmd = "load %s %d" % (value, -1)
self.onecmd(cmd)
physMask = self._mpu.memory.physMask
reset = self._mpu.ResetTo & physMask
2012-11-19 20:44:30 +00:00
dest = self._mpu.memory[reset] + \
(self._mpu.memory[reset + 1] << self.byteWidth)
cmd = "goto %08x" % dest
self.onecmd(cmd)
2012-11-19 20:44:30 +00:00
if opt in ('-g', '--goto'):
cmd = "goto %s" % value
self.onecmd(cmd)
2012-11-19 20:44:30 +00:00
if opt in ('-m', '--mpu'):
if self._get_mpu(value) is None:
mpus = list(self.Microprocessors.keys())
2012-01-15 21:10:42 +00:00
mpus.sort()
2012-11-19 20:44:30 +00:00
msg = "Fatal: no such MPU. Available MPUs: %s"
self._output(msg % ', '.join(mpus))
sys.exit(1)
cmd = "mpu %s" % value
self.onecmd(cmd)
2012-11-19 20:44:30 +00:00
elif opt in ("-h", "--help"):
2012-01-05 05:22:56 +00:00
self._usage()
self._exit(1)
2012-01-05 05:22:56 +00:00
def _usage(self):
2012-01-01 23:56:56 +00:00
usage = __doc__ % sys.argv[0]
self._output(usage)
2008-09-07 06:07:58 +00:00
def onecmd(self, line):
line = self._preprocess_line(line)
result = None
try:
result = cmd.Cmd.onecmd(self, line)
except KeyboardInterrupt:
self._output("Interrupt")
2013-10-26 20:39:35 +00:00
except Exception:
(file, fun, line), t, v, tbinfo = compact_traceback()
error = 'Error: %s, %s: file: %s line: %s' % (t, v, file, line)
self._output(error)
if not line.startswith("quit"):
self._output_mpu_status()
2008-09-07 06:07:58 +00:00
return result
def _reset(self, mpu_type):
self._mpu = mpu_type()
2012-02-24 21:08:15 +00:00
self.addrWidth = self._mpu.ADDR_WIDTH
self.byteWidth = self._mpu.BYTE_WIDTH
self.addrFmt = self._mpu.ADDR_FORMAT
self.byteFmt = self._mpu.BYTE_FORMAT
self.addrMask = self._mpu.addrMask
self.byteMask = self._mpu.byteMask
self._install_mpu_observers()
self._address_parser = AddressParser()
self._disassembler = Disassembler(self._mpu, self._address_parser)
self._assembler = Assembler(self._mpu, self._address_parser)
2008-11-29 07:06:38 +00:00
def _add_shortcuts(self):
self._shortcuts = {'EOF': 'quit',
'~': 'tilde',
'a': 'assemble',
'al': 'add_label',
'd': 'disassemble',
'dl': 'delete_label',
'exit': 'quit',
'f': 'fill',
'>': 'fill',
'g': 'goto',
'h': 'help',
'?': 'help',
'l': 'load',
'm': 'mem',
'q': 'quit',
'r': 'registers',
'ret': 'return',
'rad': 'radix',
's': 'save',
'shl': 'show_labels',
'x': 'quit',
'z': 'step'}
2008-11-29 07:06:38 +00:00
def _preprocess_line(self, line):
# line comments
quoted = False
for pos, char in enumerate(line):
if char in ('"', "'"):
quoted = not quoted
if (not quoted) and (char == ';'):
line = line[:pos]
break
# whitespace & leading dots
line = line.strip(' \t').lstrip('.')
# special case for vice compatibility
if line.startswith('~'):
2012-11-19 20:44:30 +00:00
line = self._shortcuts['~'] + ' ' + line[1:]
2008-11-29 07:06:38 +00:00
# command shortcuts
2013-10-26 20:18:01 +00:00
for shortcut, command in self._shortcuts.items():
if line == shortcut:
line = command
break
2008-11-29 07:06:38 +00:00
pattern = '^%s\s+' % re.escape(shortcut)
matches = re.match(pattern, line)
if matches:
start, end = matches.span()
line = "%s %s" % (command, line[end:])
break
return line
def _get_mpu(self, name):
requested = name.lower()
mpu = None
for key, klass in self.Microprocessors.items():
if key.lower() == requested:
mpu = klass
break
return mpu
def _install_mpu_observers(self):
def putc(address, value):
self.stdout.write(chr(value))
2008-11-17 05:59:59 +00:00
self.stdout.flush()
def getc(address):
char = console.getch_noblock(self.stdin)
if char:
byte = ord(char)
else:
byte = 0
return byte
m = ObservableMemory(addrWidth=self.addrWidth)
m.subscribe_to_write([0xF001], putc)
m.subscribe_to_read([0xF004], getc)
self._mpu.memory = m
def _output_mpu_status(self):
self._output("\n" + repr(self._mpu))
2008-09-07 06:07:58 +00:00
def _output(self, stuff):
if stuff is not None:
2009-08-19 04:33:48 +00:00
self.stdout.write(stuff + "\n")
2008-09-07 06:07:58 +00:00
def _exit(self, exitcode=0):
sys.exit(exitcode)
2009-08-22 20:12:26 +00:00
def do_help(self, args):
args = self._shortcuts.get(args.strip(), args)
return cmd.Cmd.do_help(self, args)
2008-09-07 06:07:58 +00:00
def help_version(self):
self._output("version\t\tDisplay Py65 version information.")
def do_version(self, args):
2009-08-19 04:33:48 +00:00
self._output("\nPy65 Monitor")
2008-09-07 06:07:58 +00:00
def help_help(self):
self._output("help\t\tPrint a list of available actions.")
self._output("help <action>\tPrint help for <action>.")
def help_reset(self):
self._output("reset\t\tReset the microprocessor")
def do_reset(self, args):
klass = self._mpu.__class__
self._reset(mpu_type=klass)
def do_mpu(self, args):
def available_mpus():
mpus = list(self.Microprocessors.keys())
2012-01-15 21:10:42 +00:00
mpus.sort()
self._output("Available MPUs: %s" % ', '.join(mpus))
if args == '':
self._output("Current MPU is %s" % self._mpu.name)
available_mpus()
else:
new_mpu = self._get_mpu(args)
if new_mpu is None:
self._output("Unknown MPU: %s" % args)
available_mpus()
else:
self._reset(new_mpu)
self._output("Reset with new MPU %s" % self._mpu.name)
def help_mpu(self):
self._output("mpu\t\tPrint available microprocessors.")
self._output("mpu <type>\tSelect a new microprocessor.")
def do_quit(self, args):
2008-09-07 06:07:58 +00:00
self._output('')
return 1
def help_quit(self):
self._output("To quit, type ^D or use the quit command.")
2008-09-07 06:07:58 +00:00
2008-11-21 05:44:25 +00:00
def do_assemble(self, args):
splitted = args.split(None, 1)
if len(splitted) != 2:
return self._interactive_assemble(args)
statement = splitted[1]
try:
start = self._address_parser.number(splitted[0])
bytes = self._assembler.assemble(statement, start)
2008-11-21 05:44:25 +00:00
end = start + len(bytes)
self._mpu.memory[start:end] = bytes
self.do_disassemble(self.addrFmt % start)
except KeyError:
self._output("Bad label: %s" % args)
except OverflowError:
self._output("Overflow error: %s" % args)
except SyntaxError:
self._output("Syntax error: %s" % statement)
2008-11-21 05:44:25 +00:00
def help_assemble(self):
2012-11-26 00:13:20 +00:00
self._output("assemble\t\t\t"
"Start interactive assembly at the program counter.")
self._output("assemble <address>\t\t"
"Start interactive assembly at the address.")
self._output("assemble <address> <statement>\t"
"Assemble a statement at the address.")
def _interactive_assemble(self, args):
if args == '':
2012-11-19 00:21:50 +00:00
start = self._mpu.pc
else:
2012-11-19 00:21:50 +00:00
try:
start = self._address_parser.number(args)
except KeyError:
self._output("Bad label: %s" % args)
2012-11-19 00:21:50 +00:00
return
while True:
2012-11-19 20:44:30 +00:00
prompt = "\r$" + (self.addrFmt % start) + " " + \
2013-10-27 00:36:52 +00:00
(" " * int(1 + self.byteWidth / 4) * 3)
2012-11-19 20:44:30 +00:00
2012-11-19 00:21:50 +00:00
line = console.line_input(prompt,
2012-11-19 20:44:30 +00:00
stdin=self.stdin, stdout=self.stdout)
2012-11-19 00:21:50 +00:00
if not line.strip():
2012-11-19 00:21:50 +00:00
self.stdout.write("\n")
return
# assemble into memory
try:
bytes = self._assembler.assemble(line, pc=start)
numbytes = len(bytes)
end = start + numbytes
self._mpu.memory[start:end] = bytes
# print disassembly
_, disasm = self._disassembler.instruction_at(start)
fdisasm = self._format_disassembly(start, numbytes, disasm)
2012-11-19 20:44:30 +00:00
indent = ' ' * (len(prompt + line) + 5)
self.stdout.write("\r" + indent + "\r")
self.stdout.write(fdisasm + "\n")
# advance to next address
start += numbytes
if start >= (2 ** self._mpu.ADDR_WIDTH):
start = 0
except KeyError:
2012-11-19 20:44:30 +00:00
addr = self.addrFmt % start
self.stdout.write("\r$%s ?Label\n" % addr)
except OverflowError:
2012-11-19 20:44:30 +00:00
addr = self.addrFmt % start
self.stdout.write("\r$%s ?Overflow\n" % addr)
except SyntaxError:
2012-11-19 20:44:30 +00:00
addr = self.addrFmt % start
self.stdout.write("\r$%s ?Syntax\n" % addr)
2008-11-18 06:57:17 +00:00
def do_disassemble(self, args):
splitted = shlex.split(args)
if len(splitted) != 1:
return self.help_disassemble()
address_parts = splitted[0].split(":")
start = self._address_parser.number(address_parts[0])
if len(address_parts) > 1:
end = self._address_parser.number(address_parts[1])
else:
end = start
max_address = (2 ** self._mpu.ADDR_WIDTH) - 1
cur_address = start
needs_wrap = start > end
while needs_wrap or cur_address <= end:
length, disasm = self._disassembler.instruction_at(cur_address)
self._output(self._format_disassembly(cur_address, length, disasm))
remaining = length
while remaining:
remaining -= 1
cur_address += 1
if start > end and cur_address > max_address:
needs_wrap = False
cur_address = 0
def _format_disassembly(self, address, length, disasm):
cur_address = address
max_address = (2 ** self._mpu.ADDR_WIDTH) - 1
bytes_remaining = length
dump = ''
while bytes_remaining:
if cur_address > max_address:
cur_address = 0
dump += self.byteFmt % self._mpu.memory[cur_address] + " "
cur_address += 1
bytes_remaining -= 1
2013-10-27 00:36:52 +00:00
fieldwidth = 1 + int(1 + self.byteWidth / 4) * 3
fieldfmt = "%%-%ds" % fieldwidth
return "$" + self.addrFmt % address + " " + fieldfmt % dump + disasm
2008-11-18 06:57:17 +00:00
def help_disassemble(self):
self._output("disassemble <address_range>")
self._output("Disassemble instructions in the address range.")
self._output('Range is specified like "<start>:<end>".')
2008-11-18 06:57:17 +00:00
2008-09-07 06:07:58 +00:00
def help_step(self):
2009-08-23 05:14:33 +00:00
self._output("step")
2008-09-07 06:07:58 +00:00
self._output("Single-step through instructions.")
def do_step(self, args):
self._mpu.step()
self.do_disassemble(self.addrFmt % self._mpu.pc)
2008-09-07 06:07:58 +00:00
def help_return(self):
2009-08-23 05:14:33 +00:00
self._output("return")
2008-09-07 06:07:58 +00:00
self._output("Continues execution and returns to the monitor just")
self._output("before the next RTS or RTI is executed.")
2008-09-07 06:07:58 +00:00
def do_return(self, args):
2012-11-19 20:44:30 +00:00
returns = [0x60, 0x40] # RTS, RTI
self._run(stopcodes=returns)
2008-11-18 06:57:17 +00:00
def help_goto(self):
self._output("goto <address>")
self._output("Change the PC to address and continue execution.")
def do_goto(self, args):
if args == '':
return self.help_goto()
self._mpu.pc = self._address_parser.number(args)
2012-11-19 20:44:30 +00:00
brks = [0x00] # BRK
self._run(stopcodes=brks)
def _run(self, stopcodes=[]):
2008-09-07 06:07:58 +00:00
last_instruct = None
while last_instruct not in stopcodes:
2008-09-07 06:07:58 +00:00
self._mpu.step()
last_instruct = self._mpu.memory[self._mpu.pc]
2008-09-07 06:07:58 +00:00
def help_radix(self):
self._output("radix [H|D|O|B]")
2012-11-19 20:44:30 +00:00
self._output("Set default radix to hex, decimal, octal, or binary.")
2008-09-07 06:07:58 +00:00
self._output("With no argument, the current radix is printed.")
2008-09-07 06:07:58 +00:00
def help_cycles(self):
self._output("Display the total number of cycles executed.")
2008-09-07 06:07:58 +00:00
def do_cycles(self, args):
self._output(str(self._mpu.processorCycles))
2008-09-07 06:07:58 +00:00
def do_radix(self, args):
radixes = {'Hexadecimal': 16, 'Decimal': 10, 'Octal': 8, 'Binary': 2}
if args != '':
new = args[0].lower()
changed = False
2013-10-26 20:18:01 +00:00
for name, radix in radixes.items():
2008-09-07 06:07:58 +00:00
if name[0].lower() == new:
self._address_parser.radix = radix
2008-09-07 06:07:58 +00:00
changed = True
if not changed:
self._output("Illegal radix: %s" % args)
2013-10-26 20:18:01 +00:00
for name, radix in radixes.items():
if self._address_parser.radix == radix:
2008-09-07 06:07:58 +00:00
self._output("Default radix is %s" % name)
2008-09-07 06:07:58 +00:00
def help_tilde(self):
self._output("~ <number>")
2012-11-19 20:44:30 +00:00
self._output("Display a number in decimal, hex, octal, and binary.")
def do_tilde(self, args):
if args == '':
return self.help_tilde()
2008-09-07 06:07:58 +00:00
try:
num = self._address_parser.number(args)
self._output("+%u" % num)
self._output("$" + self.byteFmt % num)
self._output("%04o" % num)
self._output(itoa(num, 2).zfill(8))
except KeyError:
self._output("Bad label: %s" % args)
except OverflowError:
self._output("Overflow error: %s" % args)
2008-09-07 06:07:58 +00:00
def help_registers(self):
2012-11-19 20:44:30 +00:00
self._output("registers[<name>=<value> [, <name>=<value>]*]")
2008-09-07 06:07:58 +00:00
self._output("Assign respective registers. With no parameters,")
self._output("display register values.")
2008-09-07 06:07:58 +00:00
def do_registers(self, args):
if args == '':
return
2008-09-07 06:07:58 +00:00
pairs = re.findall('([^=,\s]*)=([^=,\s]*)', args)
if pairs == []:
return self._output("Syntax error: %s" % args)
for register, value in pairs:
if register not in ('pc', 'sp', 'a', 'x', 'y', 'p'):
2008-09-07 06:07:58 +00:00
self._output("Invalid register: %s" % register)
else:
try:
intval = self._address_parser.number(value) & self.addrMask
2008-09-07 06:07:58 +00:00
if len(register) == 1:
intval &= self.byteMask
2008-09-07 06:07:58 +00:00
setattr(self._mpu, register, intval)
2013-10-26 20:39:35 +00:00
except KeyError as exc:
2013-10-26 22:48:13 +00:00
self._output(exc.args[0])
def help_cd(self):
2008-09-07 06:07:58 +00:00
self._output("cd <directory>")
self._output("Change the working directory.")
2008-09-07 06:07:58 +00:00
def do_cd(self, args):
if args == '':
return self.help_cd()
2008-09-07 06:07:58 +00:00
try:
os.chdir(args)
2013-10-26 20:39:35 +00:00
except OSError as exc:
2013-10-26 20:55:02 +00:00
msg = "Cannot change directory: [%d] %s" % (exc.errno,
exc.strerror)
2008-09-07 06:07:58 +00:00
self._output(msg)
self.do_pwd()
def help_pwd(self):
self._output("Show the current working directory.")
2008-09-07 06:07:58 +00:00
def do_pwd(self, args=None):
cwd = os.getcwd()
self._output(cwd)
def help_load(self):
self._output("load \"filename\" <address>")
2012-11-19 20:44:30 +00:00
self._output("Load a file into memory at the specified address.")
2008-09-07 06:07:58 +00:00
self._output("Commodore-style load address bytes are ignored.")
def do_load(self, args):
split = shlex.split(args)
if len(split) > 2:
self._output("Syntax error: %s" % args)
return
filename = split[0]
2012-01-03 01:13:40 +00:00
if "://" in filename:
try:
2013-10-26 22:15:51 +00:00
f = urlopen(filename)
2012-01-03 01:13:40 +00:00
bytes = f.read()
f.close()
2013-10-26 22:15:51 +00:00
except Exception as exc:
msg = "Cannot fetch remote file: %s" % str(exc)
2012-01-03 01:13:40 +00:00
self._output(msg)
return
else:
try:
f = open(filename, 'rb')
bytes = f.read()
f.close()
2013-10-26 20:39:35 +00:00
except (OSError, IOError) as exc:
2013-10-26 20:55:02 +00:00
msg = "Cannot load file: [%d] %s" % (exc.errno, exc.strerror)
2012-01-03 01:13:40 +00:00
self._output(msg)
return
2008-09-07 06:07:58 +00:00
2013-04-01 11:28:26 +00:00
if len(split) == 2:
if split[1] == "-1":
# load a ROM to top of memory
2013-10-27 00:36:52 +00:00
start = self.addrMask - len(bytes) / int(self.byteWidth / 8) + 1
2013-04-01 11:28:26 +00:00
else:
start = self._address_parser.number(split[1])
else:
start = self._mpu.pc
2012-11-19 20:44:30 +00:00
if self.byteWidth == 8:
if isinstance(bytes, str):
bytes = map(ord, bytes)
else: # Python 3
bytes = [ b for b in bytes ]
2012-11-19 20:44:30 +00:00
elif self.byteWidth == 16:
def format(msb, lsb):
if isinstance(bytes, str):
return (ord(msb) << 8) + ord(lsb)
else: # Python 3
return (msb << 8) + lsb
bytes = list(map(format, bytes[0::2], bytes[1::2]))
self._fill(start, start, bytes)
def do_save(self, args):
split = shlex.split(args)
if len(split) != 3:
self._output("Syntax error: %s" % args)
return
filename = split[0]
start = self._address_parser.number(split[1])
2012-11-19 20:44:30 +00:00
end = self._address_parser.number(split[2])
mem = self._mpu.memory[start:end + 1]
try:
f = open(filename, 'wb')
for m in mem:
# output each octect from msb first
2012-11-19 20:44:30 +00:00
for shift in range(self.byteWidth - 8, -1, -8):
f.write(bytearray([(m >> shift) & 0xff]))
f.close()
2013-10-26 20:39:35 +00:00
except (OSError, IOError) as exc:
2013-10-26 20:55:02 +00:00
msg = "Cannot save file: [%d] %s" % (exc.errno, exc.strerror)
self._output(msg)
return
self._output("Saved +%d bytes to %s" % (len(mem), filename))
def help_save(self):
self._output("save \"filename\" <start> <end>")
2012-11-19 20:44:30 +00:00
self._output("Save the specified memory range as a binary file.")
self._output("Commodore-style load address bytes are not written.")
2008-09-07 06:07:58 +00:00
def help_fill(self):
2008-11-29 07:06:38 +00:00
self._output("fill <address_range> <data_list>")
2012-11-19 20:44:30 +00:00
self._output("Fill memory in the address range with the data in")
self._output("<data_list>. If the size of the address range is")
self._output("greater than the size of the data_list, the data_list ")
self._output("is repeated.")
2008-09-07 06:07:58 +00:00
def do_fill(self, args):
split = shlex.split(args)
if len(split) < 2:
return self.help_fill()
2008-09-07 06:07:58 +00:00
start, end = self._address_parser.range(split[0])
filler = list(map(self._address_parser.number, split[1:]))
self._fill(start, end, filler)
2008-09-07 06:07:58 +00:00
def _fill(self, start, end, filler):
2008-09-07 06:07:58 +00:00
address = start
length, index = len(filler), 0
if start == end:
end = start + length - 1
if (end > self.addrMask):
end = self.addrMask
2008-09-07 06:07:58 +00:00
while address <= end:
address &= self.addrMask
self._mpu.memory[address] = (filler[index] & self.byteMask)
index += 1
if index == length:
index = 0
2008-09-07 06:07:58 +00:00
address += 1
2008-09-07 06:07:58 +00:00
fmt = (end - start + 1, start, end)
starttoend = "$" + self.addrFmt + " to $" + self.addrFmt
self._output(("Wrote +%d bytes from " + starttoend) % fmt)
2008-09-07 06:07:58 +00:00
def help_mem(self):
self._output("mem <address_range>")
self._output("Display the contents of memory.")
self._output('Range is specified like "<start:end>".')
2008-09-07 06:07:58 +00:00
def do_mem(self, args):
split = shlex.split(args)
if len(split) != 1:
return self.help_mem()
start, end = self._address_parser.range(split[0])
2008-09-07 06:07:58 +00:00
line = self.addrFmt % start + ":"
2012-11-19 20:44:30 +00:00
for address in range(start, end + 1):
2008-11-29 23:32:46 +00:00
byte = self._mpu.memory[address]
more = " " + self.byteFmt % byte
2008-11-29 23:32:46 +00:00
exceeded = len(line) + len(more) > self._width
if exceeded:
self._output(line)
line = self.addrFmt % address + ":"
2008-11-29 23:32:46 +00:00
line += more
self._output(line)
2008-09-07 06:07:58 +00:00
2008-11-18 06:57:17 +00:00
def help_add_label(self):
self._output("add_label <address> <label>")
self._output("Map a given address to a label.")
def do_add_label(self, args):
split = shlex.split(args)
if len(split) != 2:
self._output("Syntax error: %s" % args)
return self.help_add_label()
address = self._address_parser.number(split[0])
2012-11-19 20:44:30 +00:00
label = split[1]
self._address_parser.labels[label] = address
2008-11-18 06:57:17 +00:00
def help_show_labels(self):
self._output("show_labels")
self._output("Display current label mappings.")
def do_show_labels(self, args):
values = list(self._address_parser.labels.values())
keys = list(self._address_parser.labels.keys())
byaddress = list(zip(values, keys))
byaddress.sort()
for address, label in byaddress:
self._output(self.addrFmt % address + ": " + label)
2008-11-18 06:57:17 +00:00
def help_delete_label(self):
self._output("delete_label <label>")
self._output("Remove the specified label from the label tables.")
def do_delete_label(self, args):
2009-03-17 06:23:17 +00:00
if args == '':
return self.help_delete_label()
if args in self._address_parser.labels:
del self._address_parser.labels[args]
2008-11-29 23:32:46 +00:00
def do_width(self, args):
if args != '':
try:
new_width = int(args)
if new_width >= 10:
self._width = new_width
else:
self._output("Minimum terminal width is 10")
except ValueError:
self._output("Illegal width: %s" % args)
self._output("Terminal width is %d" % self._width)
def help_width(self):
self._output("width <columns>")
self._output("Set the width used by some commands to wrap output.")
self._output("With no argument, the current width is printed.")
2008-09-07 06:07:58 +00:00
2012-11-19 20:44:30 +00:00
def main(args=None):
c = Monitor()
2008-09-07 06:07:58 +00:00
try:
import readline
2013-10-26 23:55:53 +00:00
readline = readline # pyflakes
2008-09-07 06:07:58 +00:00
except ImportError:
pass
try:
c.onecmd('version')
c.cmdloop()
except KeyboardInterrupt:
c._output('')
if __name__ == "__main__":
main()