1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
Files
rzzzwilson.pymlac/pymlac/pymlac
2016-03-04 16:40:17 +07:00

255 lines
8.7 KiB
Python
Executable File

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
A simulator for an Imlac PDS-1 or PDS-4.
Usage: pymlac [ <option> ]*
That is, the user may specify zero or more options interspersed in any manner
required. The options are:
-b (ptr | tty | none) sets the bootstrap ROM code:
ptr uses the papertape bootstrap ROM
tty uses the teletype bootstrap ROM
none uses no bootstrap ROM
-c clears core including bootstrap ROM, if write enabled
-cf <filename> sets the name of the core file to read and write
(default file is 'pymlac.core')
-d <value> sets the console data switches to the <value>
-h prints this help
-ptp <file> loads a file on to the papertape punch device
-ptr <file> loads a file on to the papertape reader device
-r (<address> | pc) executes from <address> or the current PC contents
-s <setfile> sets memory adress values from <setfile>
-t (<range>[:<range>] | off) controls the execution trace:
-t 0100,0200 trace from 0100 octal to 200 decimal
-t 0100,0200:0210,0300 trace from 0100 to 0200 and 0210 to 0300
-t off turns trace off
-ttyin <file> loads a file on to the teletype reader device
-ttyout <file> loads a file on to the teletype writer device
-v <viewfile> views contents of memory addresses from file
-w (on | off) controls ROM write property:
-w on ROM addresses are writable
-w off ROM addresses are write protected
"""
import sys
import getopt
import collections
from Globals import *
import MainCPU
import Memory
import PtrPtp
import TtyIn
import TtyOut
import Trace
import log
log = log.Log('test.log', log.Log.DEBUG)
trace = Trace.Trace(TRACE_FILENAME)
def str2int(s):
"""Convert a string to an integer value.
s the string to convert
The string may indicate a decimal or octal value.
None is returned if the string cannot be converted.
"""
base = 10
if s[0] == '0':
base = 8
try:
value = int(s, base=base)
except:
return None
return value
def usage(msg=None):
if msg:
print('*'*60)
print(msg)
print('*'*60)
print(__doc__)
def start_running(cpu, memory, ptrptp, ttyin):
"""Run the Imlac machine until it stops."""
cpu.running = True
while cpu.running:
(cycles, tracestr) = cpu.execute_one_instruction()
if tracestr:
endstr = trace.itraceend(False)
log('%s\t%s' % (tracestr, endstr))
# trace.comment('%s\t%s' % (tracestr, endstr))
# trace.flush()
ptrptp.ptr_tick(cycles)
ptrptp.ptp_tick(cycles)
ttyin.tick(cycles)
def main():
"""Main function of the simulator. Mostly interpret CLI args."""
# prepare the Imlac machine
imlac_memory = Memory.Memory()
imlac_ptrptp = PtrPtp.PtrPtp()
imlac_ttyin = TtyIn.TtyIn()
imlac_ttyout = TtyOut.TtyOut()
imlac_cpu = MainCPU.MainCPU(imlac_memory, None, None,
None, imlac_ttyin, imlac_ttyout, imlac_ptrptp)
imlac_cpu.running = True
imlac_display_state = False
# prepare the trace
trace.add_maincpu(imlac_cpu)
# trace_map defines addresses we are tracing at
# initially, no tracing
trace_map = collections.defaultdict(bool)
len_sys_argv = len(sys.argv)
ndx = 1
while ndx < len_sys_argv:
opt = sys.argv[ndx]
ndx += 1
if opt[0] != '-':
usage("Bad option: '%s'" % str(opt))
if opt == '-b':
if ndx >= len_sys_argv:
usage("'-b' option needs a following device name")
sys.exit(10)
dev = sys.argv[ndx].lower()
ndx += 1
if dev == 'ptr':
imlac_memory.set_ROM('ptr')
elif dev == 'tty':
imlac_memory.set_ROM('tty')
elif dev == 'none':
imlac_memory.set_ROM(None)
else:
usage("-b option must be followed by 'ptr', 'tty' or 'none'")
sys.exit(10)
elif opt == '-c':
imlac_memory.clear_core()
elif opt == '-cf':
if ndx >= len_sys_argv:
usage("'-cf' option needs a following filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
imlac_memory.set_corefile(filename)
elif opt == '-d':
if ndx >= len_sys_argv:
usage("'-d' option needs a following data switch value")
sys.exit(10)
value = str2int(sys.argv[ndx])
ndx += 1
if value is None:
usage("The '-d' option must be followed by a decimal or octal value")
sys.exit(10)
imlac_cpu.DS = value
elif opt == '-h':
usage()
sys.exit(0)
elif opt == '-ptp':
if ndx >= len_sys_argv:
usage("'-ptp' option needs a following PTP filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
imlac_ptrptp.ptp_mount(filename)
elif opt == '-ptr':
if ndx >= len_sys_argv:
usage("'-ptr' option needs a following PTR filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
imlac_ptrptp.ptr_mount(filename)
elif opt == '-r':
if ndx >= len_sys_argv:
usage("'-r' option needs a following address or 'pc'")
sys.exit(10)
address = sys.argv[ndx].lower()
ndx += 1
if address != 'pc':
addr_value = str2int(address)
if addr_value is None:
usage("'-r' option needs a following address or 'pc'")
sys.exit(10)
imlac_cpu.PC = addr_value
trace.set_trace_map(trace_map)
start_running(imlac_cpu, imlac_memory, imlac_ptrptp, imlac_ttyin)
elif opt == '-s':
if ndx >= len_sys_argv:
usage("'-s' option needs a following data filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
set_mem_from_file(filename)
elif opt == '-t':
if ndx >= len_sys_argv:
usage("'-t' option needs following address ranges or 'off'")
sys.exit(10)
r = sys.argv[ndx]
ndx += 1
trace_map = collections.defaultdict(bool)
if r != 'off':
for rng in r.split(':'):
be = rng.split(',')
if len(be) != 2:
usage("'-t' ranges must have form 'begin,end'")
sys.exit(10)
(begin, end) = be
begin = str2int(begin)
end = str2int(end)
for addr in range(begin, end+1):
trace_map[addr] = True
elif opt == '-ttyin':
if ndx >= len_sys_argv:
usage("'-ttyin' option needs a following data filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
imlac_ttyin.mount(filename)
elif opt == '-ttyout':
if ndx >= len_sys_argv:
usage("'-ttyout' option needs a following data filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
imlac_ttyout.mount(filename)
elif opt == '-v':
if ndx >= len_sys_argv:
usage("'-v' option needs a following address filename")
sys.exit(10)
filename = sys.argv[ndx]
ndx += 1
view_mem(filename)
elif opt == '-w':
if ndx >= len_sys_argv:
usage("'-v' option needs a following 'on' or 'off'")
sys.exit(10)
state = sys.argv[ndx]
ndx += 1
if state == 'on':
state = True
elif state == 'off':
state = False
else:
usage("'-v' option needs a following 'on' or 'off'")
sys.exit(10)
imlac_memory.set_ROM_writable(state)
if __name__ == '__main__':
main()