enhance breakpoints with xinfo and remove instruction logging because can be done with breakpoints
This commit is contained in:
parent
eaa9b1d01c
commit
c7fe81b551
1 changed files with 15 additions and 35 deletions
50
machine.py
50
machine.py
|
@ -27,7 +27,7 @@ from types import SimpleNamespace
|
||||||
from pdptraps import PDPTrap, PDPTraps
|
from pdptraps import PDPTrap, PDPTraps
|
||||||
from mmu import MemoryMgmt
|
from mmu import MemoryMgmt
|
||||||
from unibus import UNIBUS, UNIBUS_1170
|
from unibus import UNIBUS, UNIBUS_1170
|
||||||
from breakpoints import StepsBreakpoint, PCBreakpoint
|
from breakpoints import StepsBreakpoint, PCBreakpoint, XInfo
|
||||||
|
|
||||||
from op4 import op4_dispatch_table
|
from op4 import op4_dispatch_table
|
||||||
|
|
||||||
|
@ -185,8 +185,7 @@ class PDP11:
|
||||||
def __init__(self, *,
|
def __init__(self, *,
|
||||||
physmem=None, # default will be 512KB
|
physmem=None, # default will be 512KB
|
||||||
unibus=None, # subclasses may want to supply variant
|
unibus=None, # subclasses may want to supply variant
|
||||||
logger="pdp11", loglevel='INFO',
|
logger="pdp11", loglevel='WARNING'):
|
||||||
instlog=False, pswlog=False):
|
|
||||||
|
|
||||||
# logging is enabled by default and will go to
|
# logging is enabled by default and will go to
|
||||||
# a file logger + ".log" (i.e., "pdp11.log" by default).
|
# a file logger + ".log" (i.e., "pdp11.log" by default).
|
||||||
|
@ -214,11 +213,6 @@ class PDP11:
|
||||||
|
|
||||||
self.logger.info(f"{self.__class__.__name__} started;"
|
self.logger.info(f"{self.__class__.__name__} started;"
|
||||||
f" Logging level={logging.getLevelName(loglevel)}.")
|
f" Logging level={logging.getLevelName(loglevel)}.")
|
||||||
# instruction logging and/or PSW logging - HUGE LOGS but
|
|
||||||
# sometimes helpful. Often the best way to use this is to insert
|
|
||||||
# custom code into the run loop to trigger these as desired.
|
|
||||||
self.instlog = instlog
|
|
||||||
self.pswlog = pswlog
|
|
||||||
|
|
||||||
self.ub = unibus(self) if unibus else UNIBUS(self)
|
self.ub = unibus(self) if unibus else UNIBUS(self)
|
||||||
self.mmu = MemoryMgmt(self)
|
self.mmu = MemoryMgmt(self)
|
||||||
|
@ -543,7 +537,7 @@ class PDP11:
|
||||||
bpt = PCBreakpoint(stoppc=stoppc, stopmode=stopmode)
|
bpt = PCBreakpoint(stoppc=stoppc, stopmode=stopmode)
|
||||||
return self.run(*args, breakpoint=bpt, **kwargs)
|
return self.run(*args, breakpoint=bpt, **kwargs)
|
||||||
|
|
||||||
def run(self, *, pc=None, loglevel=None, breakpoint=None):
|
def run(self, *, pc=None, breakpoint=None):
|
||||||
"""Run the machine for a number of steps (instructions).
|
"""Run the machine for a number of steps (instructions).
|
||||||
|
|
||||||
If steps is None (default), the machine runs until a HALT instruction
|
If steps is None (default), the machine runs until a HALT instruction
|
||||||
|
@ -553,11 +547,11 @@ class PDP11:
|
||||||
|
|
||||||
If pc is None (default) execution begins at the current pc; otherwise
|
If pc is None (default) execution begins at the current pc; otherwise
|
||||||
the pc is set to the given value first.
|
the pc is set to the given value first.
|
||||||
"""
|
|
||||||
|
|
||||||
if loglevel is not None:
|
If breakpoint is not None (default), it is expected to be a callable.
|
||||||
loglevel = logging.getLevelNamesMapping().get(loglevel, loglevel)
|
It will be invoked after every instruction and if it returns True
|
||||||
self.logger.setLevel(loglevel)
|
then a breakpoint will occur (the run() method returns).
|
||||||
|
"""
|
||||||
|
|
||||||
if pc is not None:
|
if pc is not None:
|
||||||
self.r[self.PC] = pc
|
self.r[self.PC] = pc
|
||||||
|
@ -570,7 +564,7 @@ class PDP11:
|
||||||
self.halted = False
|
self.halted = False
|
||||||
|
|
||||||
# NOTE WELL: everything in this loop is per-instruction overhead
|
# NOTE WELL: everything in this loop is per-instruction overhead
|
||||||
while not self.halted: # stop_here function will also break
|
while not self.halted:
|
||||||
|
|
||||||
# SUBTLETY: Trap handlers expect the PC to be 2 beyond the
|
# SUBTLETY: Trap handlers expect the PC to be 2 beyond the
|
||||||
# instruction causing the trap. Hence "+2 then execute"
|
# instruction causing the trap. Hence "+2 then execute"
|
||||||
|
@ -579,11 +573,10 @@ class PDP11:
|
||||||
|
|
||||||
mmu.MMR1_staged = 0 # see discussion in go_trap
|
mmu.MMR1_staged = 0 # see discussion in go_trap
|
||||||
mmu.MMR2 = thisPC # per handbook
|
mmu.MMR2 = thisPC # per handbook
|
||||||
|
inst = None # so bkpt can know if wordRW faulted
|
||||||
|
|
||||||
try:
|
try:
|
||||||
inst = mmu.wordRW(thisPC)
|
inst = mmu.wordRW(thisPC)
|
||||||
if self.instlog:
|
|
||||||
self.instlogging(inst, thisPC)
|
|
||||||
op4_dispatch_table[inst >> 12](self, inst)
|
op4_dispatch_table[inst >> 12](self, inst)
|
||||||
except PDPTrap as trap:
|
except PDPTrap as trap:
|
||||||
abort_trap = trap
|
abort_trap = trap
|
||||||
|
@ -595,13 +588,15 @@ class PDP11:
|
||||||
elif interrupt_mgr.pri_pending > self.psw_pri:
|
elif interrupt_mgr.pri_pending > self.psw_pri:
|
||||||
self.go_trap(interrupt_mgr.get_pending(self.psw_pri))
|
self.go_trap(interrupt_mgr.get_pending(self.psw_pri))
|
||||||
|
|
||||||
if breakpoint and breakpoint(self):
|
if breakpoint and breakpoint(self, XInfo(thisPC, inst)):
|
||||||
break
|
break
|
||||||
|
|
||||||
# fall through to here if self.halted or a stop_here condition
|
# fall through to here if self.halted or breakpoont
|
||||||
# log halts (stop_here was already logged)
|
|
||||||
if self.halted:
|
if self.halted:
|
||||||
self.logger.debug(f".run HALTED: {self.machinestate()}")
|
reason = ".run -- HALTED: {}"
|
||||||
|
else:
|
||||||
|
reason = ".run -- breakpoint: {}"
|
||||||
|
self.logger.info(reason.format(self.machinestate()))
|
||||||
|
|
||||||
def redyellowcheck(self):
|
def redyellowcheck(self):
|
||||||
"""stack limits: possibly sets YELLOW straps, or go RED."""
|
"""stack limits: possibly sets YELLOW straps, or go RED."""
|
||||||
|
@ -726,17 +721,6 @@ class PDP11:
|
||||||
# alrighty then, can finally jump to the PC from the vector
|
# alrighty then, can finally jump to the PC from the vector
|
||||||
self.r[self.PC] = newpc
|
self.r[self.PC] = newpc
|
||||||
|
|
||||||
# This is called when the run loop wants to log an instruction.
|
|
||||||
# Pulled out so can be overridden for specific debugging sceanrios.
|
|
||||||
def instlogging(self, inst, pc):
|
|
||||||
try:
|
|
||||||
logit = self.instlog(self, inst, pc)
|
|
||||||
except TypeError:
|
|
||||||
logit = True
|
|
||||||
if logit:
|
|
||||||
m = "KS!U"[self.psw_curmode]
|
|
||||||
self.logger.debug(f"{oct(pc)}/{m} :: {oct(inst)}")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swleds(self):
|
def swleds(self):
|
||||||
return 0 # no switches implementation, yet
|
return 0 # no switches implementation, yet
|
||||||
|
@ -962,10 +946,6 @@ class PDP1170(PDP11):
|
||||||
self.psw_regset = (value >> 11) & 1
|
self.psw_regset = (value >> 11) & 1
|
||||||
|
|
||||||
newpri = (value >> 5) & 7
|
newpri = (value >> 5) & 7
|
||||||
if self.pswlog and newpri != self.psw_pri:
|
|
||||||
self.logger.debug(f"PSW pri change: {self.spsw()} -> "
|
|
||||||
f"{self.spsw(value)}")
|
|
||||||
|
|
||||||
self.psw_pri = newpri
|
self.psw_pri = newpri
|
||||||
|
|
||||||
self.psw_trap = (value >> 4) & 1
|
self.psw_trap = (value >> 4) & 1
|
||||||
|
|
Loading…
Add table
Reference in a new issue