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

CPU1541_SC.cpp

Go to the documentation of this file.
00001 /*
00002  *  CPU1541_SC.cpp - Single-cycle 6502 (1541) emulation
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Notes:
00009  * ------
00010  *
00011  * Opcode execution:
00012  *  - All opcodes are resolved into single clock cycles. There is one
00013  *    switch case for each cycle.
00014  *  - The "state" variable specifies the routine to be executed in the
00015  *    next cycle. Its upper 8 bits contain the current opcode, its lower
00016  *    8 bits contain the cycle number (0..7) within the opcode.
00017  *  - Opcodes are fetched in cycle 0 (state = 0)
00018  *  - The states 0x0010..0x0027 are used for interrupts
00019  *  - There is exactly one memory access in each clock cycle
00020  *
00021  * Memory map (1541C, the 1541 and 1541-II are a bit different):
00022  *
00023  * $0000-$07ff RAM (2K)
00024  * $0800-$0fff RAM mirror
00025  * $1000-$17ff free
00026  * $1800-$1bff VIA 1
00027  * $1c00-$1fff VIA 2
00028  * $2000-$bfff free
00029  * $c000-$ffff ROM (16K)
00030  *
00031  *  - All memory accesses are done with the read_byte() and
00032  *    write_byte() functions which also do the memory address
00033  *    decoding.
00034  *  - The possible interrupt sources are:
00035  *      INT_VIA1IRQ: I flag is checked, jump to ($fffe) (unused)
00036  *      INT_VIA2IRQ: I flag is checked, jump to ($fffe) (unused)
00037  *      INT_IECIRQ: I flag is checked, jump to ($fffe) (unused)
00038  *      INT_RESET: Jump to ($fffc)
00039  *  - The z_flag variable has the inverse meaning of the
00040  *    6502 Z flag
00041  *  - Only the highest bit of the n_flag variable is used
00042  *  - The $f2 opcode that would normally crash the 6502 is
00043  *    used to implement emulator-specific functions
00044  *  - The 1541 6502 emulation also includes a very simple VIA
00045  *    emulation (enough to make the IEC bus and GCR loading work).
00046  *    It's too small to move it to a source file of its own.
00047  *
00048  * Incompatibilities:
00049  * ------------------
00050  *
00051  *  - VIA emulation incomplete
00052  */
00053 
00054 #include "sysdeps.h"
00055 
00056 #include "CPU1541.h"
00057 #include "CPU_common.h"
00058 #include "1541job.h"
00059 #include "C64.h"
00060 #include "CIA.h"
00061 #include "Display.h"
00062 
00063 
00064 enum {
00065         INT_RESET = 3
00066 };
00067 
00068 
00069 /*
00070  *  6502 constructor: Initialize registers
00071  */
00072 
00073 MOS6502_1541::MOS6502_1541(C64 *c64, Job1541 *job, C64Display *disp, uint8 *Ram, uint8 *Rom)
00074  : ram(Ram), rom(Rom), the_c64(c64), the_display(disp), the_job(job)
00075 {
00076         a = x = y = 0;
00077         sp = 0xff;
00078         n_flag = z_flag = 0;
00079         v_flag = d_flag = c_flag = false;
00080         i_flag = true;
00081 
00082         via1_t1c = via1_t1l = via1_t2c = via1_t2l = 0;
00083         via1_sr = 0;
00084         via2_t1c = via2_t1l = via2_t2c = via2_t2l = 0;
00085         via2_sr = 0;
00086 
00087         first_irq_cycle = 0;
00088         Idle = false;
00089 }
00090 
00091 
00092 /*
00093  *  Reset CPU asynchronously
00094  */
00095 
00096 void MOS6502_1541::AsyncReset(void)
00097 {
00098         interrupt.intr[INT_RESET] = true;
00099         Idle = false;
00100 }
00101 
00102 
00103 /*
00104  *  Get 6502 register state
00105  */
00106 
00107 void MOS6502_1541::GetState(MOS6502State *s)
00108 {
00109         s->a = a;
00110         s->x = x;
00111         s->y = y;
00112 
00113         s->p = 0x20 | (n_flag & 0x80);
00114         if (v_flag) s->p |= 0x40;
00115         if (d_flag) s->p |= 0x08;
00116         if (i_flag) s->p |= 0x04;
00117         if (!z_flag) s->p |= 0x02;
00118         if (c_flag) s->p |= 0x01;
00119         
00120         s->pc = pc;
00121         s->sp = sp | 0x0100;
00122 
00123         s->intr[INT_VIA1IRQ] = interrupt.intr[INT_VIA1IRQ];
00124         s->intr[INT_VIA2IRQ] = interrupt.intr[INT_VIA2IRQ];
00125         s->intr[INT_IECIRQ] = interrupt.intr[INT_IECIRQ];
00126         s->intr[INT_RESET] = interrupt.intr[INT_RESET];
00127         s->idle = Idle;
00128 
00129         s->via1_pra = via1_pra; s->via1_ddra = via1_ddra;
00130         s->via1_prb = via1_prb; s->via1_ddrb = via1_ddrb;
00131         s->via1_t1c = via1_t1c; s->via1_t1l = via1_t1l;
00132         s->via1_t2c = via1_t2c; s->via1_t2l = via1_t2l;
00133         s->via1_sr = via1_sr;
00134         s->via1_acr = via1_acr; s->via1_pcr = via1_pcr;
00135         s->via1_ifr = via1_ifr; s->via1_ier = via1_ier;
00136 
00137         s->via2_pra = via2_pra; s->via2_ddra = via2_ddra;
00138         s->via2_prb = via2_prb; s->via2_ddrb = via2_ddrb;
00139         s->via2_t1c = via2_t1c; s->via2_t1l = via2_t1l;
00140         s->via2_t2c = via2_t2c; s->via2_t2l = via2_t2l;
00141         s->via2_sr = via2_sr;
00142         s->via2_acr = via2_acr; s->via2_pcr = via2_pcr;
00143         s->via2_ifr = via2_ifr; s->via2_ier = via2_ier;
00144 }
00145 
00146 
00147 /*
00148  *  Restore 6502 state
00149  */
00150 
00151 void MOS6502_1541::SetState(MOS6502State *s)
00152 {
00153         a = s->a;
00154         x = s->x;
00155         y = s->y;
00156 
00157         n_flag = s->p;
00158         v_flag = s->p & 0x40;
00159         d_flag = s->p & 0x08;
00160         i_flag = s->p & 0x04;
00161         z_flag = !(s->p & 0x02);
00162         c_flag = s->p & 0x01;
00163 
00164         pc = s->pc;
00165         sp = s->sp & 0xff;
00166 
00167         interrupt.intr[INT_VIA1IRQ] = s->intr[INT_VIA1IRQ];
00168         interrupt.intr[INT_VIA2IRQ] = s->intr[INT_VIA2IRQ];
00169         interrupt.intr[INT_IECIRQ] = s->intr[INT_IECIRQ];
00170         interrupt.intr[INT_RESET] = s->intr[INT_RESET];
00171         Idle = s->idle;
00172 
00173         via1_pra = s->via1_pra; via1_ddra = s->via1_ddra;
00174         via1_prb = s->via1_prb; via1_ddrb = s->via1_ddrb;
00175         via1_t1c = s->via1_t1c; via1_t1l = s->via1_t1l;
00176         via1_t2c = s->via1_t2c; via1_t2l = s->via1_t2l;
00177         via1_sr = s->via1_sr;
00178         via1_acr = s->via1_acr; via1_pcr = s->via1_pcr;
00179         via1_ifr = s->via1_ifr; via1_ier = s->via1_ier;
00180 
00181         via2_pra = s->via2_pra; via2_ddra = s->via2_ddra;
00182         via2_prb = s->via2_prb; via2_ddrb = s->via2_ddrb;
00183         via2_t1c = s->via2_t1c; via2_t1l = s->via2_t1l;
00184         via2_t2c = s->via2_t2c; via2_t2l = s->via2_t2l;
00185         via2_sr = s->via2_sr;
00186         via2_acr = s->via2_acr; via2_pcr = s->via2_pcr;
00187         via2_ifr = s->via2_ifr; via2_ier = s->via2_ier;
00188 }
00189 
00190 
00191 /*
00192  *  Read a byte from I/O space
00193  */
00194 
00195 inline uint8 MOS6502_1541::read_byte_io(uint16 adr)
00196 {
00197         if ((adr & 0xfc00) == 0x1800)   // VIA 1
00198                 switch (adr & 0xf) {
00199                         case 0:
00200                                 return (via1_prb & 0x1a
00201                                         | ((IECLines & TheCIA2->IECLines) >> 7)                 // DATA
00202                                         | ((IECLines & TheCIA2->IECLines) >> 4) & 0x04  // CLK
00203                                         | (TheCIA2->IECLines << 3) & 0x80) ^ 0x85;              // ATN
00204                         case 1:
00205                         case 15:
00206                                 return 0xff;    // Keep 1541C ROMs happy (track 0 sensor)
00207                         case 2:
00208                                 return via1_ddrb;
00209                         case 3:
00210                                 return via1_ddra;
00211                         case 4:
00212                                 via1_ifr &= 0xbf;
00213                                 return via1_t1c;
00214                         case 5:
00215                                 return via1_t1c >> 8;
00216                         case 6:
00217                                 return via1_t1l;
00218                         case 7:
00219                                 return via1_t1l >> 8;
00220                         case 8:
00221                                 via1_ifr &= 0xdf;
00222                                 return via1_t2c;
00223                         case 9:
00224                                 return via1_t2c >> 8;
00225                         case 10:
00226                                 return via1_sr;
00227                         case 11:
00228                                 return via1_acr;
00229                         case 12:
00230                                 return via1_pcr;
00231                         case 13:
00232                                 return via1_ifr | (via1_ifr & via1_ier ? 0x80 : 0);
00233                         case 14:
00234                                 return via1_ier | 0x80;
00235                         default:        // Can't happen
00236                                 return 0;
00237                 }
00238 
00239         else if ((adr & 0xfc00) == 0x1c00)      // VIA 2
00240                 switch (adr & 0xf) {
00241                         case 0:
00242                                 if (the_job->SyncFound())
00243                                         return via2_prb & 0x7f | the_job->WPState();
00244                                 else
00245                                         return via2_prb | 0x80 | the_job->WPState();
00246                         case 1:
00247                         case 15:
00248                                 return the_job->ReadGCRByte();
00249                         case 2:
00250                                 return via2_ddrb;
00251                         case 3:
00252                                 return via2_ddra;
00253                         case 4:
00254                                 via2_ifr &= 0xbf;
00255                                 interrupt.intr[INT_VIA2IRQ] = false;    // Clear job IRQ
00256                                 return via2_t1c;
00257                         case 5:
00258                                 return via2_t1c >> 8;
00259                         case 6:
00260                                 return via2_t1l;
00261                         case 7:
00262                                 return via2_t1l >> 8;
00263                         case 8:
00264                                 via2_ifr &= 0xdf;
00265                                 return via2_t2c;
00266                         case 9:
00267                                 return via2_t2c >> 8;
00268                         case 10:
00269                                 return via2_sr;
00270                         case 11:
00271                                 return via2_acr;
00272                         case 12:
00273                                 return via2_pcr;
00274                         case 13:
00275                                 return via2_ifr | (via2_ifr & via2_ier ? 0x80 : 0);
00276                         case 14:
00277                                 return via2_ier | 0x80;
00278                         default:        // Can't happen
00279                                 return 0;
00280                 }
00281 
00282         else
00283                 return adr >> 8;
00284 }
00285 
00286 
00287 /*
00288  *  Read a byte from the CPU's address space
00289  */
00290 
00291 uint8 MOS6502_1541::read_byte(uint16 adr)
00292 {
00293         if (adr >= 0xc000)
00294                 return rom[adr & 0x3fff];
00295         else if (adr < 0x1000)
00296                 return ram[adr & 0x07ff];
00297         else
00298                 return read_byte_io(adr);
00299 }
00300 
00301 
00302 /*
00303  *  Read a word (little-endian) from the CPU's address space
00304  */
00305 
00306 inline uint16 MOS6502_1541::read_word(uint16 adr)
00307 {
00308         return read_byte(adr) | (read_byte(adr+1) << 8);
00309 }
00310 
00311 
00312 /*
00313  *  Write a byte to I/O space
00314  */
00315 
00316 void MOS6502_1541::write_byte_io(uint16 adr, uint8 byte)
00317 {
00318         if ((adr & 0xfc00) == 0x1800)           // VIA 1
00319                 switch (adr & 0xf) {
00320                         case 0:
00321                                 via1_prb = byte;
00322                                 byte = ~via1_prb & via1_ddrb;
00323                                 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
00324                                         | (byte << 3) & 0x40;
00325                                 break;
00326                         case 1:
00327                         case 15:
00328                                 via1_pra = byte;
00329                                 break;
00330                         case 2:
00331                                 via1_ddrb = byte;
00332                                 byte &= ~via1_prb;
00333                                 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
00334                                         | (byte << 3) & 0x40;
00335                                 break;
00336                         case 3:
00337                                 via1_ddra = byte;
00338                                 break;
00339                         case 4:
00340                         case 6:
00341                                 via1_t1l = via1_t1l & 0xff00 | byte;
00342                                 break;
00343                         case 5:
00344                                 via1_t1l = via1_t1l & 0xff | (byte << 8);
00345                                 via1_ifr &= 0xbf;
00346                                 via1_t1c = via1_t1l;
00347                                 break;
00348                         case 7:
00349                                 via1_t1l = via1_t1l & 0xff | (byte << 8);
00350                                 break;
00351                         case 8:
00352                                 via1_t2l = via1_t2l & 0xff00 | byte;
00353                                 break;
00354                         case 9:
00355                                 via1_t2l = via1_t2l & 0xff | (byte << 8);
00356                                 via1_ifr &= 0xdf;
00357                                 via1_t2c = via1_t2l;
00358                                 break;
00359                         case 10:
00360                                 via1_sr = byte;
00361                                 break;
00362                         case 11:
00363                                 via1_acr = byte;
00364                                 break;
00365                         case 12:
00366                                 via1_pcr = byte;
00367                                 break;
00368                         case 13:
00369                                 via1_ifr &= ~byte;
00370                                 break;
00371                         case 14:
00372                                 if (byte & 0x80)
00373                                         via1_ier |= byte & 0x7f;
00374                                 else
00375                                         via1_ier &= ~byte;
00376                                 break;
00377                 }
00378 
00379         else if ((adr & 0xfc00) == 0x1c00)
00380                 switch (adr & 0xf) {
00381                         case 0:
00382                                 if ((via2_prb ^ byte) & 8)      // Bit 3: Drive LED
00383                                         the_display->UpdateLEDs(byte & 8 ? 1 : 0, 0, 0, 0);
00384                                 if ((via2_prb ^ byte) & 3)      // Bits 0/1: Stepper motor
00385                                         if ((via2_prb & 3) == ((byte+1) & 3))
00386                                                 the_job->MoveHeadOut();
00387                                         else if ((via2_prb & 3) == ((byte-1) & 3))
00388                                                 the_job->MoveHeadIn();
00389                                 via2_prb = byte & 0xef;
00390                                 break;
00391                         case 1:
00392                         case 15:
00393                                 via2_pra = byte;
00394                                 break;
00395                         case 2:
00396                                 via2_ddrb = byte;
00397                                 break;
00398                         case 3:
00399                                 via2_ddra = byte;
00400                                 break;
00401                         case 4:
00402                         case 6:
00403                                 via2_t1l = via2_t1l & 0xff00 | byte;
00404                                 break;
00405                         case 5:
00406                                 via2_t1l = via2_t1l & 0xff | (byte << 8);
00407                                 via2_ifr &= 0xbf;
00408                                 via2_t1c = via2_t1l;
00409                                 break;
00410                         case 7:
00411                                 via2_t1l = via2_t1l & 0xff | (byte << 8);
00412                                 break;
00413                         case 8:
00414                                 via2_t2l = via2_t2l & 0xff00 | byte;
00415                                 break;
00416                         case 9:
00417                                 via2_t2l = via2_t2l & 0xff | (byte << 8);
00418                                 via2_ifr &= 0xdf;
00419                                 via2_t2c = via2_t2l;
00420                                 break;
00421                         case 10:
00422                                 via2_sr = byte;
00423                                 break;
00424                         case 11:
00425                                 via2_acr = byte;
00426                                 break;
00427                         case 12:
00428                                 via2_pcr = byte;
00429                                 break;
00430                         case 13:
00431                                 via2_ifr &= ~byte;
00432                                 break;
00433                         case 14:
00434                                 if (byte & 0x80)
00435                                         via2_ier |= byte & 0x7f;
00436                                 else
00437                                         via2_ier &= ~byte;
00438                                 break;
00439                 }
00440 }
00441 
00442 
00443 /*
00444  *  Write a byte to the CPU's address space
00445  */
00446 
00447 inline void MOS6502_1541::write_byte(uint16 adr, uint8 byte)
00448 {
00449         if (adr < 0x1000)
00450                 ram[adr & 0x7ff] = byte;
00451         else
00452                 write_byte_io(adr, byte);
00453 }
00454 
00455 
00456 /*
00457  *  Read byte from 6502/1541 address space (used by SAM)
00458  */
00459 
00460 uint8 MOS6502_1541::ExtReadByte(uint16 adr)
00461 {
00462         return read_byte(adr);
00463 }
00464 
00465 
00466 /*
00467  *  Write byte to 6502/1541 address space (used by SAM)
00468  */
00469 
00470 void MOS6502_1541::ExtWriteByte(uint16 adr, uint8 byte)
00471 {
00472         write_byte(adr, byte);
00473 }
00474 
00475 
00476 /*
00477  *  Adc instruction
00478  */
00479 
00480 inline void MOS6502_1541::do_adc(uint8 byte)
00481 {
00482         if (!d_flag) {
00483                 uint16 tmp;
00484 
00485                 // Binary mode
00486                 tmp = a + byte + (c_flag ? 1 : 0);
00487                 c_flag = tmp > 0xff;
00488                 v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
00489                 z_flag = n_flag = a = tmp;
00490 
00491         } else {
00492                 uint16 al, ah;
00493 
00494                 // Decimal mode
00495                 al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0);             // Calculate lower nybble
00496                 if (al > 9) al += 6;                                                                    // BCD fixup for lower nybble
00497 
00498                 ah = (a >> 4) + (byte >> 4);                                                    // Calculate upper nybble
00499                 if (al > 0x0f) ah++;
00500 
00501                 z_flag = a + byte + (c_flag ? 1 : 0);                                   // Set flags
00502                 n_flag = ah << 4;       // Only highest bit used
00503                 v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
00504 
00505                 if (ah > 9) ah += 6;                                                                    // BCD fixup for upper nybble
00506                 c_flag = ah > 0x0f;                                                                             // Set carry flag
00507                 a = (ah << 4) | (al & 0x0f);                                                    // Compose result
00508         }
00509 }
00510 
00511 
00512 /*
00513  * Sbc instruction
00514  */
00515 
00516 inline void MOS6502_1541::do_sbc(uint8 byte)
00517 {
00518         uint16 tmp = a - byte - (c_flag ? 0 : 1);
00519 
00520         if (!d_flag) {
00521 
00522                 // Binary mode
00523                 c_flag = tmp < 0x100;
00524                 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00525                 z_flag = n_flag = a = tmp;
00526 
00527         } else {
00528                 uint16 al, ah;
00529 
00530                 // Decimal mode
00531                 al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1);             // Calculate lower nybble
00532                 ah = (a >> 4) - (byte >> 4);                                                    // Calculate upper nybble
00533                 if (al & 0x10) {
00534                         al -= 6;                                                                                        // BCD fixup for lower nybble
00535                         ah--;
00536                 }
00537                 if (ah & 0x10) ah -= 6;                                                                 // BCD fixup for upper nybble
00538 
00539                 c_flag = tmp < 0x100;                                                                   // Set flags
00540                 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
00541                 z_flag = n_flag = tmp;
00542 
00543                 a = (ah << 4) | (al & 0x0f);                                                    // Compose result
00544         }
00545 }
00546 
00547 
00548 /*
00549  *  Reset CPU
00550  */
00551 
00552 void MOS6502_1541::Reset(void)
00553 {
00554         // IEC lines and VIA registers
00555         IECLines = 0xc0;
00556 
00557         via1_pra = via1_ddra = via1_prb = via1_ddrb = 0;
00558         via1_acr = via1_pcr = 0;
00559         via1_ifr = via1_ier = 0;
00560         via2_pra = via2_ddra = via2_prb = via2_ddrb = 0;
00561         via2_acr = via2_pcr = 0;
00562         via2_ifr = via2_ier = 0;
00563 
00564         // Clear all interrupt lines
00565         interrupt.intr_any = 0;
00566 
00567         // Read reset vector
00568         pc = read_word(0xfffc);
00569         state = 0;
00570 
00571         // Wake up 1541
00572         Idle = false;
00573 }
00574 
00575 
00576 /*
00577  *  Illegal opcode encountered
00578  */
00579 
00580 void MOS6502_1541::illegal_op(uint8 op, uint16 at)
00581 {
00582         char illop_msg[80];
00583 
00584         sprintf(illop_msg, "1541: Illegal opcode %02x at %04x.", op, at);
00585         if (ShowRequester(illop_msg, "Reset 1541", "Reset C64"))
00586                 the_c64->Reset();
00587         Reset();
00588 }
00589 
00590 
00591 /*
00592  *  Emulate one 6502 clock cycle
00593  */
00594 
00595 // Read byte from memory
00596 #define read_to(adr, to) \
00597         to = read_byte(adr);
00598 
00599 // Read byte from memory, throw away result
00600 #define read_idle(adr) \
00601         read_byte(adr);
00602 
00603 void MOS6502_1541::EmulateCycle(void)
00604 {
00605         uint8 data, tmp;
00606 
00607         // Any pending interrupts in state 0 (opcode fetch)?
00608         if (!state && interrupt.intr_any) {
00609                 if (interrupt.intr[INT_RESET])
00610                         Reset();
00611                 else if ((interrupt.intr[INT_VIA1IRQ] || interrupt.intr[INT_VIA2IRQ] || interrupt.intr[INT_IECIRQ]) && (the_c64->CycleCounter-first_irq_cycle >= 2) && !i_flag)
00612                         state = 0x0008;
00613         }
00614 
00615 #define IS_CPU_1541
00616 #include "CPU_emulcycle.i"
00617 
00618                 // Extension opcode
00619                 case O_EXT:
00620                         if (pc < 0xc000) {
00621                                 illegal_op(0xf2, pc-1);
00622                                 break;
00623                         }
00624                         switch (read_byte(pc++)) {
00625                                 case 0x00:      // Go to sleep in DOS idle loop if error flag is clear and no command received
00626                                         Idle = !(ram[0x26c] | ram[0x7c]);
00627                                         pc = 0xebff;
00628                                         Last;
00629                                 case 0x01:      // Write sector
00630                                         the_job->WriteSector();
00631                                         pc = 0xf5dc;
00632                                         Last;
00633                                 case 0x02:      // Format track
00634                                         the_job->FormatTrack();
00635                                         pc = 0xfd8b;
00636                                         Last;
00637                                 default:
00638                                         illegal_op(0xf2, pc-1);
00639                                         break;
00640                         }
00641                         break;
00642 
00643                 default:
00644                         illegal_op(op, pc-1);
00645                         break;
00646         }
00647 }

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