ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/CIA_SC.cpp
Revision: 1.8
Committed: 2010-04-25T12:02:13Z (13 years, 11 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +52 -3 lines
Log Message:
TA/TB output to PB6/PB7

File Contents

# Content
1 /*
2 * CIA_SC.cpp - Single-cycle 6526 emulation
3 *
4 * Frodo Copyright (C) Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * Notes:
23 * ------
24 *
25 * - The Emulate() function is called for every emulated Phi2
26 * clock cycle. It counts down the timers and triggers
27 * interrupts if necessary.
28 * - The TOD clocks are counted by CountTOD() during the VBlank, so
29 * the input frequency is 50Hz
30 * - The fields KeyMatrix and RevMatrix contain one bit for each
31 * key on the C64 keyboard (0: key pressed, 1: key released).
32 * KeyMatrix is used for normal keyboard polling (PRA->PRB),
33 * RevMatrix for reversed polling (PRB->PRA).
34 *
35 * Incompatibilities:
36 * ------------------
37 *
38 * - The TOD clock should not be stopped on a read access, but be
39 * latched
40 * - The SDR interrupt is faked
41 * - Some small incompatibilities with the timers
42 */
43
44 #include "sysdeps.h"
45
46 #include "CIA.h"
47 #include "CPUC64.h"
48 #include "CPU1541.h"
49 #include "VIC.h"
50 #include "Prefs.h"
51
52
53 // Timer states
54 enum {
55 T_STOP,
56 T_WAIT_THEN_COUNT,
57 T_LOAD_THEN_STOP,
58 T_LOAD_THEN_COUNT,
59 T_LOAD_THEN_WAIT_THEN_COUNT,
60 T_COUNT,
61 T_COUNT_THEN_STOP
62 };
63
64
65 /*
66 * Constructors
67 */
68
69 MOS6526::MOS6526(MOS6510 *CPU) : the_cpu(CPU) {}
70 MOS6526_1::MOS6526_1(MOS6510 *CPU, MOS6569 *VIC) : MOS6526(CPU), the_vic(VIC) {}
71 MOS6526_2::MOS6526_2(MOS6510 *CPU, MOS6569 *VIC, MOS6502_1541 *CPU1541) : MOS6526(CPU), the_vic(VIC), the_cpu_1541(CPU1541) {}
72
73
74 /*
75 * Reset the CIA
76 */
77
78 void MOS6526::Reset(void)
79 {
80 pra = prb = ddra = ddrb = 0;
81
82 ta = tb = 0xffff;
83 latcha = latchb = 1;
84
85 tod_10ths = tod_sec = tod_min = tod_hr = 0;
86 alm_10ths = alm_sec = alm_min = alm_hr = 0;
87
88 sdr = icr = cra = crb = int_mask = 0;
89
90 tod_halt = false;
91 tod_divider = 0;
92
93 ta_cnt_phi2 = tb_cnt_phi2 = tb_cnt_ta = false;
94
95 ta_irq_next_cycle = tb_irq_next_cycle = false;
96 has_new_cra = has_new_crb = false;
97 ta_toggle = tb_toggle = false;
98 ta_state = tb_state = T_STOP;
99 }
100
101 void MOS6526_1::Reset(void)
102 {
103 MOS6526::Reset();
104
105 // Clear keyboard matrix and joystick states
106 for (int i=0; i<8; i++)
107 KeyMatrix[i] = RevMatrix[i] = 0xff;
108
109 Joystick1 = Joystick2 = 0xff;
110 prev_lp = 0x10;
111 }
112
113 void MOS6526_2::Reset(void)
114 {
115 MOS6526::Reset();
116
117 // VA14/15 = 0
118 the_vic->ChangedVA(0);
119
120 // IEC
121 IECLines = 0xd0;
122 }
123
124
125 /*
126 * Get CIA state
127 */
128
129 void MOS6526::GetState(MOS6526State *cs)
130 {
131 cs->pra = pra;
132 cs->prb = prb;
133 cs->ddra = ddra;
134 cs->ddrb = ddrb;
135
136 cs->ta_lo = ta & 0xff;
137 cs->ta_hi = ta >> 8;
138 cs->tb_lo = tb & 0xff;
139 cs->tb_hi = tb >> 8;
140 cs->latcha = latcha;
141 cs->latchb = latchb;
142 cs->cra = cra;
143 cs->crb = crb;
144
145 cs->tod_10ths = tod_10ths;
146 cs->tod_sec = tod_sec;
147 cs->tod_min = tod_min;
148 cs->tod_hr = tod_hr;
149 cs->alm_10ths = alm_10ths;
150 cs->alm_sec = alm_sec;
151 cs->alm_min = alm_min;
152 cs->alm_hr = alm_hr;
153
154 cs->sdr = sdr;
155
156 cs->int_data = icr;
157 cs->int_mask = int_mask;
158 }
159
160
161 /*
162 * Restore CIA state
163 */
164
165 void MOS6526::SetState(MOS6526State *cs)
166 {
167 pra = cs->pra;
168 prb = cs->prb;
169 ddra = cs->ddra;
170 ddrb = cs->ddrb;
171
172 ta = (cs->ta_hi << 8) | cs->ta_lo;
173 tb = (cs->tb_hi << 8) | cs->tb_lo;
174 latcha = cs->latcha;
175 latchb = cs->latchb;
176 cra = cs->cra;
177 crb = cs->crb;
178
179 tod_10ths = cs->tod_10ths;
180 tod_sec = cs->tod_sec;
181 tod_min = cs->tod_min;
182 tod_hr = cs->tod_hr;
183 alm_10ths = cs->alm_10ths;
184 alm_sec = cs->alm_sec;
185 alm_min = cs->alm_min;
186 alm_hr = cs->alm_hr;
187
188 sdr = cs->sdr;
189
190 icr = cs->int_data;
191 int_mask = cs->int_mask;
192
193 tod_halt = false;
194 ta_cnt_phi2 = ((cra & 0x20) == 0x00);
195 tb_cnt_phi2 = ((crb & 0x60) == 0x00);
196 tb_cnt_ta = ((crb & 0x60) == 0x40);
197
198 ta_state = (cra & 1) ? T_COUNT : T_STOP;
199 tb_state = (crb & 1) ? T_COUNT : T_STOP;
200 }
201
202
203 /*
204 * Output TA/TB to PB6/7
205 */
206
207 inline uint8 MOS6526::timer_on_pb(uint8 prb)
208 {
209 if (cra & 0x02) {
210
211 // TA output to PB6
212 if ((cra & 0x04) ? ta_toggle : ta_irq_next_cycle) {
213 prb |= 0x40;
214 } else {
215 prb &= 0xbf;
216 }
217 }
218
219 if (crb & 0x02) {
220
221 // TB output to PB7
222 if ((crb & 0x04) ? tb_toggle : tb_irq_next_cycle) {
223 prb |= 0x80;
224 } else {
225 prb &= 0x7f;
226 }
227 }
228
229 return prb;
230 }
231
232
233 /*
234 * Read from register (CIA 1)
235 */
236
237 uint8 MOS6526_1::ReadRegister(uint16 adr)
238 {
239 switch (adr) {
240 case 0x00: {
241 uint8 ret = pra | ~ddra, tst = (prb | ~ddrb) & Joystick1;
242 if (!(tst & 0x01)) ret &= RevMatrix[0]; // AND all active columns
243 if (!(tst & 0x02)) ret &= RevMatrix[1];
244 if (!(tst & 0x04)) ret &= RevMatrix[2];
245 if (!(tst & 0x08)) ret &= RevMatrix[3];
246 if (!(tst & 0x10)) ret &= RevMatrix[4];
247 if (!(tst & 0x20)) ret &= RevMatrix[5];
248 if (!(tst & 0x40)) ret &= RevMatrix[6];
249 if (!(tst & 0x80)) ret &= RevMatrix[7];
250 return ret & Joystick2;
251 }
252 case 0x01: {
253 uint8 ret = ~ddrb, tst = (pra | ~ddra) & Joystick2;
254 if (!(tst & 0x01)) ret &= KeyMatrix[0]; // AND all active rows
255 if (!(tst & 0x02)) ret &= KeyMatrix[1];
256 if (!(tst & 0x04)) ret &= KeyMatrix[2];
257 if (!(tst & 0x08)) ret &= KeyMatrix[3];
258 if (!(tst & 0x10)) ret &= KeyMatrix[4];
259 if (!(tst & 0x20)) ret &= KeyMatrix[5];
260 if (!(tst & 0x40)) ret &= KeyMatrix[6];
261 if (!(tst & 0x80)) ret &= KeyMatrix[7];
262 ret = (ret | (prb & ddrb)) & Joystick1;
263
264 // TA/TB output to PB enabled?
265 if ((cra | crb) & 0x02)
266 ret = timer_on_pb(ret);
267
268 return ret;
269 }
270 case 0x02: return ddra;
271 case 0x03: return ddrb;
272 case 0x04: return ta;
273 case 0x05: return ta >> 8;
274 case 0x06: return tb;
275 case 0x07: return tb >> 8;
276 case 0x08: tod_halt = false; return tod_10ths;
277 case 0x09: return tod_sec;
278 case 0x0a: return tod_min;
279 case 0x0b: tod_halt = true; return tod_hr;
280 case 0x0c: return sdr;
281 case 0x0d: {
282 uint8 ret = icr; // Read and clear ICR
283 icr = 0;
284 the_cpu->ClearCIAIRQ(); // Clear IRQ
285 return ret;
286 }
287 case 0x0e: return cra;
288 case 0x0f: return crb;
289 }
290 return 0; // Can't happen
291 }
292
293
294 /*
295 * Read from register (CIA 2)
296 */
297
298 uint8 MOS6526_2::ReadRegister(uint16 adr)
299 {
300 switch (adr) {
301 case 0x00:
302 return (pra | ~ddra) & 0x3f
303 | IECLines & the_cpu_1541->IECLines;
304 case 0x01: {
305 uint8 ret = prb | ~ddrb;
306
307 // TA/TB output to PB enabled?
308 if ((cra | crb) & 0x02)
309 ret = timer_on_pb(ret);
310
311 return ret;
312 }
313 case 0x02: return ddra;
314 case 0x03: return ddrb;
315 case 0x04: return ta;
316 case 0x05: return ta >> 8;
317 case 0x06: return tb;
318 case 0x07: return tb >> 8;
319 case 0x08: tod_halt = false; return tod_10ths;
320 case 0x09: return tod_sec;
321 case 0x0a: return tod_min;
322 case 0x0b: tod_halt = true; return tod_hr;
323 case 0x0c: return sdr;
324 case 0x0d: {
325 uint8 ret = icr; // Read and clear ICR
326 icr = 0;
327 the_cpu->ClearNMI();
328 return ret;
329 }
330 case 0x0e: return cra;
331 case 0x0f: return crb;
332 }
333 return 0; // Can't happen
334 }
335
336
337 /*
338 * Write to register (CIA 1)
339 */
340
341 // Write to port B, check for lightpen interrupt
342 inline void MOS6526_1::check_lp(void)
343 {
344 if ((prb | ~ddrb) & 0x10 != prev_lp)
345 the_vic->TriggerLightpen();
346 prev_lp = (prb | ~ddrb) & 0x10;
347 }
348
349 void MOS6526_1::WriteRegister(uint16 adr, uint8 byte)
350 {
351 switch (adr) {
352 case 0x0: pra = byte; break;
353 case 0x1:
354 prb = byte;
355 check_lp();
356 break;
357 case 0x2: ddra = byte; break;
358 case 0x3:
359 ddrb = byte;
360 check_lp();
361 break;
362
363 case 0x4: latcha = (latcha & 0xff00) | byte; break;
364 case 0x5:
365 latcha = (latcha & 0xff) | (byte << 8);
366 if (!(cra & 1)) // Reload timer if stopped
367 ta = latcha;
368 break;
369
370 case 0x6: latchb = (latchb & 0xff00) | byte; break;
371 case 0x7:
372 latchb = (latchb & 0xff) | (byte << 8);
373 if (!(crb & 1)) // Reload timer if stopped
374 tb = latchb;
375 break;
376
377 case 0x8:
378 if (crb & 0x80)
379 alm_10ths = byte & 0x0f;
380 else
381 tod_10ths = byte & 0x0f;
382 break;
383 case 0x9:
384 if (crb & 0x80)
385 alm_sec = byte & 0x7f;
386 else
387 tod_sec = byte & 0x7f;
388 break;
389 case 0xa:
390 if (crb & 0x80)
391 alm_min = byte & 0x7f;
392 else
393 tod_min = byte & 0x7f;
394 break;
395 case 0xb:
396 if (crb & 0x80)
397 alm_hr = byte & 0x9f;
398 else
399 tod_hr = byte & 0x9f;
400 break;
401
402 case 0xc:
403 sdr = byte;
404 TriggerInterrupt(8); // Fake SDR interrupt for programs that need it
405 break;
406
407 case 0xd:
408 if (byte & 0x80)
409 int_mask |= byte & 0x7f;
410 else
411 int_mask &= ~byte;
412 if (icr & int_mask & 0x7f) { // Trigger IRQ if pending
413 icr |= 0x80;
414 the_cpu->TriggerCIAIRQ();
415 }
416 break;
417
418 case 0xe:
419 has_new_cra = true; // Delay write by 1 cycle
420 new_cra = byte;
421 ta_cnt_phi2 = ((byte & 0x20) == 0x00);
422 break;
423
424 case 0xf:
425 has_new_crb = true; // Delay write by 1 cycle
426 new_crb = byte;
427 tb_cnt_phi2 = ((byte & 0x60) == 0x00);
428 tb_cnt_ta = ((byte & 0x60) == 0x40);
429 break;
430 }
431 }
432
433
434 /*
435 * Write to register (CIA 2)
436 */
437
438 void MOS6526_2::WriteRegister(uint16 adr, uint8 byte)
439 {
440 switch (adr) {
441 case 0x0:{
442 pra = byte;
443 the_vic->ChangedVA(~(pra | ~ddra) & 3);
444 uint8 old_lines = IECLines;
445 IECLines = (~byte << 2) & 0x80 // DATA
446 | (~byte << 2) & 0x40 // CLK
447 | (~byte << 1) & 0x10; // ATN
448 if ((IECLines ^ old_lines) & 0x10) { // ATN changed
449 the_cpu_1541->NewATNState();
450 if (old_lines & 0x10) // ATN 1->0
451 the_cpu_1541->IECInterrupt();
452 }
453 break;
454 }
455 case 0x1: prb = byte; break;
456
457 case 0x2:
458 ddra = byte;
459 the_vic->ChangedVA(~(pra | ~ddra) & 3);
460 break;
461 case 0x3: ddrb = byte; break;
462
463 case 0x4: latcha = (latcha & 0xff00) | byte; break;
464 case 0x5:
465 latcha = (latcha & 0xff) | (byte << 8);
466 if (!(cra & 1)) // Reload timer if stopped
467 ta = latcha;
468 break;
469
470 case 0x6: latchb = (latchb & 0xff00) | byte; break;
471 case 0x7:
472 latchb = (latchb & 0xff) | (byte << 8);
473 if (!(crb & 1)) // Reload timer if stopped
474 tb = latchb;
475 break;
476
477 case 0x8:
478 if (crb & 0x80)
479 alm_10ths = byte & 0x0f;
480 else
481 tod_10ths = byte & 0x0f;
482 break;
483 case 0x9:
484 if (crb & 0x80)
485 alm_sec = byte & 0x7f;
486 else
487 tod_sec = byte & 0x7f;
488 break;
489 case 0xa:
490 if (crb & 0x80)
491 alm_min = byte & 0x7f;
492 else
493 tod_min = byte & 0x7f;
494 break;
495 case 0xb:
496 if (crb & 0x80)
497 alm_hr = byte & 0x9f;
498 else
499 tod_hr = byte & 0x9f;
500 break;
501
502 case 0xc:
503 sdr = byte;
504 TriggerInterrupt(8); // Fake SDR interrupt for programs that need it
505 break;
506
507 case 0xd:
508 if (byte & 0x80)
509 int_mask |= byte & 0x7f;
510 else
511 int_mask &= ~byte;
512 if (icr & int_mask & 0x1f) { // Trigger NMI if pending
513 icr |= 0x80;
514 the_cpu->TriggerNMI();
515 }
516 break;
517
518 case 0xe:
519 has_new_cra = true; // Delay write by 1 cycle
520 new_cra = byte;
521 ta_cnt_phi2 = ((byte & 0x20) == 0x00);
522 break;
523
524 case 0xf:
525 has_new_crb = true; // Delay write by 1 cycle
526 new_crb = byte;
527 tb_cnt_phi2 = ((byte & 0x60) == 0x00);
528 tb_cnt_ta = ((byte & 0x60) == 0x40);
529 break;
530 }
531 }
532
533
534 /*
535 * Emulate CIA for one cycle/raster line
536 */
537
538 void MOS6526::EmulateCycle(void)
539 {
540 bool ta_underflow = false;
541
542 // Timer A state machine
543 switch (ta_state) {
544 case T_WAIT_THEN_COUNT:
545 ta_state = T_COUNT; // fall through
546 case T_STOP:
547 goto ta_idle;
548 case T_LOAD_THEN_STOP:
549 ta_state = T_STOP;
550 ta = latcha; // Reload timer
551 goto ta_idle;
552 case T_LOAD_THEN_COUNT:
553 ta_state = T_COUNT;
554 ta = latcha; // Reload timer
555 goto ta_idle;
556 case T_LOAD_THEN_WAIT_THEN_COUNT:
557 ta_state = T_WAIT_THEN_COUNT;
558 if (ta == 1)
559 goto ta_interrupt; // Interrupt if timer == 1
560 else {
561 ta = latcha; // Reload timer
562 goto ta_idle;
563 }
564 case T_COUNT:
565 goto ta_count;
566 case T_COUNT_THEN_STOP:
567 ta_state = T_STOP;
568 goto ta_count;
569 }
570
571 // Count timer A
572 ta_count:
573 if (ta_cnt_phi2)
574 if (!ta || !--ta) { // Decrement timer, underflow?
575 if (ta_state != T_STOP) {
576 ta_interrupt:
577 ta = latcha; // Reload timer
578 ta_irq_next_cycle = true; // Trigger interrupt in next cycle
579 icr |= 1; // But set ICR bit now
580 ta_toggle = !ta_toggle; // Toggle PB6 output
581
582 if (cra & 8) { // One-shot?
583 cra &= 0xfe; // Yes, stop timer
584 new_cra &= 0xfe;
585 ta_state = T_LOAD_THEN_STOP; // Reload in next cycle
586 } else
587 ta_state = T_LOAD_THEN_COUNT; // No, delay one cycle (and reload)
588 }
589 ta_underflow = true;
590 }
591
592 // Delayed write to CRA?
593 ta_idle:
594 if (has_new_cra) {
595 switch (ta_state) {
596 case T_STOP:
597 case T_LOAD_THEN_STOP:
598 if (new_cra & 1) { // Timer started, wasn't running
599 ta_toggle = true; // Starting the timer resets the toggle bit
600 if (new_cra & 0x10) // Force load
601 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
602 else // No force load
603 ta_state = T_WAIT_THEN_COUNT;
604 } else { // Timer stopped, was already stopped
605 if (new_cra & 0x10) // Force load
606 ta_state = T_LOAD_THEN_STOP;
607 }
608 break;
609 case T_COUNT:
610 if (new_cra & 1) { // Timer started, was already running
611 if (new_cra & 0x10) // Force load
612 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
613 } else { // Timer stopped, was running
614 if (new_cra & 0x10) // Force load
615 ta_state = T_LOAD_THEN_STOP;
616 else // No force load
617 ta_state = T_COUNT_THEN_STOP;
618 }
619 break;
620 case T_LOAD_THEN_COUNT:
621 case T_WAIT_THEN_COUNT:
622 if (new_cra & 1) {
623 if (new_cra & 8) { // One-shot?
624 new_cra &= 0xfe; // Yes, stop timer
625 ta_state = T_STOP;
626 } else if (new_cra & 0x10) // Force load
627 ta_state = T_LOAD_THEN_WAIT_THEN_COUNT;
628 } else {
629 ta_state = T_STOP;
630 }
631 break;
632 }
633 cra = new_cra & 0xef;
634 has_new_cra = false;
635 }
636
637 // Timer B state machine
638 switch (tb_state) {
639 case T_WAIT_THEN_COUNT:
640 tb_state = T_COUNT; // fall through
641 case T_STOP:
642 goto tb_idle;
643 case T_LOAD_THEN_STOP:
644 tb_state = T_STOP;
645 tb = latchb; // Reload timer
646 goto tb_idle;
647 case T_LOAD_THEN_COUNT:
648 tb_state = T_COUNT;
649 tb = latchb; // Reload timer
650 goto tb_idle;
651 case T_LOAD_THEN_WAIT_THEN_COUNT:
652 tb_state = T_WAIT_THEN_COUNT;
653 if (tb == 1)
654 goto tb_interrupt; // Interrupt if timer == 1
655 else {
656 tb = latchb; // Reload timer
657 goto tb_idle;
658 }
659 case T_COUNT:
660 goto tb_count;
661 case T_COUNT_THEN_STOP:
662 tb_state = T_STOP;
663 goto tb_count;
664 }
665
666 // Count timer B
667 tb_count:
668 if (tb_cnt_phi2 || (tb_cnt_ta && ta_underflow))
669 if (!tb || !--tb) { // Decrement timer, underflow?
670 if (tb_state != T_STOP) {
671 tb_interrupt:
672 tb = latchb; // Reload timer
673 tb_irq_next_cycle = true; // Trigger interrupt in next cycle
674 icr |= 2; // But set ICR bit now
675 tb_toggle = !tb_toggle; // Toggle PB7 output
676
677 if (crb & 8) { // One-shot?
678 crb &= 0xfe; // Yes, stop timer
679 new_crb &= 0xfe;
680 tb_state = T_LOAD_THEN_STOP; // Reload in next cycle
681 } else
682 tb_state = T_LOAD_THEN_COUNT; // No, delay one cycle (and reload)
683 }
684 }
685
686 // Delayed write to CRB?
687 tb_idle:
688 if (has_new_crb) {
689 switch (tb_state) {
690 case T_STOP:
691 case T_LOAD_THEN_STOP:
692 if (new_crb & 1) { // Timer started, wasn't running
693 tb_toggle = true; // Starting the timer resets the toggle bit
694 if (new_crb & 0x10) // Force load
695 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
696 else // No force load
697 tb_state = T_WAIT_THEN_COUNT;
698 } else { // Timer stopped, was already stopped
699 if (new_crb & 0x10) // Force load
700 tb_state = T_LOAD_THEN_STOP;
701 }
702 break;
703 case T_COUNT:
704 if (new_crb & 1) { // Timer started, was already running
705 if (new_crb & 0x10) // Force load
706 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
707 } else { // Timer stopped, was running
708 if (new_crb & 0x10) // Force load
709 tb_state = T_LOAD_THEN_STOP;
710 else // No force load
711 tb_state = T_COUNT_THEN_STOP;
712 }
713 break;
714 case T_LOAD_THEN_COUNT:
715 case T_WAIT_THEN_COUNT:
716 if (new_crb & 1) {
717 if (new_crb & 8) { // One-shot?
718 new_crb &= 0xfe; // Yes, stop timer
719 tb_state = T_STOP;
720 } else if (new_crb & 0x10) // Force load
721 tb_state = T_LOAD_THEN_WAIT_THEN_COUNT;
722 } else {
723 tb_state = T_STOP;
724 }
725 break;
726 }
727 crb = new_crb & 0xef;
728 has_new_crb = false;
729 }
730 }
731
732
733 /*
734 * Count CIA TOD clock (called during VBlank)
735 */
736
737 void MOS6526::CountTOD(void)
738 {
739 uint8 lo, hi;
740
741 // Decrement frequency divider
742 if (tod_divider)
743 tod_divider--;
744 else {
745
746 // Reload divider according to 50/60 Hz flag
747 if (cra & 0x80)
748 tod_divider = 4;
749 else
750 tod_divider = 5;
751
752 // 1/10 seconds
753 tod_10ths++;
754 if (tod_10ths > 9) {
755 tod_10ths = 0;
756
757 // Seconds
758 lo = (tod_sec & 0x0f) + 1;
759 hi = tod_sec >> 4;
760 if (lo > 9) {
761 lo = 0;
762 hi++;
763 }
764 if (hi > 5) {
765 tod_sec = 0;
766
767 // Minutes
768 lo = (tod_min & 0x0f) + 1;
769 hi = tod_min >> 4;
770 if (lo > 9) {
771 lo = 0;
772 hi++;
773 }
774 if (hi > 5) {
775 tod_min = 0;
776
777 // Hours
778 lo = (tod_hr & 0x0f) + 1;
779 hi = (tod_hr >> 4) & 1;
780 tod_hr &= 0x80; // Keep AM/PM flag
781 if (lo > 9) {
782 lo = 0;
783 hi++;
784 }
785 tod_hr |= (hi << 4) | lo;
786 if ((tod_hr & 0x1f) > 0x11)
787 tod_hr = tod_hr & 0x80 ^ 0x80;
788 } else
789 tod_min = (hi << 4) | lo;
790 } else
791 tod_sec = (hi << 4) | lo;
792 }
793
794 // Alarm time reached? Trigger interrupt if enabled
795 if (tod_10ths == alm_10ths && tod_sec == alm_sec &&
796 tod_min == alm_min && tod_hr == alm_hr)
797 TriggerInterrupt(4);
798 }
799 }
800
801
802 /*
803 * Trigger IRQ (CIA 1)
804 */
805
806 void MOS6526_1::TriggerInterrupt(int bit)
807 {
808 icr |= bit;
809 if (int_mask & bit) {
810 icr |= 0x80;
811 the_cpu->TriggerCIAIRQ();
812 }
813 }
814
815
816 /*
817 * Trigger NMI (CIA 2)
818 */
819
820 void MOS6526_2::TriggerInterrupt(int bit)
821 {
822 icr |= bit;
823 if (int_mask & bit) {
824 icr |= 0x80;
825 the_cpu->TriggerNMI();
826 }
827 }