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