OXYGENHUB
◆ main enhanced-x16-emulator / src / cpu / instructions.h
23.2 KiB · Objective-C · last changed chore(): initial commit 25 days ago source blame history raw
9120e874 Andy McCall 1
/*
2
3
						Extracted from original single fake6502.c file
4
5
*/
6
//
7
//          65C02 changes.
8
//
9
//          BRK                 now clears D
10
//          ADC/SBC             set N and Z in decimal mode. They also set V
11
//
12
//
13
//
14
//          instruction handler functions
15
//
16
static void adc() {
17
    pay_for_wide_memory(1);
18
    penaltyop = 1;
19
    if (regs.status & FLAG_DECIMAL) {
20
        uint16_t tmp, tmp2;
21
        uint32_t tmpov;
22
        if (memory_16bit()) {
23
            uint16_t tmp3;
24
            uint32_t tmp4;
25
            value = getvalue(1);
26
            tmp = (regs.c & 0x000F) + (value & 0x000F) + (uint16_t)(regs.status & FLAG_CARRY);
27
            tmp2 = (regs.c & 0x00F0) + (value & 0x00F0);
28
            tmp3 = (regs.c & 0x0F00) + (value & 0x0F00);
29
            tmp4 = ((uint32_t)regs.c & 0xF000) + (value & 0xF000);
30
            if (tmp > 0x0009) {
31
                tmp2 += 0x0010;
32
                tmp += 0x0006;
33
            }
34
            if (tmp2 > 0x0090) {
35
                tmp3 += 0x0100;
36
                tmp2 += 0x0060;
37
            }
38
            if (tmp3 > 0x0900) {
39
                tmp4 += 0x1000;
40
                tmp3 += 0x0600;
41
            }
42
            tmpov = tmp4;
43
            if (tmp4 > 0x9000) {
44
                tmp4 += 0x6000;
45
            }
46
            if (tmp4 & 0xFFFF0000) {
47
                setcarry();
48
            } else {
49
                clearcarry();
50
            }
51
            result = (tmp & 0x000F) | (tmp2 & 0x00F0) | (tmp3 & 0x0F00) | (tmp4 & 0xF000);
52
            uint16_t ovresult = (tmp & 0x000F) | (tmp2 & 0x00F0) | (tmp3 & 0x0F00) | (tmpov & 0xF000);
53
            overflowcalc16(ovresult, regs.c, value);
54
        } else {
55
            value = getvalue(0);
56
            tmp = ((uint16_t)regs.a & 0x0F) + (value & 0x0F) + (uint16_t)(regs.status & FLAG_CARRY);
57
            tmp2 = ((uint16_t)regs.a & 0xF0) + (value & 0xF0);
58
            if (tmp > 0x09) {
59
                tmp2 += 0x10;
60
                tmp += 0x06;
61
            }
62
            tmpov = tmp2;
63
            if (tmp2 > 0x90) {
64
                tmp2 += 0x60;
65
            }
66
            if (tmp2 & 0xFF00) {
67
                setcarry();
68
            } else {
69
                clearcarry();
70
            }
71
            result = (tmp & 0x0F) | (tmp2 & 0xF0);
72
            uint8_t ovresult = (tmp & 0x0F) | (tmpov & 0xF0);
73
            overflowcalc8((uint16_t)ovresult, (uint16_t)regs.a, value);
74
        }
75
        clockticks6502 += (uint32_t)(!regs.is65c816);
76
    } else {
77
        if (memory_16bit()) {
78
            value = getvalue(1);
79
            result = regs.c + value + (uint16_t) (regs.status & FLAG_CARRY);
80
            overflowcalc16(result, regs.c, value);
81
            carrycalc(result, 1);
82
        } else {
83
            value = getvalue(0);
84
            result = (uint16_t)regs.a + value + (uint16_t) (regs.status & FLAG_CARRY);
85
            overflowcalc8(result, (uint16_t)regs.a, value);
86
            carrycalc(result, 0);
87
        }
88
    }
89
90
    zerocalc(result, memory_16bit());
91
    signcalc(result, memory_16bit());
92
93
    saveaccum(result);
94
}
95
96
static void and() {
97
    pay_for_wide_memory(1);
98
    penaltyop = 1;
99
    value = getvalue(memory_16bit());
100
    result = acc_for_mode() & value;
101
102
    zerocalc(result, memory_16bit());
103
    signcalc(result, memory_16bit());
104
105
    saveaccum(result);
106
}
107
108
static void asl() {
109
    pay_for_wide_memory(2);
110
    // On the 65C02 the page-crossing cycle is conditional here; the NMOS
111
    // part always paid it and the 65C816 has its own flat timing, so this
112
    // penalty applies to the 65C02 only.
113
    penaltyop = (uint8_t)!regs.is65c816;
114
    value = getvalue(memory_16bit());
115
    result = value << 1;
116
117
    carrycalc(result, memory_16bit());
118
    zerocalc(result, memory_16bit());
119
    signcalc(result, memory_16bit());
120
121
    putvalue(result, memory_16bit());
122
}
123
124
static void _do_branch(int condition) {
125
    if (condition) {
126
        oldpc = regs.pc;
127
        regs.pc += reladdr;
128
        clockticks6502++;
129
        if ((oldpc & 0xFF00) != (regs.pc & 0xFF00)) //check if jump crossed a page boundary
130
            penaltye = 1;
131
    }
132
}
133
134
static void bcc() {
135
    _do_branch((regs.status & FLAG_CARRY) == 0);
136
}
137
138
static void bcs() {
139
    _do_branch((regs.status & FLAG_CARRY) == FLAG_CARRY);
140
}
141
142
static void beq() {
143
    _do_branch((regs.status & FLAG_ZERO) == FLAG_ZERO);
144
}
145
146
static void bit() {
147
    pay_for_wide_memory(1);
148
    // BIT abs,X pays the page-crossing cycle on both CPUs, unlike the
149
    // read-modify-write forms below it, which are flat on the 65C816.
150
    penaltyop = 1;
151
    value = getvalue(memory_16bit());
152
    result = acc_for_mode() & value;
153
154
    zerocalc(result, memory_16bit());
155
    // Xark - BUGFIX: 65C02 BIT #$xx only affects Z  See: http://6502.org/tutorials/65c02opcodes.html#2
156
    if (opcode != 0x89)
157
    {
158
        // N and V come from the top two bits of the operand, which are bits 15
159
        // and 14 when the accumulator is 16 bits wide.
160
        uint16_t top = memory_16bit() ? (uint16_t)(value >> 8) : value;
161
        regs.status = (regs.status & 0x3F) | (uint8_t)(top & 0xC0);
162
    }
163
}
164
165
static void bmi() {
166
    _do_branch((regs.status & FLAG_SIGN) == FLAG_SIGN);
167
}
168
169
static void bne() {
170
    _do_branch((regs.status & FLAG_ZERO) == 0);
171
}
172
173
static void bpl() {
174
    _do_branch((regs.status & FLAG_SIGN) == 0);
175
}
176
177
static void brk() {
178
    penaltyn = 1;
179
    regs.pc++;
180
181
    interrupt6502(INT_BRK);
182
}
183
184
static void brl() {
185
    regs.pc += reladdr;
186
}
187
188
static void bvc() {
189
    _do_branch((regs.status & FLAG_OVERFLOW) == 0);
190
}
191
192
static void bvs() {
193
    _do_branch((regs.status & FLAG_OVERFLOW) == FLAG_OVERFLOW);
194
}
195
196
static void clc() {
197
    clearcarry();
198
}
199
200
static void cld() {
201
    cleardecimal();
202
}
203
204
static void cli() {
205
    clearinterrupt();
206
}
207
208
static void clv() {
209
    clearoverflow();
210
}
211
212
static void cmp() {
213
    pay_for_wide_memory(1);
214
    penaltyop = 1;
215
    value = getvalue(memory_16bit());
216
217
    if (memory_16bit()) {
218
        result = regs.c - value;
219
        if (regs.c >= value) setcarry();
220
        else clearcarry();
221
        if (regs.c == value) setzero();
222
        else clearzero();
223
    } else {
224
        result = (uint16_t)regs.a - value;
225
        if (regs.a >= (uint8_t)(value & 0x00FF)) setcarry();
226
        else clearcarry();
227
        if (regs.a == (uint8_t)(value & 0x00FF)) setzero();
228
        else clearzero();
229
    }
230
231
    signcalc(result, memory_16bit());
232
}
233
234
static void cop() {
235
    penaltyn = 1;
236
    regs.pc++;
237
238
    interrupt6502(INT_COP);
239
}
240
241
static void cpx() {
242
    penaltyx = 1;
243
    value = getvalue(index_16bit());
244
245
    if (index_16bit()) {
246
        result = regs.x - value;
247
        if(regs.x >= value) setcarry();
248
        else clearcarry();
249
        if (regs.x == value) setzero();
250
        else clearzero();
251
    } else {
252
        result = (uint16_t)regs.xl - value;
253
        if (regs.xl >= (uint8_t)(value & 0x00FF)) setcarry();
254
        else clearcarry();
255
        if (regs.xl == (uint8_t)(value & 0x00FF)) setzero();
256
        else clearzero();
257
    }
258
    signcalc(result, index_16bit());
259
}
260
261
static void cpy() {
262
    penaltyx = 1;
263
    value = getvalue(index_16bit());
264
265
    if (index_16bit()) {
266
        result = regs.y - value;
267
        if(regs.y >= value) setcarry();
268
        else clearcarry();
269
        if (regs.y == value) setzero();
270
        else clearzero();
271
    } else {
272
        result = (uint16_t)regs.yl - value;
273
        if (regs.yl >= (uint8_t)(value & 0x00FF)) setcarry();
274
        else clearcarry();
275
        if (regs.yl == (uint8_t)(value & 0x00FF)) setzero();
276
        else clearzero();
277
    }
278
    signcalc(result, index_16bit());
279
}
280
281
static void dec() {
282
    pay_for_wide_memory(2);
283
    value = getvalue(memory_16bit());
284
    result = value - 1;
285
286
    zerocalc(result, memory_16bit());
287
    signcalc(result, memory_16bit());
288
289
    putvalue(result, memory_16bit());
290
}
291
292
static void dex() {
293
    if (index_16bit()) {
294
        regs.x--;
295
        zerocalc(regs.x, 1);
296
        signcalc(regs.x, 1);
297
    } else {
298
        regs.xl--;
299
        zerocalc(regs.xl, 0);
300
        signcalc(regs.xl, 0);
301
    }
302
}
303
304
static void dey() {
305
    if (index_16bit()) {
306
        regs.y--;
307
        zerocalc(regs.y, 1);
308
        signcalc(regs.y, 1);
309
    } else {
310
        regs.yl--;
311
        zerocalc(regs.yl, 0);
312
        signcalc(regs.yl, 0);
313
    }
314
}
315
316
static void eor() {
317
    pay_for_wide_memory(1);
318
    penaltyop = 1;
319
    value = getvalue(memory_16bit());
320
    result = acc_for_mode() ^ value;
321
322
    zerocalc(result, memory_16bit());
323
    signcalc(result, memory_16bit());
324
325
    saveaccum(result);
326
}
327
328
static void inc() {
329
    pay_for_wide_memory(2);
330
    value = getvalue(memory_16bit());
331
    result = value + 1;
332
333
    zerocalc(result, memory_16bit());
334
    signcalc(result, memory_16bit());
335
336
    putvalue(result, memory_16bit());
337
}
338
339
static void inx() {
340
    if (index_16bit()) {
341
        regs.x++;
342
        zerocalc(regs.x, 1);
343
        signcalc(regs.x, 1);
344
    } else {
345
        regs.xl++;
346
        zerocalc(regs.xl, 0);
347
        signcalc(regs.xl, 0);
348
    }
349
}
350
351
static void iny() {
352
    if (index_16bit()) {
353
        regs.y++;
354
        zerocalc(regs.y, 1);
355
        signcalc(regs.y, 1);
356
    } else {
357
        regs.yl++;
358
        zerocalc(regs.yl, 0);
359
        signcalc(regs.yl, 0);
360
    }
361
}
362
363
static void jml() {
364
    regs.pc = ea & 0xFFFF;
365
    regs.k = ea >> 16;
366
}
367
368
static void jmp() {
369
    regs.pc = ea;
370
}
371
372
static void jsr() {
373
    push16(regs.pc - 1);
374
    regs.pc = ea;
375
}
376
377
static void jsl() {
378
    push8_long(regs.k);
379
    push16_long(regs.pc - 1);
380
    regs.pc = ea & 0xFFFF;
381
    regs.k = ea >> 16;
382
}
383
384
static void lda() {
385
    penaltyop = 1;
386
    penaltym = 1;
387
388
    if (memory_16bit()) {
389
        regs.c = getvalue(1);
390
        zerocalc(regs.c, 1);
391
        signcalc(regs.c, 1);
392
    } else {
393
        value = getvalue(0);
394
        regs.a = (uint8_t)(value & 0x00FF);
395
        zerocalc(regs.a, 0);
396
        signcalc(regs.a, 0);
397
    }
398
}
399
400
static void ldx() {
401
    penaltyop = 1;
402
    penaltyx = 1;
403
404
    if (index_16bit()) {
405
        regs.x = getvalue(1);
406
        zerocalc(regs.x, 1);
407
        signcalc(regs.x, 1);
408
    } else {
409
        value = getvalue(0);
410
        regs.xl = (uint8_t)(value & 0x00FF);
411
        zerocalc(regs.xl, 0);
412
        signcalc(regs.xl, 0);
413
    }
414
}
415
416
static void ldy() {
417
    penaltyop = 1;
418
    penaltyx = 1;
419
420
    if (index_16bit()) {
421
        regs.y = getvalue(1);
422
        zerocalc(regs.y, 1);
423
        signcalc(regs.y, 1);
424
    } else {
425
        regs.yl = (uint8_t)(getvalue(0) & 0x00FF);
426
        zerocalc(regs.yl, 0);
427
        signcalc(regs.yl, 0);
428
    }
429
}
430
431
static void lsr() {
432
    pay_for_wide_memory(2);
433
    // On the 65C02 the page-crossing cycle is conditional here; the NMOS
434
    // part always paid it and the 65C816 has its own flat timing, so this
435
    // penalty applies to the 65C02 only.
436
    penaltyop = (uint8_t)!regs.is65c816;
437
    value = getvalue(memory_16bit());
438
    result = value >> 1;
439
440
    if (value & 1) setcarry();
441
        else clearcarry();
442
    zerocalc(result, memory_16bit());
443
    signcalc(result, memory_16bit());
444
445
    putvalue(result, memory_16bit());
446
}
447
448
static void nop() {
449
    switch (opcode) {
450
        case 0x1C:
451
        case 0x3C:
452
        case 0x5C:
453
        case 0x7C:
454
        case 0xDC:
455
        case 0xFC:
456
            penaltyop = 1;
457
            break;
458
    }
459
}
460
461
static void ora() {
462
    pay_for_wide_memory(1);
463
    penaltyop = 1;
464
    value = getvalue(memory_16bit());
465
    result = acc_for_mode() | value;
466
467
    zerocalc(result, memory_16bit());
468
    signcalc(result, memory_16bit());
469
470
    saveaccum(result);
471
}
472
473
static void pea() {
474
    push16_long(getvalue(1));
475
}
476
477
static void pei() {
478
    push16_long(ea);
479
}
480
481
static void per() {
482
    push16_long(regs.pc + reladdr);
483
}
484
485
static void pha() {
486
    pay_for_wide_memory(1);
487
    if (memory_16bit()) {
488
        push16(regs.c);
489
    } else {
490
        push8(regs.a);
491
    }
492
}
493
494
static void phb() {
495
    push8_long(regs.db);
496
}
497
498
static void phd() {
499
    push16_long(regs.dp);
500
}
501
502
static void phk() {
503
    push8_long(regs.k);
504
}
505
506
static void php() {
507
    push8(regs.e ? regs.status | FLAG_BREAK : regs.status);
508
}
509
510
static void pla() {
511
    pay_for_wide_memory(1);
512
    if (memory_16bit()) {
513
        regs.c = pull16();
514
        zerocalc(regs.c, 1);
515
        signcalc(regs.c, 1);
516
    } else {
517
        regs.a = pull8();
518
        zerocalc(regs.a, 0);
519
        signcalc(regs.a, 0);
520
    }
521
}
522
523
static void plb() {
524
    regs.db = pull8_long();
525
    zerocalc(regs.db, 0);
526
    signcalc(regs.db, 0);
527
}
528
529
static void pld() {
530
    regs.dp = pull16_long();
531
    zerocalc(regs.dp, 1);
532
    signcalc(regs.dp, 1);
533
}
534
535
static void plp() {
536
    regs.status = cpu_merge_pulled_status(pull8());
537
    if (regs.is65c816) {
538
        if (regs.e) {
539
            regs.status |= FLAG_INDEX_WIDTH | FLAG_MEMORY_WIDTH;
540
        } else if (regs.status & FLAG_INDEX_WIDTH) {
541
            regs.xh = 0;
542
            regs.yh = 0;
543
        }
544
    }
545
}
546
547
static void rep() {
548
    value = getvalue(0);
549
    regs.status &= ~(value & 0xFF);
550
551
    if (regs.e) {
552
        regs.status |= FLAG_INDEX_WIDTH | FLAG_MEMORY_WIDTH;
553
    }
554
}
555
556
static void rol() {
557
    pay_for_wide_memory(2);
558
    // On the 65C02 the page-crossing cycle is conditional here; the NMOS
559
    // part always paid it and the 65C816 has its own flat timing, so this
560
    // penalty applies to the 65C02 only.
561
    penaltyop = (uint8_t)!regs.is65c816;
562
    value = getvalue(memory_16bit());
563
    result = (value << 1) | (regs.status & FLAG_CARRY);
564
565
    carrycalc(result, memory_16bit());
566
    zerocalc(result, memory_16bit());
567
    signcalc(result, memory_16bit());
568
569
    putvalue(result, memory_16bit());
570
}
571
572
static void ror() {
573
    pay_for_wide_memory(2);
574
    // On the 65C02 the page-crossing cycle is conditional here; the NMOS
575
    // part always paid it and the 65C816 has its own flat timing, so this
576
    // penalty applies to the 65C02 only.
577
    penaltyop = (uint8_t)!regs.is65c816;
578
    value = getvalue(memory_16bit());
579
    result = (value >> 1) | ((regs.status & FLAG_CARRY) << (memory_16bit() ? 15 : 7));
580
581
    if (value & 1) setcarry();
582
        else clearcarry();
583
    zerocalc(result, memory_16bit());
584
    signcalc(result, memory_16bit());
585
586
    putvalue(result, memory_16bit());
587
}
588
589
static void rti() {
590
    // Native mode pulls the program bank as well, which costs a cycle.
591
    penaltyn = 1;
592
    regs.status = cpu_merge_pulled_status(pull8());
593
    value = pull16();
594
    regs.pc = value;
595
596
    if (regs.is65c816) {
597
        if (regs.e) {
598
            regs.status |= FLAG_INDEX_WIDTH | FLAG_MEMORY_WIDTH;
599
        } else {
600
            if (regs.status & FLAG_INDEX_WIDTH) {
601
                regs.xh = 0;
602
                regs.yh = 0;
603
            }
604
            regs.k = pull8();
605
        }
606
    }
607
608
    // Pair this with the interrupt entry that set the stack up. Reported after
609
    // every pull, so regs.sp is back to what it was when the interrupt was
610
    // taken. See cpu/irq_ctx.h.
611
    cpu_irq_ctx_leave(regs.sp);
612
}
613
614
static void rtl() {
615
    value = pull16_long();
616
    regs.pc = value + 1;
617
    regs.k = pull8_long();
618
}
619
620
static void rts() {
621
    value = pull16();
622
    regs.pc = value + 1;
623
}
624
625
static void sbc() {
626
    pay_for_wide_memory(1);
627
    penaltyop = 1;
628
629
    if (regs.status & FLAG_DECIMAL) {
630
        if (memory_16bit()) {
631
            value = getvalue(1);
632
            const uint16_t carry_in = regs.status & FLAG_CARRY;
633
634
            // Four digits, each corrected when the one below borrows. Signed
635
            // throughout: the top digit corrects on a borrow out, matching the
636
            // 8-bit path, where testing the digit against $A instead left the
637
            // result $6000 low whenever a high digit was $A-$F.
638
            int32_t d0 = (int32_t)(regs.c & 0x000F) - (int32_t)(value & 0x000F) +
639
                         (int32_t)carry_in - 1;
640
            int32_t d1 = (int32_t)(regs.c & 0x00F0) - (int32_t)(value & 0x00F0);
641
            int32_t d2 = (int32_t)(regs.c & 0x0F00) - (int32_t)(value & 0x0F00);
642
            int32_t d3 = (int32_t)(regs.c & 0xF000) - (int32_t)(value & 0xF000);
643
644
            if (d0 & ~0x000F) {
645
                d1 -= 0x0010;
646
                d0 -= 0x0006;
647
            }
648
            if (d1 & ~0x00FF) {
649
                d2 -= 0x0100;
650
                d1 -= 0x0060;
651
            }
652
            if (d2 & ~0x0FFF) {
653
                d3 -= 0x1000;
654
                d2 -= 0x0600;
655
            }
656
657
            if (d3 < 0) {
658
                d3 -= 0x6000;
659
            }
660
661
            result = (uint16_t)((d0 & 0x000F) | (d1 & 0x00F0) | (d2 & 0x0F00) |
662
                                (d3 & 0xF000));
663
664
            // Carry reports the binary borrow, as in the 8-bit path, rather
665
            // than a comparison against the corrected result.
666
            int32_t binary = (int32_t)regs.c - (int32_t)value +
667
                             (int32_t)carry_in - 1;
668
            if (binary >= 0) {
669
                setcarry();
670
            } else {
671
                clearcarry();
672
            }
673
            uint16_t ovresult = regs.c + (value ^ 0xFFFF) + carry_in;
674
            overflowcalc16(ovresult, regs.c, value ^ 0xFFFF);
675
        } else {
676
            value = getvalue(0);
677
            // Captured before setcarry() below, which would otherwise feed the
678
            // freshly computed carry back into the overflow calculation.
679
            const uint16_t carry_in = regs.status & FLAG_CARRY;
680
681
            // The 65C02 subtracts in binary and corrects afterwards; the 65C816
682
            // corrects each nibble as it goes, as the NMOS part did. The two
683
            // agree on valid BCD and differ when a digit is $A-$F.
684
            int16_t lo  = (int16_t)(regs.a & 0x0F) - (int16_t)(value & 0x0F) +
685
                          (int16_t)carry_in - 1;
686
            int16_t bin = (int16_t)regs.a - (int16_t)value +
687
                          (int16_t)carry_in - 1;
688
689
            int16_t adjusted;
690
            if (regs.is65c816) {
691
                int16_t al = lo;
692
                if (al < 0) {
693
                    al = (int16_t)(((al - 0x06) & 0x0F) - 0x10);
694
                }
695
                adjusted = (int16_t)((int16_t)(regs.a & 0xF0) -
696
                                     (int16_t)(value & 0xF0) + al);
697
                if (adjusted < 0) {
698
                    adjusted -= 0x60;
699
                }
700
            } else {
701
                adjusted = bin;
702
                if (adjusted < 0) {
703
                    adjusted -= 0x60;
704
                }
705
                if (lo < 0) {
706
                    adjusted -= 0x06;
707
                }
708
            }
709
            result = (uint16_t)(adjusted & 0xFF);
710
711
            uint8_t ovresult = (uint8_t)(regs.a + (value ^ 0xFF) + carry_in);
712
            overflowcalc8((uint16_t)ovresult, (uint16_t)regs.a, value ^ 0xFF);
713
714
            // Carry reports the binary borrow, not the corrected result.
715
            if (bin >= 0) {
716
                setcarry();
717
            } else {
718
                clearcarry();
719
            }
720
        }
721
722
        clockticks6502 += (uint32_t)(!regs.is65c816);
723
    } else {
724
        if (memory_16bit()) {
725
            value = getvalue(1) ^ 0xFFFF;
726
            result = regs.c + value + (regs.status & FLAG_CARRY);
727
            overflowcalc16(result, regs.c, value);
728
        } else {
729
            value = getvalue(0) ^ 0x00FF;
730
            result = (uint16_t)regs.a + value + (uint16_t)(regs.status & FLAG_CARRY);
731
            overflowcalc8(result, (uint16_t)regs.a, value);
732
        }
733
734
        carrycalc(result, memory_16bit());
735
    }
736
737
    zerocalc(result, memory_16bit());
738
    signcalc(result, memory_16bit());
739
740
    saveaccum(result);
741
}
742
743
static void sec() {
744
    setcarry();
745
}
746
747
static void sed() {
748
    setdecimal();
749
}
750
751
static void sei() {
752
    setinterrupt();
753
}
754
755
static void sep() {
756
    regs.status |= getvalue(0) & 0xFF;
757
    if (regs.e) {
758
        regs.status |= FLAG_INDEX_WIDTH | FLAG_MEMORY_WIDTH;
759
    }
760
    if (regs.status & FLAG_INDEX_WIDTH) {
761
        regs.xh = 0;
762
        regs.yh = 0;
763
    }
764
}
765
766
static void sta() {
767
    pay_for_wide_memory(1);
768
    putvalue(acc_for_mode(), memory_16bit());
769
}
770
771
static void stx() {
772
    penaltyx = 1;
773
    putvalue(index_16bit() ? regs.x : regs.xl, index_16bit());
774
}
775
776
static void sty() {
777
    penaltyx = 1;
778
    putvalue(index_16bit() ? regs.y : regs.yl, index_16bit());
779
}
780
781
static void tax() {
782
    if (index_16bit()) {
783
        regs.x = regs.c; // 16 bits transferred, no matter the state of m
784
        zerocalc(regs.x, 1);
785
        signcalc(regs.x, 1);
786
    } else {
787
        regs.xl = (uint8_t)(regs.a & 0x00FF);
788
        zerocalc(regs.xl, 0);
789
        signcalc(regs.xl, 0);
790
    }
791
}
792
793
static void tay() {
794
    if (index_16bit()) {
795
        regs.y = regs.c; // 16 bits transferred, no matter the state of m
796
        zerocalc(regs.y, 1);
797
        signcalc(regs.y, 1);
798
    } else {
799
        regs.yl = (uint8_t)(regs.a & 0x00FF);
800
        zerocalc(regs.yl, 0);
801
        signcalc(regs.yl, 0);
802
    }
803
}
804
805
static void tcd() {
806
    regs.dp = regs.c;
807
    zerocalc(regs.dp, 1);
808
    signcalc(regs.dp, 1);
809
}
810
811
static void tdc() {
812
    regs.c = regs.dp;
813
    zerocalc(regs.c, 1);
814
    signcalc(regs.c, 1);
815
}
816
817
static void tsx() {
818
    if (index_16bit()) {
819
        regs.x = regs.sp; // 16 bits transferred, no matter the state of m
820
        zerocalc(regs.x, 1);
821
        signcalc(regs.x, 1);
822
    } else {
823
        regs.xl = (uint8_t)(regs.sp & 0x00FF);
824
        regs.xh = 0;
825
        zerocalc(regs.xl, 0);
826
        signcalc(regs.xl, 0);
827
    }
828
}
829
830
static void txa() {
831
    if (memory_16bit()) {
832
        // The transfer is the accumulator's width, so the flags are too, even
833
        // where an 8-bit X supplies only the low byte.
834
        if (index_16bit()) {
835
            regs.c = regs.x;
836
        } else {
837
            regs.a = regs.xl;
838
            regs.b = 0;
839
        }
840
        zerocalc(regs.c, 1);
841
        signcalc(regs.c, 1);
842
    } else {
843
        regs.a = regs.xl;
844
        zerocalc(regs.a, 0);
845
        signcalc(regs.a, 0);
846
    }
847
}
848
849
static void txs() {
850
    if (regs.e) {
851
        regs.sp = 0x100 | regs.xl;
852
    } else {
853
        regs.sp = regs.x;
854
    }
855
}
856
857
static void txy() {
858
    if (index_16bit()) {
859
        regs.y = regs.x;
860
        zerocalc(regs.y, 1);
861
        signcalc(regs.y, 1);
862
    } else {
863
        regs.yl = regs.xl;
864
        zerocalc(regs.yl, 0);
865
        signcalc(regs.yl, 0);
866
    }
867
}
868
869
static void tya() {
870
    if (memory_16bit()) {
871
        if (index_16bit()) {
872
            regs.c = regs.y;
873
        } else {
874
            regs.a = regs.yl;
875
            regs.b = 0;
876
        }
877
        zerocalc(regs.c, 1);
878
        signcalc(regs.c, 1);
879
    } else {
880
        regs.a = regs.yl;
881
        zerocalc(regs.a, 0);
882
        signcalc(regs.a, 0);
883
    }
884
}
885
886
static void tyx() {
887
    if (index_16bit()) {
888
        regs.x = regs.y;
889
        zerocalc(regs.x, 1);
890
        signcalc(regs.x, 1);
891
    } else {
892
        regs.xl = regs.yl;
893
        zerocalc(regs.xl, 0);
894
        signcalc(regs.xl, 0);
895
    }
896
}
897
898
static void tcs() {
899
    regs.sp = regs.c;
900
}
901
902
static void tsc() {
903
    regs.c = regs.sp;
904
    zerocalc(regs.c, 1);
905
    signcalc(regs.c, 1);
906
}
907
908
static void mvn() {
909
    uint8_t sourceBank = ea >> 8;
910
    uint8_t destBank = ea;
911
    regs.db = destBank;
912
913
    if (index_16bit()) {
914
        write6502(regs.y++, destBank, read6502(regs.x++, sourceBank));
915
    } else {
916
        write6502(regs.yl++, destBank, read6502(regs.xl++, sourceBank));
917
    }
918
    if (--regs.c != 0xFFFF) {
919
        regs.pc -= 3;
920
    }
921
}
922
923
static void mvp() {
924
    uint8_t sourceBank = ea >> 8;
925
    uint8_t destBank = ea;
926
    regs.db = ea;
927
928
    if (index_16bit()) {
929
        write6502(regs.y--, destBank, read6502(regs.x--, sourceBank));
930
    } else {
931
        write6502(regs.yl--, destBank, read6502(regs.xl--, sourceBank));
932
    }
933
    if (--regs.c != 0xFFFF) {
934
        regs.pc -= 3;
935
    }
936
}
937
938
static void wdm() {
939
}
940
941
static void xba() {
942
    uint8_t tmp = regs.b;
943
    regs.b = regs.a;
944
    regs.a = tmp;
945
    zerocalc(regs.a, 0);
946
    signcalc(regs.a, 0);
947
}
948
949
static void xce() {
950
    uint8_t carry = regs.status & FLAG_CARRY;
951
    regs.status = (regs.status & ~FLAG_CARRY) | (regs.e ? FLAG_CARRY : 0);
952
    regs.e = carry != 0;
953
954
    if (regs.e) {
955
        regs.status |= FLAG_INDEX_WIDTH | FLAG_MEMORY_WIDTH;
956
        regs.sp = 0x0100 | (regs.sp & 0x00FF);
957
        regs.xh = 0x00;
958
        regs.yh = 0x00;
959
    }
960
}