ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64.cpp
Revision: 1.1
Committed: 2003-07-01T17:09:43Z (20 years, 9 months ago) by cebix
Branch: MAIN
Log Message:
imported files

File Contents

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