ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64.cpp
Revision: 1.2
Committed: 2003-07-01T17:51:17Z (20 years, 9 months ago) by cebix
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
updated copyright date

File Contents

# Content
1 /*
2 * C64.cpp - Put the pieces together
3 *
4 * Frodo (C) 1994-1997,2002-2003 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