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 (13 years, 11 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +12 -4 lines
Log Message:
better interrupt timing

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * CPU1541_SC.cpp - Single-cycle 6502 (1541) emulation
3     *
4 cebix 1.5 * Frodo Copyright (C) Christian Bauer
5 cebix 1.1 *
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 cebix 1.5 opflags = 0;
103 cebix 1.1 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 cebix 1.5 opflags = 0;
582 cebix 1.1
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 cebix 1.5 if (interrupt.intr[INT_RESET]) {
626 cebix 1.1 Reset();
627 cebix 1.5 } 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 cebix 1.1 }
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     }