1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | #ifndef _CPUADDR_H_ |
8 | #define _CPUADDR_H_ |
9 | |
10 | typedef enum |
11 | { |
12 | NONE = 0, |
13 | READ = 1, |
14 | WRITE = 2, |
15 | MODIFY = 3, |
16 | JUMP = 5, |
17 | JSR = 8 |
18 | } AccessMode; |
19 | |
20 | static inline uint8 Immediate8Slow (AccessMode a) |
21 | { |
22 | uint8 val = S9xGetByte(Registers.PBPC); |
23 | if (a & READ) |
24 | OpenBus = val; |
25 | Registers.PCw++; |
26 | |
27 | return (val); |
28 | } |
29 | |
30 | static inline uint8 Immediate8 (AccessMode a) |
31 | { |
32 | uint8 val = CPU.PCBase[Registers.PCw]; |
33 | if (a & READ) |
34 | OpenBus = val; |
35 | AddCycles(CPU.MemSpeed); |
36 | Registers.PCw++; |
37 | |
38 | return (val); |
39 | } |
40 | |
41 | static inline uint16 Immediate16Slow (AccessMode a) |
42 | { |
43 | uint16 val = S9xGetWord(Registers.PBPC, WRAP_BANK); |
44 | if (a & READ) |
45 | OpenBus = (uint8) (val >> 8); |
46 | Registers.PCw += 2; |
47 | |
48 | return (val); |
49 | } |
50 | |
51 | static inline uint16 Immediate16 (AccessMode a) |
52 | { |
53 | uint16 val = READ_WORD(CPU.PCBase + Registers.PCw); |
54 | if (a & READ) |
55 | OpenBus = (uint8) (val >> 8); |
56 | AddCycles(CPU.MemSpeedx2); |
57 | Registers.PCw += 2; |
58 | |
59 | return (val); |
60 | } |
61 | |
62 | static inline uint32 RelativeSlow (AccessMode a) // branch $xx |
63 | { |
64 | int8 offset = Immediate8Slow(a); |
65 | |
66 | return ((int16) Registers.PCw + offset) & 0xffff; |
67 | } |
68 | |
69 | static inline uint32 Relative (AccessMode a) // branch $xx |
70 | { |
71 | int8 offset = Immediate8(a); |
72 | |
73 | return ((int16) Registers.PCw + offset) & 0xffff; |
74 | } |
75 | |
76 | static inline uint32 RelativeLongSlow (AccessMode a) // BRL $xxxx |
77 | { |
78 | int16 offset = Immediate16Slow(a); |
79 | |
80 | return ((int32) Registers.PCw + offset) & 0xffff; |
81 | } |
82 | |
83 | static inline uint32 RelativeLong (AccessMode a) // BRL $xxxx |
84 | { |
85 | int16 offset = Immediate16(a); |
86 | |
87 | return ((int32) Registers.PCw + offset) & 0xffff; |
88 | } |
89 | |
90 | static inline uint32 AbsoluteIndexedIndirectSlow (AccessMode a) // (a,X) |
91 | { |
92 | uint16 addr; |
93 | |
94 | if (a & JSR) |
95 | { |
96 | // JSR (a,X) pushes the old address in the middle of loading the new. |
97 | // OpenBus needs to be set to account for this. |
98 | addr = Immediate8Slow(READ); |
99 | if (a == JSR) |
100 | OpenBus = Registers.PCl; |
101 | addr |= Immediate8Slow(READ) << 8; |
102 | } |
103 | else |
104 | addr = Immediate16Slow(READ); |
105 | |
106 | AddCycles(ONE_CYCLE); |
107 | addr += Registers.X.W; |
108 | |
109 | // Address load wraps within the bank |
110 | uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); |
111 | OpenBus = addr2 >> 8; |
112 | |
113 | return (addr2); |
114 | } |
115 | |
116 | static inline uint32 AbsoluteIndexedIndirect (AccessMode a) // (a,X) |
117 | { |
118 | uint16 addr = Immediate16Slow(READ); |
119 | |
120 | AddCycles(ONE_CYCLE); |
121 | addr += Registers.X.W; |
122 | |
123 | // Address load wraps within the bank |
124 | uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); |
125 | OpenBus = addr2 >> 8; |
126 | |
127 | return (addr2); |
128 | } |
129 | |
130 | static inline uint32 AbsoluteIndirectLongSlow (AccessMode a) // [a] |
131 | { |
132 | uint16 addr = Immediate16Slow(READ); |
133 | |
134 | // No info on wrapping, but it doesn't matter anyway due to mirroring |
135 | uint32 addr2 = S9xGetWord(addr); |
136 | OpenBus = addr2 >> 8; |
137 | addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; |
138 | |
139 | return (addr2); |
140 | } |
141 | |
142 | static inline uint32 AbsoluteIndirectLong (AccessMode a) // [a] |
143 | { |
144 | uint16 addr = Immediate16(READ); |
145 | |
146 | // No info on wrapping, but it doesn't matter anyway due to mirroring |
147 | uint32 addr2 = S9xGetWord(addr); |
148 | OpenBus = addr2 >> 8; |
149 | addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; |
150 | |
151 | return (addr2); |
152 | } |
153 | |
154 | static inline uint32 AbsoluteIndirectSlow (AccessMode a) // (a) |
155 | { |
156 | // No info on wrapping, but it doesn't matter anyway due to mirroring |
157 | uint16 addr2 = S9xGetWord(Immediate16Slow(READ)); |
158 | OpenBus = addr2 >> 8; |
159 | |
160 | return (addr2); |
161 | } |
162 | |
163 | static inline uint32 AbsoluteIndirect (AccessMode a) // (a) |
164 | { |
165 | // No info on wrapping, but it doesn't matter anyway due to mirroring |
166 | uint16 addr2 = S9xGetWord(Immediate16(READ)); |
167 | OpenBus = addr2 >> 8; |
168 | |
169 | return (addr2); |
170 | } |
171 | |
172 | static inline uint32 AbsoluteSlow (AccessMode a) // a |
173 | { |
174 | return (ICPU.ShiftedDB | Immediate16Slow(a)); |
175 | } |
176 | |
177 | static inline uint32 Absolute (AccessMode a) // a |
178 | { |
179 | return (ICPU.ShiftedDB | Immediate16(a)); |
180 | } |
181 | |
182 | static inline uint32 AbsoluteLongSlow (AccessMode a) // l |
183 | { |
184 | uint32 addr = Immediate16Slow(READ); |
185 | |
186 | // JSR l pushes the old bank in the middle of loading the new. |
187 | // OpenBus needs to be set to account for this. |
188 | if (a == JSR) |
189 | OpenBus = Registers.PB; |
190 | |
191 | addr |= Immediate8Slow(a) << 16; |
192 | |
193 | return (addr); |
194 | } |
195 | |
196 | static inline uint32 AbsoluteLong (AccessMode a) // l |
197 | { |
198 | uint32 addr = READ_3WORD(CPU.PCBase + Registers.PCw); |
199 | AddCycles(CPU.MemSpeedx2 + CPU.MemSpeed); |
200 | if (a & READ) |
201 | OpenBus = addr >> 16; |
202 | Registers.PCw += 3; |
203 | |
204 | return (addr); |
205 | } |
206 | |
207 | static inline uint32 DirectSlow (AccessMode a) // d |
208 | { |
209 | uint16 addr = Immediate8Slow(a) + Registers.D.W; |
210 | if (Registers.DL != 0) |
211 | AddCycles(ONE_CYCLE); |
212 | |
213 | return (addr); |
214 | } |
215 | |
216 | static inline uint32 Direct (AccessMode a) // d |
217 | { |
218 | uint16 addr = Immediate8(a) + Registers.D.W; |
219 | if (Registers.DL != 0) |
220 | AddCycles(ONE_CYCLE); |
221 | |
222 | return (addr); |
223 | } |
224 | |
225 | static inline uint32 DirectIndirectSlow (AccessMode a) // (d) |
226 | { |
227 | uint32 addr = S9xGetWord(DirectSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE); |
228 | if (a & READ) |
229 | OpenBus = (uint8) (addr >> 8); |
230 | addr |= ICPU.ShiftedDB; |
231 | |
232 | return (addr); |
233 | } |
234 | |
235 | static inline uint32 DirectIndirectE0 (AccessMode a) // (d) |
236 | { |
237 | uint32 addr = S9xGetWord(Direct(READ)); |
238 | if (a & READ) |
239 | OpenBus = (uint8) (addr >> 8); |
240 | addr |= ICPU.ShiftedDB; |
241 | |
242 | return (addr); |
243 | } |
244 | |
245 | static inline uint32 DirectIndirectE1 (AccessMode a) // (d) |
246 | { |
247 | uint32 addr = S9xGetWord(DirectSlow(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE); |
248 | if (a & READ) |
249 | OpenBus = (uint8) (addr >> 8); |
250 | addr |= ICPU.ShiftedDB; |
251 | |
252 | return (addr); |
253 | } |
254 | |
255 | static inline uint32 DirectIndirectIndexedSlow (AccessMode a) // (d),Y |
256 | { |
257 | uint32 addr = DirectIndirectSlow(a); |
258 | if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100) |
259 | AddCycles(ONE_CYCLE); |
260 | |
261 | return (addr + Registers.Y.W); |
262 | } |
263 | |
264 | static inline uint32 DirectIndirectIndexedE0X0 (AccessMode a) // (d),Y |
265 | { |
266 | uint32 addr = DirectIndirectE0(a); |
267 | AddCycles(ONE_CYCLE); |
268 | |
269 | return (addr + Registers.Y.W); |
270 | } |
271 | |
272 | static inline uint32 DirectIndirectIndexedE0X1 (AccessMode a) // (d),Y |
273 | { |
274 | uint32 addr = DirectIndirectE0(a); |
275 | if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) |
276 | AddCycles(ONE_CYCLE); |
277 | |
278 | return (addr + Registers.Y.W); |
279 | } |
280 | |
281 | static inline uint32 DirectIndirectIndexedE1 (AccessMode a) // (d),Y |
282 | { |
283 | uint32 addr = DirectIndirectE1(a); |
284 | if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) |
285 | AddCycles(ONE_CYCLE); |
286 | |
287 | return (addr + Registers.Y.W); |
288 | } |
289 | |
290 | static inline uint32 DirectIndirectLongSlow (AccessMode a) // [d] |
291 | { |
292 | uint16 addr = DirectSlow(READ); |
293 | uint32 addr2 = S9xGetWord(addr); |
294 | OpenBus = addr2 >> 8; |
295 | addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; |
296 | |
297 | return (addr2); |
298 | } |
299 | |
300 | static inline uint32 DirectIndirectLong (AccessMode a) // [d] |
301 | { |
302 | uint16 addr = Direct(READ); |
303 | uint32 addr2 = S9xGetWord(addr); |
304 | OpenBus = addr2 >> 8; |
305 | addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; |
306 | |
307 | return (addr2); |
308 | } |
309 | |
310 | static inline uint32 DirectIndirectIndexedLongSlow (AccessMode a) // [d],Y |
311 | { |
312 | return (DirectIndirectLongSlow(a) + Registers.Y.W); |
313 | } |
314 | |
315 | static inline uint32 DirectIndirectIndexedLong (AccessMode a) // [d],Y |
316 | { |
317 | return (DirectIndirectLong(a) + Registers.Y.W); |
318 | } |
319 | |
320 | static inline uint32 DirectIndexedXSlow (AccessMode a) // d,X |
321 | { |
322 | pair addr; |
323 | addr.W = DirectSlow(a); |
324 | if (!CheckEmulation() || Registers.DL) |
325 | addr.W += Registers.X.W; |
326 | else |
327 | addr.B.l += Registers.XL; |
328 | |
329 | AddCycles(ONE_CYCLE); |
330 | |
331 | return (addr.W); |
332 | } |
333 | |
334 | static inline uint32 DirectIndexedXE0 (AccessMode a) // d,X |
335 | { |
336 | uint16 addr = Direct(a) + Registers.X.W; |
337 | AddCycles(ONE_CYCLE); |
338 | |
339 | return (addr); |
340 | } |
341 | |
342 | static inline uint32 DirectIndexedXE1 (AccessMode a) // d,X |
343 | { |
344 | if (Registers.DL) |
345 | return (DirectIndexedXE0(a)); |
346 | else |
347 | { |
348 | pair addr; |
349 | addr.W = Direct(a); |
350 | addr.B.l += Registers.XL; |
351 | AddCycles(ONE_CYCLE); |
352 | |
353 | return (addr.W); |
354 | } |
355 | } |
356 | |
357 | static inline uint32 DirectIndexedYSlow (AccessMode a) // d,Y |
358 | { |
359 | pair addr; |
360 | addr.W = DirectSlow(a); |
361 | if (!CheckEmulation() || Registers.DL) |
362 | addr.W += Registers.Y.W; |
363 | else |
364 | addr.B.l += Registers.YL; |
365 | |
366 | AddCycles(ONE_CYCLE); |
367 | |
368 | return (addr.W); |
369 | } |
370 | |
371 | static inline uint32 DirectIndexedYE0 (AccessMode a) // d,Y |
372 | { |
373 | uint16 addr = Direct(a) + Registers.Y.W; |
374 | AddCycles(ONE_CYCLE); |
375 | |
376 | return (addr); |
377 | } |
378 | |
379 | static inline uint32 DirectIndexedYE1 (AccessMode a) // d,Y |
380 | { |
381 | if (Registers.DL) |
382 | return (DirectIndexedYE0(a)); |
383 | else |
384 | { |
385 | pair addr; |
386 | addr.W = Direct(a); |
387 | addr.B.l += Registers.YL; |
388 | AddCycles(ONE_CYCLE); |
389 | |
390 | return (addr.W); |
391 | } |
392 | } |
393 | |
394 | static inline uint32 DirectIndexedIndirectSlow (AccessMode a) // (d,X) |
395 | { |
396 | uint32 addr = S9xGetWord(DirectIndexedXSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE); |
397 | if (a & READ) |
398 | OpenBus = (uint8) (addr >> 8); |
399 | |
400 | return (ICPU.ShiftedDB | addr); |
401 | } |
402 | |
403 | static inline uint32 DirectIndexedIndirectE0 (AccessMode a) // (d,X) |
404 | { |
405 | uint32 addr = S9xGetWord(DirectIndexedXE0(READ)); |
406 | if (a & READ) |
407 | OpenBus = (uint8) (addr >> 8); |
408 | |
409 | return (ICPU.ShiftedDB | addr); |
410 | } |
411 | |
412 | static inline uint32 DirectIndexedIndirectE1 (AccessMode a) // (d,X) |
413 | { |
414 | uint32 addr = S9xGetWord(DirectIndexedXE1(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE); |
415 | if (a & READ) |
416 | OpenBus = (uint8) (addr >> 8); |
417 | |
418 | return (ICPU.ShiftedDB | addr); |
419 | } |
420 | |
421 | static inline uint32 AbsoluteIndexedXSlow (AccessMode a) // a,X |
422 | { |
423 | uint32 addr = AbsoluteSlow(a); |
424 | if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.XL >= 0x100) |
425 | AddCycles(ONE_CYCLE); |
426 | |
427 | return (addr + Registers.X.W); |
428 | } |
429 | |
430 | static inline uint32 AbsoluteIndexedXX0 (AccessMode a) // a,X |
431 | { |
432 | uint32 addr = Absolute(a); |
433 | AddCycles(ONE_CYCLE); |
434 | |
435 | return (addr + Registers.X.W); |
436 | } |
437 | |
438 | static inline uint32 AbsoluteIndexedXX1 (AccessMode a) // a,X |
439 | { |
440 | uint32 addr = Absolute(a); |
441 | if (a & WRITE || (addr & 0xff) + Registers.XL >= 0x100) |
442 | AddCycles(ONE_CYCLE); |
443 | |
444 | return (addr + Registers.X.W); |
445 | } |
446 | |
447 | static inline uint32 AbsoluteIndexedYSlow (AccessMode a) // a,Y |
448 | { |
449 | uint32 addr = AbsoluteSlow(a); |
450 | if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100) |
451 | AddCycles(ONE_CYCLE); |
452 | |
453 | return (addr + Registers.Y.W); |
454 | } |
455 | |
456 | static inline uint32 AbsoluteIndexedYX0 (AccessMode a) // a,Y |
457 | { |
458 | uint32 addr = Absolute(a); |
459 | AddCycles(ONE_CYCLE); |
460 | |
461 | return (addr + Registers.Y.W); |
462 | } |
463 | |
464 | static inline uint32 AbsoluteIndexedYX1 (AccessMode a) // a,Y |
465 | { |
466 | uint32 addr = Absolute(a); |
467 | if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) |
468 | AddCycles(ONE_CYCLE); |
469 | |
470 | return (addr + Registers.Y.W); |
471 | } |
472 | |
473 | static inline uint32 AbsoluteLongIndexedXSlow (AccessMode a) // l,X |
474 | { |
475 | return (AbsoluteLongSlow(a) + Registers.X.W); |
476 | } |
477 | |
478 | static inline uint32 AbsoluteLongIndexedX (AccessMode a) // l,X |
479 | { |
480 | return (AbsoluteLong(a) + Registers.X.W); |
481 | } |
482 | |
483 | static inline uint32 StackRelativeSlow (AccessMode a) // d,S |
484 | { |
485 | uint16 addr = Immediate8Slow(a) + Registers.S.W; |
486 | AddCycles(ONE_CYCLE); |
487 | |
488 | return (addr); |
489 | } |
490 | |
491 | static inline uint32 StackRelative (AccessMode a) // d,S |
492 | { |
493 | uint16 addr = Immediate8(a) + Registers.S.W; |
494 | AddCycles(ONE_CYCLE); |
495 | |
496 | return (addr); |
497 | } |
498 | |
499 | static inline uint32 StackRelativeIndirectIndexedSlow (AccessMode a) // (d,S),Y |
500 | { |
501 | uint32 addr = S9xGetWord(StackRelativeSlow(READ)); |
502 | if (a & READ) |
503 | OpenBus = (uint8) (addr >> 8); |
504 | addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff; |
505 | AddCycles(ONE_CYCLE); |
506 | |
507 | return (addr); |
508 | } |
509 | |
510 | static inline uint32 StackRelativeIndirectIndexed (AccessMode a) // (d,S),Y |
511 | { |
512 | uint32 addr = S9xGetWord(StackRelative(READ)); |
513 | if (a & READ) |
514 | OpenBus = (uint8) (addr >> 8); |
515 | addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff; |
516 | AddCycles(ONE_CYCLE); |
517 | |
518 | return (addr); |
519 | } |
520 | |
521 | #endif |
522 | |