ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/CPU1541_SC.cpp
Revision: 1.3
Committed: 2004-01-12T15:13:20Z (20 years, 3 months ago) by cebix
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * CPU1541_SC.cpp - Single-cycle 6502 (1541) emulation
3     *
4 cebix 1.3 * Frodo (C) 1994-1997,2002-2004 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     Idle = false;
103     }
104    
105    
106     /*
107     * Reset CPU asynchronously
108     */
109    
110     void MOS6502_1541::AsyncReset(void)
111     {
112     interrupt.intr[INT_RESET] = true;
113     Idle = false;
114     }
115    
116    
117     /*
118     * Get 6502 register state
119     */
120    
121     void MOS6502_1541::GetState(MOS6502State *s)
122     {
123     s->a = a;
124     s->x = x;
125     s->y = y;
126    
127     s->p = 0x20 | (n_flag & 0x80);
128     if (v_flag) s->p |= 0x40;
129     if (d_flag) s->p |= 0x08;
130     if (i_flag) s->p |= 0x04;
131     if (!z_flag) s->p |= 0x02;
132     if (c_flag) s->p |= 0x01;
133    
134     s->pc = pc;
135     s->sp = sp | 0x0100;
136    
137     s->intr[INT_VIA1IRQ] = interrupt.intr[INT_VIA1IRQ];
138     s->intr[INT_VIA2IRQ] = interrupt.intr[INT_VIA2IRQ];
139     s->intr[INT_IECIRQ] = interrupt.intr[INT_IECIRQ];
140     s->intr[INT_RESET] = interrupt.intr[INT_RESET];
141     s->idle = Idle;
142    
143     s->via1_pra = via1_pra; s->via1_ddra = via1_ddra;
144     s->via1_prb = via1_prb; s->via1_ddrb = via1_ddrb;
145     s->via1_t1c = via1_t1c; s->via1_t1l = via1_t1l;
146     s->via1_t2c = via1_t2c; s->via1_t2l = via1_t2l;
147     s->via1_sr = via1_sr;
148     s->via1_acr = via1_acr; s->via1_pcr = via1_pcr;
149     s->via1_ifr = via1_ifr; s->via1_ier = via1_ier;
150    
151     s->via2_pra = via2_pra; s->via2_ddra = via2_ddra;
152     s->via2_prb = via2_prb; s->via2_ddrb = via2_ddrb;
153     s->via2_t1c = via2_t1c; s->via2_t1l = via2_t1l;
154     s->via2_t2c = via2_t2c; s->via2_t2l = via2_t2l;
155     s->via2_sr = via2_sr;
156     s->via2_acr = via2_acr; s->via2_pcr = via2_pcr;
157     s->via2_ifr = via2_ifr; s->via2_ier = via2_ier;
158     }
159    
160    
161     /*
162     * Restore 6502 state
163     */
164    
165     void MOS6502_1541::SetState(MOS6502State *s)
166     {
167     a = s->a;
168     x = s->x;
169     y = s->y;
170    
171     n_flag = s->p;
172     v_flag = s->p & 0x40;
173     d_flag = s->p & 0x08;
174     i_flag = s->p & 0x04;
175     z_flag = !(s->p & 0x02);
176     c_flag = s->p & 0x01;
177    
178     pc = s->pc;
179     sp = s->sp & 0xff;
180    
181     interrupt.intr[INT_VIA1IRQ] = s->intr[INT_VIA1IRQ];
182     interrupt.intr[INT_VIA2IRQ] = s->intr[INT_VIA2IRQ];
183     interrupt.intr[INT_IECIRQ] = s->intr[INT_IECIRQ];
184     interrupt.intr[INT_RESET] = s->intr[INT_RESET];
185     Idle = s->idle;
186    
187     via1_pra = s->via1_pra; via1_ddra = s->via1_ddra;
188     via1_prb = s->via1_prb; via1_ddrb = s->via1_ddrb;
189     via1_t1c = s->via1_t1c; via1_t1l = s->via1_t1l;
190     via1_t2c = s->via1_t2c; via1_t2l = s->via1_t2l;
191     via1_sr = s->via1_sr;
192     via1_acr = s->via1_acr; via1_pcr = s->via1_pcr;
193     via1_ifr = s->via1_ifr; via1_ier = s->via1_ier;
194    
195     via2_pra = s->via2_pra; via2_ddra = s->via2_ddra;
196     via2_prb = s->via2_prb; via2_ddrb = s->via2_ddrb;
197     via2_t1c = s->via2_t1c; via2_t1l = s->via2_t1l;
198     via2_t2c = s->via2_t2c; via2_t2l = s->via2_t2l;
199     via2_sr = s->via2_sr;
200     via2_acr = s->via2_acr; via2_pcr = s->via2_pcr;
201     via2_ifr = s->via2_ifr; via2_ier = s->via2_ier;
202     }
203    
204    
205     /*
206     * Read a byte from I/O space
207     */
208    
209     inline uint8 MOS6502_1541::read_byte_io(uint16 adr)
210     {
211     if ((adr & 0xfc00) == 0x1800) // VIA 1
212     switch (adr & 0xf) {
213     case 0:
214     return (via1_prb & 0x1a
215     | ((IECLines & TheCIA2->IECLines) >> 7) // DATA
216     | ((IECLines & TheCIA2->IECLines) >> 4) & 0x04 // CLK
217     | (TheCIA2->IECLines << 3) & 0x80) ^ 0x85; // ATN
218     case 1:
219     case 15:
220     return 0xff; // Keep 1541C ROMs happy (track 0 sensor)
221     case 2:
222     return via1_ddrb;
223     case 3:
224     return via1_ddra;
225     case 4:
226     via1_ifr &= 0xbf;
227     return via1_t1c;
228     case 5:
229     return via1_t1c >> 8;
230     case 6:
231     return via1_t1l;
232     case 7:
233     return via1_t1l >> 8;
234     case 8:
235     via1_ifr &= 0xdf;
236     return via1_t2c;
237     case 9:
238     return via1_t2c >> 8;
239     case 10:
240     return via1_sr;
241     case 11:
242     return via1_acr;
243     case 12:
244     return via1_pcr;
245     case 13:
246     return via1_ifr | (via1_ifr & via1_ier ? 0x80 : 0);
247     case 14:
248     return via1_ier | 0x80;
249     default: // Can't happen
250     return 0;
251     }
252    
253     else if ((adr & 0xfc00) == 0x1c00) // VIA 2
254     switch (adr & 0xf) {
255     case 0:
256     if (the_job->SyncFound())
257     return via2_prb & 0x7f | the_job->WPState();
258     else
259     return via2_prb | 0x80 | the_job->WPState();
260     case 1:
261     case 15:
262     return the_job->ReadGCRByte();
263     case 2:
264     return via2_ddrb;
265     case 3:
266     return via2_ddra;
267     case 4:
268     via2_ifr &= 0xbf;
269     interrupt.intr[INT_VIA2IRQ] = false; // Clear job IRQ
270     return via2_t1c;
271     case 5:
272     return via2_t1c >> 8;
273     case 6:
274     return via2_t1l;
275     case 7:
276     return via2_t1l >> 8;
277     case 8:
278     via2_ifr &= 0xdf;
279     return via2_t2c;
280     case 9:
281     return via2_t2c >> 8;
282     case 10:
283     return via2_sr;
284     case 11:
285     return via2_acr;
286     case 12:
287     return via2_pcr;
288     case 13:
289     return via2_ifr | (via2_ifr & via2_ier ? 0x80 : 0);
290     case 14:
291     return via2_ier | 0x80;
292     default: // Can't happen
293     return 0;
294     }
295    
296     else
297     return adr >> 8;
298     }
299    
300    
301     /*
302     * Read a byte from the CPU's address space
303     */
304    
305     uint8 MOS6502_1541::read_byte(uint16 adr)
306     {
307     if (adr >= 0xc000)
308     return rom[adr & 0x3fff];
309     else if (adr < 0x1000)
310     return ram[adr & 0x07ff];
311     else
312     return read_byte_io(adr);
313     }
314    
315    
316     /*
317     * Read a word (little-endian) from the CPU's address space
318     */
319    
320     inline uint16 MOS6502_1541::read_word(uint16 adr)
321     {
322     return read_byte(adr) | (read_byte(adr+1) << 8);
323     }
324    
325    
326     /*
327     * Write a byte to I/O space
328     */
329    
330     void MOS6502_1541::write_byte_io(uint16 adr, uint8 byte)
331     {
332     if ((adr & 0xfc00) == 0x1800) // VIA 1
333     switch (adr & 0xf) {
334     case 0:
335     via1_prb = byte;
336     byte = ~via1_prb & via1_ddrb;
337     IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
338     | (byte << 3) & 0x40;
339     break;
340     case 1:
341     case 15:
342     via1_pra = byte;
343     break;
344     case 2:
345     via1_ddrb = byte;
346     byte &= ~via1_prb;
347     IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
348     | (byte << 3) & 0x40;
349     break;
350     case 3:
351     via1_ddra = byte;
352     break;
353     case 4:
354     case 6:
355     via1_t1l = via1_t1l & 0xff00 | byte;
356     break;
357     case 5:
358     via1_t1l = via1_t1l & 0xff | (byte << 8);
359     via1_ifr &= 0xbf;
360     via1_t1c = via1_t1l;
361     break;
362     case 7:
363     via1_t1l = via1_t1l & 0xff | (byte << 8);
364     break;
365     case 8:
366     via1_t2l = via1_t2l & 0xff00 | byte;
367     break;
368     case 9:
369     via1_t2l = via1_t2l & 0xff | (byte << 8);
370     via1_ifr &= 0xdf;
371     via1_t2c = via1_t2l;
372     break;
373     case 10:
374     via1_sr = byte;
375     break;
376     case 11:
377     via1_acr = byte;
378     break;
379     case 12:
380     via1_pcr = byte;
381     break;
382     case 13:
383     via1_ifr &= ~byte;
384     break;
385     case 14:
386     if (byte & 0x80)
387     via1_ier |= byte & 0x7f;
388     else
389     via1_ier &= ~byte;
390     break;
391     }
392    
393     else if ((adr & 0xfc00) == 0x1c00)
394     switch (adr & 0xf) {
395     case 0:
396     if ((via2_prb ^ byte) & 8) // Bit 3: Drive LED
397     the_display->UpdateLEDs(byte & 8 ? 1 : 0, 0, 0, 0);
398     if ((via2_prb ^ byte) & 3) // Bits 0/1: Stepper motor
399     if ((via2_prb & 3) == ((byte+1) & 3))
400     the_job->MoveHeadOut();
401     else if ((via2_prb & 3) == ((byte-1) & 3))
402     the_job->MoveHeadIn();
403     via2_prb = byte & 0xef;
404     break;
405     case 1:
406     case 15:
407     via2_pra = byte;
408     break;
409     case 2:
410     via2_ddrb = byte;
411     break;
412     case 3:
413     via2_ddra = byte;
414     break;
415     case 4:
416     case 6:
417     via2_t1l = via2_t1l & 0xff00 | byte;
418     break;
419     case 5:
420     via2_t1l = via2_t1l & 0xff | (byte << 8);
421     via2_ifr &= 0xbf;
422     via2_t1c = via2_t1l;
423     break;
424     case 7:
425     via2_t1l = via2_t1l & 0xff | (byte << 8);
426     break;
427     case 8:
428     via2_t2l = via2_t2l & 0xff00 | byte;
429     break;
430     case 9:
431     via2_t2l = via2_t2l & 0xff | (byte << 8);
432     via2_ifr &= 0xdf;
433     via2_t2c = via2_t2l;
434     break;
435     case 10:
436     via2_sr = byte;
437     break;
438     case 11:
439     via2_acr = byte;
440     break;
441     case 12:
442     via2_pcr = byte;
443     break;
444     case 13:
445     via2_ifr &= ~byte;
446     break;
447     case 14:
448     if (byte & 0x80)
449     via2_ier |= byte & 0x7f;
450     else
451     via2_ier &= ~byte;
452     break;
453     }
454     }
455    
456    
457     /*
458     * Write a byte to the CPU's address space
459     */
460    
461     inline void MOS6502_1541::write_byte(uint16 adr, uint8 byte)
462     {
463     if (adr < 0x1000)
464     ram[adr & 0x7ff] = byte;
465     else
466     write_byte_io(adr, byte);
467     }
468    
469    
470     /*
471     * Read byte from 6502/1541 address space (used by SAM)
472     */
473    
474     uint8 MOS6502_1541::ExtReadByte(uint16 adr)
475     {
476     return read_byte(adr);
477     }
478    
479    
480     /*
481     * Write byte to 6502/1541 address space (used by SAM)
482     */
483    
484     void MOS6502_1541::ExtWriteByte(uint16 adr, uint8 byte)
485     {
486     write_byte(adr, byte);
487     }
488    
489    
490     /*
491     * Adc instruction
492     */
493    
494     inline void MOS6502_1541::do_adc(uint8 byte)
495     {
496     if (!d_flag) {
497     uint16 tmp;
498    
499     // Binary mode
500     tmp = a + byte + (c_flag ? 1 : 0);
501     c_flag = tmp > 0xff;
502     v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
503     z_flag = n_flag = a = tmp;
504    
505     } else {
506     uint16 al, ah;
507    
508     // Decimal mode
509     al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0); // Calculate lower nybble
510     if (al > 9) al += 6; // BCD fixup for lower nybble
511    
512     ah = (a >> 4) + (byte >> 4); // Calculate upper nybble
513     if (al > 0x0f) ah++;
514    
515     z_flag = a + byte + (c_flag ? 1 : 0); // Set flags
516     n_flag = ah << 4; // Only highest bit used
517     v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
518    
519     if (ah > 9) ah += 6; // BCD fixup for upper nybble
520     c_flag = ah > 0x0f; // Set carry flag
521     a = (ah << 4) | (al & 0x0f); // Compose result
522     }
523     }
524    
525    
526     /*
527     * Sbc instruction
528     */
529    
530     inline void MOS6502_1541::do_sbc(uint8 byte)
531     {
532     uint16 tmp = a - byte - (c_flag ? 0 : 1);
533    
534     if (!d_flag) {
535    
536     // Binary mode
537     c_flag = tmp < 0x100;
538     v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
539     z_flag = n_flag = a = tmp;
540    
541     } else {
542     uint16 al, ah;
543    
544     // Decimal mode
545     al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1); // Calculate lower nybble
546     ah = (a >> 4) - (byte >> 4); // Calculate upper nybble
547     if (al & 0x10) {
548     al -= 6; // BCD fixup for lower nybble
549     ah--;
550     }
551     if (ah & 0x10) ah -= 6; // BCD fixup for upper nybble
552    
553     c_flag = tmp < 0x100; // Set flags
554     v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
555     z_flag = n_flag = tmp;
556    
557     a = (ah << 4) | (al & 0x0f); // Compose result
558     }
559     }
560    
561    
562     /*
563     * Reset CPU
564     */
565    
566     void MOS6502_1541::Reset(void)
567     {
568     // IEC lines and VIA registers
569     IECLines = 0xc0;
570    
571     via1_pra = via1_ddra = via1_prb = via1_ddrb = 0;
572     via1_acr = via1_pcr = 0;
573     via1_ifr = via1_ier = 0;
574     via2_pra = via2_ddra = via2_prb = via2_ddrb = 0;
575     via2_acr = via2_pcr = 0;
576     via2_ifr = via2_ier = 0;
577    
578     // Clear all interrupt lines
579     interrupt.intr_any = 0;
580    
581     // Read reset vector
582     pc = read_word(0xfffc);
583     state = 0;
584    
585     // Wake up 1541
586     Idle = false;
587     }
588    
589    
590     /*
591     * Illegal opcode encountered
592     */
593    
594     void MOS6502_1541::illegal_op(uint8 op, uint16 at)
595     {
596     char illop_msg[80];
597    
598     sprintf(illop_msg, "1541: Illegal opcode %02x at %04x.", op, at);
599     if (ShowRequester(illop_msg, "Reset 1541", "Reset C64"))
600     the_c64->Reset();
601     Reset();
602     }
603    
604    
605     /*
606     * Emulate one 6502 clock cycle
607     */
608    
609     // Read byte from memory
610     #define read_to(adr, to) \
611     to = read_byte(adr);
612    
613     // Read byte from memory, throw away result
614     #define read_idle(adr) \
615     read_byte(adr);
616    
617     void MOS6502_1541::EmulateCycle(void)
618     {
619     uint8 data, tmp;
620    
621     // Any pending interrupts in state 0 (opcode fetch)?
622     if (!state && interrupt.intr_any) {
623     if (interrupt.intr[INT_RESET])
624     Reset();
625     else if ((interrupt.intr[INT_VIA1IRQ] || interrupt.intr[INT_VIA2IRQ] || interrupt.intr[INT_IECIRQ]) && (the_c64->CycleCounter-first_irq_cycle >= 2) && !i_flag)
626     state = 0x0008;
627     }
628    
629     #define IS_CPU_1541
630     #include "CPU_emulcycle.h"
631    
632     // Extension opcode
633     case O_EXT:
634     if (pc < 0xc000) {
635     illegal_op(0xf2, pc-1);
636     break;
637     }
638     switch (read_byte(pc++)) {
639     case 0x00: // Go to sleep in DOS idle loop if error flag is clear and no command received
640     Idle = !(ram[0x26c] | ram[0x7c]);
641     pc = 0xebff;
642     Last;
643     case 0x01: // Write sector
644     the_job->WriteSector();
645     pc = 0xf5dc;
646     Last;
647     case 0x02: // Format track
648     the_job->FormatTrack();
649     pc = 0xfd8b;
650     Last;
651     default:
652     illegal_op(0xf2, pc-1);
653     break;
654     }
655     break;
656    
657     default:
658     illegal_op(op, pc-1);
659     break;
660     }
661     }