OXYGENHUB
# 2980b7b6d7cd enhanced-x16-emulator / src / cpu / modes.h
7.9 KiB · Objective-C · last changed chore(): initial commit 25 days ago source blame history raw
1
/*
2
3
						Extracted from original single fake6502.c file
4
5
*/
6
7
//
8
//          65C02 changes.
9
//
10
//          ind         absolute indirect
11
//
12
//                      A 6502 has a bug whereby if you jmp ($12FF) it reads the address from
13
//                      $12FF and $1200. This has been fixed in the 65C02.
14
//
15
static void imp() { //implied
16
}
17
18
static void imp8() { // brk / cop
19
}
20
21
static void acc() { //accumulator
22
    addressing_is_acc = true;
23
}
24
25
static void imm8() { //immediate, 8bit
26
    ea = addr_with_k(regs.pc++);
27
}
28
29
static void immm() { //immediate, 16bit if M = 0
30
    ea = addr_with_k(regs.pc++);
31
32
    if (memory_16bit()) {
33
        regs.pc++;
34
    }
35
}
36
37
static void immx() { //immediate, 16bit if X = 0
38
    ea = addr_with_k(regs.pc++);
39
40
    if (index_16bit()) {
41
        regs.pc++;
42
    }
43
}
44
45
static void imm16() {
46
    ea = addr_with_k(regs.pc);
47
    regs.pc += 2;
48
}
49
50
static void _zp_with_offset(uint16_t offset) {
51
    uint16_t imm_value = (uint16_t) read6502((uint16_t)regs.pc++, regs.k);
52
53
    if (regs.dp & 0x00FF) {
54
        penaltyd = 1;
55
    }
56
57
    ea = direct_page_add(imm_value + offset);
58
}
59
60
static void _zp_long_with_offset(uint16_t offset) {
61
    uint16_t eahelp;
62
    eahelp = (uint16_t)read6502(regs.pc++, regs.k);
63
64
    ea = (uint32_t)read6502(direct_page_add(eahelp), 0) | ((uint32_t)read6502(direct_page_add(eahelp + 1), 0) << 8) | ((uint32_t)read6502(direct_page_add(eahelp + 2), 0) << 16);
65
    ea = mask_long_addr(ea + offset);
66
67
    if (regs.dp & 0x00FF) {
68
        penaltyd = 1;
69
    }
70
}
71
72
static void zp() { //zero-page
73
    _zp_with_offset(0);
74
}
75
76
static void zpx() { //zero-page,X
77
    _zp_with_offset(regs.x);
78
}
79
80
static void zpy() { //zero-page,Y
81
    _zp_with_offset(regs.y);
82
}
83
84
static void rel() { //relative for branch ops (8-bit immediate value, sign-extended)
85
    reladdr = (uint16_t)read6502(regs.pc++, regs.k);
86
    if (reladdr & 0x80) reladdr |= 0xFF00;
87
}
88
89
static void rel16() { //relative for PER and BRL (16-bit immediate value)
90
    reladdr = (uint16_t)read6502(regs.pc, regs.k) | ((uint16_t)read6502(regs.pc+1, regs.k) << 8);
91
    regs.pc += 2;
92
}
93
94
static void abso() { //absolute
95
    ea = addr_with_db((uint16_t) read6502(regs.pc, regs.k) | ((uint16_t)read6502(regs.pc+1, regs.k) << 8));
96
    regs.pc += 2;
97
}
98
99
static void absl() { // absolute long
100
    ea = (uint32_t) read6502(regs.pc, regs.k) | ((uint32_t)read6502(regs.pc+1, regs.k) << 8) | ((uint32_t)read6502(regs.pc+2, regs.k) << 16);
101
    regs.pc += 3;
102
}
103
104
static void absx() { //absolute,X
105
    uint32_t startpage;
106
    ea = addr_with_db((uint16_t)read6502(regs.pc, regs.k) | ((uint16_t)read6502(regs.pc+1, regs.k) << 8));
107
    startpage = ea & 0xFFFF00;
108
    ea = mask_long_addr(ea + regs.x);
109
110
    // Compared across the whole 24-bit address: indexing that carries into
111
    // the next bank costs the same cycle as crossing a page inside one. With
112
    // 16-bit index registers the cycle is charged whether or not it crosses,
113
    // which is the datasheet's "add 1 cycle for indexing across page
114
    // boundaries, or write, or X=0".
115
    if (index_16bit() || startpage != (ea & 0xFFFF00)) {
116
        penaltyaddr = 1;
117
    }
118
119
    regs.pc += 2;
120
}
121
122
static void abslx() { // absolute long, X
123
    ea = (uint32_t)read6502(regs.pc, regs.k) | ((uint32_t)read6502(regs.pc+1, regs.k) << 8) | ((uint32_t)read6502(regs.pc+2, regs.k) << 16);
124
    ea = mask_long_addr(ea + regs.x);
125
126
    // No page-crossing penalty: a long address already names the bank, so
127
    // indexing across a page costs nothing. Measured flat at five cycles.
128
129
    regs.pc += 3;
130
}
131
132
static void absy() { //absolute,Y
133
    uint32_t startpage;
134
    ea = addr_with_db((uint16_t)read6502(regs.pc, regs.k) | ((uint16_t)read6502(regs.pc+1, regs.k) << 8));
135
    startpage = ea & 0xFFFF00;
136
    ea = mask_long_addr(ea + regs.y);
137
138
    // Compared across the whole 24-bit address: indexing that carries into
139
    // the next bank costs the same cycle as crossing a page inside one. With
140
    // 16-bit index registers the cycle is charged whether or not it crosses,
141
    // which is the datasheet's "add 1 cycle for indexing across page
142
    // boundaries, or write, or X=0".
143
    if (index_16bit() || startpage != (ea & 0xFFFF00)) {
144
        penaltyaddr = 1;
145
    }
146
147
    regs.pc += 2;
148
}
149
150
static void ind() { //indirect - used for jmp, which assumes the pointer is in bank 0!
151
    uint16_t eahelp, eahelp2;
152
    eahelp = (uint16_t)read6502(regs.pc, regs.k) | (uint16_t)((uint16_t)read6502(regs.pc+1, regs.k) << 8);
153
    //
154
    //      The 6502 page boundary wraparound bug does not occur on a 65C02.
155
    //
156
    //eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug
157
    eahelp2 = (eahelp+1) & 0xFFFF;
158
    ea = (uint16_t)read6502(eahelp, 0) | ((uint16_t)read6502(eahelp2, 0) << 8);
159
    regs.pc += 2;
160
}
161
162
static void aindl() { // [addr]    uint16_t eahelp, eahelp2;
163
    uint16_t eahelp, eahelp2;
164
    eahelp = (uint16_t)read6502(regs.pc, regs.k) | (uint16_t)((uint16_t)read6502(regs.pc+1, regs.k) << 8);
165
    eahelp2 = (eahelp+1) & 0xFFFF;
166
    ea = (uint32_t)read6502(eahelp, 0) | ((uint32_t)read6502(eahelp2, 0) << 8) | ((uint16_t)read6502((eahelp2 + 1) & 0xFFFF, 0) << 16);
167
    regs.pc += 2;
168
}
169
170
static void ind0() { // (zp)
171
    uint16_t eahelp;
172
    eahelp = (uint16_t)read6502(regs.pc++, regs.k);
173
    // The pointer lives in the direct page, which is always bank zero. The
174
    // address it holds is in the data bank.
175
    ea = addr_with_db((uint16_t)read6502(direct_page_add(eahelp), 0) | ((uint16_t)read6502(direct_page_add(eahelp + 1), 0) << 8));
176
177
    if (regs.dp & 0x00FF) {
178
        penaltyd = 1;
179
    }
180
}
181
182
static void indl0() { // [dp]
183
    _zp_long_with_offset(0);
184
}
185
186
static void indx() { // (indirect,X)
187
    uint16_t eahelp;
188
    eahelp = (uint16_t)read6502(regs.pc++, regs.k) + regs.x;
189
    ea = addr_with_db((uint16_t)read6502(direct_page_add(eahelp), 0) | ((uint16_t)read6502(direct_page_add(eahelp + 1), 0) << 8));
190
191
    if (regs.dp & 0x00FF) {
192
        penaltyd = 1;
193
    }
194
}
195
196
static void indy() { // (indirect),Y
197
    uint16_t eahelp;
198
    eahelp = (uint16_t)read6502(regs.pc++, regs.k);
199
    uint16_t pointer = (uint16_t)read6502(direct_page_add(eahelp), 0) | ((uint16_t)read6502(direct_page_add(eahelp + 1), 0) << 8);
200
    // Indexing applies to the whole 24-bit address, so carrying past $FFFF
201
    // moves into the next bank rather than wrapping inside this one, and the
202
    // crossing costs the same cycle as one inside a bank.
203
    uint32_t startpage = addr_with_db(pointer) & 0xFFFF00;
204
    ea = mask_long_addr(addr_with_db(pointer) + regs.y);
205
206
    if (regs.dp & 0x00FF) {
207
        penaltyd = 1;
208
    }
209
210
    if (index_16bit() || startpage != (ea & 0xFFFF00)) {
211
        penaltyaddr = 1;
212
    }
213
}
214
215
static void indly() { // [dp],Y
216
    _zp_long_with_offset(regs.y);
217
}
218
219
static void ind0p() { // (zp) used by PEI, which doesn't do wraparound calculations
220
    uint16_t eahelp;
221
    eahelp = (uint16_t)read6502(regs.pc++, regs.k);
222
    ea = (uint16_t)read6502(regs.dp + eahelp, 0) | ((uint16_t)read6502(regs.dp + eahelp + 1, 0) << 8);
223
224
    if (regs.dp & 0x00FF) {
225
        penaltyd = 1;
226
    }
227
}
228
229
static void zprel() { // zero-page, relative for branch ops (8-bit immediatel value, sign-extended) - only used for the 65C02's Rockwell extensions
230
	ea = (uint16_t)read6502(regs.pc, 0);
231
	reladdr = (uint16_t)read6502(regs.pc+1, 0);
232
	if (reladdr & 0x80) reladdr |= 0xFF00;
233
234
	regs.pc += 2;
235
}
236
237
static void sr() { // absolute,S
238
    // Masked to 16 bits: S can put the stack anywhere inside bank zero, but not
239
    // outside it, so an offset running past $FFFF wraps rather than reaching
240
    // bank one.
241
    ea = (uint16_t)(regs.sp + (uint16_t)read6502(regs.pc++, regs.k));
242
}
243
244
static void sridy() { // (indirect,S),Y
245
    uint16_t eahelp;
246
    eahelp = regs.sp + (uint16_t)read6502(regs.pc++, regs.k);
247
    uint16_t pointer = (uint16_t)read6502(eahelp, 0) | ((uint16_t)read6502(eahelp + 1, 0) << 8);
248
    ea = mask_long_addr(addr_with_db(pointer) + (uint16_t)regs.y);
249
250
    // No page-crossing penalty: measured flat at seven cycles.
251
}
252
253
static void bmv() { // block move
254
    uint8_t dest = read6502(regs.pc++, regs.k);
255
    ea = (read6502(regs.pc++, regs.k) << 8) | dest;
256
}