ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/CPU1541_SC.cpp
Revision: 1.5
Committed: 2010-04-22T15:08:18Z (14 years, 6 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +12 -4 lines
Log Message:
better interrupt timing

File Contents

# Content
1 /*
2 * CPU1541_SC.cpp - Single-cycle 6502 (1541) 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 * Opcode execution:
26 * - All opcodes are resolved into single clock cycles. There is one
27 * switch case for each cycle.
28 * - The "state" variable specifies the routine to be executed in the
29 * next cycle. Its upper 8 bits contain the current opcode, its lower
30 * 8 bits contain the cycle number (0..7) within the opcode.
31 * - Opcodes are fetched in cycle 0 (state = 0)
32 * - The states 0x0010..0x0027 are used for interrupts
33 * - There is exactly one memory access in each clock cycle
34 *
35 * Memory map (1541C, the 1541 and 1541-II are a bit different):
36 *
37 * $0000-$07ff RAM (2K)
38 * $0800-$0fff RAM mirror
39 * $1000-$17ff free
40 * $1800-$1bff VIA 1
41 * $1c00-$1fff VIA 2
42 * $2000-$bfff free
43 * $c000-$ffff ROM (16K)
44 *
45 * - All memory accesses are done with the read_byte() and
46 * write_byte() functions which also do the memory address
47 * decoding.
48 * - The possible interrupt sources are:
49 * INT_VIA1IRQ: I flag is checked, jump to ($fffe) (unused)
50 * INT_VIA2IRQ: I flag is checked, jump to ($fffe) (unused)
51 * INT_IECIRQ: I flag is checked, jump to ($fffe) (unused)
52 * INT_RESET: Jump to ($fffc)
53 * - The z_flag variable has the inverse meaning of the
54 * 6502 Z flag
55 * - Only the highest bit of the n_flag variable is used
56 * - The $f2 opcode that would normally crash the 6502 is
57 * used to implement emulator-specific functions
58 * - The 1541 6502 emulation also includes a very simple VIA
59 * emulation (enough to make the IEC bus and GCR loading work).
60 * It's too small to move it to a source file of its own.
61 *
62 * Incompatibilities:
63 * ------------------
64 *
65 * - VIA emulation incomplete
66 */
67
68 #include "sysdeps.h"
69
70 #include "CPU1541.h"
71 #include "CPU_common.h"
72 #include "1541job.h"
73 #include "C64.h"
74 #include "CIA.h"
75 #include "Display.h"
76
77
78 enum {
79 INT_RESET = 3
80 };
81
82
83 /*
84 * 6502 constructor: Initialize registers
85 */
86
87 MOS6502_1541::MOS6502_1541(C64 *c64, Job1541 *job, C64Display *disp, uint8 *Ram, uint8 *Rom)
88 : ram(Ram), rom(Rom), the_c64(c64), the_display(disp), the_job(job)
89 {
90 a = x = y = 0;
91 sp = 0xff;
92 n_flag = z_flag = 0;
93 v_flag = d_flag = c_flag = false;
94 i_flag = true;
95
96 via1_t1c = via1_t1l = via1_t2c = via1_t2l = 0;
97 via1_sr = 0;
98 via2_t1c = via2_t1l = via2_t2c = via2_t2l = 0;
99 via2_sr = 0;
100
101 first_irq_cycle = 0;
102 opflags = 0;
103 Idle = false;
104 }
105
106
107 /*
108 * Reset CPU asynchronously
109 */
110
111 void MOS6502_1541::AsyncReset(void)
112 {
113 interrupt.intr[INT_RESET] = true;
114 Idle = false;
115 }
116
117
118 /*
119 * Get 6502 register state
120 */
121
122 void MOS6502_1541::GetState(MOS6502State *s)
123 {
124 s->a = a;
125 s->x = x;
126 s->y = y;
127
128 s->p = 0x20 | (n_flag & 0x80);
129 if (v_flag) s->p |= 0x40;
130 if (d_flag) s->p |= 0x08;
131 if (i_flag) s->p |= 0x04;
132 if (!z_flag) s->p |= 0x02;
133 if (c_flag) s->p |= 0x01;
134
135 s->pc = pc;
136 s->sp = sp | 0x0100;
137
138 s->intr[INT_VIA1IRQ] = interrupt.intr[INT_VIA1IRQ];
139 s->intr[INT_VIA2IRQ] = interrupt.intr[INT_VIA2IRQ];
140 s->intr[INT_IECIRQ] = interrupt.intr[INT_IECIRQ];
141 s->intr[INT_RESET] = interrupt.intr[INT_RESET];
142 s->idle = Idle;
143
144 s->via1_pra = via1_pra; s->via1_ddra = via1_ddra;
145 s->via1_prb = via1_prb; s->via1_ddrb = via1_ddrb;
146 s->via1_t1c = via1_t1c; s->via1_t1l = via1_t1l;
147 s->via1_t2c = via1_t2c; s->via1_t2l = via1_t2l;
148 s->via1_sr = via1_sr;
149 s->via1_acr = via1_acr; s->via1_pcr = via1_pcr;
150 s->via1_ifr = via1_ifr; s->via1_ier = via1_ier;
151
152 s->via2_pra = via2_pra; s->via2_ddra = via2_ddra;
153 s->via2_prb = via2_prb; s->via2_ddrb = via2_ddrb;
154 s->via2_t1c = via2_t1c; s->via2_t1l = via2_t1l;
155 s->via2_t2c = via2_t2c; s->via2_t2l = via2_t2l;
156 s->via2_sr = via2_sr;
157 s->via2_acr = via2_acr; s->via2_pcr = via2_pcr;
158 s->via2_ifr = via2_ifr; s->via2_ier = via2_ier;
159 }
160
161
162 /*
163 * Restore 6502 state
164 */
165
166 void MOS6502_1541::SetState(MOS6502State *s)
167 {
168 a = s->a;
169 x = s->x;
170 y = s->y;
171
172 n_flag = s->p;
173 v_flag = s->p & 0x40;
174 d_flag = s->p & 0x08;
175 i_flag = s->p & 0x04;
176 z_flag = !(s->p & 0x02);
177 c_flag = s->p & 0x01;
178
179 pc = s->pc;
180 sp = s->sp & 0xff;
181
182 interrupt.intr[INT_VIA1IRQ] = s->intr[INT_VIA1IRQ];
183 interrupt.intr[INT_VIA2IRQ] = s->intr[INT_VIA2IRQ];
184 interrupt.intr[INT_IECIRQ] = s->intr[INT_IECIRQ];
185 interrupt.intr[INT_RESET] = s->intr[INT_RESET];
186 Idle = s->idle;
187
188 via1_pra = s->via1_pra; via1_ddra = s->via1_ddra;
189 via1_prb = s->via1_prb; via1_ddrb = s->via1_ddrb;
190 via1_t1c = s->via1_t1c; via1_t1l = s->via1_t1l;
191 via1_t2c = s->via1_t2c; via1_t2l = s->via1_t2l;
192 via1_sr = s->via1_sr;
193 via1_acr = s->via1_acr; via1_pcr = s->via1_pcr;
194 via1_ifr = s->via1_ifr; via1_ier = s->via1_ier;
195
196 via2_pra = s->via2_pra; via2_ddra = s->via2_ddra;
197 via2_prb = s->via2_prb; via2_ddrb = s->via2_ddrb;
198 via2_t1c = s->via2_t1c; via2_t1l = s->via2_t1l;
199 via2_t2c = s->via2_t2c; via2_t2l = s->via2_t2l;
200 via2_sr = s->via2_sr;
201 via2_acr = s->via2_acr; via2_pcr = s->via2_pcr;
202 via2_ifr = s->via2_ifr; via2_ier = s->via2_ier;
203 }
204
205
206 /*
207 * Read a byte from I/O space
208 */
209
210 inline uint8 MOS6502_1541::read_byte_io(uint16 adr)
211 {
212 if ((adr & 0xfc00) == 0x1800) // VIA 1
213 switch (adr & 0xf) {
214 case 0:
215 return (via1_prb & 0x1a
216 | ((IECLines & TheCIA2->IECLines) >> 7) // DATA
217 | ((IECLines & TheCIA2->IECLines) >> 4) & 0x04 // CLK
218 | (TheCIA2->IECLines << 3) & 0x80) ^ 0x85; // ATN
219 case 1:
220 case 15:
221 return 0xff; // Keep 1541C ROMs happy (track 0 sensor)
222 case 2:
223 return via1_ddrb;
224 case 3:
225 return via1_ddra;
226 case 4:
227 via1_ifr &= 0xbf;
228 return via1_t1c;
229 case 5:
230 return via1_t1c >> 8;
231 case 6:
232 return via1_t1l;
233 case 7:
234 return via1_t1l >> 8;
235 case 8:
236 via1_ifr &= 0xdf;
237 return via1_t2c;
238 case 9:
239 return via1_t2c >> 8;
240 case 10:
241 return via1_sr;
242 case 11:
243 return via1_acr;
244 case 12:
245 return via1_pcr;
246 case 13:
247 return via1_ifr | (via1_ifr & via1_ier ? 0x80 : 0);
248 case 14:
249 return via1_ier | 0x80;
250 default: // Can't happen
251 return 0;
252 }
253
254 else if ((adr & 0xfc00) == 0x1c00) // VIA 2
255 switch (adr & 0xf) {
256 case 0:
257 if (the_job->SyncFound())
258 return via2_prb & 0x7f | the_job->WPState();
259 else
260 return via2_prb | 0x80 | the_job->WPState();
261 case 1:
262 case 15:
263 return the_job->ReadGCRByte();
264 case 2:
265 return via2_ddrb;
266 case 3:
267 return via2_ddra;
268 case 4:
269 via2_ifr &= 0xbf;
270 interrupt.intr[INT_VIA2IRQ] = false; // Clear job IRQ
271 return via2_t1c;
272 case 5:
273 return via2_t1c >> 8;
274 case 6:
275 return via2_t1l;
276 case 7:
277 return via2_t1l >> 8;
278 case 8:
279 via2_ifr &= 0xdf;
280 return via2_t2c;
281 case 9:
282 return via2_t2c >> 8;
283 case 10:
284 return via2_sr;
285 case 11:
286 return via2_acr;
287 case 12:
288 return via2_pcr;
289 case 13:
290 return via2_ifr | (via2_ifr & via2_ier ? 0x80 : 0);
291 case 14:
292 return via2_ier | 0x80;
293 default: // Can't happen
294 return 0;
295 }
296
297 else
298 return adr >> 8;
299 }
300
301
302 /*
303 * Read a byte from the CPU's address space
304 */
305
306 uint8 MOS6502_1541::read_byte(uint16 adr)
307 {
308 if (adr >= 0xc000)
309 return rom[adr & 0x3fff];
310 else if (adr < 0x1000)
311 return ram[adr & 0x07ff];
312 else
313 return read_byte_io(adr);
314 }
315
316
317 /*
318 * Read a word (little-endian) from the CPU's address space
319 */
320
321 inline uint16 MOS6502_1541::read_word(uint16 adr)
322 {
323 return read_byte(adr) | (read_byte(adr+1) << 8);
324 }
325
326
327 /*
328 * Write a byte to I/O space
329 */
330
331 void MOS6502_1541::write_byte_io(uint16 adr, uint8 byte)
332 {
333 if ((adr & 0xfc00) == 0x1800) // VIA 1
334 switch (adr & 0xf) {
335 case 0:
336 via1_prb = byte;
337 byte = ~via1_prb & via1_ddrb;
338 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
339 | (byte << 3) & 0x40;
340 break;
341 case 1:
342 case 15:
343 via1_pra = byte;
344 break;
345 case 2:
346 via1_ddrb = byte;
347 byte &= ~via1_prb;
348 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
349 | (byte << 3) & 0x40;
350 break;
351 case 3:
352 via1_ddra = byte;
353 break;
354 case 4:
355 case 6:
356 via1_t1l = via1_t1l & 0xff00 | byte;
357 break;
358 case 5:
359 via1_t1l = via1_t1l & 0xff | (byte << 8);
360 via1_ifr &= 0xbf;
361 via1_t1c = via1_t1l;
362 break;
363 case 7:
364 via1_t1l = via1_t1l & 0xff | (byte << 8);
365 break;
366 case 8:
367 via1_t2l = via1_t2l & 0xff00 | byte;
368 break;
369 case 9:
370 via1_t2l = via1_t2l & 0xff | (byte << 8);
371 via1_ifr &= 0xdf;
372 via1_t2c = via1_t2l;
373 break;
374 case 10:
375 via1_sr = byte;
376 break;
377 case 11:
378 via1_acr = byte;
379 break;
380 case 12:
381 via1_pcr = byte;
382 break;
383 case 13:
384 via1_ifr &= ~byte;
385 break;
386 case 14:
387 if (byte & 0x80)
388 via1_ier |= byte & 0x7f;
389 else
390 via1_ier &= ~byte;
391 break;
392 }
393
394 else if ((adr & 0xfc00) == 0x1c00)
395 switch (adr & 0xf) {
396 case 0:
397 if ((via2_prb ^ byte) & 8) // Bit 3: Drive LED
398 the_display->UpdateLEDs(byte & 8 ? 1 : 0, 0, 0, 0);
399 if ((via2_prb ^ byte) & 3) // Bits 0/1: Stepper motor
400 if ((via2_prb & 3) == ((byte+1) & 3))
401 the_job->MoveHeadOut();
402 else if ((via2_prb & 3) == ((byte-1) & 3))
403 the_job->MoveHeadIn();
404 via2_prb = byte & 0xef;
405 break;
406 case 1:
407 case 15:
408 via2_pra = byte;
409 break;
410 case 2:
411 via2_ddrb = byte;
412 break;
413 case 3:
414 via2_ddra = byte;
415 break;
416 case 4:
417 case 6:
418 via2_t1l = via2_t1l & 0xff00 | byte;
419 break;
420 case 5:
421 via2_t1l = via2_t1l & 0xff | (byte << 8);
422 via2_ifr &= 0xbf;
423 via2_t1c = via2_t1l;
424 break;
425 case 7:
426 via2_t1l = via2_t1l & 0xff | (byte << 8);
427 break;
428 case 8:
429 via2_t2l = via2_t2l & 0xff00 | byte;
430 break;
431 case 9:
432 via2_t2l = via2_t2l & 0xff | (byte << 8);
433 via2_ifr &= 0xdf;
434 via2_t2c = via2_t2l;
435 break;
436 case 10:
437 via2_sr = byte;
438 break;
439 case 11:
440 via2_acr = byte;
441 break;
442 case 12:
443 via2_pcr = byte;
444 break;
445 case 13:
446 via2_ifr &= ~byte;
447 break;
448 case 14:
449 if (byte & 0x80)
450 via2_ier |= byte & 0x7f;
451 else
452 via2_ier &= ~byte;
453 break;
454 }
455 }
456
457
458 /*
459 * Write a byte to the CPU's address space
460 */
461
462 inline void MOS6502_1541::write_byte(uint16 adr, uint8 byte)
463 {
464 if (adr < 0x1000)
465 ram[adr & 0x7ff] = byte;
466 else
467 write_byte_io(adr, byte);
468 }
469
470
471 /*
472 * Read byte from 6502/1541 address space (used by SAM)
473 */
474
475 uint8 MOS6502_1541::ExtReadByte(uint16 adr)
476 {
477 return read_byte(adr);
478 }
479
480
481 /*
482 * Write byte to 6502/1541 address space (used by SAM)
483 */
484
485 void MOS6502_1541::ExtWriteByte(uint16 adr, uint8 byte)
486 {
487 write_byte(adr, byte);
488 }
489
490
491 /*
492 * Adc instruction
493 */
494
495 inline void MOS6502_1541::do_adc(uint8 byte)
496 {
497 if (!d_flag) {
498 uint16 tmp;
499
500 // Binary mode
501 tmp = a + byte + (c_flag ? 1 : 0);
502 c_flag = tmp > 0xff;
503 v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
504 z_flag = n_flag = a = tmp;
505
506 } else {
507 uint16 al, ah;
508
509 // Decimal mode
510 al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0); // Calculate lower nybble
511 if (al > 9) al += 6; // BCD fixup for lower nybble
512
513 ah = (a >> 4) + (byte >> 4); // Calculate upper nybble
514 if (al > 0x0f) ah++;
515
516 z_flag = a + byte + (c_flag ? 1 : 0); // Set flags
517 n_flag = ah << 4; // Only highest bit used
518 v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
519
520 if (ah > 9) ah += 6; // BCD fixup for upper nybble
521 c_flag = ah > 0x0f; // Set carry flag
522 a = (ah << 4) | (al & 0x0f); // Compose result
523 }
524 }
525
526
527 /*
528 * Sbc instruction
529 */
530
531 inline void MOS6502_1541::do_sbc(uint8 byte)
532 {
533 uint16 tmp = a - byte - (c_flag ? 0 : 1);
534
535 if (!d_flag) {
536
537 // Binary mode
538 c_flag = tmp < 0x100;
539 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
540 z_flag = n_flag = a = tmp;
541
542 } else {
543 uint16 al, ah;
544
545 // Decimal mode
546 al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1); // Calculate lower nybble
547 ah = (a >> 4) - (byte >> 4); // Calculate upper nybble
548 if (al & 0x10) {
549 al -= 6; // BCD fixup for lower nybble
550 ah--;
551 }
552 if (ah & 0x10) ah -= 6; // BCD fixup for upper nybble
553
554 c_flag = tmp < 0x100; // Set flags
555 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
556 z_flag = n_flag = tmp;
557
558 a = (ah << 4) | (al & 0x0f); // Compose result
559 }
560 }
561
562
563 /*
564 * Reset CPU
565 */
566
567 void MOS6502_1541::Reset(void)
568 {
569 // IEC lines and VIA registers
570 IECLines = 0xc0;
571
572 via1_pra = via1_ddra = via1_prb = via1_ddrb = 0;
573 via1_acr = via1_pcr = 0;
574 via1_ifr = via1_ier = 0;
575 via2_pra = via2_ddra = via2_prb = via2_ddrb = 0;
576 via2_acr = via2_pcr = 0;
577 via2_ifr = via2_ier = 0;
578
579 // Clear all interrupt lines
580 interrupt.intr_any = 0;
581 opflags = 0;
582
583 // Read reset vector
584 pc = read_word(0xfffc);
585 state = 0;
586
587 // Wake up 1541
588 Idle = false;
589 }
590
591
592 /*
593 * Illegal opcode encountered
594 */
595
596 void MOS6502_1541::illegal_op(uint8 op, uint16 at)
597 {
598 char illop_msg[80];
599
600 sprintf(illop_msg, "1541: Illegal opcode %02x at %04x.", op, at);
601 if (ShowRequester(illop_msg, "Reset 1541", "Reset C64"))
602 the_c64->Reset();
603 Reset();
604 }
605
606
607 /*
608 * Emulate one 6502 clock cycle
609 */
610
611 // Read byte from memory
612 #define read_to(adr, to) \
613 to = read_byte(adr);
614
615 // Read byte from memory, throw away result
616 #define read_idle(adr) \
617 read_byte(adr);
618
619 void MOS6502_1541::EmulateCycle(void)
620 {
621 uint8 data, tmp;
622
623 // Any pending interrupts in state 0 (opcode fetch)?
624 if (!state && interrupt.intr_any) {
625 if (interrupt.intr[INT_RESET]) {
626 Reset();
627 } else if ((interrupt.intr[INT_VIA1IRQ] || interrupt.intr[INT_VIA2IRQ] || interrupt.intr[INT_IECIRQ]) &&
628 (!i_flag || (opflags & OPFLAG_IRQ_DISABLED)) && !(opflags & OPFLAG_IRQ_ENABLED)) {
629 uint32 int_delay = (opflags & OPFLAG_INT_DELAYED) ? 1 : 0; // Taken branches to the same page delay the IRQ
630 if (the_c64->CycleCounter - first_irq_cycle - int_delay >= 2) {
631 state = 0x0008;
632 opflags = 0;
633 }
634 }
635 }
636
637 #define IS_CPU_1541
638 #include "CPU_emulcycle.h"
639
640 // Extension opcode
641 case O_EXT:
642 if (pc < 0xc000) {
643 illegal_op(0xf2, pc-1);
644 break;
645 }
646 switch (read_byte(pc++)) {
647 case 0x00: // Go to sleep in DOS idle loop if error flag is clear and no command received
648 Idle = !(ram[0x26c] | ram[0x7c]);
649 pc = 0xebff;
650 Last;
651 case 0x01: // Write sector
652 the_job->WriteSector();
653 pc = 0xf5dc;
654 Last;
655 case 0x02: // Format track
656 the_job->FormatTrack();
657 pc = 0xfd8b;
658 Last;
659 default:
660 illegal_op(0xf2, pc-1);
661 break;
662 }
663 break;
664
665 default:
666 illegal_op(op, pc-1);
667 break;
668 }
669 }