diff --git a/emulator/firmware-decomp/emu860.py b/emulator/firmware-decomp/emu860.py index 0a8c501..c822800 100644 --- a/emulator/firmware-decomp/emu860.py +++ b/emulator/firmware-decomp/emu860.py @@ -126,6 +126,7 @@ class I860: self.stop = False self.stopmsg = '' self._branch = None # (target, delayed?) + self._squash = False # annul the next delay slot (bc.t/bnc.t not taken) self.tailn = 60 # ring buffer of last-N executed self.tail = [] self.stopat = set() # halt when pc first reaches one of these @@ -211,6 +212,7 @@ class I860: self.log(f"{pc:#010x}: {w:08x} {m:<10} {ops}") dim_at_fetch = self._dim # DIM-ness of a branch's slot is fixed at self._branch = None # fetch (pair membership), not post-exec + self._squash = False # cleared each fetch; set by a not-taken .t self.execute(w, pc) self.steps += 1 self._dim_track(w, pc) @@ -241,6 +243,14 @@ class I860: else: self.pc = target self._dim_half = 0 + elif self._squash: + # bc.t / bnc.t NOT taken: the i860 annuls the delay-slot instruction + # (whole next PAIR in DIM). Skip it -- executing it corrupts loops whose + # exit relies on the slot NOT running (e.g. the registry tail-find walk, + # which only chains -- and only breaks -- above 512 live objects). + nslots = 2 if dim_at_fetch else 1 + self._squash = False + self.pc = pc + 4 + nslots * 4 else: self.pc = pc + 4 return not self.stop @@ -371,11 +381,17 @@ class I860: self.wr(1, pc + 8); self.branch(pc + 4 + s26(w & 0x03ffffff) * 4); return if op in (0x1c, 0x1d): # bc / bc.t (branch if CC) tgt = pc + 4 + s26(w & 0x03ffffff) * 4 - if self.cc(): self.branch(tgt, delayed=(op == 0x1d)) + if self.cc(): + self.branch(tgt, delayed=(op == 0x1d)) + elif op == 0x1d: # bc.t not taken: i860 ANNULS the delay slot + self._squash = True return if op in (0x1e, 0x1f): # bnc / bnc.t (branch if !CC) tgt = pc + 4 + s26(w & 0x03ffffff) * 4 - if not self.cc(): self.branch(tgt, delayed=(op == 0x1f)) + if not self.cc(): + self.branch(tgt, delayed=(op == 0x1f)) + elif op == 0x1f: # bnc.t not taken: i860 ANNULS the delay slot + self._squash = True return if op in (0x14, 0x15, 0x16, 0x17): # btne / bte (compare & branch) broff = s16(((dest << 11) | (w & 0x7ff)) & 0xffff)