mirror of
https://github.com/rzzzwilson/pymlac.git
synced 2025-06-10 09:32:41 +00:00
209 lines
4.7 KiB
Python
209 lines
4.7 KiB
Python
"""
|
|
The Imlac trace stuff.
|
|
|
|
Simple usage:
|
|
import Trace
|
|
Trace.init('my_log.log', maincpu, dispcpu)
|
|
Trace.set_trace_map(map)
|
|
while running:
|
|
Trace.start()
|
|
Trace.itrace(inst_str)
|
|
Trace.dtrace(inst_str)
|
|
Trace.end()
|
|
|
|
The idea is that trace system will handle formatting and writing trace data to
|
|
the trace file and the "main" code will perform the above steps. The
|
|
.endtrace() method will grab the register values after the instructions and
|
|
format the trace data and write it to the file.
|
|
"""
|
|
|
|
import os
|
|
import collections
|
|
|
|
from Globals import *
|
|
|
|
import log
|
|
log = log.Log('test.log', log.Log.DEBUG)
|
|
|
|
|
|
Tracing = False
|
|
TrafeFilename = None
|
|
TraceFile = None
|
|
CPU = None
|
|
DCPU = None
|
|
TraceMap = collections.defaultdict(bool)
|
|
CPUInst = ''
|
|
DCPUInst = ''
|
|
CPU_PC = None
|
|
DCPU_PC = None
|
|
|
|
|
|
def init(filename, maincpu=None, displaycpu=None):
|
|
"""Initialize the trace:
|
|
|
|
filename name of the trace file
|
|
maincpu the main CPU object (may be added later)
|
|
displaycpu the display CPU object (may be added later)
|
|
"""
|
|
|
|
global Tracing, TraceFile, TraceFilename, TraceMap
|
|
global CPU, DCPU, CPUInst, DCPUInst
|
|
|
|
# set internal state
|
|
Tracing = True
|
|
TraceFilename = filename
|
|
try:
|
|
os.remove(filename)
|
|
except:
|
|
pass
|
|
TraceFile = open(filename, 'w')
|
|
TraceFile.write(f"{PYMLAC_VERSION} trace\n{'-'*97}\n")
|
|
|
|
CPU = maincpu
|
|
DCPU = displaycpu
|
|
|
|
def start():
|
|
"""Prepare trace system for new execution."""
|
|
|
|
global CPU_PC, DCPU_PC, CPUInst, DCPUInst
|
|
|
|
CPUInst = ''
|
|
DCPUInst = ''
|
|
CPU_PC = CPU.PC
|
|
DCPU_PC = DCPU.DPC
|
|
|
|
def set_TraceMap(trace_map):
|
|
"""Set the trace address dict mapping."""
|
|
|
|
global TraceMap
|
|
|
|
TraceMap = trace_map
|
|
log(f'Trace.set_TraceMap: TraceMap={TraceMap}')
|
|
|
|
def add_CPU(maincpu):
|
|
"""Add the main CPU object."""
|
|
|
|
global CPU
|
|
|
|
CPU = maincpu
|
|
|
|
def add_DCPU(dispcpu):
|
|
"""Add the display CPU object."""
|
|
|
|
global DCPU
|
|
DCPU = dispcpu
|
|
|
|
def close():
|
|
"""Close trace."""
|
|
|
|
global TraceFile, Tracing
|
|
|
|
# TraceFile.close()
|
|
TraceFile = None
|
|
Tracing = False
|
|
|
|
#def deimtrace(opcode, code):
|
|
# """Trace the DEIM instruction.
|
|
#
|
|
# opcode DEIM opcode
|
|
# code the operation
|
|
# """
|
|
#
|
|
# log(f"deimtrace: Tracing={Tracing}, writing '{opcode} {code}'")
|
|
# if Tracing:
|
|
# TraceFile.write('%s %s\t' % (opcode, code))
|
|
# TraceFile.flush()
|
|
|
|
def dtrace(ddot, opcode, address=None):
|
|
"""Trace the display CPU.
|
|
|
|
ddot address of instruction being traced
|
|
opcode display opcode
|
|
address address for the opcode
|
|
|
|
Places the final trace string into DCPUInst.
|
|
"""
|
|
|
|
global DCPUInst
|
|
|
|
log(f'Trace.dtrace: ddot={ddot}, opcode={opcode}, address={address}')
|
|
|
|
# convert an int address to a string
|
|
if isinstance(address, int):
|
|
address = f'{address:05o}'
|
|
|
|
if Tracing:
|
|
if address is None:
|
|
DCPUInst = '%04o %s' % (ddot, opcode)
|
|
else:
|
|
DCPUInst = '%04o %s %s' % (ddot, opcode, address)
|
|
|
|
log(f"dtrace: DCPUInst='{DCPUInst}'")
|
|
|
|
def itrace(dot, opcode, indirect=False, address=None):
|
|
"""Main CPU trace.
|
|
|
|
dot address of instruction being traced
|
|
opcode the main CPU opcode
|
|
indirect True if instruction was indirect
|
|
address address for the instruction (if any)
|
|
|
|
Places the final trace string in CPUInst.
|
|
"""
|
|
|
|
global CPUInst
|
|
|
|
log(f'itrace: dot={dot}, opcode={opcode}, indirect={indirect}, address={address}')
|
|
log(f'itrace: Tracing={Tracing}, TraceMap[dot]={TraceMap[dot]}')
|
|
|
|
if Tracing and TraceMap[dot]:
|
|
char = '*' if indirect else ''
|
|
if address is None:
|
|
CPUInst = '%04o %s %s' % (dot, opcode, char)
|
|
else:
|
|
CPUInst = '%04o %s %s%5.5o' % (dot, opcode, char, address)
|
|
|
|
log(f"itrace: CPUInst='{CPUInst}'")
|
|
|
|
#def itraceend(dispon):
|
|
# """Trace at the end of one execution cycle.
|
|
#
|
|
# dispon True if the display was on
|
|
#
|
|
# Places the final trace string in DCPUInst.
|
|
# """
|
|
#
|
|
# global DCPUInst
|
|
#
|
|
# DCPUInst = f'L={CPU.L:1.1o} AC={CPU.AC:6.6oi} PC={CPU.PC:6.6o}'
|
|
#
|
|
# if dispon:
|
|
# DCPUInst += ' DX=%5.5o DY=%5.5o' % (DCPU.DX, DCPU.DY)
|
|
|
|
def end_line():
|
|
"""Write the line for this set of I/D instructions."""
|
|
|
|
registers = f'L={CPU.L:1o} AC={CPU.AC:6o} PC={CPU.PC:6o}'
|
|
|
|
if DCPU.Running:
|
|
registers += f' DX={DCPU.DX:5o} DY={DCPU.DY:5o}'
|
|
|
|
TraceFile.write('%-25s %-30s%s\n' % (CPUInst, DCPUInst, registers))
|
|
|
|
def flush():
|
|
TraceFile.flush()
|
|
|
|
def comment(msg):
|
|
"""Write a line to the trace file."""
|
|
|
|
TraceFile.write(msg + '\n')
|
|
TraceFile.flush()
|
|
|
|
def settrace(new_tracing):
|
|
"""Set the trace ON or OFF."""
|
|
|
|
global Tracing
|
|
|
|
Tracing = new_tracing
|
|
log(f'Trace.settrace: Tracing={Tracing}')
|