From ece9e2c7122a58552397c46c85152abb2a3f0094 Mon Sep 17 00:00:00 2001 From: Ross Wilson Date: Fri, 19 Jun 2015 18:07:13 +0700 Subject: [PATCH] Still writing new 'pymlac' main executable --- pymlac/Display.py | 1 + pymlac/xyzzy | 899 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 900 insertions(+) create mode 100755 pymlac/xyzzy diff --git a/pymlac/Display.py b/pymlac/Display.py index 93afff6..136bbb4 100644 --- a/pymlac/Display.py +++ b/pymlac/Display.py @@ -101,6 +101,7 @@ class _BufferedCanvas(wx.Panel): (width, height) = self.GetClientSizeTuple() + # keep widget square minsize = min(width, height) self.SetSize((minsize, minsize)) diff --git a/pymlac/xyzzy b/pymlac/xyzzy new file mode 100755 index 0000000..a175ae0 --- /dev/null +++ b/pymlac/xyzzy @@ -0,0 +1,899 @@ +#!/usr/bin/python + +""" +The Python Imlac emulator (pymlac). + +Usage: pymlac ()* + +where options may be zero or more of: + -b PTR|TTY|NONE set boot ROM + -c clear memory (not ROM if write protected) + -cf set core file (default is pymlac.core) + -d set dataswitch value + -h print this help and stop + -ptp set papertape punch output file + -ptr set papertape reader input file + -r [] run machine (optionally starting at given address) + -s set memory from data in file + -t [,]|OFF set trace OFF or start/within range + -ttyin set TTY input file + -ttyout set TTY output file + -v set memory contents view file + -w ON|OFF set ROM write to ON or OFF +""" + +import sys +import os +import traceback +from threading import * +import wx + +import Display +from Globals import * +import Imlac + +import Memory +import Ptr +import Ptp +import MainCPU +import Trace + + +# if we don't have log.py, don't crash +try: + import log + log = log.Log('test.log', log.Log.DEBUG) +except ImportError: + def log(*args, **kwargs): + pass + + +###### +# Various demo constants +###### + +WindowTitleHeight = 22 +DefaultAppSize = (600, 600+WindowTitleHeight) + + + +# map ROM name to type +RomTypeMap = {'ptr': ROM_PTR, + 'tty': ROM_TTY, + 'none': ROM_NONE} + +count = 1 + +def abort(msg): + """Handle a terminal problem.""" + + print(msg) + sys.exit(1) + +def check_int(value, msg): + """Check that a value is a valid 16 bit positive value. + + We allow decimal and octal number representations. + """ + + try: + if str(value)[0] == '0': + data = int(value, 8) + else: + data = int(value) + except: + abort(msg) + if data < 0 or data > 0177777: + abort(msg) + + return data + +def get_next(options, index, msg): + """If possible, get next arg in list.""" + + if index < len(options): + next_arg = options[index] + else: + abort(msg) + + return next_arg + +def handle_options(): + """Routine to analyse command line options. + + Returns a list of operation objects which are tuples: + (OPERATION, ARGS) + """ + + options = sys.argv[1:] + + index = 0 + result = [] + boot_rom = 'ptr' + + while index < len(options): + arg = options[index] + index += 1 + + if arg[0] == '-': + if arg == '-b': + next_arg = get_next(options, index, + "-b option must be 'ptr' or 'tty' or 'none'") + index += 1 + next_arg = next_arg.lower() + #next_arg = RomTypeMap.get(next_arg, False) + + if next_arg: + op = ('boot', next_arg) + boot_rom = next_arg + else: + abort("-b option must be 'ptr', 'tty' or 'none'") + elif arg == '-c': + op = ('clear', boot_rom) + elif arg == '-d': + next_arg = get_next(options, index, + "-d option must be data switch value, positive & max 16 bits") + index += 1 + data = check_int(next_arg, + "-d option must be data switch value, positive & max 16 bits") + op = ('data', data) + elif arg == '-h': + usage() + elif arg == '-ptp': + next_arg = get_next(options, index, + "-ptp option must be papertape punch file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a papertape file" % next_arg) + op = ('load_ptp', next_arg) + elif arg == '-ptr': + next_arg = get_next(options, index, + "-ptr option must be papertape reader file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a papertape file" % next_arg) + op = ('load_ptr', next_arg) + elif arg == '-r': + next_arg = get_next(options, index, + "-r option must be 'PC' or run address, positive & max 16 bits") + index += 1 + next_arg = next_arg.lower() + if next_arg == 'pc': + op = ('run', None) + else: + address = check_int(next_arg, + "-r option must be 'PC' or run address, positive & max 16 bits") + op = ('run', address) + elif arg == '-s': + next_arg = get_next(options, index, + "-s option must be set file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a 'set' file" % next_arg) + op = ('set', next_arg) + elif arg == '-t': + next_arg = get_next(options, index, + "-t option must be trace range") + index += 1 + addr = next_arg.split(',') + if len(addr) == 1: + trace1 = addr[0] + if trace1.lower() == 'off': + trace1 = None + else: + trace1 = check_int(trace1, + "-t option must be trace range") + trace2 = None + elif len(addr) == 2: + trace1 = check_int(addr[0], "-t option must be trace range") + trace2 = check_int(addr[1], "-t option must be trace range") + else: + abort("-t option must be trace range") + op = ('trace', (trace1, trace2)) + elif arg == '-ttyin': + next_arg = get_next(options, index, + "-ttyin option must be teletype input file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a teletype file" % next_arg) + op = ('load_ttyin', next_arg) + elif arg == '-ttyout': + next_arg = get_next(options, index, + "-ttyout option must be teletype output file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a teletype file" % next_arg) + op = ('load_ttyout', next_arg) + elif arg == '-v': + next_arg = get_next(options, index, + "-v option must be view file") + index += 1 + if not os.path.isfile(next_arg): + abort("File %s isn't a 'view' file" % next_arg) + op = ('view', next_arg) + elif arg == '-w': + next_arg = get_next(options, index, + "-W option must be ON|OFF") + index += 1 + next_arg = next_arg.lower() + if next_arg in ['on', 'off']: + op = ('write', next_arg) + else: + abort("-w option must be 'ON' or 'OFF'") + else: + usage() + else: + usage() + + result.append(op) + return result + +def usage(): + """Help for befuddled user.""" + + print(__doc__) + sys.exit() + + +def main(): + """Start of the emulator.""" + + # get operations list + ops = handle_options() + + # Initialize the emulator. + boot_rom = 'ptr' # default ROM loader + Imlac.init(0, TRACE_FILENAME, None, None, boot_rom, CORE_FILENAME) + + # now perform operations + for (operation, args) in ops: + if operation == 'boot': + Memory.set_ROM(args) + Trace.comment('Bootstrap ROM set to %s' % args.upper()) + elif operation == 'clear': + Memory.clear_core() + Trace.comment('Core cleared') + elif operation == 'load_ptp': + Ptp.mount(args) + Trace.comment("File '%s' mounted on PTP" % args) + elif operation == 'load_ptr': + Ptr.mount(args) + Trace.comment("File '%s' mounted on PTR" % args) + elif operation == 'data': + MainCPU.DS = args + Trace.comment('Dataswitch value set to %06o' % args) + elif operation == 'run': + MainCPU.PC = args + Trace.comment('Running from address %06o' % args) + if Imlac.tracestart: + Trace.comment('DPC\tDisplay\t\tPC\tMain\t\tRegs') + Trace.comment('------ ------------- ------ -------------- ' + '-----------------------') + Imlac.run() + Trace.comment('Imlac halted') + elif operation == 'set': + Trace.comment("Setting memory from file '%s'" % args) + elif operation == 'trace': + if args == 'off': + Imlac.tracestart = None + Imlac.traceend = None + else: + (start, end) = args + Imlac.tracestart = start + Imlac.traceend = end + tstart = Imlac.tracestart + if tstart is not None: + tstart = '%06o' % tstart + tend = Imlac.traceend + if tend is not None: + tend = '%06o' % tend + Trace.comment('Trace set to (%s, %s)' % (tstart, tend)) + elif operation == 'ttyin': + TtyIn.mount(args) + Trace.comment("File '%s' mounted on TTYIN" % args) + elif operation == 'ttyout': + TtyOut.mount(args) + Trace.comment("File '%s' mounted on TTYOUT" % args) + elif operation == 'view': + Trace.comment("Viewing memory from file '%s'" % args) + elif operation == 'write': + if args == 'on': + Memory.using_rom = True + elif args == 'off': + Memory.using_rom = False + else: + abort("Invalid view arg: %s" % args) + Trace.comment('ROM write protect set %s' % args.upper()) + else: + abort('Invalid internal operation: %s' % operation) + + Imlac.close(CORE_FILENAME) + +class Led_1(object): + def __init__(self, parent, label, x, y, off, on): + wx.StaticText(parent, -1, label, pos=(x, y)) + y += 15 + wx.StaticBitmap(parent, -1, off, pos=(x-1, y)) + self.led = wx.StaticBitmap(parent, -1, on, pos=(x-1, y)) + self.set_value(0) + + def set_value(self, value): + if value: + self.led.Enable() + else: + self.led.Disable() + + +class Led_16(object): + def __init__(self, parent, label, x, y, off, on): + led_width = off.GetWidth() + led_height = off.GetHeight() + wx.StaticText(parent, -1, label, pos=(x, y)) + y += 15 + self.leds = [] + mark_count = 2 + ticks = [(x-17+led_width,y+led_height/2+5)] +# dc = wx.PaintDC(parent) + for i in range(16): + wx.StaticBitmap(parent, -1, off, pos=(x-1+i*17, y)) + led = wx.StaticBitmap(parent, -1, on, pos=(x-1+i*17, y)) + self.leds.append(led) + mark_count += 1 + if mark_count >= 3: + mark_count = 0 + ticks.append((x+i*17 + led_width, y+led_height/2+5)) + + self.set_value(0) + self.ticks = ticks + + def set_value(self, value): + mask = 0x8000 + for l in self.leds: + if value & mask: + l.Enable() + else: + l.Disable() + mask = mask >> 1 + + +class PymlacFrame(wx.Frame): + """a frame with two panels""" + + WIDTH_SCREEN = 1024 + HEIGHT_SCREEN = 1024 + WIDTH_CONSOLE = 330 # 400 # 256 + HEIGHT_CONSOLE = HEIGHT_SCREEN + + SCREEN_COLOUR = (0, 0, 0) + CONSOLE_COLOUR = (255, 223, 169) + PHOSPHOR_COLOUR = '#F0F000' # yellow + #PHOSPHOR_COLOUR = '#40FF40' # green + + V_MARGIN = 20 + CTL_MARGIN = 15 + LED_MARGIN = 5 + + IMAGE_LED_OFF = 'images/led_off.png' + IMAGE_LED_ON = 'images/led_on.png' + + INC = 0.01 + + def __init__(self, parent=None, id=-1, title=None): + wx.Frame.__init__(self, parent, id, title) + + self.make_gui() + self.run() + + def make_gui(self): + self.screen = wx.Panel(self, + size=(self.WIDTH_SCREEN, self.HEIGHT_SCREEN), + pos=(0,0)) + self.screen.SetBackgroundColour(self.SCREEN_COLOUR) + self.console = wx.Panel(self, style=wx.SIMPLE_BORDER, + size=(self.WIDTH_CONSOLE, self.HEIGHT_SCREEN), + pos=(self.WIDTH_SCREEN,0)) + self.console.SetBackgroundColour(self.CONSOLE_COLOUR) + + python_png = wx.Image('images/PythonPowered.png', + wx.BITMAP_TYPE_PNG).ConvertToBitmap() + python_height = python_png.GetHeight() + python_width = python_png.GetWidth() + + wxpython_png = wx.Image('images/wxPython2.png', + wx.BITMAP_TYPE_PNG).ConvertToBitmap() + wxpython_height = wxpython_png.GetHeight() + wxpython_width = wxpython_png.GetWidth() + + h_margin = (self.WIDTH_CONSOLE - wxpython_width - python_width) / 3 + + png_height = max(python_height, wxpython_height) + self.V_MARGIN + + v_margin = (png_height - python_height)/2 + python_ypos = self.HEIGHT_CONSOLE - png_height + v_margin + v_margin = (png_height - wxpython_height)/2 + wxpython_ypos = self.HEIGHT_CONSOLE - png_height + v_margin + + wx.StaticBitmap(self.console, -1, python_png, + pos=(h_margin, python_ypos)) + wx.StaticBitmap(self.console, -1, wxpython_png, + pos=(python_width + 2*h_margin, wxpython_ypos)) + + self.png_height = png_height + + led_off = wx.Image('images/led_off.png', + wx.BITMAP_TYPE_PNG).ConvertToBitmap() + led_on = wx.Image('images/led_on.png', + wx.BITMAP_TYPE_PNG).ConvertToBitmap() + + y_pos = 8 + self.led_l = Led_1(self.console, 'l', self.CTL_MARGIN, y_pos, + led_off, led_on) + self.led_ac = Led_16(self.console, 'ac', 3*self.CTL_MARGIN, y_pos, + led_off, led_on) + y_pos += 35 + self.led_pc = Led_16(self.console, 'pc', 3*self.CTL_MARGIN, y_pos, + led_off, led_on) + + + y_pos = 305 + wx.StaticText(self.console, -1, 'ptr', pos=(self.CTL_MARGIN, y_pos)) + y_pos += 15 + self.txt_ptrFile = wx.TextCtrl(self.console, -1, + pos=(self.CTL_MARGIN, y_pos), + size=(self.WIDTH_CONSOLE-2*self.CTL_MARGIN, 25)) + y_pos += 30 + + wx.StaticText(self.console, -1, 'ptp', pos=(self.CTL_MARGIN, y_pos)) + y_pos += 15 + self.txt_ptpFile = wx.TextCtrl(self.console, -1, + pos=(self.CTL_MARGIN, y_pos), + size=(self.WIDTH_CONSOLE-2*self.CTL_MARGIN, 25)) + y_pos += 15 + + dc = wx.PaintDC(self.console) + dc.SetPen(wx.Pen('black', 1)) + dc.DrawLine(0, self.HEIGHT_CONSOLE - self.png_height, + self.WIDTH_CONSOLE-1, self.HEIGHT_CONSOLE - self.png_height) + + for (x, y) in self.led_ac.ticks: + dc.DrawLine(x, y, x, y+5) + first = self.led_ac.ticks[0] + last = self.led_ac.ticks[-1] + (x1, y1) = first + (x2, y2) = last + dc.DrawLine(x1, y2+5, x2, y2+5) + + for (x, y) in self.led_pc.ticks: + dc.DrawLine(x, y, x, y+5) + first = self.led_pc.ticks[0] + last = self.led_pc.ticks[-1] + (x1, y1) = first + (x2, y2) = last + dc.DrawLine(x1, y2+5, x2, y2+5) + + self.y_offset = 0 + self.y_sign = +1 + + self.Fit() + + def run_machine(self, ops): + """Run the console options.""" + + for (operation, args) in ops: + if operation == 'boot': + Memory.set_ROM(args) + Trace.comment('Bootstrap ROM set to %s' % args.upper()) + self.on_paint() + elif operation == 'clear': + Memory.clear_core() + Trace.comment('Core cleared') + self.on_paint() + elif operation == 'load_ptp': + Ptp.mount(args) + Trace.comment("File '%s' mounted on PTP" % args) + self.on_paint() + elif operation == 'load_ptr': + Ptr.mount(args) + Trace.comment("File '%s' mounted on PTR" % args) + self.on_paint() + elif operation == 'data': + MainCPU.DS = args + Trace.comment('Dataswitch value set to %06o' % args) + self.on_paint() + elif operation == 'run': + MainCPU.PC = args + Trace.comment('Running from address %06o' % args) + if Imlac.tracestart: + Trace.comment('DPC\tDisplay\t\tPC\tMain\t\tRegs') + Trace.comment('------ ------------- ------ -------------- ' + '-----------------------') + self.on_paint() + Imlac.run() + self.on_paint() + Trace.comment('Imlac halted') + self.on_paint() + elif operation == 'set': + Trace.comment("Setting memory from file '%s'" % args) + self.on_paint() + elif operation == 'trace': + if args == 'off': + Imlac.tracestart = None + Imlac.traceend = None + else: + (start, end) = args + Imlac.tracestart = start + Imlac.traceend = end + tstart = Imlac.tracestart + if tstart is not None: + tstart = '%06o' % tstart + tend = Imlac.traceend + if tend is not None: + tend = '%06o' % tend + Trace.comment('Trace set to (%s, %s)' % (tstart, tend)) + self.on_paint() + elif operation == 'ttyin': + TtyIn.mount(args) + Trace.comment("File '%s' mounted on TTYIN" % args) + self.on_paint() + elif operation == 'ttyout': + TtyOut.mount(args) + Trace.comment("File '%s' mounted on TTYOUT" % args) + self.on_paint() + elif operation == 'view': + Trace.comment("Viewing memory from file '%s'" % args) + self.on_paint() + elif operation == 'write': + if args == 'on': + Memory.using_rom = True + elif args == 'off': + Memory.using_rom = False + else: + abort("Invalid view arg: %s" % args) + Trace.comment('ROM write protect set %s' % args.upper()) + self.on_paint() + else: + abort('Invalid internal operation: %s' % operation) + + Imlac.close(CORE_FILENAME) + + + def on_paint(self, event=None): + global count + + # establish the painting surface + dc = wx.PaintDC(self.screen) + dc.SetBackground(wx.Brush(self.SCREEN_COLOUR, 1)) + dc.SetPen(wx.Pen(self.PHOSPHOR_COLOUR, 1)) + dc.Clear() + if self.y_sign > 0: + self.y_offset = self.y_offset + self.INC + if self.y_offset > self.HEIGHT_SCREEN-1: + self.y_sign = -1 + self.y_offset = self.HEIGHT_SCREEN-1 + else: + self.y_offset = self.y_offset - self.INC + if self.y_offset < 0: + self.y_sign = +1 + self.y_offset = 0 + dc.DrawLine(0, int(self.y_offset), self.WIDTH_SCREEN-1, int(self.HEIGHT_SCREEN-self.y_offset-1)) + dc.DrawLine(0, int(self.HEIGHT_SCREEN-self.y_offset-1), self.WIDTH_SCREEN-1, int(self.y_offset)) + + dc = wx.PaintDC(self.console) + #dc.SetPen(wx.Pen('black', wx.DOT)) + dc.SetPen(wx.Pen('black', 1)) + dc.DrawLine(0, self.HEIGHT_CONSOLE - self.png_height, + self.WIDTH_CONSOLE-1, self.HEIGHT_CONSOLE - self.png_height) + + for (x, y) in self.led_ac.ticks: + dc.DrawLine(x, y, x, y+5) + first = self.led_ac.ticks[0] + last = self.led_ac.ticks[-1] + (x1, y1) = first + (x2, y2) = last + dc.DrawLine(x1, y2+5, x2, y2+5) + + for (x, y) in self.led_pc.ticks: + dc.DrawLine(x, y, x, y+5) + first = self.led_pc.ticks[0] + last = self.led_pc.ticks[-1] + (x1, y1) = first + (x2, y2) = last + dc.DrawLine(x1, y2+5, x2, y2+5) + + count += 1 + self.led_ac.set_value(count) + + + pass + + + +################################################################################ +# Stuff for the interpreter thead +################################################################################ + +# type of interpreter events +(InterpreterStop, InterpreterDraw) = range(2) + +# interpreter stop event +_myEVT_INTERPRETER_STOP = wx.NewEventType() +EVT_INTERPRETER_STOP = wx.PyEventBinder(_myEVT_INTERPRETER_STOP, 1) + +# interpreter draw event +_myEVT_INTERPRETER_DRAW = wx.NewEventType() +EVT_INTERPRETER_DRAW = wx.PyEventBinder(_myEVT_INTERPRETER_DRAW, 1) + + +class _InterpreterEvent(wx.PyCommandEvent): + """Event sent from the interpreter.""" + + def __init__(self, type, id): + """Construct an interpreter event. + + type the type of event + id unique event number + + Event will be adorned with attributes by raising code. + """ + + wx.PyCommandEvent.__init__(self, type, id) + + + +# Thread class that executes processing +class InterpreterThread(Thread): + """Worker Thread Class.""" + + def __init__(self, parent): + """Init Worker Thread Class.""" + Thread.__init__(self) + self.parent = parent + self._want_abort = 0 + # This starts the thread running on creation, but you could + # also make the GUI thread responsible for calling this + self.start() + + def RaiseInterpreterStop(self, data=None): + """Raise an interpreter stop event.""" + + event = _InterpreterEvent(_myEVT_INTERPRETER_STOP, self.parent.GetId()) + event.type = EVT_INTERPRETER_STOP + event.data = data + self.parent.GetEventHandler().ProcessEvent(event) + + def RaiseInterpreterDraw(self, data=None): + """Raise an interpreter draw event.""" + + event = _InterpreterEvent(_myEVT_INTERPRETER_DRAW, self.parent.GetId()) + event.type = EVT_INTERPRETER_DRAW + event.data = data + self.parent.GetEventHandler().ProcessEvent(event) + + def run(self): + """Run the interpreter.""" + + Imlac.run() + self.RaiseInterpreterStop() + + def abort(self): + """abort worker thread.""" + # Method for use by main thread to signal an abort + self._want_abort = 1 + +################################################################################ +# The main application frame +################################################################################ + +class DisplayFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, parent=None, size=DefaultAppSize) +# title=('pymlac v%s' % Display.__version__)) + self.SetMinSize(DefaultAppSize) + self.panel = wx.Panel(self, wx.ID_ANY) + self.panel.ClearBackground() + + # build the GUI + box = wx.BoxSizer(wx.VERTICAL) + self.display = Display.Display(self.panel) + box.Add(self.display, proportion=1, border=1, flag=wx.EXPAND) + self.panel.SetSizer(box) + self.panel.Layout() + self.Centre() + self.Show(True) + + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Refresh() + + self.lock = False + + # Set up handler for interpreter thread events + self.Bind(EVT_INTERPRETER_STOP, self.OnInterpreterStop) + + # And indicate we don't have an interpreter thread yet + self.interpreter = None + + self.run_machine() + + def OnInterpreterStop(self, event): + """A STOP event from the interpreter.""" + + print('OnInterpreterStop: event=%s' % str(dir(event))) + + def OnSize(self, event): + """Maintain square window.""" + + if not self.lock: + self.lock = True + (w, h) = event.GetSize() + size = min(w, h) + self.SetSize((size-WindowTitleHeight, size)) + self.lock = False + + event.Skip() + + def run_machine(self): + """Run the interpreter.""" + + # get operations list + ops = handle_options() + + # Initialize the emulator. + boot_rom = 'ptr' # default ROM loader + Imlac.init(0, TRACE_FILENAME, None, None, boot_rom, CORE_FILENAME) + + for (operation, args) in ops: + if operation == 'boot': + Memory.set_ROM(args) + Trace.comment('Bootstrap ROM set to %s' % args.upper()) + #self.on_paint() + elif operation == 'clear': + Memory.clear_core() + Trace.comment('Core cleared') + #self.on_paint() + elif operation == 'load_ptp': + Ptp.mount(args) + Trace.comment("File '%s' mounted on PTP" % args) + #self.on_paint() + elif operation == 'load_ptr': + Ptr.mount(args) + Trace.comment("File '%s' mounted on PTR" % args) + #self.on_paint() + elif operation == 'data': + MainCPU.DS = args + Trace.comment('Dataswitch value set to %06o' % args) + #self.on_paint() + elif operation == 'run': + MainCPU.PC = args + Trace.comment('Running from address %06o' % args) + if Imlac.tracestart: + Trace.comment('DPC\tDisplay\t\tPC\tMain\t\tRegs') + Trace.comment('------ ------------- ------ -------------- ' + '-----------------------') + #self.on_paint() + self.interpreter = InterpreterThread(self) +# Imlac.run() + #self.on_paint() +# Trace.comment('Imlac halted') + #self.on_paint() + elif operation == 'set': + Trace.comment("Setting memory from file '%s'" % args) + #self.on_paint() + elif operation == 'trace': + if args == 'off': + Imlac.tracestart = None + Imlac.traceend = None + else: + (start, end) = args + Imlac.tracestart = start + Imlac.traceend = end + tstart = Imlac.tracestart + if tstart is not None: + tstart = '%06o' % tstart + tend = Imlac.traceend + if tend is not None: + tend = '%06o' % tend + Trace.comment('Trace set to (%s, %s)' % (tstart, tend)) + #self.on_paint() + elif operation == 'ttyin': + TtyIn.mount(args) + Trace.comment("File '%s' mounted on TTYIN" % args) + #self.on_paint() + elif operation == 'ttyout': + TtyOut.mount(args) + Trace.comment("File '%s' mounted on TTYOUT" % args) + #self.on_paint() + elif operation == 'view': + Trace.comment("Viewing memory from file '%s'" % args) + #self.on_paint() + elif operation == 'write': + if args == 'on': + Memory.using_rom = True + elif args == 'off': + Memory.using_rom = False + else: + abort("Invalid view arg: %s" % args) + Trace.comment('ROM write protect set %s' % args.upper()) + #self.on_paint() + else: + abort('Invalid internal operation: %s' % operation) + + Imlac.close(CORE_FILENAME) + + +# our own handler for uncaught exceptions +def excepthook(type, value, tb): + msg = '\n' + '=' * 80 + msg += '\nUncaught exception:\n' + msg += ''.join(traceback.format_exception(type, value, tb)) + msg += '=' * 80 + '\n' + print(msg) + sys.exit(1) + +# plug our handler into the python system +sys.excepthook = excepthook + +# start wxPython app +app = wx.App() +DisplayFrame().Show() +app.MainLoop() +sys.exit(0) + + +# GUI Frame class that spins off the worker thread +class MainFrame(wx.Frame): + """Class MainFrame.""" + def __init__(self, parent, id): + """Create the MainFrame.""" + wx.Frame.__init__(self, parent, id, 'Thread Test') + + # Dumb sample frame with two buttons + wx.Button(self, ID_START, 'Start', pos=(0,0)) + wx.Button(self, ID_STOP, 'Stop', pos=(0,50)) + self.status = wx.StaticText(self, -1, '', pos=(0,100)) + + self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START) + self.Bind(wx.EVT_BUTTON, self.OnStop, id=ID_STOP) + + # Set up event handler for any worker thread results + EVT_INTERPRETER(self,self.OnResult) + + # And indicate we don't have a worker thread yet + self.interpreter = None + + def OnStart(self, event): + """Start Computation.""" + # Trigger the worker thread unless it's already busy + if not self.interpreter: + self.status.SetLabel('Starting computation') + self.interpreter = InterpreterThread(self) + + def OnStop(self, event): + """Stop Computation.""" + # Flag the worker thread to stop if running + if self.interpreter: + self.status.SetLabel('Trying to abort computation') + self.interpreter.abort() + + def OnResult(self, event): + """Show Result status.""" + if event.data is None: + # Thread aborted (using our convention of None return) + self.status.SetLabel('Computation aborted') + else: + # Process results here + self.status.SetLabel('Computation Result: %s' % event.data) + # In either event, the worker is done + self.interpreter = None + +class MainApp(wx.App): + """Class Main App.""" + def OnInit(self): + """Init Main App.""" + self.frame = MainFrame(None, -1) + self.frame.Show(True) + self.SetTopWindow(self.frame) + return True + +if __name__ == '__main__': + app = MainApp(0) + app.MainLoop()