1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00

Still writing new 'pymlac' main executable

This commit is contained in:
Ross Wilson
2015-06-19 18:07:13 +07:00
parent fd10322acc
commit ece9e2c712
2 changed files with 900 additions and 0 deletions

View File

@@ -101,6 +101,7 @@ class _BufferedCanvas(wx.Panel):
(width, height) = self.GetClientSizeTuple()
# keep widget square
minsize = min(width, height)
self.SetSize((minsize, minsize))

899
pymlac/xyzzy Executable file
View File

@@ -0,0 +1,899 @@
#!/usr/bin/python
"""
The Python Imlac emulator (pymlac).
Usage: pymlac (<options>)*
where options may be zero or more of:
-b PTR|TTY|NONE set boot ROM
-c clear memory (not ROM if write protected)
-cf <file> set core file (default is pymlac.core)
-d <value> set dataswitch value
-h print this help and stop
-ptp <file> set papertape punch output file
-ptr <file> set papertape reader input file
-r [<addr>] run machine (optionally starting at given address)
-s <file> set memory from data in file
-t <addr>[,<addr>]|OFF set trace OFF or start/within range
-ttyin <file> set TTY input file
-ttyout <file> set TTY output file
-v <file> 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()