ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64.cpp
Revision: 1.6
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.5: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * C64.cpp - Put the pieces together
3 *
4 * Frodo (C) 1994-1997,2002-2005 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 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 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
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 p = RAM;
90 for (unsigned i=0; i<512; i++) {
91 for (unsigned j=0; j<64; j++)
92 *p++ = 0;
93 for (unsigned j=0; j<64; j++)
94 *p++ = 0xff;
95 }
96
97 // Initialize color RAM with random values
98 p = Color;
99 for (unsigned i=0; i<COLOR_RAM_SIZE; i++)
100 *p++ = rand() & 0x0f;
101
102 // Clear 1541 RAM
103 memset(RAM1541, 0, DRIVE_RAM_SIZE);
104
105 // Open joystick drivers if required
106 open_close_joysticks(0, 0, ThePrefs.Joystick1Port, ThePrefs.Joystick2Port);
107 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 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, 0, 0);
125
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 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, prefs->Joystick1Port, prefs->Joystick2Port);
183 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