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 (13 years, 11 months 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

# Content
1 /*
2 * C64.cpp - Put the pieces together
3 *
4 * Frodo Copyright (C) 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 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 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, 0, 0);
123
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 open_close_joysticks(ThePrefs.Joystick1Port, ThePrefs.Joystick2Port, prefs->Joystick1Port, prefs->Joystick2Port);
181 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 # if defined(QTOPIA) or defined(MAEMO)
715 # include "C64_Embedded.h"
716 # else
717 # include "C64_x.h"
718 # endif
719 #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