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:
@@ -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
899
pymlac/xyzzy
Executable 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()
|
||||
Reference in New Issue
Block a user