Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

CPUC64.cpp

Go to the documentation of this file.
00001 /*
00002  *  CPUC64.cpp - 6510 (C64) emulation (line based)
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Notes:
00009  * ------
00010  *
00011  *  - The EmulateLine() function is called for every emulated
00012  *    raster line. It has a cycle counter that is decremented
00013  *    by every executed opcode and if the counter goes below
00014  *    zero, the function returns.
00015  *  - Memory configurations:
00016  *     $01  $a000-$bfff  $d000-$dfff  $e000-$ffff
00017  *     -----------------------------------------------
00018  *      0       RAM          RAM          RAM
00019  *      1       RAM       Char ROM        RAM
00020  *      2       RAM       Char ROM    Kernal ROM
00021  *      3    Basic ROM    Char ROM    Kernal ROM
00022  *      4       RAM          RAM          RAM
00023  *      5       RAM          I/O          RAM
00024  *      6       RAM          I/O      Kernal ROM
00025  *      7    Basic ROM       I/O      Kernal ROM
00026  *  - All memory accesses are done with the read_byte() and
00027  *    write_byte() functions which also do the memory address
00028  *    decoding. The read_zp() and write_zp() functions allow
00029  *    faster access to the zero page, the pop_byte() and
00030  *    push_byte() macros for the stack.
00031  *  - If a write occurs to addresses 0 or 1, new_config is
00032  *    called to check whether the memory configuration has
00033  *    changed
00034  *  - The PC is either emulated with a 16 bit address or a
00035  *    direct memory pointer (for faster access), depending on
00036  *    the PC_IS_POINTER #define. In the latter case, a second
00037  *    pointer, pc_base, is kept to allow recalculating the
00038  *    16 bit 6510 PC if it has to be pushed on the stack.
00039  *  - The possible interrupt sources are:
00040  *      INT_VICIRQ: I flag is checked, jump to ($fffe)
00041  *      INT_CIAIRQ: I flag is checked, jump to ($fffe)
00042  *      INT_NMI: Jump to ($fffa)
00043  *      INT_RESET: Jump to ($fffc)
00044  *  - Interrupts are not checked before every opcode but only
00045  *    at certain times:
00046  *      On entering EmulateLine()
00047  *      On CLI
00048  *      On PLP if the I flag was cleared
00049  *      On RTI if the I flag was cleared
00050  *  - The z_flag variable has the inverse meaning of the
00051  *    6510 Z flag
00052  *  - Only the highest bit of the n_flag variable is used
00053  *  - The $f2 opcode that would normally crash the 6510 is
00054  *    used to implement emulator-specific functions, mainly
00055  *    those for the IEC routines
00056  *
00057  * Incompatibilities:
00058  * ------------------
00059  *
00060  *  - If PC_IS_POINTER is set, neither branches accross memory
00061  *    areas nor jumps to I/O space are possible
00062  *  - Extra cycles for crossing page boundaries are not
00063  *    accounted for
00064  *  - The cassette sense line is always closed
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 //#include "e32frodo.h"
00081 
00082 enum {
00083         INT_RESET = 3
00084 };
00085 
00086 
00087 /*
00088  *  6510 constructor: Initialize registers
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  *  Reset CPU asynchronously
00120  */
00121 
00122 void MOS6510::AsyncReset(void)
00123 {
00124         interrupt.intr[INT_RESET] = true;
00125 }
00126 
00127 
00128 /*
00129  *  Raise NMI asynchronously (Restore key)
00130  */
00131 
00132 void MOS6510::AsyncNMI(void)
00133 {
00134         if (!nmi_state)
00135                 interrupt.intr[INT_NMI] = true;
00136 }
00137 
00138 
00139 /*
00140  *  Memory configuration has probably changed
00141  */
00142 
00143 void MOS6510::new_config(void)
00144 {
00145         uint8 port = ~ram[0] | ram[1];
00146 
00147         basic_in = (port & 3) == 3;
00148 //      kernal_in = port & 2;
00149         kernal_in = BOOL_BIT(port, 2);  //AEH 991113
00150         char_in = (port & 3) && !(port & 4);
00151         io_in = (port & 3) && (port & 4);
00152 }
00153 
00154 
00155 /*
00156  *  Read a byte from I/O / ROM space
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:       // VIC
00174                                         case 0x1:
00175                                         case 0x2:
00176                                         case 0x3:
00177                                                 return TheVIC->ReadRegister(adr & 0x3f);
00178                                         case 0x4:       // SID
00179                                         case 0x5:
00180                                         case 0x6:
00181                                         case 0x7:
00182                                                 return TheSID->ReadRegister(adr & 0x1f);
00183                                         case 0x8:       // Color RAM
00184                                         case 0x9:
00185                                         case 0xa:
00186                                         case 0xb:
00187                                                 return color_ram[adr & 0x03ff] | rand() & 0xf0;
00188                                         case 0xc:       // CIA 1
00189                                                 return TheCIA1->ReadRegister(adr & 0x0f);
00190                                         case 0xd:       // CIA 2
00191                                                 return TheCIA2->ReadRegister(adr & 0x0f);
00192                                         case 0xe:       // REU/Open I/O
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:        // Can't happen
00212                         return 0;
00213         }
00214 }
00215 
00216 
00217 /*
00218  *  Read a byte from the CPU's address space
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  *  $dfa0-$dfff: Emulator identification
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:      // $dffc: revision
00240                         return FRODO_REVISION << 4;
00241                 case 0x7d:      // $dffd: version
00242                         return FRODO_VERSION;
00243                 case 0x7e:      // $dffe returns 'F' (Frodo ID)
00244                         return 'F';
00245                 case 0x7f:      // $dfff alternates between $55 and $aa
00246                         dfff_byte = ~dfff_byte;
00247                         return dfff_byte;
00248                 default:
00249                         return frodo_id[adr - 0x20];
00250         }
00251 }
00252 
00253 
00254 /*
00255  *  Read a word (little-endian) from the CPU's address space
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:        // Can't happen
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  *  Write byte to I/O space
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:       // VIC
00324                         case 0x1:
00325                         case 0x2:
00326                         case 0x3:
00327                                 TheVIC->WriteRegister(adr & 0x3f, byte);
00328                                 return;
00329                         case 0x4:       // SID
00330                         case 0x5:
00331                         case 0x6:
00332                         case 0x7:
00333                                 TheSID->WriteRegister(adr & 0x1f, byte);
00334                                 return;
00335                         case 0x8:       // Color RAM
00336                         case 0x9:
00337                         case 0xa:
00338                         case 0xb:
00339                                 color_ram[adr & 0x03ff] = byte & 0x0f;
00340                                 return;
00341                         case 0xc:       // CIA 1
00342                                 TheCIA1->WriteRegister(adr & 0x0f, byte);
00343                                 return;
00344                         case 0xd:       // CIA 2
00345                                 TheCIA2->WriteRegister(adr & 0x0f, byte);
00346                                 return;
00347                         case 0xe:       // REU/Open I/O
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  *  Write a byte to the CPU's address space
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  *  Read a byte from the zeropage
00375  */
00376 
00377 inline uint8 MOS6510::read_zp(uint16 adr)
00378 {
00379         return ram[adr];
00380 }
00381 
00382 
00383 /*
00384  *  Read a word (little-endian) from the zeropage
00385  */
00386 
00387 inline uint16 MOS6510::read_zp_word(uint16 adr)
00388 {
00389 // !! zeropage word addressing wraps around !!
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  *  Write a byte to the zeropage
00400  */
00401 
00402 inline void MOS6510::write_zp(uint16 adr, uint8 byte)
00403 {
00404         ram[adr] = byte;
00405 
00406         // Check if memory configuration may have changed.
00407         if (adr < 2)
00408                 new_config();
00409 }
00410 
00411 
00412 /*
00413  *  Read byte from 6510 address space with special memory config (used by SAM)
00414  */
00415 
00416 uint8 MOS6510::ExtReadByte(uint16 adr)
00417 {
00418         // Save old memory configuration
00419         bool bi = basic_in, ki = kernal_in, ci = char_in, ii = io_in;
00420 
00421         // Set new configuration
00422         basic_in = (ExtConfig & 3) == 3;
00423 //      kernal_in = ExtConfig & 2;
00424         kernal_in = BOOL_BIT(ExtConfig, 2);     //AEH 991113
00425         char_in = (ExtConfig & 3) && ~(ExtConfig & 4);
00426         io_in = (ExtConfig & 3) && (ExtConfig & 4);
00427 
00428         // Read byte
00429         uint8 byte = read_byte(adr);
00430 
00431         // Restore old configuration
00432         basic_in = bi; kernal_in = ki; char_in = ci; io_in = ii;
00433 
00434         return byte;
00435 }
00436 
00437 
00438 /*
00439  *  Write byte to 6510 address space with special memory config (used by SAM)
00440  */
00441 
00442 void MOS6510::ExtWriteByte(uint16 adr, uint8 byte)
00443 {
00444         // Save old memory configuration
00445         bool bi = basic_in, ki = kernal_in, ci = char_in, ii = io_in;
00446 
00447         // Set new configuration
00448         basic_in = (ExtConfig & 3) == 3;
00449 //      kernal_in = ExtConfig & 2;
00450         kernal_in = BOOL_BIT(ExtConfig, 2);     //AEH 991113
00451         char_in = (ExtConfig & 3) && ~(ExtConfig & 4);
00452         io_in = (ExtConfig & 3) && (ExtConfig & 4);
00453 
00454         // Write byte
00455         write_byte(adr, byte);
00456 
00457         // Restore old configuration
00458         basic_in = bi; kernal_in = ki; char_in = ci; io_in = ii;
00459 }
00460 
00461 
00462 /*
00463  *  Read byte from 6510 address space with current memory config (used by REU)
00464  */
00465 
00466 uint8 MOS6510::REUReadByte(uint16 adr)
00467 {
00468         return read_byte(adr);
00469 }
00470 
00471 
00472 /*
00473  *  Write byte to 6510 address space with current memory config (used by REU)
00474  */
00475 
00476 void MOS6510::REUWriteByte(uint16 adr, uint8 byte)
00477 {
00478         write_byte(adr, byte);
00479 }
00480 
00481 
00482 /*
00483  *  Jump to address
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  *  Adc instruction
00541  */
00542 
00543 void MOS6510::do_adc(uint8 byte)
00544 {
00545         if (!d_flag) {
00546                 uint16 tmp;
00547 
00548                 // Binary mode
00549                 tmp = a + byte + (c_flag ? 1 : 0);
00550                 c_flag = tmp > 0xff;
00551                 v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
00552 //              z_flag = n_flag = a = tmp;
00553                 z_flag = n_flag = a = (uint8)tmp;       //AEH 991113
00554 
00555         } else {
00556                 uint16 al, ah;
00557 
00558                 // Decimal mode
00559                 al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0);             // Calculate lower nybble
00560                 if (al > 9) al += 6;                                                                    // BCD fixup for lower nybble
00561 
00562                 ah = (a >> 4) + (byte >> 4);                                                    // Calculate upper nybble
00563                 if (al > 0x0f) ah++;
00564 
00565                 z_flag = a + byte + (c_flag ? 1 : 0);                                   // Set flags
00566                 n_flag = ah << 4;       // Only highest bit used
00567                 v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
00568 
00569                 if (ah > 9) ah += 6;                                                                    // BCD fixup for upper nybble
00570                 c_flag = ah > 0x0f;                                                                             // Set carry flag
00571                 a = (ah << 4) | (al & 0x0f);                                                    // Compose result
00572         }
00573 }
00574 
00575 
00576 /*
00577  * Sbc instruction
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                 // Binary mode
00587                 c_flag = tmp < 0x100;
00588                 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00589 //              z_flag = n_flag = a = tmp;
00590                 z_flag = n_flag = a = (uint8)tmp;       //AEH 991113
00591 
00592         } else {
00593                 uint16 al, ah;
00594 
00595                 // Decimal mode
00596                 al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1);             // Calculate lower nybble
00597                 ah = (a >> 4) - (byte >> 4);                                                    // Calculate upper nybble
00598                 if (al & 0x10) {
00599                         al -= 6;                                                                                        // BCD fixup for lower nybble
00600                         ah--;
00601                 }
00602                 if (ah & 0x10) ah -= 6;                                                                 // BCD fixup for upper nybble
00603 
00604                 c_flag = tmp < 0x100;                                                                   // Set flags
00605                 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00606 //              z_flag = n_flag = tmp;
00607                 z_flag = n_flag = (uint8)tmp;   //AEH 991113
00608 
00609                 a = (ah << 4) | (al & 0x0f);                                                    // Compose result
00610         }
00611 }
00612 
00613 
00614 /*
00615  *  Get 6510 register state
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  *  Restore 6510 state
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         v_flag = s->p & 0x40;
00665         d_flag = s->p & 0x08;
00666         i_flag = s->p & 0x04;
00667         */
00668 
00669         //AEH 991113 - start
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         //AEH 991113 - end
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  *  Reset CPU
00696  */
00697 
00698 void MOS6510::Reset(void)
00699 {
00700         // Delete 'CBM80' if present
00701         if (ram[0x8004] == 0xc3 && ram[0x8005] == 0xc2 && ram[0x8006] == 0xcd
00702          && ram[0x8007] == 0x38 && ram[0x8008] == 0x30)
00703                 ram[0x8004] = 0;
00704 
00705         // Initialize extra 6510 registers and memory configuration
00706         ram[0] = ram[1] = 0;
00707         new_config();
00708 
00709         // Clear all interrupt lines
00710         interrupt.intr_any = 0;
00711         nmi_state = false;
00712 
00713         // Read reset vector
00714         jump(read_word(0xfffc));
00715 
00716         ELOG1(_L8("6510 reset\n"));
00717 }
00718 
00719 
00720 /*
00721  *  Illegal opcode encountered
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  *  Jump to illegal address space (PC_IS_POINTER only)
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  *  Stack macros
00752  */
00753 
00754 // Pop a byte from the stack
00755 #define pop_byte() ram[(++sp) | 0x0100]
00756 
00757 // Push a byte onto the stack
00758 #define push_byte(byte) (ram[(sp--) & 0xff | 0x0100] = (byte))
00759 
00760 // Pop processor flags from the stack
00761 /*
00762 #define pop_flags() \
00763         n_flag = tmp = pop_byte(); \
00764         v_flag = tmp & 0x40; \
00765         d_flag = tmp & 0x08; \
00766         i_flag = tmp & 0x04; \
00767         z_flag = !(tmp & 0x02); \
00768         c_flag = tmp & 0x01;
00769 */
00770 
00771 //AEH 991113
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 // Push processor flags onto the stack
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  *  Emulate cycles_left worth of 6510 instructions
00794  *  Returns number of cycles of last instruction
00795  */
00796 
00797 int MOS6510::EmulateLine(int cycles_left)
00798 {
00799         uint8 tmp, tmp2, tmpb;
00800         uint16 adr;             // Used by read_adr_abs()!
00801         int last_cycles = 0;
00802 
00803         // Any pending interrupts?
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;        // Simulate an edge-triggered input
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                 // Extension opcode
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 //                                      ram[0x90] |= TheIEC->Out(ram[0x95], ram[0xa3] & 0x80);
00850                                         ram[0x90] |= TheIEC->Out(ram[0x95], BOOL_BIT(ram[0xa3], 0x80) );        //AEH 991113
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 }

Generated on Tue Feb 8 04:07:39 2005 for E32frodo by doxygen 1.3.3