From bbaf5e8bc613e9cbc92c80e70d0e4c3034d2e6da Mon Sep 17 00:00:00 2001 From: outofmbufs Date: Tue, 8 Apr 2025 22:16:48 -0500 Subject: [PATCH] Fixes #23 RTT/RTI too trusting --- machine.py | 50 +++++++++++++++++++++++++++++--------------------- op000.py | 16 ++++++++++++++-- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/machine.py b/machine.py index 623fc97..492fce6 100644 --- a/machine.py +++ b/machine.py @@ -956,29 +956,13 @@ class PDP1170(PDP11): # could test if necessary but it's just easier to do this every time self._syncregs() # in case any mode/regset changes - # prevent UNDEFINED_MODE from entering the PSW (current mode) - m = (value >> 14) & 3 - if m == self.UNDEFINED_MODE: + d = self._psw2dict(value) + + if self.UNDEFINED_MODE in (d['curmode'], d['prevmode']): raise PDPTraps.ReservedInstruction - self.psw_curmode = m - # prevent UNDEFINED_MODE from entering the PSW (previous mode) - m = (value >> 12) & 3 - if m == self.UNDEFINED_MODE: - raise PDPTraps.ReservedInstruction - self.psw_prevmode = m - - prevregset = self.psw_regset - self.psw_regset = (value >> 11) & 1 - - newpri = (value >> 5) & 7 - self.psw_pri = newpri - - self.psw_trap = (value >> 4) & 1 - self.psw_n = (value >> 3) & 1 - self.psw_z = (value >> 2) & 1 - self.psw_v = (value >> 1) & 1 - self.psw_c = value & 1 + for attr, val in d.items(): + setattr(self, 'psw_' + attr, val) # set up the correct register file and install correct SP self.r = self.registerfiles[self.psw_regset] @@ -986,6 +970,30 @@ class PDP1170(PDP11): # the PC was already sync'd in syncregs() + _pswfields = { + 'curmode': (14, 3), # bits 14:15 + 'prevmode': (12, 3), # bits 12:13 + 'regset': (11, 1), # bit 11 + # 8 9 10 unused + 'pri': (5, 7), # bits: 5:7 + 'trap': (4, 1), + 'n': (3, 1), + 'z': (2, 1), + 'v': (1, 1), + 'c': (0, 1), + } + + def _psw2dict(self, pswval): + return {attr: (pswval >> bi[0]) & bi[1] + for attr, bi in self._pswfields.items()} + + def _dict2psw(self, d): + psw = 0 + for attr, val in d.items(): + shf, mask = self._pswfields[attr] + psw |= (val & mask) << shf + return psw + @property def logging_hack(self): return self.logger.level diff --git a/op000.py b/op000.py index 2e75098..eec3519 100644 --- a/op000.py +++ b/op000.py @@ -48,7 +48,19 @@ def op_wait(cpu, inst): def op_rtt(cpu, inst): cpu.r[cpu.PC] = cpu.stackpop() - cpu.psw = cpu.stackpop() + newpsw_d = cpu._psw2dict(cpu.stackpop()) + + # this knows KERNEL < SUPERVISOR < USER + newpsw_d['curmode'] = max(cpu.psw_curmode, newpsw_d['curmode']) + newpsw_d['prevmode'] = max(cpu.psw_prevmode, newpsw_d['prevmode']) + + # if not in kernel mode, cannot change pri + if cpu.psw_curmode != cpu.KERNEL: + newpsw_d['pri'] = cpu.psw_pri + + # Regset cannot be changed to zero if it is currently 1 + newpsw_d['pri'] |= (cpu.psw_regset | newpsw_d['pri']) + cpu.psw = cpu._dict2psw(newpsw_d) def op_02xx(cpu, inst): @@ -115,7 +127,7 @@ def op000_dispatcher(cpu, inst): if inst == 0: op_halt(cpu, inst) elif inst == 6 or inst == 2: # RTI and RTT are identical!! - op_rtt(cpu, inst) + op_rtt(cpu, inst) # (because trace not implemented) elif inst == 1: op_wait(cpu, inst) elif inst == 3: