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

CIA_SC.cpp

Go to the documentation of this file.
00001 /*
00002  *  CIA_SC.cpp - Single-cycle 6526 emulation
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Notes:
00009  * ------
00010  *
00011  *  - The Emulate() function is called for every emulated Phi2
00012  *    clock cycle. It counts down the timers and triggers
00013  *    interrupts if necessary.
00014  *  - The TOD clocks are counted by CountTOD() during the VBlank, so
00015  *    the input frequency is 50Hz
00016  *  - The fields KeyMatrix and RevMatrix contain one bit for each
00017  *    key on the C64 keyboard (0: key pressed, 1: key released).
00018  *    KeyMatrix is used for normal keyboard polling (PRA->PRB),
00019  *    RevMatrix for reversed polling (PRB->PRA).
00020  *
00021  * Incompatibilities:
00022  * ------------------
00023  *
00024  *  - The TOD clock should not be stopped on a read access, but be
00025  *    latched
00026  *  - The SDR interrupt is faked
00027  *  - Some small incompatibilities with the timers
00028  */
00029 
00030 #include "sysdeps.h"
00031 
00032 #include "CIA.h"
00033 #include "CPUC64.h"
00034 #include "CPU1541.h"
00035 #include "VIC.h"
00036 #include "Prefs.h"
00037 
00038 
00039 // Timer states
00040 enum {
00041         T_STOP,
00042         T_WAIT_THEN_COUNT,
00043         T_LOAD_THEN_STOP,
00044         T_LOAD_THEN_COUNT,
00045         T_LOAD_THEN_WAIT_THEN_COUNT,
00046         T_COUNT,
00047         T_COUNT_THEN_STOP,
00048 };
00049 
00050 
00051 /*
00052  *  Constructors
00053  */
00054 
00055 MOS6526::MOS6526(MOS6510 *CPU) : the_cpu(CPU) {}
00056 MOS6526_1::MOS6526_1(MOS6510 *CPU, MOS6569 *VIC) : MOS6526(CPU), the_vic(VIC) {}
00057 MOS6526_2::MOS6526_2(MOS6510 *CPU, MOS6569 *VIC, MOS6502_1541 *CPU1541) : MOS6526(CPU), the_vic(VIC), the_cpu_1541(CPU1541) {}
00058 
00059 
00060 /*
00061  *  Reset the CIA
00062  */
00063 
00064 void MOS6526::Reset(void)
00065 {
00066         pra = prb = ddra = ddrb = 0;
00067 
00068         ta = tb = 0xffff;
00069         latcha = latchb = 1;
00070 
00071         tod_10ths = tod_sec = tod_min = tod_hr = 0;
00072         alm_10ths = alm_sec = alm_min = alm_hr = 0;
00073 
00074         sdr = icr = cra = crb = int_mask = 0;
00075 
00076         tod_halt = false;
00077         tod_divider = 0;
00078 
00079         ta_cnt_phi2 = tb_cnt_phi2 = tb_cnt_ta = false;
00080 
00081         ta_irq_next_cycle = tb_irq_next_cycle = false;
00082         ta_state = tb_state = T_STOP;
00083 }
00084 
00085 void MOS6526_1::Reset(void)
00086 {
00087         MOS6526::Reset();
00088 
00089         // Clear keyboard matrix and joystick states
00090         for (int i=0; i<8; i++)
00091                 KeyMatrix[i] = RevMatrix[i] = 0xff;
00092 
00093         Joystick1 = Joystick2 = 0xff;
00094         prev_lp = 0x10;
00095 }
00096 
00097 void MOS6526_2::Reset(void)
00098 {
00099         MOS6526::Reset();
00100 
00101         // VA14/15 = 0
00102         the_vic->ChangedVA(0);
00103 
00104         // IEC
00105         IECLines = 0xd0;
00106 }
00107 
00108 
00109 /*
00110  *  Get CIA state
00111  */
00112 
00113 void MOS6526::GetState(MOS6526State *cs)
00114 {
00115         cs->pra = pra;
00116         cs->prb = prb;
00117         cs->ddra = ddra;
00118         cs->ddrb = ddrb;
00119 
00120         cs->ta_lo = ta & 0xff;
00121         cs->ta_hi = ta >> 8;
00122         cs->tb_lo = tb & 0xff;
00123         cs->tb_hi = tb >> 8;
00124         cs->latcha = latcha;
00125         cs->latchb = latchb;
00126         cs->cra = cra;
00127         cs->crb = crb;
00128 
00129         cs->tod_10ths = tod_10ths;
00130         cs->tod_sec = tod_sec;
00131         cs->tod_min = tod_min;
00132         cs->tod_hr = tod_hr;
00133         cs->alm_10ths = alm_10ths;
00134         cs->alm_sec = alm_sec;
00135         cs->alm_min = alm_min;
00136         cs->alm_hr = alm_hr;
00137 
00138         cs->sdr = sdr;
00139 
00140         cs->int_data = icr;
00141         cs->int_mask = int_mask;
00142 }
00143 
00144 
00145 /*
00146  *  Restore CIA state
00147  */
00148 
00149 void MOS6526::SetState(MOS6526State *cs)
00150 {
00151         pra = cs->pra;
00152         prb = cs->prb;
00153         ddra = cs->ddra;
00154         ddrb = cs->ddrb;
00155 
00156         ta = (cs->ta_hi << 8) | cs->ta_lo;
00157         tb = (cs->tb_hi << 8) | cs->tb_lo;
00158         latcha = cs->latcha;
00159         latchb = cs->latchb;
00160         cra = cs->cra;
00161         crb = cs->crb;
00162 
00163         tod_10ths = cs->tod_10ths;
00164         tod_sec = cs->tod_sec;
00165         tod_min = cs->tod_min;
00166         tod_hr = cs->tod_hr;
00167         alm_10ths = cs->alm_10ths;
00168         alm_sec = cs->alm_sec;
00169         alm_min = cs->alm_min;
00170         alm_hr = cs->alm_hr;
00171 
00172         sdr = cs->sdr;
00173 
00174         icr = cs->int_data;
00175         int_mask = cs->int_mask;
00176 
00177         tod_halt = false;
00178         ta_cnt_phi2 = ((cra & 0x20) == 0x00);
00179         tb_cnt_phi2 = ((crb & 0x60) == 0x00);
00180         tb_cnt_ta = ((crb & 0x60) == 0x40);
00181 
00182         ta_state = (cra & 1) ? T_COUNT : T_STOP;
00183         tb_state = (crb & 1) ? T_COUNT : T_STOP;
00184 }
00185 
00186 
00187 /*
00188  *  Read from register (CIA 1)
00189  */
00190 
00191 uint8 MOS6526_1::ReadRegister(uint16 adr)
00192 {
00193         switch (adr) {
00194                 case 0x00: {
00195                         uint8 ret = pra | ~ddra, tst = (prb | ~ddrb) & Joystick1;
00196                         if (!(tst & 0x01)) ret &= RevMatrix[0]; // AND all active columns
00197                         if (!(tst & 0x02)) ret &= RevMatrix[1];
00198                         if (!(tst & 0x04)) ret &= RevMatrix[2];
00199                         if (!(tst & 0x08)) ret &= RevMatrix[3];
00200                         if (!(tst & 0x10)) ret &= RevMatrix[4];
00201                         if (!(tst & 0x20)) ret &= RevMatrix[5];
00202                         if (!(tst & 0x40)) ret &= RevMatrix[6];
00203                         if (!(tst & 0x80)) ret &= RevMatrix[7];
00204                         return ret & Joystick2;
00205                 }
00206                 case 0x01: {
00207                         uint8 ret = ~ddrb, tst = (pra | ~ddra) & Joystick2;
00208                         if (!(tst & 0x01)) ret &= KeyMatrix[0]; // AND all active rows
00209                         if (!(tst & 0x02)) ret &= KeyMatrix[1];
00210                         if (!(tst & 0x04)) ret &= KeyMatrix[2];
00211                         if (!(tst & 0x08)) ret &= KeyMatrix[3];
00212                         if (!(tst & 0x10)) ret &= KeyMatrix[4];
00213                         if (!(tst & 0x20)) ret &= KeyMatrix[5];
00214                         if (!(tst & 0x40)) ret &= KeyMatrix[6];
00215                         if (!(tst & 0x80)) ret &= KeyMatrix[7];
00216                         return (ret | (prb & ddrb)) & Joystick1;
00217                 }
00218                 case 0x02: return ddra;
00219                 case 0x03: return ddrb;
00220                 case 0x04: return ta;
00221                 case 0x05: return ta >> 8;
00222                 case 0x06: return tb;
00223                 case 0x07: return tb >> 8;
00224                 case 0x08: tod_halt = false; return tod_10ths;
00225                 case 0x09: return tod_sec;
00226                 case 0x0a: return tod_min;
00227                 case 0x0b: tod_halt = true; return tod_hr;
00228                 case 0x0c: return sdr;
00229                 case 0x0d: {
00230                         uint8 ret = icr;                        // Read and clear ICR
00231                         icr = 0;
00232                         the_cpu->ClearCIAIRQ();         // Clear IRQ
00233                         return ret;
00234                 }
00235                 case 0x0e: return cra;
00236                 case 0x0f: return crb;
00237         }
00238         return 0;       // Can't happen
00239 }
00240 
00241 
00242 /*
00243  *  Read from register (CIA 2)
00244  */
00245 
00246 uint8 MOS6526_2::ReadRegister(uint16 adr)
00247 {
00248         switch (adr) {
00249                 case 0x00:
00250                         return (pra | ~ddra) & 0x3f
00251                                 | IECLines & the_cpu_1541->IECLines;
00252                 case 0x01: return prb | ~ddrb;
00253                 case 0x02: return ddra;
00254                 case 0x03: return ddrb;
00255                 case 0x04: return ta;
00256                 case 0x05: return ta >> 8;
00257                 case 0x06: return tb;
00258                 case 0x07: return tb >> 8;
00259                 case 0x08: tod_halt = false; return tod_10ths;
00260                 case 0x09: return tod_sec;
00261                 case 0x0a: return tod_min;
00262                 case 0x0b: tod_halt = true; return tod_hr;
00263                 case 0x0c: return sdr;
00264                 case 0x0d: {
00265                         uint8 ret = icr; // Read and clear ICR
00266                         icr = 0;
00267                         the_cpu->ClearNMI();
00268                         return ret;
00269                 }
00270                 case 0x0e: return cra;
00271                 case 0x0f: return crb;
00272         }
00273         return 0;       // Can't happen
00274 }
00275 
00276 
00277 /*
00278  *  Write to register (CIA 1)
00279  */
00280 
00281 // Write to port B, check for lightpen interrupt
00282 inline void MOS6526_1::check_lp(void)
00283 {
00284         if ((prb | ~ddrb) & 0x10 != prev_lp)
00285                 the_vic->TriggerLightpen();
00286         prev_lp = (prb | ~ddrb) & 0x10;
00287 }
00288 
00289 void MOS6526_1::WriteRegister(uint16 adr, uint8 byte)
00290 {
00291         switch (adr) {
00292                 case 0x0: pra = byte; break;
00293                 case 0x1:
00294                         prb = byte;
00295                         check_lp();
00296                         break;
00297                 case 0x2: ddra = byte; break;
00298                 case 0x3:
00299                         ddrb = byte;
00300                         check_lp();
00301                         break;
00302 
00303                 case 0x4: latcha = (latcha & 0xff00) | byte; break;
00304                 case 0x5:
00305                         latcha = (latcha & 0xff) | (byte << 8);
00306                         if (!(cra & 1)) // Reload timer if stopped
00307                                 ta = latcha;
00308                         break;
00309 
00310                 case 0x6: latchb = (latchb & 0xff00) | byte; break;
00311                 case 0x7:
00312                         latchb = (latchb & 0xff) | (byte << 8);
00313                         if (!(crb & 1)) // Reload timer if stopped
00314                                 tb = latchb;
00315                         break;
00316 
00317                 case 0x8:
00318                         if (crb & 0x80)
00319                                 alm_10ths = byte & 0x0f;
00320                         else
00321                                 tod_10ths = byte & 0x0f;
00322                         break;
00323                 case 0x9:
00324                         if (crb & 0x80)
00325                                 alm_sec = byte & 0x7f;
00326                         else
00327                                 tod_sec = byte & 0x7f;
00328                         break;
00329                 case 0xa:
00330                         if (crb & 0x80)
00331                                 alm_min = byte & 0x7f;
00332                         else
00333                                 tod_min = byte & 0x7f;
00334                         break;
00335                 case 0xb:
00336                         if (crb & 0x80)
00337                                 alm_hr = byte & 0x9f;
00338                         else
00339                                 tod_hr = byte & 0x9f;
00340                         break;
00341 
00342                 case 0xc:
00343                         sdr = byte;
00344                         TriggerInterrupt(8);    // Fake SDR interrupt for programs that need it
00345                         break;
00346 
00347                 case 0xd:
00348                         if (byte & 0x80)
00349                                 int_mask |= byte & 0x7f;
00350                         else
00351                                 int_mask &= ~byte;
00352                         if (icr & int_mask & 0x1f) { // Trigger IRQ if pending
00353                                 icr |= 0x80;
00354                                 the_cpu->TriggerCIAIRQ();
00355                         }
00356                         break;
00357 
00358                 case 0xe:
00359                         has_new_cra = true;             // Delay write by 1 cycle
00360                         new_cra = byte;
00361                         ta_cnt_phi2 = ((byte & 0x20) == 0x00);
00362                         break;
00363 
00364                 case 0xf:
00365                         has_new_crb = true;             // Delay write by 1 cycle
00366                         new_crb = byte;
00367                         tb_cnt_phi2 = ((byte & 0x60) == 0x00);
00368                         tb_cnt_ta = ((byte & 0x60) == 0x40);
00369                         break;
00370         }
00371 }
00372 
00373 
00374 /*
00375  *  Write to register (CIA 2)
00376  */
00377 
00378 void MOS6526_2::WriteRegister(uint16 adr, uint8 byte)
00379 {
00380         switch (adr) {
00381                 case 0x0:{
00382                         pra = byte;
00383                         the_vic->ChangedVA(~(pra | ~ddra) & 3);
00384                         uint8 old_lines = IECLines;
00385                         IECLines = (~byte << 2) & 0x80  // DATA
00386                                 | (~byte << 2) & 0x40           // CLK
00387                                 | (~byte << 1) & 0x10;          // ATN
00388                         if ((IECLines ^ old_lines) & 0x10) {    // ATN changed
00389                                 the_cpu_1541->NewATNState();
00390                                 if (old_lines & 0x10)                           // ATN 1->0
00391                                         the_cpu_1541->IECInterrupt();
00392                         }
00393                         break;
00394                 }
00395                 case 0x1: prb = byte; break;
00396 
00397                 case 0x2:
00398                         ddra = byte;
00399                         the_vic->ChangedVA(~(pra | ~ddra) & 3);
00400                         break;
00401                 case 0x3: ddrb = byte; break;
00402 
00403                 case 0x4: latcha = (latcha & 0xff00) | byte; break;
00404                 case 0x5:
00405                         latcha = (latcha & 0xff) | (byte << 8);
00406                         if (!(cra & 1)) // Reload timer if stopped
00407                                 ta = latcha;
00408                         break;
00409 
00410                 case 0x6: latchb = (latchb & 0xff00) | byte; break;
00411                 case 0x7:
00412                         latchb = (latchb & 0xff) | (byte << 8);
00413                         if (!(crb & 1)) // Reload timer if stopped
00414                                 tb = latchb;
00415                         break;
00416 
00417                 case 0x8:
00418                         if (crb & 0x80)
00419                                 alm_10ths = byte & 0x0f;
00420                         else
00421                                 tod_10ths = byte & 0x0f;
00422                         break;
00423                 case 0x9:
00424                         if (crb & 0x80)
00425                                 alm_sec = byte & 0x7f;
00426                         else
00427                                 tod_sec = byte & 0x7f;
00428                         break;
00429                 case 0xa:
00430                         if (crb & 0x80)
00431                                 alm_min = byte & 0x7f;
00432                         else
00433                                 tod_min = byte & 0x7f;
00434                         break;
00435                 case 0xb:
00436                         if (crb & 0x80)
00437                                 alm_hr = byte & 0x9f;
00438                         else
00439                                 tod_hr = byte & 0x9f;
00440                         break;
00441 
00442                 case 0xc:
00443                         sdr = byte;
00444                         TriggerInterrupt(8);    // Fake SDR interrupt for programs that need it
00445                         break;
00446 
00447                 case 0xd:
00448                         if (byte & 0x80)
00449                                 int_mask |= byte & 0x7f;
00450                         else
00451                                 int_mask &= ~byte;
00452                         if (icr & int_mask & 0x1f) { // Trigger NMI if pending
00453                                 icr |= 0x80;
00454                                 the_cpu->TriggerNMI();
00455                         }
00456                         break;
00457 
00458                 case 0xe:
00459                         has_new_cra = true;             // Delay write by 1 cycle
00460                         new_cra = byte;
00461                         ta_cnt_phi2 = ((byte & 0x20) == 0x00);
00462                         break;
00463 
00464                 case 0xf:
00465                         has_new_crb = true;             // Delay write by 1 cycle
00466                         new_crb = byte;
00467                         tb_cnt_phi2 = ((byte & 0x60) == 0x00);
00468                         tb_cnt_ta = ((byte & 0x60) == 0x40);
00469                         break;
00470         }
00471 }
00472 
00473 
00474 /*
00475  *  Emulate CIA for one cycle/raster line
00476  */
00477 
00478 void MOS6526::EmulateCycle(void)
00479 {
00480         bool ta_underflow = false;
00481 
00482         // Timer A state machine
00483         switch (ta_state) {
00484                 case T_WAIT_THEN_COUNT:
00485                         ta_state = T_COUNT;             // fall through
00486                 case T_STOP:
00487                         goto ta_idle;
00488                 case T_LOAD_THEN_STOP:
00489                         ta_state = T_STOP;
00490                         ta = latcha;                    // Reload timer
00491                         goto ta_idle;
00492                 case T_LOAD_THEN_COUNT:
00493                         ta_state = T_COUNT;
00494                         ta = latcha;                    // Reload timer
00495                         goto ta_idle;
00496                 case T_LOAD_THEN_WAIT_THEN_COUNT:
00497                         ta_state = T_WAIT_THEN_COUNT;
00498                         if (ta == 1)
00499                                 goto ta_interrupt;      // Interrupt if timer == 1
00500                         else {
00501                                 ta = latcha;            // Reload timer
00502                                 goto ta_idle;
00503                         }
00504                 case T_COUNT:
00505                         goto ta_count;
00506                 case T_COUNT_THEN_STOP:
00507                         ta_state = T_STOP;
00508                         goto ta_count;
00509         }
00510 
00511         // Count timer A
00512 ta_count:
00513         if (ta_cnt_phi2)
00514                 if (!ta || !--ta) {                             // Decrement timer, underflow?
00515                         if (ta_state != T_STOP) {
00516 ta_interrupt:
00517                                 ta = latcha;                    // Reload timer
00518                                 ta_irq_next_cycle = true; // Trigger interrupt in next cycle
00519                                 icr |= 1;                               // But set ICR bit now
00520 
00521                                 if (cra & 8) {                  // One-shot?
00522                                         cra &= 0xfe;            // Yes, stop timer
00523                                         new_cra &= 0xfe;
00524                                         ta_state = T_LOAD_THEN_STOP;    // Reload in next cycle
00525                                 } else
00526                                         ta_state = T_LOAD_THEN_COUNT;   // No, delay one cycle (and reload)
00527                         }
00528                         ta_underflow = true;
00529                 }
00530 
00531         // Delayed write to CRA?
00532 ta_idle:
00533         if (has_new_cra) {
00534                 switch (ta_state) {
00535                         case T_STOP:
00536                         case T_LOAD_THEN_STOP:
00537                                 if (new_cra & 1) {              // Timer started, wasn't running
00538                                         if (new_cra & 0x10)     // Force load
00539                                                 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00540                                         else                            // No force load
00541                                                 ta_state = T_WAIT_THEN_COUNT;
00542                                 } else {                                // Timer stopped, was already stopped
00543                                         if (new_cra & 0x10)     // Force load
00544                                                 ta_state = T_LOAD_THEN_STOP;
00545                                 }
00546                                 break;
00547                         case T_COUNT:
00548                                 if (new_cra & 1) {              // Timer started, was already running
00549                                         if (new_cra & 0x10)     // Force load
00550                                                 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00551                                 } else {                                // Timer stopped, was running
00552                                         if (new_cra & 0x10)     // Force load
00553                                                 ta_state = T_LOAD_THEN_STOP;
00554                                         else                            // No force load
00555                                                 ta_state = T_COUNT_THEN_STOP;
00556                                 }
00557                                 break;
00558                         case T_LOAD_THEN_COUNT:
00559                         case T_WAIT_THEN_COUNT:
00560                                 if (new_cra & 1) {
00561                                         if (new_cra & 8) {              // One-shot?
00562                                                 new_cra &= 0xfe;        // Yes, stop timer
00563                                                 ta_state = T_STOP;
00564                                         } else if (new_cra & 0x10)      // Force load
00565                                                 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00566                                 } else {
00567                                         ta_state = T_STOP;
00568                                 }
00569                                 break;
00570                 }
00571                 cra = new_cra & 0xef;
00572                 has_new_cra = false;
00573         }
00574 
00575         // Timer B state machine
00576         switch (tb_state) {
00577                 case T_WAIT_THEN_COUNT:
00578                         tb_state = T_COUNT;             // fall through
00579                 case T_STOP:
00580                         goto tb_idle;
00581                 case T_LOAD_THEN_STOP:
00582                         tb_state = T_STOP;
00583                         tb = latchb;                    // Reload timer
00584                         goto tb_idle;
00585                 case T_LOAD_THEN_COUNT:
00586                         tb_state = T_COUNT;
00587                         tb = latchb;                    // Reload timer
00588                         goto ta_idle;
00589                 case T_LOAD_THEN_WAIT_THEN_COUNT:
00590                         tb_state = T_WAIT_THEN_COUNT;
00591                         if (tb == 1)
00592                                 goto tb_interrupt;      // Interrupt if timer == 1
00593                         else {
00594                                 tb = latchb;            // Reload timer
00595                                 goto tb_idle;
00596                         }
00597                 case T_COUNT:
00598                         goto tb_count;
00599                 case T_COUNT_THEN_STOP:
00600                         tb_state = T_STOP;
00601                         goto tb_count;
00602         }
00603 
00604         // Count timer B
00605 tb_count:
00606         if (tb_cnt_phi2 || (tb_cnt_ta && ta_underflow))
00607                 if (!tb || !--tb) {                             // Decrement timer, underflow?
00608                         if (tb_state != T_STOP) {
00609 tb_interrupt:
00610                                 tb = latchb;                    // Reload timer
00611                                 tb_irq_next_cycle = true; // Trigger interrupt in next cycle
00612                                 icr |= 2;                               // But set ICR bit now
00613 
00614                                 if (crb & 8) {                  // One-shot?
00615                                         crb &= 0xfe;            // Yes, stop timer
00616                                         new_crb &= 0xfe;
00617                                         tb_state = T_LOAD_THEN_STOP;    // Reload in next cycle
00618                                 } else
00619                                         tb_state = T_LOAD_THEN_COUNT;   // No, delay one cycle (and reload)
00620                         }
00621                 }
00622 
00623         // Delayed write to CRB?
00624 tb_idle:
00625         if (has_new_crb) {
00626                 switch (tb_state) {
00627                         case T_STOP:
00628                         case T_LOAD_THEN_STOP:
00629                                 if (new_crb & 1) {              // Timer started, wasn't running
00630                                         if (new_crb & 0x10)     // Force load
00631                                                 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00632                                         else                            // No force load
00633                                                 tb_state = T_WAIT_THEN_COUNT;
00634                                 } else {                                // Timer stopped, was already stopped
00635                                         if (new_crb & 0x10)     // Force load
00636                                                 tb_state = T_LOAD_THEN_STOP;
00637                                 }
00638                                 break;
00639                         case T_COUNT:
00640                                 if (new_crb & 1) {              // Timer started, was already running
00641                                         if (new_crb & 0x10)     // Force load
00642                                                 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00643                                 } else {                                // Timer stopped, was running
00644                                         if (new_crb & 0x10)     // Force load
00645                                                 tb_state = T_LOAD_THEN_STOP;
00646                                         else                            // No force load
00647                                                 tb_state = T_COUNT_THEN_STOP;
00648                                 }
00649                                 break;
00650                         case T_LOAD_THEN_COUNT:
00651                         case T_WAIT_THEN_COUNT:
00652                                 if (new_crb & 1) {
00653                                         if (new_crb & 8) {              // One-shot?
00654                                                 new_crb &= 0xfe;        // Yes, stop timer
00655                                                 tb_state = T_STOP;
00656                                         } else if (new_crb & 0x10)      // Force load
00657                                                 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
00658                                 } else {
00659                                         tb_state = T_STOP;
00660                                 }
00661                                 break;
00662                 }
00663                 crb = new_crb & 0xef;
00664                 has_new_crb = false;
00665         }
00666 }
00667 
00668 
00669 /*
00670  *  Count CIA TOD clock (called during VBlank)
00671  */
00672 
00673 void MOS6526::CountTOD(void)
00674 {
00675         uint8 lo, hi;
00676 
00677         // Decrement frequency divider
00678         if (tod_divider)
00679                 tod_divider--;
00680         else {
00681 
00682                 // Reload divider according to 50/60 Hz flag
00683                 if (cra & 0x80)
00684                         tod_divider = 4;
00685                 else
00686                         tod_divider = 5;
00687 
00688                 // 1/10 seconds
00689                 tod_10ths++;
00690                 if (tod_10ths > 9) {
00691                         tod_10ths = 0;
00692 
00693                         // Seconds
00694                         lo = (tod_sec & 0x0f) + 1;
00695                         hi = tod_sec >> 4;
00696                         if (lo > 9) {
00697                                 lo = 0;
00698                                 hi++;
00699                         }
00700                         if (hi > 5) {
00701                                 tod_sec = 0;
00702 
00703                                 // Minutes
00704                                 lo = (tod_min & 0x0f) + 1;
00705                                 hi = tod_min >> 4;
00706                                 if (lo > 9) {
00707                                         lo = 0;
00708                                         hi++;
00709                                 }
00710                                 if (hi > 5) {
00711                                         tod_min = 0;
00712 
00713                                         // Hours
00714                                         lo = (tod_hr & 0x0f) + 1;
00715                                         hi = (tod_hr >> 4) & 1;
00716                                         tod_hr &= 0x80;         // Keep AM/PM flag
00717                                         if (lo > 9) {
00718                                                 lo = 0;
00719                                                 hi++;
00720                                         }
00721                                         tod_hr |= (hi << 4) | lo;
00722                                         if ((tod_hr & 0x1f) > 0x11)
00723                                                 tod_hr = tod_hr & 0x80 ^ 0x80;
00724                                 } else
00725                                         tod_min = (hi << 4) | lo;
00726                         } else
00727                                 tod_sec = (hi << 4) | lo;
00728                 }
00729 
00730                 // Alarm time reached? Trigger interrupt if enabled
00731                 if (tod_10ths == alm_10ths && tod_sec == alm_sec &&
00732                         tod_min == alm_min && tod_hr == alm_hr)
00733                         TriggerInterrupt(4);
00734         }
00735 }
00736 
00737 
00738 /*
00739  *  Trigger IRQ (CIA 1)
00740  */
00741 
00742 void MOS6526_1::TriggerInterrupt(int bit)
00743 {
00744         icr |= bit;
00745         if (int_mask & bit) {
00746                 icr |= 0x80;
00747                 the_cpu->TriggerCIAIRQ();
00748         }
00749 }
00750 
00751 
00752 /*
00753  *  Trigger NMI (CIA 2)
00754  */
00755 
00756 void MOS6526_2::TriggerInterrupt(int bit)
00757 {
00758         icr |= bit;
00759         if (int_mask & bit) {
00760                 icr |= 0x80;
00761                 the_cpu->TriggerNMI();
00762         }
00763 }

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