m68000-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- m68000_python/__init__.py +73 -0
- m68000_python/__main__.py +112 -0
- m68000_python/_alu.py +656 -0
- m68000_python/_bcd.py +137 -0
- m68000_python/_bits.py +100 -0
- m68000_python/_control.py +208 -0
- m68000_python/_core.py +545 -0
- m68000_python/_dispatch.py +243 -0
- m68000_python/_ea.py +177 -0
- m68000_python/_flags.py +152 -0
- m68000_python/_loads.py +405 -0
- m68000_python/_shifts.py +168 -0
- m68000_python/_system.py +314 -0
- m68000_python/conformance.py +796 -0
- m68000_python/console.py +254 -0
- m68000_python/cpu.py +373 -0
- m68000_python/debug.py +361 -0
- m68000_python/disasm.py +354 -0
- m68000_python/py.typed +0 -0
- m68000_python/state.py +76 -0
- m68000_python/trace.py +296 -0
- m68000_python-0.1.0.dist-info/METADATA +379 -0
- m68000_python-0.1.0.dist-info/RECORD +25 -0
- m68000_python-0.1.0.dist-info/WHEEL +4 -0
- m68000_python-0.1.0.dist-info/licenses/LICENSE +21 -0
m68000_python/_bcd.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Binary-coded decimal: ABCD, SBCD, NBCD (PRM Table 3-8).
|
|
2
|
+
|
|
3
|
+
PRM Table 3-18 gives X and C (the decimal carry or borrow) and a sticky Z,
|
|
4
|
+
and calls N and V undefined. They are not undefined on silicon, and the
|
|
5
|
+
rule below is the one flamewing's 68k-bcd-verifier checks exhaustively on a
|
|
6
|
+
Model 1 and a Model 3 Sega Genesis (T1; docs/undocumented-behavior.md): the
|
|
7
|
+
byte is first added or subtracted in binary, then corrected by 6 in each
|
|
8
|
+
nibble that produced a binary carry (borrow) or, for an add, a digit above 9;
|
|
9
|
+
N is bit 7 of the corrected byte, and V is set when the correction flipped
|
|
10
|
+
bit 7 -- from 0 to 1 for an add, from 1 to 0 for a subtract. C and X are set
|
|
11
|
+
by a carry (borrow) out of either the binary step or the correction.
|
|
12
|
+
|
|
13
|
+
The three instructions' bus sequences are the microcode's (SST ABCD, SBCD, NBCD; T3): the
|
|
14
|
+
register forms prefetch and then spend two internal clocks; the memory forms
|
|
15
|
+
read, prefetch, then write.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from m68000_python._core import C, N, V, X, Z
|
|
19
|
+
from m68000_python._ea import DN, EA_KIND
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def decimal_add(destination: int, source: int, extend: int) -> tuple[int, int]:
|
|
23
|
+
"""ABCD's result byte and X N Z V C bits (Z to be ANDed in: sticky)."""
|
|
24
|
+
binary = destination + source + extend
|
|
25
|
+
low_carry = (destination & 0xF) + (source & 0xF) + extend > 0xF
|
|
26
|
+
uncorrected = binary & 0xFF
|
|
27
|
+
correction = 0
|
|
28
|
+
if low_carry or (uncorrected & 0xF) > 9:
|
|
29
|
+
correction = 0x06
|
|
30
|
+
if binary > 0xFF or uncorrected > 0x99:
|
|
31
|
+
correction |= 0x60
|
|
32
|
+
corrected = uncorrected + correction
|
|
33
|
+
result = corrected & 0xFF
|
|
34
|
+
flags = Z if result == 0 else 0
|
|
35
|
+
if binary > 0xFF or corrected > 0xFF:
|
|
36
|
+
flags |= X | C
|
|
37
|
+
if result & 0x80:
|
|
38
|
+
flags |= N
|
|
39
|
+
if result & 0x80 and not uncorrected & 0x80:
|
|
40
|
+
flags |= V # the correction carried into bit 7 (T1, flamewing)
|
|
41
|
+
return result, flags
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def decimal_subtract(destination: int, source: int, extend: int) -> tuple[int, int]:
|
|
45
|
+
"""SBCD's (and NBCD's, with destination 0) result byte and X N Z V C bits."""
|
|
46
|
+
binary = destination - source - extend
|
|
47
|
+
low_borrow = (destination & 0xF) - (source & 0xF) - extend < 0
|
|
48
|
+
uncorrected = binary & 0xFF
|
|
49
|
+
correction = 0
|
|
50
|
+
if low_borrow:
|
|
51
|
+
correction = 0x06
|
|
52
|
+
if binary < 0:
|
|
53
|
+
correction |= 0x60
|
|
54
|
+
corrected = uncorrected - correction
|
|
55
|
+
result = corrected & 0xFF
|
|
56
|
+
flags = Z if result == 0 else 0
|
|
57
|
+
if binary < 0 or corrected < 0:
|
|
58
|
+
flags |= X | C
|
|
59
|
+
if result & 0x80:
|
|
60
|
+
flags |= N
|
|
61
|
+
if uncorrected & 0x80 and not result & 0x80:
|
|
62
|
+
flags |= V # the correction borrowed out of bit 7 (T1, flamewing)
|
|
63
|
+
return result, flags
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class BCDMixin:
|
|
67
|
+
"""Private BCD implementation."""
|
|
68
|
+
|
|
69
|
+
def _set_bcd_flags(self, flags: int) -> None:
|
|
70
|
+
# X N V C replaced; Z only ever cleared (PRM Table 3-18, sticky Z).
|
|
71
|
+
sr = self.SR
|
|
72
|
+
self.SR = (sr & 0xFF00) | (flags & (X | N | V | C)) | (sr & flags & Z)
|
|
73
|
+
|
|
74
|
+
def _bcd_pair(self, opcode: int, operation) -> None:
|
|
75
|
+
"""The two forms shared by ABCD and SBCD: Dy,Dx and -(Ay),-(Ax)."""
|
|
76
|
+
rx = (opcode >> 9) & 7
|
|
77
|
+
ry = opcode & 7
|
|
78
|
+
extend = (self.SR >> 4) & 1
|
|
79
|
+
R = self.R
|
|
80
|
+
if not opcode & 8:
|
|
81
|
+
result, flags = operation(R[rx] & 0xFF, R[ry] & 0xFF, extend)
|
|
82
|
+
self._set_bcd_flags(flags)
|
|
83
|
+
self._prefetch()
|
|
84
|
+
self._cycles += 2
|
|
85
|
+
R[rx] = (R[rx] & 0xFFFFFF00) | result
|
|
86
|
+
return
|
|
87
|
+
self._cycles += 2
|
|
88
|
+
self._commit_pc()
|
|
89
|
+
source_address = (R[8 + ry] - self._step_size(ry, 1)) & 0xFFFFFFFF
|
|
90
|
+
R[8 + ry] = source_address
|
|
91
|
+
source = self._read_byte(source_address)
|
|
92
|
+
destination_address = (R[8 + rx] - self._step_size(rx, 1)) & 0xFFFFFFFF
|
|
93
|
+
R[8 + rx] = destination_address
|
|
94
|
+
destination = self._read_byte(destination_address)
|
|
95
|
+
result, flags = operation(destination, source, extend)
|
|
96
|
+
self._set_bcd_flags(flags)
|
|
97
|
+
self._prefetch()
|
|
98
|
+
self._write_byte(destination_address, result)
|
|
99
|
+
|
|
100
|
+
def _op_abcd(self, opcode: int) -> None:
|
|
101
|
+
"""ABCD -- destination <- destination + source + X, decimal (PRM 4-3; UM Table 8-11).
|
|
102
|
+
|
|
103
|
+
N and V, undefined in PRM: flamewing's hardware-captured tables (T1,
|
|
104
|
+
tests/test_bcd.py). Bus order, the 2 idle clocks of the register form and
|
|
105
|
+
the PC an address error stacks: SST ABCD.
|
|
106
|
+
"""
|
|
107
|
+
self._bcd_pair(opcode, decimal_add)
|
|
108
|
+
|
|
109
|
+
def _op_sbcd(self, opcode: int) -> None:
|
|
110
|
+
"""SBCD -- destination <- destination - source - X, decimal (PRM 4-176; UM Table 8-11).
|
|
111
|
+
|
|
112
|
+
N and V: flamewing's tables (T1). Bus order and the PC an address error
|
|
113
|
+
stacks: SST SBCD.
|
|
114
|
+
"""
|
|
115
|
+
self._bcd_pair(opcode, decimal_subtract)
|
|
116
|
+
|
|
117
|
+
def _op_nbcd(self, opcode: int) -> None:
|
|
118
|
+
"""NBCD -- destination <- 0 - destination - X, decimal (PRM 4-142; UM Table 8-6).
|
|
119
|
+
|
|
120
|
+
N and V: flamewing's tables (T1). Bus order and the PC an address error
|
|
121
|
+
stacks: SST NBCD.
|
|
122
|
+
"""
|
|
123
|
+
kind = EA_KIND[opcode & 0x3F]
|
|
124
|
+
register = opcode & 7
|
|
125
|
+
extend = (self.SR >> 4) & 1
|
|
126
|
+
if kind == DN:
|
|
127
|
+
result, flags = decimal_subtract(0, self.R[register] & 0xFF, extend)
|
|
128
|
+
self._set_bcd_flags(flags)
|
|
129
|
+
self._prefetch()
|
|
130
|
+
self._cycles += 2
|
|
131
|
+
self.R[register] = (self.R[register] & 0xFFFFFF00) | result
|
|
132
|
+
return
|
|
133
|
+
address = self._ea_address(kind, register, 1)
|
|
134
|
+
result, flags = decimal_subtract(0, self._read_byte(address), extend)
|
|
135
|
+
self._set_bcd_flags(flags)
|
|
136
|
+
self._prefetch()
|
|
137
|
+
self._write_byte(address, result)
|
m68000_python/_bits.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Bit manipulation: BTST, BCHG, BCLR, BSET (PRM Table 3-6; UM Table 8-8).
|
|
2
|
+
|
|
3
|
+
The bit number comes from Dn (dynamic) or from the word after the opcode
|
|
4
|
+
(static). On a data register the operation is on the whole long and the
|
|
5
|
+
number is taken mod 32; on memory it is on a byte, mod 8 (PRM 4, BTST). Z
|
|
6
|
+
is set if the tested bit was 0; nothing else changes. On a register the
|
|
7
|
+
changing forms cost 2 clocks more for bits 16-31 (UM Table 8-8 note), and
|
|
8
|
+
BCLR 2 more again (SST BCLR, T3).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from m68000_python._core import Z
|
|
12
|
+
from m68000_python._ea import DN, EA_KIND, IMM
|
|
13
|
+
|
|
14
|
+
# The operations, by bits 7-6 of the opcode: test, change, clear, set.
|
|
15
|
+
TEST, CHANGE, CLEAR, SET = range(4)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BitsMixin:
|
|
19
|
+
"""Private bit-manipulation implementation."""
|
|
20
|
+
|
|
21
|
+
def _bit_operation(self, opcode: int, operation: int) -> None:
|
|
22
|
+
if opcode & 0x0100:
|
|
23
|
+
number = self.R[(opcode >> 9) & 7]
|
|
24
|
+
else:
|
|
25
|
+
self._commit_pc()
|
|
26
|
+
number = self._extension() & 0xFF
|
|
27
|
+
kind = EA_KIND[opcode & 0x3F]
|
|
28
|
+
register = opcode & 7
|
|
29
|
+
if kind == DN:
|
|
30
|
+
number &= 31
|
|
31
|
+
value = self.R[register]
|
|
32
|
+
self._set_z(value, number)
|
|
33
|
+
self._prefetch()
|
|
34
|
+
if operation == TEST:
|
|
35
|
+
self._cycles += 2
|
|
36
|
+
return
|
|
37
|
+
self._cycles += 4 if operation == CLEAR else 2
|
|
38
|
+
if number >= 16:
|
|
39
|
+
self._cycles += 2
|
|
40
|
+
self.R[register] = self._apply_bit(value, number, operation)
|
|
41
|
+
return
|
|
42
|
+
number &= 7
|
|
43
|
+
if kind == IMM: # BTST Dn,#data: the operand is the byte after the opcode
|
|
44
|
+
value = self._extension() & 0xFF
|
|
45
|
+
self._set_z(value, number)
|
|
46
|
+
self._prefetch()
|
|
47
|
+
self._cycles += 2
|
|
48
|
+
return
|
|
49
|
+
address, value = self._ea_fetch(kind, register, 1)
|
|
50
|
+
self._set_z(value, number)
|
|
51
|
+
self._prefetch()
|
|
52
|
+
if operation != TEST:
|
|
53
|
+
self._write_byte(address, self._apply_bit(value, number, operation))
|
|
54
|
+
|
|
55
|
+
def _set_z(self, value: int, number: int) -> None:
|
|
56
|
+
if value >> number & 1:
|
|
57
|
+
self.SR &= ~Z
|
|
58
|
+
else:
|
|
59
|
+
self.SR |= Z
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _apply_bit(value: int, number: int, operation: int) -> int:
|
|
63
|
+
bit = 1 << number
|
|
64
|
+
if operation == CHANGE:
|
|
65
|
+
return value ^ bit
|
|
66
|
+
if operation == CLEAR:
|
|
67
|
+
return value & ~bit
|
|
68
|
+
return value | bit
|
|
69
|
+
|
|
70
|
+
def _op_btst(self, opcode: int) -> None:
|
|
71
|
+
"""BTST -- Z <- NOT bit n of the destination (PRM 4-62; UM Table 8-8).
|
|
72
|
+
|
|
73
|
+
Bus order, the 2 idle clocks of the register form, and the PC an address
|
|
74
|
+
error stacks: SST BTST.
|
|
75
|
+
"""
|
|
76
|
+
self._bit_operation(opcode, TEST)
|
|
77
|
+
|
|
78
|
+
def _op_bchg(self, opcode: int) -> None:
|
|
79
|
+
"""BCHG -- Z <- NOT bit n, then invert bit n (PRM 4-28; UM Table 8-8).
|
|
80
|
+
|
|
81
|
+
On a register 6 clocks, 8 for bits 16-31 (UM Table 8-8's note); bus
|
|
82
|
+
order and the PC an address error stacks: SST BCHG.
|
|
83
|
+
"""
|
|
84
|
+
self._bit_operation(opcode, CHANGE)
|
|
85
|
+
|
|
86
|
+
def _op_bclr(self, opcode: int) -> None:
|
|
87
|
+
"""BCLR -- Z <- NOT bit n, then clear bit n (PRM 4-31; UM Table 8-8).
|
|
88
|
+
|
|
89
|
+
On a register 8 clocks, 10 for bits 16-31, 2 more than BCHG and BSET at
|
|
90
|
+
every bit; bus order and the PC an address error stacks: SST BCLR.
|
|
91
|
+
"""
|
|
92
|
+
self._bit_operation(opcode, CLEAR)
|
|
93
|
+
|
|
94
|
+
def _op_bset(self, opcode: int) -> None:
|
|
95
|
+
"""BSET -- Z <- NOT bit n, then set bit n (PRM 4-57; UM Table 8-8).
|
|
96
|
+
|
|
97
|
+
On a register 6 clocks, 8 for bits 16-31; bus order and the PC an
|
|
98
|
+
address error stacks: SST BSET.
|
|
99
|
+
"""
|
|
100
|
+
self._bit_operation(opcode, SET)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Program control: branches, jumps, returns, DBcc, Scc, NOP (PRM Table 3-9).
|
|
2
|
+
|
|
3
|
+
A taken branch or jump throws the prefetch queue away and refills it from
|
|
4
|
+
the target with two program reads (UM Table 8-9, "What prefetch does to
|
|
5
|
+
these numbers" in docs/timing.md). A target at an odd address faults on the
|
|
6
|
+
first of those reads.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from m68000_python._ea import (
|
|
10
|
+
ABSL,
|
|
11
|
+
ABSW,
|
|
12
|
+
DISP,
|
|
13
|
+
DN,
|
|
14
|
+
EA_KIND,
|
|
15
|
+
IND,
|
|
16
|
+
INDEX,
|
|
17
|
+
PCDISP,
|
|
18
|
+
PCINDEX,
|
|
19
|
+
sign_extend_8,
|
|
20
|
+
sign_extend_16,
|
|
21
|
+
word_to_long,
|
|
22
|
+
)
|
|
23
|
+
from m68000_python._flags import CONDITION
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ControlMixin:
|
|
27
|
+
"""Private program-control implementation."""
|
|
28
|
+
|
|
29
|
+
# -- branches (PRM 4, Bcc/BRA/BSR; UM Table 8-9) -------------------------
|
|
30
|
+
|
|
31
|
+
def _branch_target(self, opcode: int) -> int:
|
|
32
|
+
"""The target of a Bcc/BRA/BSR: displacement from the extension word's address.
|
|
33
|
+
|
|
34
|
+
An 8-bit displacement of 0 means a 16-bit one follows; $FF is an
|
|
35
|
+
ordinary -1 on the 68000 (the 68020's long form does not exist;
|
|
36
|
+
corpus issue #4).
|
|
37
|
+
"""
|
|
38
|
+
base = self._pc - 2 # the address of the word after the opcode
|
|
39
|
+
displacement = opcode & 0xFF
|
|
40
|
+
if displacement:
|
|
41
|
+
return (base + sign_extend_8(displacement)) & 0xFFFFFFFF
|
|
42
|
+
return (base + sign_extend_16(self.irc)) & 0xFFFFFFFF
|
|
43
|
+
|
|
44
|
+
def _op_bra(self, opcode: int) -> None:
|
|
45
|
+
"""BRA -- branch always: PC <- PC + d (PRM 4-25; UM Table 8-9: 10 clocks)."""
|
|
46
|
+
self._cycles += 2
|
|
47
|
+
self._jump(self._branch_target(opcode))
|
|
48
|
+
|
|
49
|
+
def _op_bcc(self, opcode: int) -> None:
|
|
50
|
+
"""Bcc -- branch if the condition holds (PRM 4-25; UM Table 8-9).
|
|
51
|
+
|
|
52
|
+
Taken: 10 clocks, two internal then the refill. Not taken with an
|
|
53
|
+
8-bit displacement: 8 clocks; with a 16-bit one, 12, the extra read
|
|
54
|
+
skipping the displacement word.
|
|
55
|
+
"""
|
|
56
|
+
if CONDITION[(opcode >> 8) & 0xF][self.SR & 0xF]:
|
|
57
|
+
self._cycles += 2
|
|
58
|
+
self._jump(self._branch_target(opcode))
|
|
59
|
+
return
|
|
60
|
+
self._cycles += 4
|
|
61
|
+
if not opcode & 0xFF:
|
|
62
|
+
self._extension()
|
|
63
|
+
self._prefetch()
|
|
64
|
+
|
|
65
|
+
def _op_bsr(self, opcode: int) -> None:
|
|
66
|
+
"""BSR -- push the return address, then branch (PRM 4-59; UM Table 8-9: 18 clocks).
|
|
67
|
+
|
|
68
|
+
A fault on the refill stacks the target itself: SST BSR.
|
|
69
|
+
"""
|
|
70
|
+
target = self._branch_target(opcode)
|
|
71
|
+
# The return address is past the displacement word, when there is one.
|
|
72
|
+
returns = self._pc if not opcode & 0xFF else self._pc - 2
|
|
73
|
+
self._cycles += 2
|
|
74
|
+
self._push_long(returns)
|
|
75
|
+
self._fault_pc = target # a fault on the refill stacks the target
|
|
76
|
+
self._jump(target)
|
|
77
|
+
|
|
78
|
+
# -- DBcc and Scc (PRM 4-91, 4-173) ---------------------------------------
|
|
79
|
+
|
|
80
|
+
def _op_dbcc(self, opcode: int) -> None:
|
|
81
|
+
"""DBcc -- if cc is false, decrement Dn.w; branch unless it is -1 (PRM 4-91; UM Table 8-9).
|
|
82
|
+
|
|
83
|
+
UM Table 8-9: condition true 12 clocks; false and branching 10; false
|
|
84
|
+
with the count expired 14.
|
|
85
|
+
|
|
86
|
+
The branch target's word is read before Dn is written, so an odd target
|
|
87
|
+
faults with Dn unchanged and stacks the instruction's address + 4:
|
|
88
|
+
SST DBcc. WinUAE run stacks the target + 2 instead: contested, the core
|
|
89
|
+
follows the gate (docs/claims.md).
|
|
90
|
+
"""
|
|
91
|
+
register = opcode & 7
|
|
92
|
+
if CONDITION[(opcode >> 8) & 0xF][self.SR & 0xF]:
|
|
93
|
+
self._cycles += 4
|
|
94
|
+
self._extension()
|
|
95
|
+
self._prefetch()
|
|
96
|
+
return
|
|
97
|
+
# Condition false: the word at the branch target is read whether or
|
|
98
|
+
# not the count expires, and Dn is written only after that read, so
|
|
99
|
+
# an odd target faults with Dn unchanged.
|
|
100
|
+
self._cycles += 2
|
|
101
|
+
target = (self._pc - 2 + sign_extend_16(self.irc)) & 0xFFFFFFFF
|
|
102
|
+
self._commit_pc()
|
|
103
|
+
count = (self.R[register] - 1) & 0xFFFF
|
|
104
|
+
self.irc = self._read_program_word(target)
|
|
105
|
+
if count != 0xFFFF:
|
|
106
|
+
self._pc = (target + 2) & 0xFFFFFFFF
|
|
107
|
+
else:
|
|
108
|
+
self._extension() # expired: carry on after the displacement word
|
|
109
|
+
self.R[register] = (self.R[register] & 0xFFFF0000) | count
|
|
110
|
+
self._prefetch()
|
|
111
|
+
|
|
112
|
+
def _op_scc(self, opcode: int) -> None:
|
|
113
|
+
"""Scc -- set a byte to $FF if the condition holds, else $00 (PRM 4-173; UM Table 8-6).
|
|
114
|
+
|
|
115
|
+
UM Table 8-6: register 4 clocks false, 6 true; memory 8 plus the EA,
|
|
116
|
+
the operand read before it is written. The read, the refill between it
|
|
117
|
+
and the write, and the PC an address error stacks: SST Scc.
|
|
118
|
+
"""
|
|
119
|
+
value = 0xFF if CONDITION[(opcode >> 8) & 0xF][self.SR & 0xF] else 0
|
|
120
|
+
kind = EA_KIND[opcode & 0x3F]
|
|
121
|
+
register = opcode & 7
|
|
122
|
+
if kind == DN:
|
|
123
|
+
self._prefetch()
|
|
124
|
+
if value:
|
|
125
|
+
self._cycles += 2
|
|
126
|
+
self.R[register] = (self.R[register] & 0xFFFFFF00) | value
|
|
127
|
+
return
|
|
128
|
+
address = self._ea_address(kind, register, 1)
|
|
129
|
+
self._read_byte(address)
|
|
130
|
+
self._prefetch()
|
|
131
|
+
self._write_byte(address, value)
|
|
132
|
+
|
|
133
|
+
# -- jumps and returns ----------------------------------------------------
|
|
134
|
+
|
|
135
|
+
def _control_address(self, kind: int, register: int) -> int:
|
|
136
|
+
"""The address of a control-mode operand, for JMP/JSR/LEA/PEA (UM Table 8-10).
|
|
137
|
+
|
|
138
|
+
Unlike an operand read, these modes do not take the extension word
|
|
139
|
+
from the queue as they go: the refill happens later, as part of the
|
|
140
|
+
jump or the next step. Internal clocks are the table's.
|
|
141
|
+
"""
|
|
142
|
+
R = self.R
|
|
143
|
+
if kind == IND:
|
|
144
|
+
return R[8 + register]
|
|
145
|
+
if kind == DISP:
|
|
146
|
+
return (R[8 + register] + sign_extend_16(self.irc)) & 0xFFFFFFFF
|
|
147
|
+
if kind == INDEX:
|
|
148
|
+
return self._indexed(R[8 + register], self.irc)
|
|
149
|
+
if kind == ABSW:
|
|
150
|
+
return word_to_long(self.irc)
|
|
151
|
+
if kind == ABSL:
|
|
152
|
+
high = self._extension()
|
|
153
|
+
return ((high << 16) | self.irc) & 0xFFFFFFFF
|
|
154
|
+
if kind == PCDISP:
|
|
155
|
+
return (self._pc - 2 + sign_extend_16(self.irc)) & 0xFFFFFFFF
|
|
156
|
+
if kind == PCINDEX:
|
|
157
|
+
return self._indexed(self._pc - 2, self.irc)
|
|
158
|
+
raise AssertionError(f"not a control kind: {kind}")
|
|
159
|
+
|
|
160
|
+
def _op_jmp(self, opcode: int) -> None:
|
|
161
|
+
"""JMP -- PC <- effective address (PRM 4-108; UM Table 8-10)."""
|
|
162
|
+
kind = EA_KIND[opcode & 0x3F]
|
|
163
|
+
target = self._control_address(kind, opcode & 7)
|
|
164
|
+
if kind in (DISP, ABSW, PCDISP):
|
|
165
|
+
self._cycles += 2
|
|
166
|
+
elif kind in (INDEX, PCINDEX):
|
|
167
|
+
self._cycles += 6
|
|
168
|
+
self._jump(target)
|
|
169
|
+
|
|
170
|
+
def _op_jsr(self, opcode: int) -> None:
|
|
171
|
+
"""JSR -- push the return address, PC <- effective address (PRM 4-109; UM Table 8-10).
|
|
172
|
+
|
|
173
|
+
The target's first word is read before the push, so an odd target faults
|
|
174
|
+
with nothing pushed: SST JSR. Through (d16,An), (d8,An,Xn), (d16,PC) and
|
|
175
|
+
(d8,PC,Xn) WinUAE run stacks 2 less than the gate: contested, the core
|
|
176
|
+
follows the gate (docs/claims.md).
|
|
177
|
+
"""
|
|
178
|
+
kind = EA_KIND[opcode & 0x3F]
|
|
179
|
+
target = self._control_address(kind, opcode & 7)
|
|
180
|
+
# The return address is past the extension words.
|
|
181
|
+
returns = self._pc - 2 if kind == IND else self._pc
|
|
182
|
+
if kind in (DISP, ABSW, PCDISP):
|
|
183
|
+
self._cycles += 2
|
|
184
|
+
elif kind in (INDEX, PCINDEX):
|
|
185
|
+
self._cycles += 6
|
|
186
|
+
if kind != IND:
|
|
187
|
+
self._commit_pc()
|
|
188
|
+
# The target's first word is read before the push, so an odd target
|
|
189
|
+
# faults with nothing pushed.
|
|
190
|
+
target &= 0xFFFFFFFF
|
|
191
|
+
self.irc = self._read_program_word(target)
|
|
192
|
+
self._pc = (target + 2) & 0xFFFFFFFF
|
|
193
|
+
self._push_long(returns)
|
|
194
|
+
self._prefetch()
|
|
195
|
+
|
|
196
|
+
def _op_rts(self, opcode: int) -> None:
|
|
197
|
+
"""RTS -- PC <- (SP)+ (PRM 4-169; UM Table 8-12: 16 clocks)."""
|
|
198
|
+
self._jump(self._pop_long())
|
|
199
|
+
|
|
200
|
+
def _op_rtr(self, opcode: int) -> None:
|
|
201
|
+
"""RTR -- CCR <- (SP)+, then PC <- (SP)+ (PRM 4-168; UM Table 8-12: 20 clocks)."""
|
|
202
|
+
ccr = self._pop_word()
|
|
203
|
+
self._set_ccr(ccr)
|
|
204
|
+
self._jump(self._pop_long())
|
|
205
|
+
|
|
206
|
+
def _op_nop(self, opcode: int) -> None:
|
|
207
|
+
"""NOP -- no operation (PRM 4-147; UM Table 8-12: 4 clocks, the prefetch)."""
|
|
208
|
+
self._prefetch()
|