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

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * C64.cpp - Put the pieces together
3     *
4 cebix 1.5 * 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     #include "sysdeps.h"
22    
23     #include "C64.h"
24     #include "CPUC64.h"
25     #include "CPU1541.h"
26     #include "VIC.h"
27     #include "SID.h"
28     #include "CIA.h"
29     #include "REU.h"
30     #include "IEC.h"
31     #include "1541job.h"
32     #include "Display.h"
33     #include "Prefs.h"
34    
35     #if defined(__unix) && !defined(__svgalib__)
36     #include "CmdPipe.h"
37     #endif
38    
39    
40     #ifdef FRODO_SC
41     bool IsFrodoSC = true;
42     #else
43     bool IsFrodoSC = false;
44     #endif
45    
46    
47     /*
48     * Constructor: Allocate objects and memory
49     */
50    
51     C64::C64()
52     {
53     uint8 *p;
54    
55     // The thread is not yet running
56     thread_running = false;
57     quit_thyself = false;
58     have_a_break = false;
59    
60     // System-dependent things
61     c64_ctor1();
62    
63     // Open display
64     TheDisplay = new C64Display(this);
65    
66     // Allocate RAM/ROM memory
67 cebix 1.3 RAM = new uint8[C64_RAM_SIZE];
68     Basic = new uint8[BASIC_ROM_SIZE];
69     Kernal = new uint8[KERNAL_ROM_SIZE];
70     Char = new uint8[CHAR_ROM_SIZE];
71     Color = new uint8[COLOR_RAM_SIZE];
72     RAM1541 = new uint8[DRIVE_RAM_SIZE];
73     ROM1541 = new uint8[DRIVE_ROM_SIZE];
74 cebix 1.1
75     // Create the chips
76     TheCPU = new MOS6510(this, RAM, Basic, Kernal, Char, Color);
77    
78     TheJob1541 = new Job1541(RAM1541);
79     TheCPU1541 = new MOS6502_1541(this, TheJob1541, TheDisplay, RAM1541, ROM1541);
80    
81     TheVIC = TheCPU->TheVIC = new MOS6569(this, TheDisplay, TheCPU, RAM, Char, Color);
82     TheSID = TheCPU->TheSID = new MOS6581(this);
83     TheCIA1 = TheCPU->TheCIA1 = new MOS6526_1(TheCPU, TheVIC);
84     TheCIA2 = TheCPU->TheCIA2 = TheCPU1541->TheCIA2 = new MOS6526_2(TheCPU, TheVIC, TheCPU1541);
85     TheIEC = TheCPU->TheIEC = new IEC(TheDisplay);
86     TheREU = TheCPU->TheREU = new REU(TheCPU);
87    
88     // Initialize RAM with powerup pattern
89 cebix 1.3 p = RAM;
90     for (unsigned i=0; i<512; i++) {
91     for (unsigned j=0; j<64; j++)
92 cebix 1.1 *p++ = 0;
93 cebix 1.3 for (unsigned j=0; j<64; j++)
94 cebix 1.1 *p++ = 0xff;
95     }
96    
97     // Initialize color RAM with random values
98 cebix 1.3 p = Color;
99     for (unsigned i=0; i<COLOR_RAM_SIZE; i++)
100 cebix 1.1 *p++ = rand() & 0x0f;
101    
102     // Clear 1541 RAM
103 cebix 1.3 memset(RAM1541, 0, DRIVE_RAM_SIZE);
104 cebix 1.1
105     // Open joystick drivers if required
106 cebix 1.4 open_close_joysticks(0, 0, ThePrefs.Joystick1Port, ThePrefs.Joystick2Port);
107 cebix 1.1 joykey = 0xff;
108    
109     #ifdef FRODO_SC
110     CycleCounter = 0;
111     #endif
112    
113     // System-dependent things
114     c64_ctor2();
115     }
116    
117    
118     /*
119     * Destructor: Delete all objects
120     */
121    
122     C64::~C64()
123     {
124 cebix 1.4 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, 0, 0);
125 cebix 1.1
126     delete TheJob1541;
127     delete TheREU;
128     delete TheIEC;
129     delete TheCIA2;
130     delete TheCIA1;
131     delete TheSID;
132     delete TheVIC;
133     delete TheCPU1541;
134     delete TheCPU;
135     delete TheDisplay;
136    
137     delete[] RAM;
138     delete[] Basic;
139     delete[] Kernal;
140     delete[] Char;
141     delete[] Color;
142     delete[] RAM1541;
143     delete[] ROM1541;
144    
145     c64_dtor();
146     }
147    
148    
149     /*
150     * Reset C64
151     */
152    
153     void C64::Reset(void)
154     {
155     TheCPU->AsyncReset();
156     TheCPU1541->AsyncReset();
157     TheSID->Reset();
158     TheCIA1->Reset();
159     TheCIA2->Reset();
160     TheIEC->Reset();
161     }
162    
163    
164     /*
165     * NMI C64
166     */
167    
168     void C64::NMI(void)
169     {
170     TheCPU->AsyncNMI();
171     }
172    
173    
174     /*
175     * The preferences have changed. prefs is a pointer to the new
176     * preferences, ThePrefs still holds the previous ones.
177     * The emulation must be in the paused state!
178     */
179    
180     void C64::NewPrefs(Prefs *prefs)
181     {
182 cebix 1.4 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, prefs->Joystick1Port, prefs->Joystick2Port);
183 cebix 1.1 PatchKernal(prefs->FastReset, prefs->Emul1541Proc);
184    
185     TheDisplay->NewPrefs(prefs);
186    
187     #ifdef __riscos__
188     // Changed order of calls. If 1541 mode hasn't changed the order is insignificant.
189     if (prefs->Emul1541Proc) {
190     // New prefs have 1541 enabled ==> if old prefs had disabled free drives FIRST
191     TheIEC->NewPrefs(prefs);
192     TheJob1541->NewPrefs(prefs);
193     } else {
194     // New prefs has 1541 disabled ==> if old prefs had enabled free job FIRST
195     TheJob1541->NewPrefs(prefs);
196     TheIEC->NewPrefs(prefs);
197     }
198     #else
199     TheIEC->NewPrefs(prefs);
200     TheJob1541->NewPrefs(prefs);
201     #endif
202    
203     TheREU->NewPrefs(prefs);
204     TheSID->NewPrefs(prefs);
205    
206     // Reset 1541 processor if turned on
207     if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc)
208     TheCPU1541->AsyncReset();
209     }
210    
211    
212     /*
213     * Patch kernal IEC routines
214     */
215    
216     void C64::PatchKernal(bool fast_reset, bool emul_1541_proc)
217     {
218     if (fast_reset) {
219     Kernal[0x1d84] = 0xa0;
220     Kernal[0x1d85] = 0x00;
221     } else {
222     Kernal[0x1d84] = orig_kernal_1d84;
223     Kernal[0x1d85] = orig_kernal_1d85;
224     }
225    
226     if (emul_1541_proc) {
227     Kernal[0x0d40] = 0x78;
228     Kernal[0x0d41] = 0x20;
229     Kernal[0x0d23] = 0x78;
230     Kernal[0x0d24] = 0x20;
231     Kernal[0x0d36] = 0x78;
232     Kernal[0x0d37] = 0x20;
233     Kernal[0x0e13] = 0x78;
234     Kernal[0x0e14] = 0xa9;
235     Kernal[0x0def] = 0x78;
236     Kernal[0x0df0] = 0x20;
237     Kernal[0x0dbe] = 0xad;
238     Kernal[0x0dbf] = 0x00;
239     Kernal[0x0dcc] = 0x78;
240     Kernal[0x0dcd] = 0x20;
241     Kernal[0x0e03] = 0x20;
242     Kernal[0x0e04] = 0xbe;
243     } else {
244     Kernal[0x0d40] = 0xf2; // IECOut
245     Kernal[0x0d41] = 0x00;
246     Kernal[0x0d23] = 0xf2; // IECOutATN
247     Kernal[0x0d24] = 0x01;
248     Kernal[0x0d36] = 0xf2; // IECOutSec
249     Kernal[0x0d37] = 0x02;
250     Kernal[0x0e13] = 0xf2; // IECIn
251     Kernal[0x0e14] = 0x03;
252     Kernal[0x0def] = 0xf2; // IECSetATN
253     Kernal[0x0df0] = 0x04;
254     Kernal[0x0dbe] = 0xf2; // IECRelATN
255     Kernal[0x0dbf] = 0x05;
256     Kernal[0x0dcc] = 0xf2; // IECTurnaround
257     Kernal[0x0dcd] = 0x06;
258     Kernal[0x0e03] = 0xf2; // IECRelease
259     Kernal[0x0e04] = 0x07;
260     }
261    
262     // 1541
263     ROM1541[0x2ae4] = 0xea; // Don't check ROM checksum
264     ROM1541[0x2ae5] = 0xea;
265     ROM1541[0x2ae8] = 0xea;
266     ROM1541[0x2ae9] = 0xea;
267     ROM1541[0x2c9b] = 0xf2; // DOS idle loop
268     ROM1541[0x2c9c] = 0x00;
269     ROM1541[0x3594] = 0x20; // Write sector
270     ROM1541[0x3595] = 0xf2;
271     ROM1541[0x3596] = 0xf5;
272     ROM1541[0x3597] = 0xf2;
273     ROM1541[0x3598] = 0x01;
274     ROM1541[0x3b0c] = 0xf2; // Format track
275     ROM1541[0x3b0d] = 0x02;
276     }
277    
278    
279     /*
280     * Save RAM contents
281     */
282    
283     void C64::SaveRAM(char *filename)
284     {
285     FILE *f;
286    
287     if ((f = fopen(filename, "wb")) == NULL)
288     ShowRequester("RAM save failed.", "OK", NULL);
289     else {
290     fwrite((void*)RAM, 1, 0x10000, f);
291     fwrite((void*)Color, 1, 0x400, f);
292     if (ThePrefs.Emul1541Proc)
293     fwrite((void*)RAM1541, 1, 0x800, f);
294     fclose(f);
295     }
296     }
297    
298    
299     /*
300     * Save CPU state to snapshot
301     *
302     * 0: Error
303     * 1: OK
304     * -1: Instruction not completed
305     */
306    
307     int C64::SaveCPUState(FILE *f)
308     {
309     MOS6510State state;
310     TheCPU->GetState(&state);
311    
312     if (!state.instruction_complete)
313     return -1;
314    
315     int i = fwrite(RAM, 0x10000, 1, f);
316     i += fwrite(Color, 0x400, 1, f);
317     i += fwrite((void*)&state, sizeof(state), 1, f);
318    
319     return i == 3;
320     }
321    
322    
323     /*
324     * Load CPU state from snapshot
325     */
326    
327     bool C64::LoadCPUState(FILE *f)
328     {
329     MOS6510State state;
330    
331     int i = fread(RAM, 0x10000, 1, f);
332     i += fread(Color, 0x400, 1, f);
333     i += fread((void*)&state, sizeof(state), 1, f);
334    
335     if (i == 3) {
336     TheCPU->SetState(&state);
337     return true;
338     } else
339     return false;
340     }
341    
342    
343     /*
344     * Save 1541 state to snapshot
345     *
346     * 0: Error
347     * 1: OK
348     * -1: Instruction not completed
349     */
350    
351     int C64::Save1541State(FILE *f)
352     {
353     MOS6502State state;
354     TheCPU1541->GetState(&state);
355    
356     if (!state.idle && !state.instruction_complete)
357     return -1;
358    
359     int i = fwrite(RAM1541, 0x800, 1, f);
360     i += fwrite((void*)&state, sizeof(state), 1, f);
361    
362     return i == 2;
363     }
364    
365    
366     /*
367     * Load 1541 state from snapshot
368     */
369    
370     bool C64::Load1541State(FILE *f)
371     {
372     MOS6502State state;
373    
374     int i = fread(RAM1541, 0x800, 1, f);
375     i += fread((void*)&state, sizeof(state), 1, f);
376    
377     if (i == 2) {
378     TheCPU1541->SetState(&state);
379     return true;
380     } else
381     return false;
382     }
383    
384    
385     /*
386     * Save VIC state to snapshot
387     */
388    
389     bool C64::SaveVICState(FILE *f)
390     {
391     MOS6569State state;
392     TheVIC->GetState(&state);
393     return fwrite((void*)&state, sizeof(state), 1, f) == 1;
394     }
395    
396    
397     /*
398     * Load VIC state from snapshot
399     */
400    
401     bool C64::LoadVICState(FILE *f)
402     {
403     MOS6569State state;
404    
405     if (fread((void*)&state, sizeof(state), 1, f) == 1) {
406     TheVIC->SetState(&state);
407     return true;
408     } else
409     return false;
410     }
411    
412    
413     /*
414     * Save SID state to snapshot
415     */
416    
417     bool C64::SaveSIDState(FILE *f)
418     {
419     MOS6581State state;
420     TheSID->GetState(&state);
421     return fwrite((void*)&state, sizeof(state), 1, f) == 1;
422     }
423    
424    
425     /*
426     * Load SID state from snapshot
427     */
428    
429     bool C64::LoadSIDState(FILE *f)
430     {
431     MOS6581State state;
432    
433     if (fread((void*)&state, sizeof(state), 1, f) == 1) {
434     TheSID->SetState(&state);
435     return true;
436     } else
437     return false;
438     }
439    
440    
441     /*
442     * Save CIA states to snapshot
443     */
444    
445     bool C64::SaveCIAState(FILE *f)
446     {
447     MOS6526State state;
448     TheCIA1->GetState(&state);
449    
450     if (fwrite((void*)&state, sizeof(state), 1, f) == 1) {
451     TheCIA2->GetState(&state);
452     return fwrite((void*)&state, sizeof(state), 1, f) == 1;
453     } else
454     return false;
455     }
456    
457    
458     /*
459     * Load CIA states from snapshot
460     */
461    
462     bool C64::LoadCIAState(FILE *f)
463     {
464     MOS6526State state;
465    
466     if (fread((void*)&state, sizeof(state), 1, f) == 1) {
467     TheCIA1->SetState(&state);
468     if (fread((void*)&state, sizeof(state), 1, f) == 1) {
469     TheCIA2->SetState(&state);
470     return true;
471     } else
472     return false;
473     } else
474     return false;
475     }
476    
477    
478     /*
479     * Save 1541 GCR state to snapshot
480     */
481    
482     bool C64::Save1541JobState(FILE *f)
483     {
484     Job1541State state;
485     TheJob1541->GetState(&state);
486     return fwrite((void*)&state, sizeof(state), 1, f) == 1;
487     }
488    
489    
490     /*
491     * Load 1541 GCR state from snapshot
492     */
493    
494     bool C64::Load1541JobState(FILE *f)
495     {
496     Job1541State state;
497    
498     if (fread((void*)&state, sizeof(state), 1, f) == 1) {
499     TheJob1541->SetState(&state);
500     return true;
501     } else
502     return false;
503     }
504    
505    
506     #define SNAPSHOT_HEADER "FrodoSnapshot"
507     #define SNAPSHOT_1541 1
508    
509     #define ADVANCE_CYCLES \
510     TheVIC->EmulateCycle(); \
511     TheCIA1->EmulateCycle(); \
512     TheCIA2->EmulateCycle(); \
513     TheCPU->EmulateCycle(); \
514     if (ThePrefs.Emul1541Proc) { \
515     TheCPU1541->CountVIATimers(1); \
516     if (!TheCPU1541->Idle) \
517     TheCPU1541->EmulateCycle(); \
518     }
519    
520    
521     /*
522     * Save snapshot (emulation must be paused and in VBlank)
523     *
524     * To be able to use SC snapshots with SL, SC snapshots are made thus that no
525     * partially dealt with instructions are saved. Instead all devices are advanced
526     * cycle by cycle until the current instruction has been finished. The number of
527     * cycles this takes is saved in the snapshot and will be reconstructed if the
528     * snapshot is loaded into FrodoSC again.
529     */
530    
531     void C64::SaveSnapshot(char *filename)
532     {
533     FILE *f;
534     uint8 flags;
535     uint8 delay;
536     int stat;
537    
538     if ((f = fopen(filename, "wb")) == NULL) {
539     ShowRequester("Unable to open snapshot file", "OK", NULL);
540     return;
541     }
542    
543     fprintf(f, "%s%c", SNAPSHOT_HEADER, 10);
544     fputc(0, f); // Version number 0
545     flags = 0;
546     if (ThePrefs.Emul1541Proc)
547     flags |= SNAPSHOT_1541;
548     fputc(flags, f);
549     SaveVICState(f);
550     SaveSIDState(f);
551     SaveCIAState(f);
552    
553     #ifdef FRODO_SC
554     delay = 0;
555     do {
556     if ((stat = SaveCPUState(f)) == -1) { // -1 -> Instruction not finished yet
557     ADVANCE_CYCLES; // Advance everything by one cycle
558     delay++;
559     }
560     } while (stat == -1);
561     fputc(delay, f); // Number of cycles the saved CPUC64 lags behind the previous chips
562     #else
563     SaveCPUState(f);
564     fputc(0, f); // No delay
565     #endif
566    
567     if (ThePrefs.Emul1541Proc) {
568     fwrite(ThePrefs.DrivePath[0], 256, 1, f);
569     #ifdef FRODO_SC
570     delay = 0;
571     do {
572     if ((stat = Save1541State(f)) == -1) {
573     ADVANCE_CYCLES;
574     delay++;
575     }
576     } while (stat == -1);
577     fputc(delay, f);
578     #else
579     Save1541State(f);
580     fputc(0, f); // No delay
581     #endif
582     Save1541JobState(f);
583     }
584     fclose(f);
585    
586     #ifdef __riscos__
587     TheWIMP->SnapshotSaved(true);
588     #endif
589     }
590    
591    
592     /*
593     * Load snapshot (emulation must be paused and in VBlank)
594     */
595    
596     bool C64::LoadSnapshot(char *filename)
597     {
598     FILE *f;
599    
600     if ((f = fopen(filename, "rb")) != NULL) {
601     char Header[] = SNAPSHOT_HEADER;
602     char *b = Header, c = 0;
603     uint8 delay, i;
604    
605     // For some reason memcmp()/strcmp() and so forth utterly fail here.
606     while (*b > 32) {
607     if ((c = fgetc(f)) != *b++) {
608     b = NULL;
609     break;
610     }
611     }
612     if (b != NULL) {
613     uint8 flags;
614     bool error = false;
615     #ifndef FRODO_SC
616     long vicptr; // File offset of VIC data
617     #endif
618    
619     while (c != 10)
620     c = fgetc(f); // Shouldn't be necessary
621     if (fgetc(f) != 0) {
622     ShowRequester("Unknown snapshot format", "OK", NULL);
623     fclose(f);
624     return false;
625     }
626     flags = fgetc(f);
627     #ifndef FRODO_SC
628     vicptr = ftell(f);
629     #endif
630    
631     error |= !LoadVICState(f);
632     error |= !LoadSIDState(f);
633     error |= !LoadCIAState(f);
634     error |= !LoadCPUState(f);
635    
636     delay = fgetc(f); // Number of cycles the 6510 is ahead of the previous chips
637     #ifdef FRODO_SC
638     // Make the other chips "catch up" with the 6510
639     for (i=0; i<delay; i++) {
640     TheVIC->EmulateCycle();
641     TheCIA1->EmulateCycle();
642     TheCIA2->EmulateCycle();
643     }
644     #endif
645     if ((flags & SNAPSHOT_1541) != 0) {
646     Prefs *prefs = new Prefs(ThePrefs);
647    
648     // First switch on emulation
649     error |= (fread(prefs->DrivePath[0], 256, 1, f) != 1);
650     prefs->Emul1541Proc = true;
651     NewPrefs(prefs);
652     ThePrefs = *prefs;
653     delete prefs;
654    
655     // Then read the context
656     error |= !Load1541State(f);
657    
658     delay = fgetc(f); // Number of cycles the 6502 is ahead of the previous chips
659     #ifdef FRODO_SC
660     // Make the other chips "catch up" with the 6502
661     for (i=0; i<delay; i++) {
662     TheVIC->EmulateCycle();
663     TheCIA1->EmulateCycle();
664     TheCIA2->EmulateCycle();
665     TheCPU->EmulateCycle();
666     }
667     #endif
668     Load1541JobState(f);
669     #ifdef __riscos__
670     TheWIMP->ThePrefsToWindow();
671     #endif
672     } else if (ThePrefs.Emul1541Proc) { // No emulation in snapshot, but currently active?
673     Prefs *prefs = new Prefs(ThePrefs);
674     prefs->Emul1541Proc = false;
675     NewPrefs(prefs);
676     ThePrefs = *prefs;
677     delete prefs;
678     #ifdef __riscos__
679     TheWIMP->ThePrefsToWindow();
680     #endif
681     }
682    
683     #ifndef FRODO_SC
684     fseek(f, vicptr, SEEK_SET);
685     LoadVICState(f); // Load VIC data twice in SL (is REALLY necessary sometimes!)
686     #endif
687     fclose(f);
688    
689     if (error) {
690     ShowRequester("Error reading snapshot file", "OK", NULL);
691     Reset();
692     return false;
693     } else
694     return true;
695     } else {
696     fclose(f);
697     ShowRequester("Not a Frodo snapshot file", "OK", NULL);
698     return false;
699     }
700     } else {
701     ShowRequester("Can't open snapshot file", "OK", NULL);
702     return false;
703     }
704     }
705    
706    
707     #ifdef __BEOS__
708     #include "C64_Be.h"
709     #endif
710    
711     #ifdef AMIGA
712     #include "C64_Amiga.h"
713     #endif
714    
715     #ifdef __unix
716     #include "C64_x.h"
717     #endif
718    
719     #ifdef __mac__
720     #include "C64_mac.h"
721     #endif
722    
723     #ifdef WIN32
724     #include "C64_WIN32.h"
725     #endif
726    
727     #ifdef __riscos__
728     #include "C64_Acorn.h"
729     #endif