1 //
2 // /home/ms/source/sidplay/libsidplay/emu/RCS/6510_.cpp,v
3 //
4 // --------------------------------------------------------------------------
5 // Copyright (c) 1994-1997 Michael Schwendt. All rights reserved.
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 // DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 // --------------------------------------------------------------------------
33 //
34 // MOS-6510 Interpreter. Known bugs, missing features, incompatibilities:
35 //
36 // - No support for code execution in Basic-ROM/Kernal-ROM.
37 // Only execution of code in RAM is allowed.
38 // - Probably inconsistent emulation of illegal instructions part 3.
39 // - No detection of deadlocks.
40 // - Faked RTI (= RTS).
41 // - Anybody knows, whether it is ``Kernel'' instead of ``Kernal'' ?
42 // Perhaps it is a proper name invented by CBM ?
43 // It is spelled ``Kernal'' in nearly every C64 documentation !
44 //
45
46 #include "compconf.h"
47 #ifdef SID_HAVE_EXCEPTIONS
48 #include <new>
49 #endif
50 #include "6510_.h"
51 #include "myendian.h"
52 #include "emucfg.h"
53
54
55 ubyte* c64mem1 = 0; // 64KB C64-RAM
56 ubyte* c64mem2 = 0; // Basic-ROM, VIC, SID, I/O, Kernal-ROM
57 bool sidKeysOff[32]; // key_off detection
58 bool sidKeysOn[32]; // key_on detection
59 ubyte sidLastValue = 0; // last value written to the SID
60 ubyte optr3readWave = 0; // D41B
61 ubyte optr3readEnve = 0; // D41C
62
63 // --------------------------------------------------------------------------
64
65 static ubyte AC, XR, YR; // 6510 processor registers
66 static uword PC, SP; // program-counter, stack-pointer
67 // PC is only used temporarily !
68 // The current program-counter is pPC-pPCbase
69
70 static ubyte* pPCbase; // pointer to RAM/ROM buffer base
71 static ubyte* pPCend; // pointer to RAM/ROM buffer end
72 static ubyte* pPC; // pointer to PC location
73
74 // ---------------------------------------------------- Memory de-/allocation
75
76 static ubyte* c64ramBuf = 0;
77 static ubyte* c64romBuf = 0;
78
c64memFree()79 bool c64memFree()
80 {
81 if ( c64romBuf != 0 )
82 {
83 delete[] c64romBuf;
84 c64romBuf = (c64mem2 = 0);
85 }
86 if ( c64ramBuf != 0 )
87 {
88 delete[] c64ramBuf;
89 c64ramBuf = (c64mem1 = 0);
90 }
91 return true;
92 }
93
c64memAlloc()94 bool c64memAlloc()
95 {
96 c64memFree();
97 bool wasSuccess = true;
98 #ifdef SID_HAVE_EXCEPTIONS
99 if (( c64ramBuf = new(std::nothrow) ubyte[65536+256] ) == 0 )
100 #else
101 if (( c64ramBuf = new ubyte[65536+256] ) == 0 )
102 #endif
103 {
104 wasSuccess = false;
105 }
106 #ifdef SID_HAVE_EXCEPTIONS
107 if (( c64romBuf = new(std::nothrow) ubyte[65536+256] ) == 0 )
108 #else
109 if (( c64romBuf = new ubyte[65536+256] ) == 0 )
110 #endif
111 {
112 wasSuccess = false;
113 }
114 if (!wasSuccess)
115 {
116 c64memFree();
117 }
118 else
119 {
120 // Make the memory buffers accessible to the whole emulator engine.
121 c64mem1 = c64ramBuf;
122 c64mem2 = c64romBuf;
123 }
124 return wasSuccess;
125 }
126
127 // ------------------------------------------------------ (S)tatus (R)egister
128 // MOS-6510 SR: NV-BDIZC
129 // 76543210
130 //
131
132 struct statusRegister
133 {
134 unsigned Carry : 1;
135 unsigned Zero : 1;
136 unsigned Interrupt : 1;
137 unsigned Decimal : 1;
138 unsigned Break : 1;
139 unsigned NotUsed : 1;
140 unsigned oVerflow : 1;
141 unsigned Negative : 1;
142 };
143
144 static statusRegister SR;
145
146 // Some handy defines to ease SR access.
147 #define CF SR.Carry
148 #define ZF SR.Zero
149 #define IF SR.Interrupt
150 #define DF SR.Decimal
151 #define BF SR.Break
152 #define NU SR.NotUsed
153 #define VF SR.oVerflow
154 #define NF SR.Negative
155
affectNZ(ubyte reg)156 inline void affectNZ(ubyte reg)
157 {
158 ZF = (reg == 0);
159 NF = ((reg & 0x80) != 0);
160 }
161
resetSR()162 inline void resetSR()
163 {
164 // Explicit paranthesis looks great.
165 CF = (ZF = (IF = (DF = (BF = (VF = (NF = 0))))));
166 NU = 1;
167 }
168
codeSR()169 inline ubyte codeSR()
170 {
171 register ubyte tempSR = CF;
172 tempSR |= (ZF<<1);
173 tempSR |= (IF<<2);
174 tempSR |= (DF<<3);
175 tempSR |= (BF<<4);
176 tempSR |= (NU<<5);
177 tempSR |= (VF<<6);
178 tempSR |= (NF<<7);
179 return tempSR;
180 }
181
decodeSR(ubyte stackByte)182 inline void decodeSR(ubyte stackByte)
183 {
184 CF = (stackByte & 1);
185 ZF = ((stackByte & 2) !=0 );
186 IF = ((stackByte & 4) !=0 );
187 DF = ((stackByte & 8) !=0 );
188 BF = ((stackByte & 16) !=0 );
189 NU = 1; // if used or writable, ((stackByte & 32) !=0 );
190 VF = ((stackByte & 64) !=0 );
191 NF = ((stackByte & 128) !=0 );
192 }
193
194 // --------------------------------------------------------------------------
195 // Handling conditional branches.
196
branchIfClear(ubyte flag)197 inline void branchIfClear(ubyte flag)
198 {
199 if (flag == 0)
200 {
201 PC = pPC-pPCbase; // calculate 16-bit PC
202 PC += (sbyte)*pPC; // add offset, keep it 16-bit (uword)
203 pPC = pPCbase+PC; // calc new pointer-PC
204 }
205 pPC++;
206 }
207
branchIfSet(ubyte flag)208 inline void branchIfSet(ubyte flag)
209 {
210 if (flag != 0)
211 {
212 PC = pPC-pPCbase; // calculate 16-bit PC
213 PC += (sbyte)*pPC; // add offset, keep it 16-bit (uword)
214 pPC = pPCbase+PC; // calc new pointer-PC
215 }
216 pPC++;
217 }
218
219 // --------------------------------------------------------------------------
220 // Addressing modes:
221 // Calculating 8/16-bit effective addresses out of data operands.
222
abso()223 inline uword abso()
224 {
225 return readLEword(pPC);
226 }
227
absx()228 inline uword absx()
229 {
230 return readLEword(pPC)+XR;
231 }
232
absy()233 inline uword absy()
234 {
235 return readLEword(pPC)+YR;
236 }
237
imm()238 inline ubyte imm()
239 {
240 return *pPC;
241 }
242
indx()243 inline uword indx()
244 {
245 return readEndian(c64mem1[(*pPC+1+XR)&0xFF],c64mem1[(*pPC+XR)&0xFF]);
246 }
247
indy()248 inline uword indy()
249 {
250 return YR+readEndian(c64mem1[(*pPC+1)&0xFF],c64mem1[*pPC]);
251 }
252
zp()253 inline ubyte zp()
254 {
255 return *pPC;
256 }
257
zpx()258 inline ubyte zpx()
259 {
260 return *pPC+XR;
261 }
262
zpy()263 inline ubyte zpy()
264 {
265 return *pPC+YR;
266 }
267
268 // --------------------------------------------------------------------------
269 // LIFO-Stack:
270 //
271 // |xxxxxx|
272 // |xxxxxx|
273 // |______|<- SP <= (hi)-return-address
274 // |______| <= (lo)
275 // |______|
276 //
277
278 static bool stackIsOkay = true;
279
resetSP()280 inline void resetSP()
281 {
282 SP = 0x1ff; // SP to top of stack
283 stackIsOkay = true;
284 }
285
checkSP()286 inline void checkSP()
287 {
288 stackIsOkay = ((SP>0xff)&&(SP<=0x1ff)); // check boundaries
289 }
290
RTS_()291 inline void RTS_()
292 {
293 SP++;
294 PC =readEndian( c64mem1[SP +1], c64mem1[SP] ) +1;
295 pPC = pPCbase+PC;
296 SP++;
297 checkSP();
298 }
299
300 // --------------------------------------------------------------------------
301 // Relevant configurable memory banks:
302 //
303 // $A000 to $BFFF = RAM, Basic-ROM
304 // $C000 to $CFFF = RAM
305 // $D000 to $DFFF = RAM, I/O, Char-ROM
306 // $E000 to $FFFF = RAM, Kernal-ROM
307 //
308 // Bank-Select Register $01:
309 //
310 // Bits
311 // 210 $A000-$BFFF $D000-$DFFF $E000-$FFFF
312 // ------------------------------------------------
313 // 000 RAM RAM RAM
314 // 001 RAM Char-ROM RAM
315 // 010 RAM Char-ROM Kernal-ROM
316 // 011 Basic-ROM Char-ROM Kernal-ROM
317 // 100 RAM RAM RAM
318 // 101 RAM I/O RAM
319 // 110 RAM I/O Kernal-ROM
320 // 111 Basic-ROM I/O Kernal-ROM
321 //
322 // "Transparent ROM" mode:
323 //
324 // Basic-ROM and Kernal-ROM are considered transparent to read/write access.
325 // Basic-ROM is also considered transparent to branches (JMP, BCC, ...).
326 // I/O and Kernal-ROM are togglable via bank-select register $01.
327
328 static bool isBasic; // these flags are used to not have to repeatedly
329 static bool isIO; // evaluate the bank-select register for each
330 static bool isKernal; // address operand
331
332 static ubyte* bankSelReg; // pointer to RAM[1], bank-select register
333
334 static udword fakeReadTimer;
335
336
evalBankSelect()337 inline void evalBankSelect()
338 {
339 // Determine new memory configuration.
340 isBasic = ((*bankSelReg & 3) == 3);
341 isIO = ((*bankSelReg & 7) > 4);
342 isKernal = ((*bankSelReg & 2) != 0);
343 }
344
345
346 // Upon JMP/JSR prevent code execution in Basic-ROM/Kernal-ROM.
evalBankJump()347 inline void evalBankJump()
348 {
349 if (PC < 0xA000)
350 {
351 ;
352 }
353 else
354 {
355 // Get high-nibble of address.
356 switch (PC >> 12)
357 {
358 case 0xa:
359 case 0xb:
360 {
361 if (isBasic)
362 {
363 RTS_();
364 }
365 break;
366 }
367 case 0xc:
368 {
369 break;
370 }
371 case 0xd:
372 {
373 if (isIO)
374 {
375 RTS_();
376 }
377 break;
378 }
379 case 0xe:
380 case 0xf:
381 default: // <-- just to please the compiler
382 {
383 if (isKernal)
384 {
385 RTS_();
386 }
387 break;
388 }
389 }
390 }
391 }
392
393
394 // Functions to retrieve data.
395
readData_bs(uword addr)396 static ubyte readData_bs(uword addr)
397 {
398 if (addr < 0xA000)
399 {
400 return c64mem1[addr];
401 }
402 else
403 {
404 // Get high-nibble of address.
405 switch (addr >> 12)
406 {
407 case 0xa:
408 case 0xb:
409 {
410 if (isBasic)
411 return c64mem2[addr];
412 else
413 return c64mem1[addr];
414 }
415 case 0xc:
416 {
417 return c64mem1[addr];
418 }
419 case 0xd:
420 {
421 if (isIO)
422 {
423 uword tempAddr = (addr & 0xfc1f);
424 // Not SID ?
425 if (( tempAddr & 0xff00 ) != 0xd400 )
426 {
427 switch (addr)
428 {
429 case 0xd011:
430 case 0xd012:
431 case 0xdc04:
432 case 0xdc05:
433 {
434 fakeReadTimer = fakeReadTimer*13+1;
435 return (ubyte)(fakeReadTimer>>3);
436 }
437 default:
438 {
439 return c64mem2[addr];
440 }
441 }
442 }
443 else
444 {
445 // $D41D/1E/1F, $D43D/, ... SID not mirrored
446 if (( tempAddr & 0x00ff ) >= 0x001d )
447 return(c64mem2[addr]);
448 // (Mirrored) SID.
449 else
450 {
451 switch (tempAddr)
452 {
453 case 0xd41b:
454 {
455 return optr3readWave;
456 }
457 case 0xd41c:
458 {
459 return optr3readEnve;
460 }
461 default:
462 {
463 return sidLastValue;
464 }
465 }
466 }
467 }
468 }
469 else
470 return c64mem1[addr];
471 }
472 case 0xe:
473 case 0xf:
474 default: // <-- just to please the compiler
475 {
476 if (isKernal)
477 return c64mem2[addr];
478 else
479 return c64mem1[addr];
480 }
481 }
482 }
483 }
484
readData_transp(uword addr)485 static ubyte readData_transp(uword addr)
486 {
487 if (addr < 0xD000)
488 {
489 return c64mem1[addr];
490 }
491 else
492 {
493 // Get high-nibble of address.
494 switch (addr >> 12)
495 {
496 case 0xd:
497 {
498 if (isIO)
499 {
500 uword tempAddr = (addr & 0xfc1f);
501 // Not SID ?
502 if (( tempAddr & 0xff00 ) != 0xd400 )
503 {
504 switch (addr)
505 {
506 case 0xd011:
507 case 0xd012:
508 case 0xdc04:
509 case 0xdc05:
510 {
511 fakeReadTimer = fakeReadTimer*13+1;
512 return (ubyte)(fakeReadTimer>>3);
513 }
514 default:
515 {
516 return c64mem2[addr];
517 }
518 }
519 }
520 else
521 {
522 // $D41D/1E/1F, $D43D/, ... SID not mirrored
523 if (( tempAddr & 0x00ff ) >= 0x001d )
524 return(c64mem2[addr]);
525 // (Mirrored) SID.
526 else
527 {
528 switch (tempAddr)
529 {
530 case 0xd41b:
531 {
532 return optr3readWave;
533 }
534 case 0xd41c:
535 {
536 return optr3readEnve;
537 }
538 default:
539 {
540 return sidLastValue;
541 }
542 }
543 }
544 }
545 }
546 else
547 return c64mem1[addr];
548 }
549 case 0xe:
550 case 0xf:
551 default: // <-- just to please the compiler
552 {
553 return c64mem1[addr];
554 }
555 }
556 }
557 }
558
readData_plain(uword addr)559 static ubyte readData_plain(uword addr)
560 {
561 return c64mem1[addr];
562 }
563
readData_zp(uword addr)564 inline ubyte readData_zp(uword addr)
565 {
566 return c64mem1[addr];
567 }
568
569
570 // Functions to store data.
571
writeData_bs(uword addr,ubyte data)572 static void writeData_bs(uword addr, ubyte data)
573 {
574 if ((addr < 0xd000) || (addr >= 0xe000))
575 {
576 c64mem1[addr] = data;
577 if (addr == 0x01) // write to Bank-Select Register ?
578 {
579 evalBankSelect();
580 }
581 }
582 else
583 {
584 if (isIO)
585 {
586 // Check whether real SID or mirrored SID.
587 uword tempAddr = (addr & 0xfc1f);
588 // Not SID ?
589 if (( tempAddr & 0xff00 ) != 0xd400 )
590 {
591 c64mem2[addr] = data;
592 }
593 // $D41D/1E/1F, $D43D/3E/3F, ...
594 // Map to real address to support PlaySID
595 // Extended SID Chip Registers.
596 else if (( tempAddr & 0x00ff ) >= 0x001d )
597 {
598 // Mirrored SID.
599 c64mem2[addr] = (sidLastValue = data);
600 }
601 else
602 {
603 // SID.
604 c64mem2[tempAddr] = (sidLastValue = data);
605 // Handle key_ons.
606 sidKeysOn[tempAddr&0x001f] = sidKeysOn[tempAddr&0x001f] || ((data&1)!=0);
607 // Handle key_offs.
608 sidKeysOff[tempAddr&0x001f] = sidKeysOff[tempAddr&0x001f] || ((data&1)==0);
609 }
610 }
611 else
612 {
613 c64mem1[addr] = data;
614 }
615 }
616 }
617
writeData_plain(uword addr,ubyte data)618 static void writeData_plain(uword addr, ubyte data)
619 {
620 // Check whether real SID or mirrored SID.
621 uword tempAddr = (addr & 0xfc1f);
622 // Not SID ?
623 if (( tempAddr & 0xff00 ) != 0xd400 )
624 {
625 c64mem1[addr] = data;
626 }
627 // $D41D/1E/1F, $D43D/3E/3F, ...
628 // Map to real address to support PlaySID
629 // Extended SID Chip Registers.
630 else if (( tempAddr & 0x00ff ) >= 0x001d )
631 {
632 // Mirrored SID.
633 c64mem1[addr] = (sidLastValue = data);
634 }
635 else
636 {
637 // SID.
638 c64mem2[tempAddr] = (sidLastValue = data);
639 // Handle key_ons.
640 sidKeysOn[tempAddr&0x001f] = sidKeysOn[tempAddr&0x001f] || ((data&1)!=0);
641 // Handle key_offs.
642 sidKeysOff[tempAddr&0x001f] = sidKeysOff[tempAddr&0x001f] || ((data&1)==0);
643 }
644 }
645
writeData_zp(uword addr,ubyte data)646 inline void writeData_zp(uword addr, ubyte data)
647 {
648 c64mem1[addr] = data;
649 if (addr == 0x01) // write to Bank-Select Register ?
650 {
651 evalBankSelect();
652 }
653 }
654
655
656 // Use pointers to allow plain-memory modifications.
657 static ubyte (*readData)(uword) = &readData_bs;
658 static void (*writeData)(uword,ubyte) = &writeData_bs;
659
660 // --------------------------------------------------------------------------
661 // Legal instructions in alphabetical order.
662 //
663
ADC_m(ubyte x)664 inline void ADC_m(ubyte x)
665 {
666 if ( DF == 1 )
667 {
668 uword AC2 = AC +x +CF;
669 ZF = ( AC2 == 0 );
670 if ((( AC & 15 ) + ( x & 15 ) + CF ) > 9 )
671 {
672 AC2 += 6;
673 }
674 VF = ((( AC ^ x ^ AC2 ) & 0x80 ) != 0 ) ^ CF;
675 NF = (( AC2 & 128 ) != 0 );
676 if ( AC2 > 0x99 )
677 {
678 AC2 += 96;
679 }
680 CF = ( AC2 > 0x99 );
681 AC = ( AC2 & 255 );
682 }
683 else
684 {
685 uword AC2 = AC +x +CF;
686 CF = ( AC2 > 255 );
687 VF = ((( AC ^ x ^ AC2 ) & 0x80 ) != 0 ) ^ CF;
688 affectNZ( AC = ( AC2 & 255 ));
689 }
690 }
ADC_imm()691 static void ADC_imm() { ADC_m(imm()); pPC++; }
ADC_abso()692 static void ADC_abso() { ADC_m( readData(abso()) ); pPC += 2; }
ADC_absx()693 static void ADC_absx() { ADC_m( readData(absx()) ); pPC += 2; }
ADC_absy()694 static void ADC_absy() { ADC_m( readData(absy()) ); pPC += 2; }
ADC_indx()695 static void ADC_indx() { ADC_m( readData(indx()) ); pPC++; }
ADC_indy()696 static void ADC_indy() { ADC_m( readData(indy()) ); pPC++; }
ADC_zp()697 static void ADC_zp() { ADC_m( readData_zp(zp()) ); pPC++; }
ADC_zpx()698 static void ADC_zpx() { ADC_m( readData_zp(zpx()) ); pPC++; }
699
700
AND_m(ubyte x)701 inline void AND_m(ubyte x)
702 {
703 affectNZ( AC &= x );
704 }
AND_imm()705 static void AND_imm() { AND_m(imm()); pPC++; }
AND_abso()706 static void AND_abso() { AND_m( readData(abso()) ); pPC += 2; }
AND_absx()707 static void AND_absx() { AND_m( readData(absx()) ); pPC += 2; }
AND_absy()708 static void AND_absy() { AND_m( readData(absy()) ); pPC += 2; }
AND_indx()709 static void AND_indx() { AND_m( readData(indx()) ); pPC++; }
AND_indy()710 static void AND_indy() { AND_m( readData(indy()) ); pPC++; }
AND_zp()711 static void AND_zp() { AND_m( readData_zp(zp()) ); pPC++; }
AND_zpx()712 static void AND_zpx() { AND_m( readData_zp(zpx()) ); pPC++; }
713
714
ASL_m(ubyte x)715 inline ubyte ASL_m(ubyte x)
716 {
717 CF = (( x & 128 ) != 0 );
718 affectNZ( x <<= 1);
719 return x;
720 }
ASL_AC()721 static void ASL_AC()
722 {
723 AC = ASL_m(AC);
724 }
ASL_abso()725 static void ASL_abso()
726 {
727 uword tempAddr = abso();
728 pPC += 2;
729 writeData( tempAddr, ASL_m( readData(tempAddr)) );
730 }
ASL_absx()731 static void ASL_absx()
732 {
733 uword tempAddr = absx();
734 pPC += 2;
735 writeData( tempAddr, ASL_m( readData(tempAddr)) );
736 }
ASL_zp()737 static void ASL_zp()
738 {
739 uword tempAddr = zp();
740 pPC++;
741 writeData_zp( tempAddr, ASL_m( readData_zp(tempAddr)) );
742 }
ASL_zpx()743 static void ASL_zpx()
744 {
745 uword tempAddr = zpx();
746 pPC++;
747 writeData_zp( tempAddr, ASL_m( readData_zp(tempAddr)) );
748 }
749
750
BCC_()751 static void BCC_() { branchIfClear(CF); }
752
BCS_()753 static void BCS_() { branchIfSet(CF); }
754
BEQ_()755 static void BEQ_() { branchIfSet(ZF); }
756
757
BIT_m(ubyte x)758 inline void BIT_m(ubyte x)
759 {
760 ZF = (( AC & x ) == 0 );
761 VF = (( x & 64 ) != 0 );
762 NF = (( x & 128 ) != 0 );
763 }
BIT_abso()764 static void BIT_abso() { BIT_m( readData(abso()) ); pPC += 2; }
BIT_zp()765 static void BIT_zp() { BIT_m( readData_zp(zp()) ); pPC++; }
766
767
BMI_()768 static void BMI_() { branchIfSet(NF); }
769
BNE_()770 static void BNE_() { branchIfClear(ZF); }
771
BPL_()772 static void BPL_() { branchIfClear(NF); }
773
774
BRK_()775 static void BRK_()
776 {
777 BF = (IF = 1);
778 #if !defined(NO_RTS_UPON_BRK)
779 RTS_();
780 #endif
781 }
782
783
BVC_()784 static void BVC_() { branchIfClear(VF); }
785
BVS_()786 static void BVS_() { branchIfSet(VF); }
787
788
CLC_()789 static void CLC_() { CF = 0; }
790
CLD_()791 static void CLD_() { DF = 0; }
792
CLI_()793 static void CLI_() { IF = 0; }
794
CLV_()795 static void CLV_() { VF = 0; }
796
797
CMP_m(ubyte x)798 inline void CMP_m(ubyte x)
799 {
800 ZF = ( AC == x );
801 CF = ( AC >= x );
802 NF = ( (sbyte)( AC - x ) < 0 );
803 }
CMP_abso()804 static void CMP_abso() { CMP_m( readData(abso()) ); pPC += 2; }
CMP_absx()805 static void CMP_absx() { CMP_m( readData(absx()) ); pPC += 2; }
CMP_absy()806 static void CMP_absy() { CMP_m( readData(absy()) ); pPC += 2; }
CMP_imm()807 static void CMP_imm() { CMP_m(imm()); pPC++; }
CMP_indx()808 static void CMP_indx() { CMP_m( readData(indx()) ); pPC++; }
CMP_indy()809 static void CMP_indy() { CMP_m( readData(indy()) ); pPC++; }
CMP_zp()810 static void CMP_zp() { CMP_m( readData_zp(zp()) ); pPC++; }
CMP_zpx()811 static void CMP_zpx() { CMP_m( readData_zp(zpx()) ); pPC++; }
812
813
CPX_m(ubyte x)814 inline void CPX_m(ubyte x)
815 {
816 ZF = ( XR == x );
817 CF = ( XR >= x );
818 NF = ( (sbyte)( XR - x ) < 0 );
819 }
CPX_abso()820 static void CPX_abso() { CPX_m( readData(abso()) ); pPC += 2; }
CPX_imm()821 static void CPX_imm() { CPX_m(imm()); pPC++; }
CPX_zp()822 static void CPX_zp() { CPX_m( readData_zp(zp()) ); pPC++; }
823
824
CPY_m(ubyte x)825 inline void CPY_m(ubyte x)
826 {
827 ZF = ( YR == x );
828 CF = ( YR >= x );
829 NF = ( (sbyte)( YR - x ) < 0 );
830 }
CPY_abso()831 static void CPY_abso() { CPY_m( readData(abso()) ); pPC += 2; }
CPY_imm()832 static void CPY_imm() { CPY_m(imm()); pPC++; }
CPY_zp()833 static void CPY_zp() { CPY_m( readData_zp(zp()) ); pPC++; }
834
835
DEC_m(uword addr)836 inline void DEC_m(uword addr)
837 {
838 ubyte x = readData(addr);
839 affectNZ(--x);
840 writeData(addr, x);
841 }
DEC_m_zp(uword addr)842 inline void DEC_m_zp(uword addr)
843 {
844 ubyte x = readData_zp(addr);
845 affectNZ(--x);
846 writeData_zp(addr, x);
847 }
DEC_abso()848 static void DEC_abso() { DEC_m( abso() ); pPC += 2; }
DEC_absx()849 static void DEC_absx() { DEC_m( absx() ); pPC += 2; }
DEC_zp()850 static void DEC_zp() { DEC_m_zp( zp() ); pPC++; }
DEC_zpx()851 static void DEC_zpx() { DEC_m_zp( zpx() ); pPC++; }
852
853
DEX_()854 static void DEX_() { affectNZ(--XR); }
855
DEY_()856 static void DEY_() { affectNZ(--YR); }
857
858
EOR_m(ubyte x)859 inline void EOR_m(ubyte x)
860 {
861 AC ^= x;
862 affectNZ(AC);
863 }
EOR_abso()864 static void EOR_abso() { EOR_m( readData(abso()) ); pPC += 2; }
EOR_absx()865 static void EOR_absx() { EOR_m( readData(absx()) ); pPC += 2; }
EOR_absy()866 static void EOR_absy() { EOR_m( readData(absy()) ); pPC += 2; }
EOR_imm()867 static void EOR_imm() { EOR_m(imm()); pPC++; }
EOR_indx()868 static void EOR_indx() { EOR_m( readData(indx()) ); pPC++; }
EOR_indy()869 static void EOR_indy() { EOR_m( readData(indy()) ); pPC++; }
EOR_zp()870 static void EOR_zp() { EOR_m( readData_zp(zp()) ); pPC++; }
EOR_zpx()871 static void EOR_zpx() { EOR_m( readData_zp(zpx()) ); pPC++; }
872
873
INC_m(uword addr)874 inline void INC_m(uword addr)
875 {
876 ubyte x = readData(addr);
877 affectNZ(++x);
878 writeData(addr, x);
879 }
INC_m_zp(uword addr)880 inline void INC_m_zp(uword addr)
881 {
882 ubyte x = readData_zp(addr);
883 affectNZ(++x);
884 writeData_zp(addr, x);
885 }
INC_abso()886 static void INC_abso() { INC_m( abso() ); pPC += 2; }
INC_absx()887 static void INC_absx() { INC_m( absx() ); pPC += 2; }
INC_zp()888 static void INC_zp() { INC_m_zp( zp() ); pPC++; }
INC_zpx()889 static void INC_zpx() { INC_m_zp( zpx() ); pPC++; }
890
891
INX_()892 static void INX_() { affectNZ(++XR); }
893
INY_()894 static void INY_() { affectNZ(++YR); }
895
896
897
JMP_()898 static void JMP_()
899 {
900 PC = abso();
901 pPC = pPCbase+PC;
902 evalBankJump();
903 }
904
JMP_transp()905 static void JMP_transp()
906 {
907 PC = abso();
908 if ( (PC>=0xd000) && isKernal )
909 {
910 RTS_(); // will set pPC
911 }
912 else
913 {
914 pPC = pPCbase+PC;
915 }
916 }
917
JMP_plain()918 static void JMP_plain()
919 {
920 PC = abso();
921 pPC = pPCbase+PC;
922 }
923
924
JMP_vec()925 static void JMP_vec()
926 {
927 uword tempAddrLo = abso();
928 uword tempAddrHi = (tempAddrLo&0xFF00) | ((tempAddrLo+1)&0x00FF);
929 PC = readEndian(readData(tempAddrHi),readData(tempAddrLo));
930 pPC = pPCbase+PC;
931 evalBankJump();
932 }
933
JMP_vec_transp()934 static void JMP_vec_transp()
935 {
936 uword tempAddrLo = abso();
937 uword tempAddrHi = (tempAddrLo&0xFF00) | ((tempAddrLo+1)&0x00FF);
938 PC = readEndian(readData(tempAddrHi),readData(tempAddrLo));
939 if ( (PC>=0xd000) && isKernal )
940 {
941 RTS_(); // will set pPC
942 }
943 else
944 {
945 pPC = pPCbase+PC;
946 }
947 }
948
JMP_vec_plain()949 static void JMP_vec_plain()
950 {
951 uword tempAddrLo = abso();
952 uword tempAddrHi = (tempAddrLo&0xFF00) | ((tempAddrLo+1)&0x00FF);
953 PC = readEndian(readData(tempAddrHi),readData(tempAddrLo));
954 pPC = pPCbase+PC;
955 }
956
957
JSR_main()958 inline void JSR_main()
959 {
960 uword tempPC = abso();
961 pPC += 2;
962 PC = pPC-pPCbase;
963 PC--;
964 SP--;
965 writeLEword(c64mem1+SP,PC);
966 SP--;
967 checkSP();
968 PC = tempPC;
969 }
970
JSR_()971 static void JSR_()
972 {
973 JSR_main();
974 pPC = pPCbase+PC;
975 evalBankJump();
976 }
977
JSR_transp()978 static void JSR_transp()
979 {
980 JSR_main();
981 if ( (PC>=0xd000) && isKernal )
982 {
983 RTS_(); // will set pPC
984 }
985 else
986 {
987 pPC = pPCbase+PC;
988 }
989 }
990
JSR_plain()991 static void JSR_plain()
992 {
993 JSR_main();
994 pPC = pPCbase+PC;
995 }
996
997
LDA_abso()998 static void LDA_abso() { affectNZ( AC = readData(abso()) ); pPC += 2; }
LDA_absx()999 static void LDA_absx() { affectNZ( AC = readData( absx() )); pPC += 2; }
LDA_absy()1000 static void LDA_absy() { affectNZ( AC = readData( absy() ) ); pPC += 2; }
LDA_imm()1001 static void LDA_imm() { affectNZ( AC = imm() ); pPC++; }
LDA_indx()1002 static void LDA_indx() { affectNZ( AC = readData( indx() ) ); pPC++; }
LDA_indy()1003 static void LDA_indy() { affectNZ( AC = readData( indy() ) ); pPC++; }
LDA_zp()1004 static void LDA_zp() { affectNZ( AC = readData_zp( zp() ) ); pPC++; }
LDA_zpx()1005 static void LDA_zpx() { affectNZ( AC = readData_zp( zpx() ) ); pPC++; }
1006
1007
LDX_abso()1008 static void LDX_abso() { affectNZ(XR=readData(abso())); pPC += 2; }
LDX_absy()1009 static void LDX_absy() { affectNZ(XR=readData(absy())); pPC += 2; }
LDX_imm()1010 static void LDX_imm() { affectNZ(XR=imm()); pPC++; }
LDX_zp()1011 static void LDX_zp() { affectNZ(XR=readData_zp(zp())); pPC++; }
LDX_zpy()1012 static void LDX_zpy() { affectNZ(XR=readData_zp(zpy())); pPC++; }
1013
1014
LDY_abso()1015 static void LDY_abso() { affectNZ(YR=readData(abso())); pPC += 2; }
LDY_absx()1016 static void LDY_absx() { affectNZ(YR=readData(absx())); pPC += 2; }
LDY_imm()1017 static void LDY_imm() { affectNZ(YR=imm()); pPC++; }
LDY_zp()1018 static void LDY_zp() { affectNZ(YR=readData_zp(zp())); pPC++; }
LDY_zpx()1019 static void LDY_zpx() { affectNZ(YR=readData_zp(zpx())); pPC++; }
1020
1021
LSR_m(ubyte x)1022 inline ubyte LSR_m(ubyte x)
1023 {
1024 CF = x & 1;
1025 x >>= 1;
1026 NF = 0;
1027 ZF = (x == 0);
1028 return x;
1029 }
LSR_AC()1030 static void LSR_AC()
1031 {
1032 AC = LSR_m(AC);
1033 }
LSR_abso()1034 static void LSR_abso()
1035 {
1036 uword tempAddr = abso();
1037 pPC += 2;
1038 writeData( tempAddr, (LSR_m( readData(tempAddr))) );
1039 }
LSR_absx()1040 static void LSR_absx()
1041 {
1042 uword tempAddr = absx();
1043 pPC += 2;
1044 writeData( tempAddr, (LSR_m( readData(tempAddr))) );
1045 }
LSR_zp()1046 static void LSR_zp()
1047 {
1048 uword tempAddr = zp();
1049 pPC++;
1050 writeData_zp( tempAddr, (LSR_m( readData_zp(tempAddr))) );
1051 }
LSR_zpx()1052 static void LSR_zpx()
1053 {
1054 uword tempAddr = zpx();
1055 pPC++;
1056 writeData_zp( tempAddr, (LSR_m( readData_zp(tempAddr))) );
1057 }
1058
1059
ORA_m(ubyte x)1060 inline void ORA_m(ubyte x)
1061 {
1062 affectNZ( AC |= x );
1063 }
ORA_abso()1064 static void ORA_abso() { ORA_m( readData(abso()) ); pPC += 2; }
ORA_absx()1065 static void ORA_absx() { ORA_m( readData(absx()) ); pPC += 2; }
ORA_absy()1066 static void ORA_absy() { ORA_m( readData(absy()) ); pPC += 2; }
ORA_imm()1067 static void ORA_imm() { ORA_m(imm()); pPC++; }
ORA_indx()1068 static void ORA_indx() { ORA_m( readData(indx()) ); pPC++; }
ORA_indy()1069 static void ORA_indy() { ORA_m( readData(indy()) ); pPC++; }
ORA_zp()1070 static void ORA_zp() { ORA_m( readData_zp(zp()) ); pPC++; }
ORA_zpx()1071 static void ORA_zpx() { ORA_m( readData_zp(zpx()) ); pPC++; }
1072
1073
NOP_()1074 static void NOP_() { }
1075
PHA_()1076 static void PHA_() { c64mem1[SP--] = AC; }
1077
1078
PHP_()1079 static void PHP_()
1080 {
1081 c64mem1[SP--] = codeSR();
1082 }
1083
1084
PLA_()1085 static void PLA_()
1086 {
1087 affectNZ(AC=c64mem1[++SP]);
1088 }
1089
1090
PLP_()1091 static void PLP_()
1092 {
1093 decodeSR(c64mem1[++SP]);
1094 }
1095
ROL_m(ubyte x)1096 inline ubyte ROL_m(ubyte x)
1097 {
1098 ubyte y = ( x << 1 ) + CF;
1099 CF = (( x & 0x80 ) != 0 );
1100 affectNZ(y);
1101 return y;
1102 }
ROL_AC()1103 static void ROL_AC() { AC=ROL_m(AC); }
ROL_abso()1104 static void ROL_abso()
1105 {
1106 uword tempAddr = abso();
1107 pPC += 2;
1108 writeData( tempAddr, ROL_m( readData(tempAddr)) );
1109 }
ROL_absx()1110 static void ROL_absx()
1111 {
1112 uword tempAddr = absx();
1113 pPC += 2;
1114 writeData( tempAddr, ROL_m( readData(tempAddr)) );
1115 }
ROL_zp()1116 static void ROL_zp()
1117 {
1118 uword tempAddr = zp();
1119 pPC++;
1120 writeData_zp( tempAddr, ROL_m( readData_zp(tempAddr)) );
1121 }
ROL_zpx()1122 static void ROL_zpx()
1123 {
1124 uword tempAddr = zpx();
1125 pPC++;
1126 writeData_zp( tempAddr, ROL_m( readData_zp(tempAddr)) );
1127 }
1128
ROR_m(ubyte x)1129 inline ubyte ROR_m(ubyte x)
1130 {
1131 ubyte y = ( x >> 1 ) | ( CF << 7 );
1132 CF = ( x & 1 );
1133 affectNZ(y);
1134 return y;
1135 }
ROR_AC()1136 static void ROR_AC()
1137 {
1138 AC = ROR_m(AC);
1139 }
ROR_abso()1140 static void ROR_abso()
1141 {
1142 uword tempAddr = abso();
1143 pPC += 2;
1144 writeData( tempAddr, ROR_m( readData(tempAddr)) );
1145 }
ROR_absx()1146 static void ROR_absx()
1147 {
1148 uword tempAddr = absx();
1149 pPC += 2;
1150 writeData( tempAddr, ROR_m( readData(tempAddr)) );
1151 }
ROR_zp()1152 static void ROR_zp()
1153 {
1154 uword tempAddr = zp();
1155 pPC++;
1156 writeData_zp( tempAddr, ROR_m( readData_zp(tempAddr)) );
1157 }
ROR_zpx()1158 static void ROR_zpx()
1159 {
1160 uword tempAddr = zpx();
1161 pPC++;
1162 writeData_zp( tempAddr, ROR_m( readData_zp(tempAddr)) );
1163 }
1164
1165
RTI_()1166 static void RTI_()
1167 {
1168 // equal to RTS_();
1169 SP++;
1170 PC =readEndian( c64mem1[SP +1], c64mem1[SP] ) +1;
1171 pPC = pPCbase+PC;
1172 SP++;
1173 checkSP();
1174 }
1175
1176
1177 // RTS_() is inline.
1178
1179
SBC_m(ubyte s)1180 inline void SBC_m(ubyte s)
1181 {
1182 s = (~s) & 255;
1183 if ( DF == 1 )
1184 {
1185 uword AC2 = AC +s +CF;
1186 ZF = ( AC2 == 0 );
1187 if ((( AC & 15 ) + ( s & 15 ) + CF ) > 9 )
1188 {
1189 AC2 += 6;
1190 }
1191 VF = ((( AC ^ s ^ AC2 ) & 0x80 ) != 0 ) ^ CF;
1192 NF = (( AC2 & 128 ) != 0 );
1193 if ( AC2 > 0x99 )
1194 {
1195 AC2 += 96;
1196 }
1197 CF = ( AC2 > 0x99 );
1198 AC = ( AC2 & 255 );
1199 }
1200 else
1201 {
1202 uword AC2 = AC + s + CF;
1203 CF = ( AC2 > 255 );
1204 VF = ((( AC ^ s ^ AC2 ) & 0x80 ) != 0 ) ^ CF;
1205 affectNZ( AC = ( AC2 & 255 ));
1206 }
1207 }
SBC_abso()1208 static void SBC_abso() { SBC_m( readData(abso()) ); pPC += 2; }
SBC_absx()1209 static void SBC_absx() { SBC_m( readData(absx()) ); pPC += 2; }
SBC_absy()1210 static void SBC_absy() { SBC_m( readData(absy()) ); pPC += 2; }
SBC_imm()1211 static void SBC_imm() { SBC_m(imm()); pPC++; }
SBC_indx()1212 static void SBC_indx() { SBC_m( readData( indx()) ); pPC++; }
SBC_indy()1213 static void SBC_indy() { SBC_m( readData(indy()) ); pPC++; }
SBC_zp()1214 static void SBC_zp() { SBC_m( readData_zp(zp()) ); pPC++; }
SBC_zpx()1215 static void SBC_zpx() { SBC_m( readData_zp(zpx()) ); pPC++; }
1216
1217
SEC_()1218 static void SEC_() { CF=1; }
1219
SED_()1220 static void SED_() { DF=1; }
1221
SEI_()1222 static void SEI_() { IF=1; }
1223
1224
STA_abso()1225 static void STA_abso() { writeData( abso(), AC ); pPC += 2; }
STA_absx()1226 static void STA_absx() { writeData( absx(), AC ); pPC += 2; }
STA_absy()1227 static void STA_absy() { writeData( absy(), AC ); pPC += 2; }
STA_indx()1228 static void STA_indx() { writeData( indx(), AC ); pPC++; }
STA_indy()1229 static void STA_indy() { writeData( indy(), AC ); pPC++; }
STA_zp()1230 static void STA_zp() { writeData_zp( zp(), AC ); pPC++; }
STA_zpx()1231 static void STA_zpx() { writeData_zp( zpx(), AC ); pPC++; }
1232
1233
STX_abso()1234 static void STX_abso() { writeData( abso(), XR ); pPC += 2; }
STX_zp()1235 static void STX_zp() { writeData_zp( zp(), XR ); pPC++; }
STX_zpy()1236 static void STX_zpy() { writeData_zp( zpy(), XR ); pPC++; }
1237
1238
STY_abso()1239 static void STY_abso() { writeData( abso(), YR ); pPC += 2; }
STY_zp()1240 static void STY_zp() { writeData_zp( zp(), YR ); pPC++; }
STY_zpx()1241 static void STY_zpx() { writeData_zp( zpx(), YR ); pPC++; }
1242
1243
TAX_()1244 static void TAX_() { affectNZ(XR=AC); }
1245
TAY_()1246 static void TAY_() { affectNZ(YR=AC); }
1247
1248
TSX_()1249 static void TSX_()
1250 {
1251 XR = SP & 255;
1252 affectNZ(XR);
1253 }
1254
TXA_()1255 static void TXA_() { affectNZ(AC=XR); }
1256
TXS_()1257 static void TXS_() { SP = XR | 0x100; checkSP(); }
1258
TYA_()1259 static void TYA_() { affectNZ(AC=YR); }
1260
1261
1262 // --------------------------------------------------------------------------
1263 // Illegal codes/instructions part (1).
1264
ILL_TILT()1265 static void ILL_TILT() { }
1266
ILL_1NOP()1267 static void ILL_1NOP() { }
1268
ILL_2NOP()1269 static void ILL_2NOP() { pPC++; }
1270
ILL_3NOP()1271 static void ILL_3NOP() { pPC += 2; }
1272
1273
1274 // --------------------------------------------------------------------------
1275 // Illegal codes/instructions part (2).
1276
ASLORA_m(uword addr)1277 inline void ASLORA_m(uword addr)
1278 {
1279 ubyte x = ASL_m(readData(addr));
1280 writeData(addr,x);
1281 ORA_m(x);
1282 }
ASLORA_m_zp(uword addr)1283 inline void ASLORA_m_zp(uword addr)
1284 {
1285 ubyte x = ASL_m(readData_zp(addr));
1286 writeData_zp(addr,x);
1287 ORA_m(x);
1288 }
ASLORA_abso()1289 static void ASLORA_abso()
1290 {
1291 ASLORA_m(abso());
1292 pPC += 2;
1293 }
ASLORA_absx()1294 static void ASLORA_absx()
1295 {
1296 ASLORA_m(absx());
1297 pPC += 2;
1298 }
ASLORA_absy()1299 static void ASLORA_absy()
1300 {
1301 ASLORA_m(absy());
1302 pPC += 2;
1303 }
ASLORA_indx()1304 static void ASLORA_indx()
1305 {
1306 ASLORA_m(indx());
1307 pPC++;
1308 }
ASLORA_indy()1309 static void ASLORA_indy()
1310 {
1311 ASLORA_m(indy());
1312 pPC++;
1313 }
ASLORA_zp()1314 static void ASLORA_zp()
1315 {
1316 ASLORA_m_zp(zp());
1317 pPC++;
1318 }
ASLORA_zpx()1319 static void ASLORA_zpx()
1320 {
1321 ASLORA_m_zp(zpx());
1322 pPC++;
1323 }
1324
1325
ROLAND_m(uword addr)1326 inline void ROLAND_m(uword addr)
1327 {
1328 uword x = ROL_m(readData(addr));
1329 writeData(addr,x);
1330 AND_m(x);
1331 }
ROLAND_m_zp(uword addr)1332 inline void ROLAND_m_zp(uword addr)
1333 {
1334 uword x = ROL_m(readData_zp(addr));
1335 writeData_zp(addr,x);
1336 AND_m(x);
1337 }
ROLAND_abso()1338 static void ROLAND_abso()
1339 {
1340 ROLAND_m(abso());
1341 pPC += 2;
1342 }
ROLAND_absx()1343 static void ROLAND_absx()
1344 {
1345 ROLAND_m(absx());
1346 pPC += 2;
1347 }
ROLAND_absy()1348 static void ROLAND_absy()
1349 {
1350 ROLAND_m(absy());
1351 pPC += 2;
1352 }
ROLAND_indx()1353 static void ROLAND_indx()
1354 {
1355 ROLAND_m(indx());
1356 pPC++;
1357 }
ROLAND_indy()1358 static void ROLAND_indy()
1359 {
1360 ROLAND_m(indy());
1361 pPC++;
1362 }
ROLAND_zp()1363 static void ROLAND_zp()
1364 {
1365 ROLAND_m_zp(zp());
1366 pPC++;
1367 }
ROLAND_zpx()1368 static void ROLAND_zpx()
1369 {
1370 ROLAND_m_zp(zpx());
1371 pPC++;
1372 }
1373
1374
LSREOR_m(uword addr)1375 inline void LSREOR_m(uword addr)
1376 {
1377 uword x = LSR_m(readData(addr));
1378 writeData(addr,x);
1379 EOR_m(x);
1380 }
LSREOR_m_zp(uword addr)1381 inline void LSREOR_m_zp(uword addr)
1382 {
1383 uword x = LSR_m(readData_zp(addr));
1384 writeData_zp(addr,x);
1385 EOR_m(x);
1386 }
LSREOR_abso()1387 static void LSREOR_abso()
1388 {
1389 LSREOR_m(abso());
1390 pPC += 2;
1391 }
LSREOR_absx()1392 static void LSREOR_absx()
1393 {
1394 LSREOR_m(absx());
1395 pPC += 2;
1396 }
LSREOR_absy()1397 static void LSREOR_absy()
1398 {
1399 LSREOR_m(absy());
1400 pPC += 2;
1401 }
LSREOR_indx()1402 static void LSREOR_indx()
1403 {
1404 LSREOR_m(indx());
1405 pPC++;
1406 }
LSREOR_indy()1407 static void LSREOR_indy()
1408 {
1409 LSREOR_m(indy());
1410 pPC++;
1411 }
LSREOR_zp()1412 static void LSREOR_zp()
1413 {
1414 LSREOR_m_zp(zp());
1415 pPC++;
1416 }
LSREOR_zpx()1417 static void LSREOR_zpx()
1418 {
1419 LSREOR_m_zp(zpx());
1420 pPC++;
1421 }
1422
1423
RORADC_m(uword addr)1424 inline void RORADC_m(uword addr)
1425 {
1426 ubyte x = ROR_m(readData(addr));
1427 writeData(addr,x);
1428 ADC_m(x);
1429 }
RORADC_m_zp(uword addr)1430 inline void RORADC_m_zp(uword addr)
1431 {
1432 ubyte x = ROR_m(readData_zp(addr));
1433 writeData_zp(addr,x);
1434 ADC_m(x);
1435 }
RORADC_abso()1436 static void RORADC_abso()
1437 {
1438 RORADC_m(abso());
1439 pPC += 2;
1440 }
RORADC_absx()1441 static void RORADC_absx()
1442 {
1443 RORADC_m(absx());
1444 pPC += 2;
1445 }
RORADC_absy()1446 static void RORADC_absy()
1447 {
1448 RORADC_m(absy());
1449 pPC += 2;
1450 }
RORADC_indx()1451 static void RORADC_indx()
1452 {
1453 RORADC_m(indx());
1454 pPC++;
1455 }
RORADC_indy()1456 static void RORADC_indy()
1457 {
1458 RORADC_m(indy());
1459 pPC++;
1460 }
RORADC_zp()1461 static void RORADC_zp()
1462 {
1463 RORADC_m_zp(zp());
1464 pPC++;
1465 }
RORADC_zpx()1466 static void RORADC_zpx()
1467 {
1468 RORADC_m_zp(zpx());
1469 pPC++;
1470 }
1471
1472
DECCMP_m(uword addr)1473 inline void DECCMP_m(uword addr)
1474 {
1475 ubyte x = readData(addr);
1476 writeData(addr,(--x));
1477 CMP_m(x);
1478 }
DECCMP_m_zp(uword addr)1479 inline void DECCMP_m_zp(uword addr)
1480 {
1481 ubyte x = readData_zp(addr);
1482 writeData_zp(addr,(--x));
1483 CMP_m(x);
1484 }
DECCMP_abso()1485 static void DECCMP_abso()
1486 {
1487 DECCMP_m(abso());
1488 pPC += 2;
1489 }
DECCMP_absx()1490 static void DECCMP_absx()
1491 {
1492 DECCMP_m(absx());
1493 pPC += 2;
1494 }
DECCMP_absy()1495 static void DECCMP_absy()
1496 {
1497 DECCMP_m(absy());
1498 pPC += 2;
1499 }
DECCMP_indx()1500 static void DECCMP_indx()
1501 {
1502 DECCMP_m(indx());
1503 pPC++;
1504 }
DECCMP_indy()1505 static void DECCMP_indy()
1506 {
1507 DECCMP_m(indy());
1508 pPC++;
1509 }
DECCMP_zp()1510 static void DECCMP_zp()
1511 {
1512 DECCMP_m_zp(zp());
1513 pPC++;
1514 }
DECCMP_zpx()1515 static void DECCMP_zpx()
1516 {
1517 DECCMP_m_zp(zpx());
1518 pPC++;
1519 }
1520
1521
INCSBC_m(uword addr)1522 inline void INCSBC_m(uword addr)
1523 {
1524 ubyte x = readData(addr);
1525 writeData(addr,(++x));
1526 SBC_m(x);
1527 }
INCSBC_m_zp(uword addr)1528 inline void INCSBC_m_zp(uword addr)
1529 {
1530 ubyte x = readData_zp(addr);
1531 writeData_zp(addr,(++x));
1532 SBC_m(x);
1533 }
INCSBC_abso()1534 static void INCSBC_abso()
1535 {
1536 INCSBC_m(abso());
1537 pPC += 2;
1538 }
INCSBC_absx()1539 static void INCSBC_absx()
1540 {
1541 INCSBC_m(absx());
1542 pPC += 2;
1543 }
INCSBC_absy()1544 static void INCSBC_absy()
1545 {
1546 INCSBC_m(absy());
1547 pPC += 2;
1548 }
INCSBC_indx()1549 static void INCSBC_indx()
1550 {
1551 INCSBC_m(indx());
1552 pPC++;
1553 }
INCSBC_indy()1554 static void INCSBC_indy()
1555 {
1556 INCSBC_m(indy());
1557 pPC++;
1558 }
INCSBC_zp()1559 static void INCSBC_zp()
1560 {
1561 INCSBC_m_zp(zp());
1562 pPC++;
1563 }
INCSBC_zpx()1564 static void INCSBC_zpx()
1565 {
1566 INCSBC_m_zp(zpx());
1567 pPC++;
1568 }
1569
1570
1571 // --------------------------------------------------------------------------
1572 // Illegal codes/instructions part (3). This implementation is considered to
1573 // be only partially working due to inconsistencies in the available
1574 // documentation.
1575 // Note: In some of the functions emulated, defined instructions are used and
1576 // already increment the PC ! Take care, and do not increment further !
1577 // Double-setting of processor flags can occur, too.
1578
ILL_0B()1579 static void ILL_0B() // equal to 2B
1580 {
1581 AND_imm();
1582 CF = NF;
1583 }
1584
ILL_4B()1585 static void ILL_4B()
1586 {
1587 AND_imm();
1588 LSR_AC();
1589 }
1590
ILL_6B()1591 static void ILL_6B()
1592 {
1593 if (DF == 0)
1594 {
1595 AND_imm();
1596 ROR_AC();
1597 CF = (AC & 1);
1598 VF = (AC >> 5) ^ (AC >> 6);
1599 }
1600 }
1601
ILL_83()1602 static void ILL_83()
1603 {
1604 writeData(indx(),AC & XR);
1605 pPC++;
1606 }
1607
ILL_87()1608 static void ILL_87()
1609 {
1610 writeData_zp(zp(),AC & XR);
1611 pPC++;
1612 }
1613
ILL_8B()1614 static void ILL_8B()
1615 {
1616 TXA_();
1617 AND_imm();
1618 }
1619
ILL_8F()1620 static void ILL_8F()
1621 {
1622 writeData(abso(),AC & XR);
1623 pPC += 2;
1624 }
1625
ILL_93()1626 static void ILL_93()
1627 {
1628 writeData(indy(), AC & XR & (1+(readData((*pPC)+1) & 0xFF)));
1629 pPC++;
1630 }
1631
ILL_97()1632 static void ILL_97()
1633 {
1634 writeData_zp(zpx(),AC & XR);
1635 pPC++;
1636 }
1637
ILL_9B()1638 static void ILL_9B()
1639 {
1640 SP = 0x100 | (AC & XR);
1641 writeData(absy(),(SP & ((*pPC+1)+1)));
1642 pPC += 2;
1643 checkSP();
1644 }
1645
ILL_9C()1646 static void ILL_9C()
1647 {
1648 writeData(absx(),(YR & ((*pPC+1)+1)));
1649 pPC += 2;
1650 }
1651
ILL_9E()1652 static void ILL_9E()
1653 {
1654 writeData(absy(),(XR & ((*pPC+1)+1)));
1655 pPC += 2;
1656 }
1657
ILL_9F()1658 static void ILL_9F()
1659 {
1660 writeData(absy(),(AC & XR & ((*pPC+1)+1)));
1661 pPC += 2;
1662 }
1663
ILL_A3()1664 static void ILL_A3()
1665 {
1666 LDA_indx();
1667 TAX_();
1668 }
1669
ILL_A7()1670 static void ILL_A7()
1671 {
1672 LDA_zp();
1673 TAX_();
1674 }
1675
ILL_AB()1676 static void ILL_AB()
1677 // Taken from VICE because a single music player has been found
1678 // (not in HVSC) which seems to need ILL_AB implemented like this
1679 // (or similarly) in order to work.
1680 {
1681 AC = XR = ((AC|0xee)&(*pPC++));
1682 affectNZ( AC );
1683 }
1684
ILL_AF()1685 static void ILL_AF()
1686 {
1687 LDA_abso();
1688 TAX_();
1689 }
1690
ILL_B3()1691 static void ILL_B3()
1692 {
1693 LDA_indy();
1694 TAX_();
1695 }
1696
ILL_B7()1697 static void ILL_B7()
1698 {
1699 affectNZ(AC = readData_zp(zpy())); // would be LDA_zpy()
1700 TAX_();
1701 pPC++;
1702 }
1703
ILL_BB()1704 static void ILL_BB()
1705 {
1706 XR = (SP & absy());
1707 pPC += 2;
1708 TXS_();
1709 TXA_();
1710 }
1711
ILL_BF()1712 static void ILL_BF()
1713 {
1714 LDA_absy();
1715 TAX_();
1716 }
1717
ILL_CB()1718 static void ILL_CB()
1719 {
1720 uword tmp = XR & AC;
1721 tmp -= imm();
1722 CF = (tmp > 255);
1723 affectNZ(XR=(tmp&255));
1724 }
1725
ILL_EB()1726 static void ILL_EB()
1727 {
1728 SBC_imm();
1729 }
1730
1731 // --------------------------------------------------------------------------
1732
1733 static ptr2func instrList[] =
1734 {
1735 &BRK_, &ORA_indx, &ILL_TILT, &ASLORA_indx, &ILL_2NOP, &ORA_zp, &ASL_zp, &ASLORA_zp,
1736 &PHP_, &ORA_imm, &ASL_AC, &ILL_0B, &ILL_3NOP, &ORA_abso, &ASL_abso, &ASLORA_abso,
1737 &BPL_, &ORA_indy, &ILL_TILT, &ASLORA_indy, &ILL_2NOP, &ORA_zpx, &ASL_zpx, &ASLORA_zpx,
1738 &CLC_, &ORA_absy, &ILL_1NOP, &ASLORA_absy, &ILL_3NOP, &ORA_absx, &ASL_absx, &ASLORA_absx,
1739 &JSR_, &AND_indx, &ILL_TILT, &ROLAND_indx, &BIT_zp, &AND_zp, &ROL_zp, &ROLAND_zp,
1740 &PLP_, &AND_imm, &ROL_AC, &ILL_0B, &BIT_abso, &AND_abso, &ROL_abso, &ROLAND_abso,
1741 &BMI_, &AND_indy, &ILL_TILT, &ROLAND_indy, &ILL_2NOP, &AND_zpx, &ROL_zpx, &ROLAND_zpx,
1742 &SEC_, &AND_absy, &ILL_1NOP, &ROLAND_absy, &ILL_3NOP, &AND_absx, &ROL_absx, &ROLAND_absx,
1743 // 0x40
1744 &RTI_, &EOR_indx, &ILL_TILT, &LSREOR_indx, &ILL_2NOP, &EOR_zp, &LSR_zp, &LSREOR_zp,
1745 &PHA_, &EOR_imm, &LSR_AC, &ILL_4B, &JMP_, &EOR_abso, &LSR_abso, &LSREOR_abso,
1746 &BVC_, &EOR_indy, &ILL_TILT, &LSREOR_indy, &ILL_2NOP, &EOR_zpx, &LSR_zpx, &LSREOR_zpx,
1747 &CLI_, &EOR_absy, &ILL_1NOP, &LSREOR_absy, &ILL_3NOP, &EOR_absx, &LSR_absx, &LSREOR_absx,
1748 &RTS_, &ADC_indx, &ILL_TILT, &RORADC_indx, &ILL_2NOP, &ADC_zp, &ROR_zp, &RORADC_zp,
1749 &PLA_, &ADC_imm, &ROR_AC, &ILL_6B, &JMP_vec, &ADC_abso, &ROR_abso, &RORADC_abso,
1750 &BVS_, &ADC_indy, &ILL_TILT, &RORADC_indy, &ILL_2NOP, &ADC_zpx, &ROR_zpx, &RORADC_zpx,
1751 &SEI_, &ADC_absy, &ILL_1NOP, &RORADC_absy, &ILL_3NOP, &ADC_absx, &ROR_absx, &RORADC_absx,
1752 // 0x80
1753 &ILL_2NOP, &STA_indx, &ILL_2NOP, &ILL_83, &STY_zp, &STA_zp, &STX_zp, &ILL_87,
1754 &DEY_, &ILL_2NOP, &TXA_, &ILL_8B, &STY_abso, &STA_abso, &STX_abso, &ILL_8F,
1755 &BCC_, &STA_indy, &ILL_TILT, &ILL_93, &STY_zpx, &STA_zpx, &STX_zpy, &ILL_97,
1756 &TYA_, &STA_absy, &TXS_, &ILL_9B, &ILL_9C, &STA_absx, &ILL_9E, &ILL_9F,
1757 &LDY_imm, &LDA_indx, &LDX_imm, &ILL_A3, &LDY_zp, &LDA_zp, &LDX_zp, &ILL_A7,
1758 &TAY_, &LDA_imm, &TAX_, &ILL_AB, &LDY_abso, &LDA_abso, &LDX_abso, &ILL_AF,
1759 &BCS_, &LDA_indy, &ILL_TILT, &ILL_B3, &LDY_zpx, &LDA_zpx, &LDX_zpy, &ILL_B7,
1760 &CLV_, &LDA_absy, &TSX_, &ILL_BB, &LDY_absx, &LDA_absx, &LDX_absy, &ILL_BF,
1761 // 0xC0
1762 &CPY_imm, &CMP_indx, &ILL_2NOP, &DECCMP_indx, &CPY_zp, &CMP_zp, &DEC_zp, &DECCMP_zp,
1763 &INY_, &CMP_imm, &DEX_, &ILL_CB, &CPY_abso, &CMP_abso, &DEC_abso, &DECCMP_abso,
1764 &BNE_, &CMP_indy, &ILL_TILT, &DECCMP_indy, &ILL_2NOP, &CMP_zpx, &DEC_zpx, &DECCMP_zpx,
1765 &CLD_, &CMP_absy, &ILL_1NOP, &DECCMP_absy, &ILL_3NOP, &CMP_absx, &DEC_absx, &DECCMP_absx,
1766 &CPX_imm, &SBC_indx, &ILL_2NOP, &INCSBC_indx, &CPX_zp, &SBC_zp, &INC_zp, &INCSBC_zp,
1767 &INX_, &SBC_imm, &NOP_, &ILL_EB, &CPX_abso, &SBC_abso, &INC_abso, &INCSBC_abso,
1768 &BEQ_, &SBC_indy, &ILL_TILT, &INCSBC_indy, &ILL_2NOP, &SBC_zpx, &INC_zpx, &INCSBC_zpx,
1769 &SED_, &SBC_absy, &ILL_1NOP, &INCSBC_absy, &ILL_3NOP, &SBC_absx, &INC_absx, &INCSBC_absx
1770 };
1771
1772
1773 static int memoryMode = MPU_TRANSPARENT_ROM; // the default
1774
1775
initInterpreter(int inMemoryMode)1776 void initInterpreter(int inMemoryMode)
1777 {
1778 memoryMode = inMemoryMode;
1779 if (memoryMode == MPU_TRANSPARENT_ROM)
1780 {
1781 readData = &readData_transp;
1782 writeData = &writeData_bs;
1783 instrList[0x20] = &JSR_transp;
1784 instrList[0x4C] = &JMP_transp;
1785 instrList[0x6C] = &JMP_vec_transp;
1786 // Make the memory buffers accessible to the whole emulator engine.
1787 // Use two distinct 64KB memory areas.
1788 c64mem1 = c64ramBuf;
1789 c64mem2 = c64romBuf;
1790 }
1791 else if (memoryMode == MPU_PLAYSID_ENVIRONMENT)
1792 {
1793 readData = &readData_plain;
1794 writeData = &writeData_plain;
1795 instrList[0x20] = &JSR_plain;
1796 instrList[0x4C] = &JMP_plain;
1797 instrList[0x6C] = &JMP_vec_plain;
1798 // Make the memory buffers accessible to the whole emulator engine.
1799 // Use a single 64KB memory area.
1800 c64mem2 = (c64mem1 = c64ramBuf);
1801 }
1802 else // if (memoryMode == MPU_BANK_SWITCHING)
1803 {
1804 readData = &readData_bs;
1805 writeData = &writeData_bs;
1806 instrList[0x20] = &JSR_;
1807 instrList[0x4C] = &JMP_;
1808 instrList[0x6C] = &JMP_vec;
1809 // Make the memory buffers accessible to the whole emulator engine.
1810 // Use two distinct 64KB memory areas.
1811 c64mem1 = c64ramBuf;
1812 c64mem2 = c64romBuf;
1813 }
1814 bankSelReg = c64ramBuf+1; // extra pointer
1815 // Set code execution segment to RAM.
1816 pPCbase = c64ramBuf;
1817 pPCend = c64ramBuf+65536;
1818 }
1819
1820
interpreter(uword p,ubyte ramrom,ubyte a,ubyte x,ubyte y)1821 bool interpreter(uword p, ubyte ramrom, ubyte a, ubyte x, ubyte y)
1822 {
1823 if (memoryMode == MPU_PLAYSID_ENVIRONMENT)
1824 {
1825 AC = a;
1826 XR = 0;
1827 YR = 0;
1828 }
1829 else
1830 {
1831 *bankSelReg = ramrom;
1832 evalBankSelect();
1833 AC = a;
1834 XR = x;
1835 YR = y;
1836 }
1837
1838 // Set program-counter (pointer instead of raw PC).
1839 pPC = pPCbase+p;
1840
1841 resetSP();
1842 resetSR();
1843 sidKeysOff[4] = (sidKeysOff[4+7] = (sidKeysOff[4+14] = false));
1844 sidKeysOn[4] = (sidKeysOn[4+7] = (sidKeysOn[4+14] = false));
1845
1846 do
1847 {
1848 (*instrList[*(pPC++)])();
1849 }
1850 while (stackIsOkay&&(pPC<pPCend));
1851
1852 return true;
1853 }
1854
1855
c64memReset(int clockSpeed,ubyte randomSeed)1856 void c64memReset(int clockSpeed, ubyte randomSeed)
1857 {
1858 fakeReadTimer += randomSeed;
1859
1860 if ((c64mem1 != 0) && (c64mem2 != 0))
1861 {
1862 c64mem1[0] = 0x2F;
1863 // defaults: Basic-ROM on, Kernal-ROM on, I/O on
1864 c64mem1[1] = 0x07;
1865 evalBankSelect();
1866
1867 // CIA-Timer A $DC04/5 = $4025 PAL, $4295 NTSC
1868 if (clockSpeed == SIDTUNE_CLOCK_NTSC)
1869 {
1870 c64mem1[0x02a6] = 0; // NTSC
1871 c64mem2[0xdc04] = 0x95;
1872 c64mem2[0xdc05] = 0x42;
1873 }
1874 else // if (clockSpeed == SIDTUNE_CLOCK_PAL)
1875 {
1876 c64mem1[0x02a6] = 1; // PAL
1877 c64mem2[0xdc04] = 0x25;
1878 c64mem2[0xdc05] = 0x40;
1879 }
1880
1881 // fake VBI-interrupts that do $D019, BMI ...
1882 c64mem2[0xd019] = 0xff;
1883
1884 // software vectors
1885 // IRQ to $EA31
1886 c64mem1[0x0314] = 0x31;
1887 c64mem1[0x0315] = 0xea;
1888 // BRK to $FE66
1889 c64mem1[0x0316] = 0x66;
1890 c64mem1[0x0317] = 0xfe;
1891 // NMI to $FE47
1892 c64mem1[0x0318] = 0x47;
1893 c64mem1[0x0319] = 0xfe;
1894
1895 // hardware vectors
1896 if (memoryMode == MPU_PLAYSID_ENVIRONMENT)
1897 {
1898 c64mem1[0xff48] = 0x6c;
1899 c64mem1[0xff49] = 0x14;
1900 c64mem1[0xff4a] = 0x03;
1901 c64mem1[0xfffa] = 0xf8;
1902 c64mem1[0xfffb] = 0xff;
1903 c64mem1[0xfffe] = 0x48;
1904 c64mem1[0xffff] = 0xff;
1905 }
1906 else
1907 {
1908 // NMI to $FE43
1909 c64mem1[0xfffa] = 0x43;
1910 c64mem1[0xfffb] = 0xfe;
1911 // RESET to $FCE2
1912 c64mem1[0xfffc] = 0xe2;
1913 c64mem1[0xfffd] = 0xfc;
1914 // IRQ to $FF48
1915 c64mem1[0xfffe] = 0x48;
1916 c64mem1[0xffff] = 0xff;
1917 }
1918
1919 // clear SID
1920 for ( int i = 0; i < 0x1d; i++ )
1921 {
1922 c64mem2[0xd400 +i] = 0;
1923 }
1924 // default Mastervolume, no filter
1925 c64mem2[0xd418] = (sidLastValue = 0x0f);
1926 }
1927 }
1928
1929
c64memClear()1930 void c64memClear()
1931 {
1932 // Clear entire RAM and ROM.
1933 for ( udword i = 0; i < 0x10000; i++ )
1934 {
1935 c64mem1[i] = 0;
1936 if (memoryMode != MPU_PLAYSID_ENVIRONMENT)
1937 {
1938 c64mem2[i] = 0;
1939 }
1940 sidLastValue = 0;
1941 }
1942 if (memoryMode == MPU_PLAYSID_ENVIRONMENT)
1943 {
1944 // Fill Kernal-ROM address space with RTI instructions.
1945 for ( udword j = 0xE000; j < 0x10000; j++ )
1946 {
1947 c64mem1[j] = 0x40;
1948 }
1949 }
1950 else
1951 {
1952 // Fill Basic-ROM address space with RTS instructions.
1953 for ( udword j1 = 0xA000; j1 < 0xC000; j1++ )
1954 {
1955 c64mem2[j1] = 0x60;
1956 }
1957 // Fill Kernal-ROM address space with RTI instructions.
1958 for ( udword j2 = 0xE000; j2 < 0x10000; j2++ )
1959 {
1960 c64mem2[j2] = 0x40;
1961 }
1962 }
1963 }
1964
1965
1966 // Input: A 16-bit effective address
1967 // Output: A default bank-select value for $01.
c64memRamRom(uword address)1968 ubyte c64memRamRom( uword address )
1969 {
1970 if (memoryMode == MPU_PLAYSID_ENVIRONMENT)
1971 {
1972 return 4; // RAM only, but special I/O mode
1973 }
1974 else
1975 {
1976 if ( address < 0xa000 )
1977 {
1978 return 7; // Basic-ROM, Kernal-ROM, I/O
1979 }
1980 else if ( address < 0xd000 )
1981 {
1982 return 6; // Kernal-ROM, I/O
1983 }
1984 else if ( address >= 0xe000 )
1985 {
1986 return 5; // I/O only
1987 }
1988 else
1989 {
1990 return 4; // RAM only
1991 }
1992 }
1993 }
1994