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
10typedef enum
11{
12 NONE = 0,
13 READ = 1,
14 WRITE = 2,
15 MODIFY = 3,
16 JUMP = 5,
17 JSR = 8
18} AccessMode;
19
20static 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
30static 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
41static 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
51static 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
62static inline uint32 RelativeSlow (AccessMode a) // branch $xx
63{
64 int8 offset = Immediate8Slow(a);
65
66 return ((int16) Registers.PCw + offset) & 0xffff;
67}
68
69static inline uint32 Relative (AccessMode a) // branch $xx
70{
71 int8 offset = Immediate8(a);
72
73 return ((int16) Registers.PCw + offset) & 0xffff;
74}
75
76static inline uint32 RelativeLongSlow (AccessMode a) // BRL $xxxx
77{
78 int16 offset = Immediate16Slow(a);
79
80 return ((int32) Registers.PCw + offset) & 0xffff;
81}
82
83static inline uint32 RelativeLong (AccessMode a) // BRL $xxxx
84{
85 int16 offset = Immediate16(a);
86
87 return ((int32) Registers.PCw + offset) & 0xffff;
88}
89
90static 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
116static 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
130static 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
142static 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
154static 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
163static 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
172static inline uint32 AbsoluteSlow (AccessMode a) // a
173{
174 return (ICPU.ShiftedDB | Immediate16Slow(a));
175}
176
177static inline uint32 Absolute (AccessMode a) // a
178{
179 return (ICPU.ShiftedDB | Immediate16(a));
180}
181
182static 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
196static 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
207static 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
216static 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
225static 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
235static 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
245static 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
255static 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
264static 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
272static 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
281static 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
290static 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
300static 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
310static inline uint32 DirectIndirectIndexedLongSlow (AccessMode a) // [d],Y
311{
312 return (DirectIndirectLongSlow(a) + Registers.Y.W);
313}
314
315static inline uint32 DirectIndirectIndexedLong (AccessMode a) // [d],Y
316{
317 return (DirectIndirectLong(a) + Registers.Y.W);
318}
319
320static 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
334static 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
342static 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
357static 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
371static 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
379static 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
394static 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
403static 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
412static 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
421static 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
430static 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
438static 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
447static 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
456static 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
464static 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
473static inline uint32 AbsoluteLongIndexedXSlow (AccessMode a) // l,X
474{
475 return (AbsoluteLongSlow(a) + Registers.X.W);
476}
477
478static inline uint32 AbsoluteLongIndexedX (AccessMode a) // l,X
479{
480 return (AbsoluteLong(a) + Registers.X.W);
481}
482
483static 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
491static 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
499static 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
510static 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