00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 #include "sysdeps.h"
00068
00069 #include "CPUC64.h"
00070 #include "C64.h"
00071 #include "VIC.h"
00072 #include "SID.h"
00073 #include "CIA.h"
00074 #include "REU.h"
00075 #include "IEC.h"
00076 #include "Display.h"
00077 #include "Version.h"
00078
00079 #include "main.h"
00080
00081
00082 enum {
00083 INT_RESET = 3
00084 };
00085
00086
00087
00088
00089
00090
00091 MOS6510::MOS6510(C64 *c64, uint8 *Ram, uint8 *Basic, uint8 *Kernal, uint8 *Char, uint8 *Color)
00092 : the_c64(c64), ram(Ram), basic_rom(Basic), kernal_rom(Kernal), char_rom(Char), color_ram(Color)
00093 {
00094 __CHECK_NULL(c64);
00095 __CHECK_NULL(Ram);
00096 __CHECK_NULL(Basic);
00097 __CHECK_NULL(Kernal);
00098 __CHECK_NULL(Char);
00099 __CHECK_NULL(Color);
00100
00101 a = x = y = 0;
00102 sp = 0xff;
00103 n_flag = z_flag = 0;
00104 v_flag = d_flag = c_flag = false;
00105 i_flag = true;
00106 dfff_byte = 0x55;
00107 borrowed_cycles = 0;
00108
00109 CTOR(MOS6510);
00110 }
00111
00112 MOS6510::~MOS6510()
00113 {
00114 DTOR(MOS6510);
00115 }
00116
00117
00118
00119
00120
00121
00122 void MOS6510::AsyncReset(void)
00123 {
00124 interrupt.intr[INT_RESET] = true;
00125 }
00126
00127
00128
00129
00130
00131
00132 void MOS6510::AsyncNMI(void)
00133 {
00134 if (!nmi_state)
00135 interrupt.intr[INT_NMI] = true;
00136 }
00137
00138
00139
00140
00141
00142
00143 void MOS6510::new_config(void)
00144 {
00145 uint8 port = ~ram[0] | ram[1];
00146
00147 basic_in = (port & 3) == 3;
00148
00149 kernal_in = BOOL_BIT(port, 2);
00150 char_in = (port & 3) && !(port & 4);
00151 io_in = (port & 3) && (port & 4);
00152 }
00153
00154
00155
00156
00157
00158
00159 inline uint8 MOS6510::read_byte_io(uint16 adr)
00160 {
00161 switch (adr >> 12) {
00162 case 0xa:
00163 case 0xb:
00164 if (basic_in)
00165 return basic_rom[adr & 0x1fff];
00166 else
00167 return ram[adr];
00168 case 0xc:
00169 return ram[adr];
00170 case 0xd:
00171 if (io_in)
00172 switch ((adr >> 8) & 0x0f) {
00173 case 0x0:
00174 case 0x1:
00175 case 0x2:
00176 case 0x3:
00177 return TheVIC->ReadRegister(adr & 0x3f);
00178 case 0x4:
00179 case 0x5:
00180 case 0x6:
00181 case 0x7:
00182 return TheSID->ReadRegister(adr & 0x1f);
00183 case 0x8:
00184 case 0x9:
00185 case 0xa:
00186 case 0xb:
00187 return color_ram[adr & 0x03ff] | rand() & 0xf0;
00188 case 0xc:
00189 return TheCIA1->ReadRegister(adr & 0x0f);
00190 case 0xd:
00191 return TheCIA2->ReadRegister(adr & 0x0f);
00192 case 0xe:
00193 case 0xf:
00194 if ((adr & 0xfff0) == 0xdf00)
00195 return TheREU->ReadRegister(adr & 0x0f);
00196 else if (adr < 0xdfa0)
00197 return rand();
00198 else
00199 return read_emulator_id(adr & 0x7f);
00200 }
00201 else if (char_in)
00202 return char_rom[adr & 0x0fff];
00203 else
00204 return ram[adr];
00205 case 0xe:
00206 case 0xf:
00207 if (kernal_in)
00208 return kernal_rom[adr & 0x1fff];
00209 else
00210 return ram[adr];
00211 default:
00212 return 0;
00213 }
00214 }
00215
00216
00217
00218
00219
00220
00221 uint8 MOS6510::read_byte(uint16 adr)
00222 {
00223 if (adr < 0xa000)
00224 return ram[adr];
00225 else
00226 return read_byte_io(adr);
00227 }
00228
00229
00230
00231
00232
00233
00234 const char frodo_id[0x5c] = "FRODO\r(C) 1994-1997 CHRISTIAN BAUER";
00235
00236 uint8 MOS6510::read_emulator_id(uint16 adr)
00237 {
00238 switch (adr) {
00239 case 0x7c:
00240 return FRODO_REVISION << 4;
00241 case 0x7d:
00242 return FRODO_VERSION;
00243 case 0x7e:
00244 return 'F';
00245 case 0x7f:
00246 dfff_byte = ~dfff_byte;
00247 return dfff_byte;
00248 default:
00249 return frodo_id[adr - 0x20];
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258 #if LITTLE_ENDIAN_UNALIGNED
00259
00260 inline uint16 MOS6510::read_word(uint16 adr)
00261 {
00262 switch (adr >> 12) {
00263 case 0x0:
00264 case 0x1:
00265 case 0x2:
00266 case 0x3:
00267 case 0x4:
00268 case 0x5:
00269 case 0x6:
00270 case 0x7:
00271 case 0x8:
00272 case 0x9:
00273 return *(uint16*)&ram[adr];
00274 break;
00275 case 0xa:
00276 case 0xb:
00277 if (basic_in)
00278 return *(uint16*)&basic_rom[adr & 0x1fff];
00279 else
00280 return *(uint16*)&ram[adr];
00281 case 0xc:
00282 return *(uint16*)&ram[adr];
00283 case 0xd:
00284 if (io_in)
00285 return read_byte(adr) | (read_byte(adr+1) << 8);
00286 else if (char_in)
00287 return *(uint16*)&char_rom[adr & 0x0fff];
00288 else
00289 return *(uint16*)&ram[adr];
00290 case 0xe:
00291 case 0xf:
00292 if (kernal_in)
00293 return *(uint16*)&kernal_rom[adr & 0x1fff];
00294 else
00295 return *(uint16*)&ram[adr];
00296 default:
00297 return 0;
00298 }
00299 }
00300
00301 #else
00302
00303 inline uint16 MOS6510::read_word(uint16 adr)
00304 {
00305 return read_byte(adr) | (read_byte(adr+1) << 8);
00306 }
00307
00308 #endif
00309
00310
00311
00312
00313
00314
00315 void MOS6510::write_byte_io(uint16 adr, uint8 byte)
00316 {
00317 if (adr >= 0xe000) {
00318 ram[adr] = byte;
00319 if (adr == 0xff00)
00320 TheREU->FF00Trigger();
00321 } else if (io_in)
00322 switch ((adr >> 8) & 0x0f) {
00323 case 0x0:
00324 case 0x1:
00325 case 0x2:
00326 case 0x3:
00327 TheVIC->WriteRegister(adr & 0x3f, byte);
00328 return;
00329 case 0x4:
00330 case 0x5:
00331 case 0x6:
00332 case 0x7:
00333 TheSID->WriteRegister(adr & 0x1f, byte);
00334 return;
00335 case 0x8:
00336 case 0x9:
00337 case 0xa:
00338 case 0xb:
00339 color_ram[adr & 0x03ff] = byte & 0x0f;
00340 return;
00341 case 0xc:
00342 TheCIA1->WriteRegister(adr & 0x0f, byte);
00343 return;
00344 case 0xd:
00345 TheCIA2->WriteRegister(adr & 0x0f, byte);
00346 return;
00347 case 0xe:
00348 case 0xf:
00349 if ((adr & 0xfff0) == 0xdf00)
00350 TheREU->WriteRegister(adr & 0x0f, byte);
00351 return;
00352 }
00353 else
00354 ram[adr] = byte;
00355 }
00356
00357
00358
00359
00360
00361
00362 inline void MOS6510::write_byte(uint16 adr, uint8 byte)
00363 {
00364 if (adr < 0xd000) {
00365 ram[adr] = byte;
00366 if (adr < 2)
00367 new_config();
00368 } else
00369 write_byte_io(adr, byte);
00370 }
00371
00372
00373
00374
00375
00376
00377 inline uint8 MOS6510::read_zp(uint16 adr)
00378 {
00379 return ram[adr];
00380 }
00381
00382
00383
00384
00385
00386
00387 inline uint16 MOS6510::read_zp_word(uint16 adr)
00388 {
00389
00390 #if LITTLE_ENDIAN_UNALIGNED
00391 return *(uint16 *)&ram[adr & 0xff];
00392 #else
00393 return ram[adr & 0xff] | (ram[(adr+1) & 0xff] << 8);
00394 #endif
00395 }
00396
00397
00398
00399
00400
00401
00402 inline void MOS6510::write_zp(uint16 adr, uint8 byte)
00403 {
00404 ram[adr] = byte;
00405
00406
00407 if (adr < 2)
00408 new_config();
00409 }
00410
00411
00412
00413
00414
00415
00416 uint8 MOS6510::ExtReadByte(uint16 adr)
00417 {
00418
00419 bool bi = basic_in, ki = kernal_in, ci = char_in, ii = io_in;
00420
00421
00422 basic_in = (ExtConfig & 3) == 3;
00423
00424 kernal_in = BOOL_BIT(ExtConfig, 2);
00425 char_in = (ExtConfig & 3) && ~(ExtConfig & 4);
00426 io_in = (ExtConfig & 3) && (ExtConfig & 4);
00427
00428
00429 uint8 byte = read_byte(adr);
00430
00431
00432 basic_in = bi; kernal_in = ki; char_in = ci; io_in = ii;
00433
00434 return byte;
00435 }
00436
00437
00438
00439
00440
00441
00442 void MOS6510::ExtWriteByte(uint16 adr, uint8 byte)
00443 {
00444
00445 bool bi = basic_in, ki = kernal_in, ci = char_in, ii = io_in;
00446
00447
00448 basic_in = (ExtConfig & 3) == 3;
00449
00450 kernal_in = BOOL_BIT(ExtConfig, 2);
00451 char_in = (ExtConfig & 3) && ~(ExtConfig & 4);
00452 io_in = (ExtConfig & 3) && (ExtConfig & 4);
00453
00454
00455 write_byte(adr, byte);
00456
00457
00458 basic_in = bi; kernal_in = ki; char_in = ci; io_in = ii;
00459 }
00460
00461
00462
00463
00464
00465
00466 uint8 MOS6510::REUReadByte(uint16 adr)
00467 {
00468 return read_byte(adr);
00469 }
00470
00471
00472
00473
00474
00475
00476 void MOS6510::REUWriteByte(uint16 adr, uint8 byte)
00477 {
00478 write_byte(adr, byte);
00479 }
00480
00481
00482
00483
00484
00485
00486 #if PC_IS_POINTER
00487 void MOS6510::jump(uint16 adr)
00488 {
00489 if (adr < 0xa000) {
00490 pc = ram + adr;
00491 pc_base = ram;
00492 } else
00493 switch (adr >> 12) {
00494 case 0xa:
00495 case 0xb:
00496 if (basic_in) {
00497 pc = basic_rom + (adr & 0x1fff);
00498 pc_base = basic_rom - 0xa000;
00499 } else {
00500 pc = ram + adr;
00501 pc_base = ram;
00502 }
00503 break;
00504 case 0xc:
00505 pc = ram + adr;
00506 pc_base = ram;
00507 break;
00508 case 0xd:
00509 if (io_in)
00510 illegal_jump(pc-pc_base, adr);
00511 else if (char_in) {
00512 pc = char_rom + (adr & 0x0fff);
00513 pc_base = char_rom - 0xd000;
00514 } else {
00515 pc = ram + adr;
00516 pc_base = ram;
00517 }
00518 break;
00519 case 0xe:
00520 case 0xf:
00521 if (kernal_in) {
00522 pc = kernal_rom + (adr & 0x1fff);
00523 pc_base = kernal_rom - 0xe000;
00524 } else {
00525 pc = ram + adr;
00526 pc_base = ram;
00527 }
00528 break;
00529 }
00530 }
00531 #else
00532 inline void MOS6510::jump(uint16 adr)
00533 {
00534 pc = adr;
00535 }
00536 #endif
00537
00538
00539
00540
00541
00542
00543 void MOS6510::do_adc(uint8 byte)
00544 {
00545 if (!d_flag) {
00546 uint16 tmp;
00547
00548
00549 tmp = a + byte + (c_flag ? 1 : 0);
00550 c_flag = tmp > 0xff;
00551 v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
00552
00553 z_flag = n_flag = a = (uint8)tmp;
00554
00555 } else {
00556 uint16 al, ah;
00557
00558
00559 al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0);
00560 if (al > 9) al += 6;
00561
00562 ah = (a >> 4) + (byte >> 4);
00563 if (al > 0x0f) ah++;
00564
00565 z_flag = a + byte + (c_flag ? 1 : 0);
00566 n_flag = ah << 4;
00567 v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
00568
00569 if (ah > 9) ah += 6;
00570 c_flag = ah > 0x0f;
00571 a = (ah << 4) | (al & 0x0f);
00572 }
00573 }
00574
00575
00576
00577
00578
00579
00580 void MOS6510::do_sbc(uint8 byte)
00581 {
00582 uint16 tmp = a - byte - (c_flag ? 0 : 1);
00583
00584 if (!d_flag) {
00585
00586
00587 c_flag = tmp < 0x100;
00588 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00589
00590 z_flag = n_flag = a = (uint8)tmp;
00591
00592 } else {
00593 uint16 al, ah;
00594
00595
00596 al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1);
00597 ah = (a >> 4) - (byte >> 4);
00598 if (al & 0x10) {
00599 al -= 6;
00600 ah--;
00601 }
00602 if (ah & 0x10) ah -= 6;
00603
00604 c_flag = tmp < 0x100;
00605 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00606
00607 z_flag = n_flag = (uint8)tmp;
00608
00609 a = (ah << 4) | (al & 0x0f);
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00618 void MOS6510::GetState(MOS6510State *s)
00619 {
00620 s->a = a;
00621 s->x = x;
00622 s->y = y;
00623
00624 s->p = 0x20 | (n_flag & 0x80);
00625 if (v_flag) s->p |= 0x40;
00626 if (d_flag) s->p |= 0x08;
00627 if (i_flag) s->p |= 0x04;
00628 if (!z_flag) s->p |= 0x02;
00629 if (c_flag) s->p |= 0x01;
00630
00631 s->ddr = ram[0];
00632 s->pr = ram[1] & 0x3f;
00633
00634 #if PC_IS_POINTER
00635 s->pc = pc - pc_base;
00636 #else
00637 s->pc = pc;
00638 #endif
00639 s->sp = sp | 0x0100;
00640
00641 s->intr[INT_VICIRQ] = interrupt.intr[INT_VICIRQ];
00642 s->intr[INT_CIAIRQ] = interrupt.intr[INT_CIAIRQ];
00643 s->intr[INT_NMI] = interrupt.intr[INT_NMI];
00644 s->intr[INT_RESET] = interrupt.intr[INT_RESET];
00645 s->nmi_state = nmi_state;
00646 s->dfff_byte = dfff_byte;
00647 s->instruction_complete = true;
00648 }
00649
00650
00651
00652
00653
00654
00655 void MOS6510::SetState(MOS6510State *s)
00656 {
00657 a = s->a;
00658 x = s->x;
00659 y = s->y;
00660
00661 n_flag = s->p;
00662
00663
00664
00665
00666
00667
00668
00669
00670 v_flag = BOOL_BIT(s->p, 0x40);
00671 d_flag = BOOL_BIT(s->p, 0x08);
00672 i_flag = BOOL_BIT(s->p, 0x04);
00673
00674
00675 z_flag = !(s->p & 0x02);
00676 c_flag = s->p & 0x01;
00677
00678 ram[0] = s->ddr;
00679 ram[1] = s->pr;
00680 new_config();
00681
00682 jump(s->pc);
00683 sp = s->sp & 0xff;
00684
00685 interrupt.intr[INT_VICIRQ] = s->intr[INT_VICIRQ];
00686 interrupt.intr[INT_CIAIRQ] = s->intr[INT_CIAIRQ];
00687 interrupt.intr[INT_NMI] = s->intr[INT_NMI];
00688 interrupt.intr[INT_RESET] = s->intr[INT_RESET];
00689 nmi_state = s->nmi_state;
00690 dfff_byte = s->dfff_byte;
00691 }
00692
00693
00694
00695
00696
00697
00698 void MOS6510::Reset(void)
00699 {
00700
00701 if (ram[0x8004] == 0xc3 && ram[0x8005] == 0xc2 && ram[0x8006] == 0xcd
00702 && ram[0x8007] == 0x38 && ram[0x8008] == 0x30)
00703 ram[0x8004] = 0;
00704
00705
00706 ram[0] = ram[1] = 0;
00707 new_config();
00708
00709
00710 interrupt.intr_any = 0;
00711 nmi_state = false;
00712
00713
00714 jump(read_word(0xfffc));
00715
00716 ELOG1(_L8("6510 reset\n"));
00717 }
00718
00719
00720
00721
00722
00723
00724 void MOS6510::illegal_op(uint8 op, uint16 at)
00725 {
00726 char illop_msg[80];
00727 sprintf(illop_msg, "Illegal opcode %02x at %04x.", op, at);
00728 ShowRequester(illop_msg, "Reset");
00729
00730 the_c64->Reset();
00731 Reset();
00732 }
00733
00734
00735
00736
00737
00738
00739 void MOS6510::illegal_jump(uint16 at, uint16 to)
00740 {
00741 char illop_msg[80];
00742
00743 sprintf(illop_msg, "Jump to I/O space at %04x to %04x.", at, to);
00744 ShowRequester(illop_msg, "Reset");
00745 the_c64->Reset();
00746 Reset();
00747 }
00748
00749
00750
00751
00752
00753
00754
00755 #define pop_byte() ram[(++sp) | 0x0100]
00756
00757
00758 #define push_byte(byte) (ram[(sp--) & 0xff | 0x0100] = (byte))
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 #define pop_flags() \
00773 n_flag = tmp = pop_byte(); \
00774 v_flag = BOOL_BIT(tmp, 0x40); \
00775 d_flag = BOOL_BIT(tmp, 0x08); \
00776 i_flag = BOOL_BIT(tmp, 0x04); \
00777 z_flag = !(tmp & 0x02); \
00778 c_flag = BOOL_BIT(tmp, 0x01);
00779
00780
00781 #define push_flags(b_flag) \
00782 tmp = 0x20 | (n_flag & 0x80); \
00783 if (v_flag) tmp |= 0x40; \
00784 if (b_flag) tmp |= 0x10; \
00785 if (d_flag) tmp |= 0x08; \
00786 if (i_flag) tmp |= 0x04; \
00787 if (!z_flag) tmp |= 0x02; \
00788 if (c_flag) tmp |= 0x01; \
00789 push_byte(tmp);
00790
00791
00792
00793
00794
00795
00796
00797 int MOS6510::EmulateLine(int cycles_left)
00798 {
00799 uint8 tmp, tmp2, tmpb;
00800 uint16 adr;
00801 int last_cycles = 0;
00802
00803
00804 if (interrupt.intr_any) {
00805 handle_int:
00806 if (interrupt.intr[INT_RESET])
00807 Reset();
00808
00809 else if (interrupt.intr[INT_NMI]) {
00810 interrupt.intr[INT_NMI] = false;
00811 #if PC_IS_POINTER
00812 push_byte((pc-pc_base) >> 8); push_byte(pc-pc_base);
00813 #else
00814 push_byte(pc >> 8); push_byte(pc);
00815 #endif
00816 push_flags(false);
00817 i_flag = true;
00818 jump(read_word(0xfffa));
00819 last_cycles = 7;
00820
00821 } else if ((interrupt.intr[INT_VICIRQ] || interrupt.intr[INT_CIAIRQ]) && !i_flag) {
00822 #if PC_IS_POINTER
00823 push_byte((pc-pc_base) >> 8); push_byte(pc-pc_base);
00824 #else
00825 push_byte(pc >> 8); push_byte(pc);
00826 #endif
00827 push_flags(false);
00828 i_flag = true;
00829 jump(read_word(0xfffe));
00830 last_cycles = 7;
00831 }
00832 }
00833
00834 #include "CPU_emulline.i"
00835
00836
00837 case 0xf2:
00838 #if PC_IS_POINTER
00839 if ((pc-pc_base) < 0xe000) {
00840 illegal_op(0xf2, pc-pc_base-1);
00841 #else
00842 if (pc < 0xe000) {
00843 illegal_op(0xf2, pc-1);
00844 #endif
00845 break;
00846 }
00847 switch (read_byte_imm()) {
00848 case 0x00:
00849
00850 ram[0x90] |= TheIEC->Out(ram[0x95], BOOL_BIT(ram[0xa3], 0x80) );
00851 c_flag = false;
00852 jump(0xedac);
00853 break;
00854 case 0x01:
00855 ram[0x90] |= TheIEC->OutATN(ram[0x95]);
00856 c_flag = false;
00857 jump(0xedac);
00858 break;
00859 case 0x02:
00860 ram[0x90] |= TheIEC->OutSec(ram[0x95]);
00861 c_flag = false;
00862 jump(0xedac);
00863 break;
00864 case 0x03:
00865 ram[0x90] |= TheIEC->In(&a);
00866 set_nz(a);
00867 c_flag = false;
00868 jump(0xedac);
00869 break;
00870 case 0x04:
00871 TheIEC->SetATN();
00872 jump(0xedfb);
00873 break;
00874 case 0x05:
00875 TheIEC->RelATN();
00876 jump(0xedac);
00877 break;
00878 case 0x06:
00879 TheIEC->Turnaround();
00880 jump(0xedac);
00881 break;
00882 case 0x07:
00883 TheIEC->Release();
00884 jump(0xedac);
00885 break;
00886 default:
00887 #if PC_IS_POINTER
00888 illegal_op(0xf2, pc-pc_base-1);
00889 #else
00890 illegal_op(0xf2, pc-1);
00891 #endif
00892 break;
00893 }
00894 break;
00895 }
00896 }
00897 return last_cycles;
00898 }