ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64.cpp
Revision: 1.8
Committed: 2010-04-21T21:58:21Z (14 years ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +1 -3 lines
Log Message:
keep object size the same whether FRODO_SC is defined or not

File Contents

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