1 /*
2  *  C64_Amiga.i - Put the pieces together, Amiga specific stuff
3  *
4  *  Frodo (C) 1994-1997,2002 Christian Bauer
5  */
6 
7 #include <proto/exec.h>
8 #include <proto/timer.h>
9 
10 
11 // Library bases
12 struct Device *TimerBase;
13 
14 
15 /*
16  *  Constructor, system-dependent things
17  */
18 
c64_ctor1(void)19 void C64::c64_ctor1(void)
20 {
21 	// Open game_io
22 	game_port = CreateMsgPort();
23 	game_io = (struct IOStdReq *)CreateIORequest(game_port, sizeof(IOStdReq));
24 	game_io->io_Message.mn_Node.ln_Type = NT_UNKNOWN;
25 	game_open = port_allocated = false;
26 	if (!OpenDevice("gameport.device", 1, (struct IORequest *)game_io, 0))
27 		game_open = true;
28 }
29 
c64_ctor2(void)30 void C64::c64_ctor2(void)
31 {
32 	// Initialize joystick variables
33 	joy_state = 0xff;
34 
35 	// Open timer_io
36 	timer_port = CreateMsgPort();
37 	timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
38 	OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0);
39 
40 	// Get timer base
41 	TimerBase = timer_io->tr_node.io_Device;
42 
43 	// Preset speedometer start time
44 	GetSysTime(&start_time);
45 }
46 
47 
48 /*
49  *  Destructor, system-dependent things
50  */
51 
c64_dtor(void)52 void C64::c64_dtor(void)
53 {
54 	// Stop and delete timer_io
55 	if (timer_io != NULL) {
56 		if (!CheckIO((struct IORequest *)timer_io))
57 			WaitIO((struct IORequest *)timer_io);
58 		CloseDevice((struct IORequest *)timer_io);
59 		DeleteIORequest((struct IORequest *)timer_io);
60 	}
61 
62 	if (timer_port != NULL)
63 		DeleteMsgPort(timer_port);
64 
65 	if (game_open) {
66 		if (!CheckIO((struct IORequest *)game_io)) {
67 			AbortIO((struct IORequest *)game_io);
68 			WaitIO((struct IORequest *)game_io);
69 		}
70 		CloseDevice((struct IORequest *)game_io);
71 	}
72 
73 	if (game_io != NULL)
74 		DeleteIORequest((struct IORequest *)game_io);
75 
76 	if (game_port != NULL)
77 		DeleteMsgPort(game_port);
78 }
79 
80 
81 /*
82  *  Start emulation
83  */
84 
Run(void)85 void C64::Run(void)
86 {
87 	// Reset chips
88 	TheCPU->Reset();
89 	TheSID->Reset();
90 	TheCIA1->Reset();
91 	TheCIA2->Reset();
92 	TheCPU1541->Reset();
93 
94 	// Patch kernal IEC routines
95 	orig_kernal_1d84 = Kernal[0x1d84];
96 	orig_kernal_1d85 = Kernal[0x1d85];
97 	PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
98 
99 	// Start timer_io
100 	timer_io->tr_node.io_Command = TR_ADDREQUEST;
101 	timer_io->tr_time.tv_secs = 0;
102 	timer_io->tr_time.tv_micro = ThePrefs.SkipFrames * 20000;  // 20ms per frame
103 	SendIO((struct IORequest *)timer_io);
104 
105 	// Start the CPU thread
106 	thread_running = true;
107 	quit_thyself = false;
108 	have_a_break = false;
109 	thread_func();
110 }
111 
112 
113 /*
114  *  Stop emulation
115  */
116 
Quit(void)117 void C64::Quit(void)
118 {
119 	// Ask the thread to quit itself if it is running
120 	if (thread_running) {
121 		quit_thyself = true;
122 		thread_running = false;
123 	}
124 }
125 
126 
127 /*
128  *  Pause emulation
129  */
130 
Pause(void)131 void C64::Pause(void)
132 {
133 	TheSID->PauseSound();
134 }
135 
136 
137 /*
138  *  Resume emulation
139  */
140 
Resume(void)141 void C64::Resume(void)
142 {
143 	TheSID->ResumeSound();
144 }
145 
146 
147 /*
148  *  Vertical blank: Poll keyboard and joysticks, update window
149  */
150 
VBlank(bool draw_frame)151 void C64::VBlank(bool draw_frame)
152 {
153 	struct timeval end_time;
154 	long speed_index;
155 
156 	// Poll keyboard
157 	TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
158 
159 	// Poll joysticks
160 	TheCIA1->Joystick1 = poll_joystick(0);
161 	TheCIA1->Joystick2 = poll_joystick(1);
162 
163 	if (ThePrefs.JoystickSwap) {
164 		uint8 tmp = TheCIA1->Joystick1;
165 		TheCIA1->Joystick1 = TheCIA1->Joystick2;
166 		TheCIA1->Joystick2 = tmp;
167 	}
168 
169 	// Joystick keyboard emulation
170 	if (TheDisplay->NumLock())
171 		TheCIA1->Joystick1 &= joykey;
172 	else
173 		TheCIA1->Joystick2 &= joykey;
174 
175 	// Count TOD clocks
176 	TheCIA1->CountTOD();
177 	TheCIA2->CountTOD();
178 
179 	// Update window if needed
180 	if (draw_frame) {
181     	TheDisplay->Update();
182 
183 		// Calculate time between VBlanks, display speedometer
184 		GetSysTime(&end_time);
185 		SubTime(&end_time, &start_time);
186 		speed_index = 20000 * 100 * ThePrefs.SkipFrames / (end_time.tv_micro + 1);
187 
188 		// Abort timer_io if speed limiter is off
189 		if (!ThePrefs.LimitSpeed) {
190 			if (!CheckIO((struct IORequest *)timer_io))
191 				AbortIO((struct IORequest *)timer_io);
192 		} else if (speed_index > 100)
193 			speed_index = 100;
194 
195 		// Wait for timer_io (limit speed)
196 		WaitIO((struct IORequest *)timer_io);
197 
198 		// Restart timer_io
199 		timer_io->tr_node.io_Command = TR_ADDREQUEST;
200 		timer_io->tr_time.tv_secs = 0;
201 		timer_io->tr_time.tv_micro = ThePrefs.SkipFrames * 20000;  // 20ms per frame
202 		SendIO((struct IORequest *)timer_io);
203 
204 		GetSysTime(&start_time);
205 
206 		TheDisplay->Speedometer(speed_index);
207 	}
208 }
209 
210 
211 /*
212  *  Open/close joystick drivers given old and new state of
213  *  joystick preferences
214  */
215 
open_close_joysticks(bool oldjoy1,bool oldjoy2,bool newjoy1,bool newjoy2)216 void C64::open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2)
217 {
218 	if (game_open && (oldjoy2 != newjoy2))
219 
220 		if (newjoy2) {	// Open joystick
221 			joy_state = 0xff;
222 			port_allocated = false;
223 
224 			// Allocate game port
225 			BYTE ctype;
226 			Forbid();
227 			game_io->io_Command = GPD_ASKCTYPE;
228 			game_io->io_Data = &ctype;
229 			game_io->io_Length = 1;
230 			DoIO((struct IORequest *)game_io);
231 
232 			if (ctype != GPCT_NOCONTROLLER)
233 				Permit();
234 			else {
235 				ctype = GPCT_ABSJOYSTICK;
236 				game_io->io_Command = GPD_SETCTYPE;
237 				game_io->io_Data = &ctype;
238 				game_io->io_Length = 1;
239 				DoIO((struct IORequest *)game_io);
240 				Permit();
241 
242 				port_allocated = true;
243 
244 				// Set trigger conditions
245 				game_trigger.gpt_Keys = GPTF_UPKEYS | GPTF_DOWNKEYS;
246 				game_trigger.gpt_Timeout = 65535;
247 				game_trigger.gpt_XDelta = 1;
248 				game_trigger.gpt_YDelta = 1;
249 				game_io->io_Command = GPD_SETTRIGGER;
250 				game_io->io_Data = &game_trigger;
251 				game_io->io_Length = sizeof(struct GamePortTrigger);
252 				DoIO((struct IORequest *)game_io);
253 
254 				// Flush device buffer
255 				game_io->io_Command = CMD_CLEAR;
256 				DoIO((struct IORequest *)game_io);
257 
258 				// Start reading joystick events
259 				game_io->io_Command = GPD_READEVENT;
260 				game_io->io_Data = &game_event;
261 				game_io->io_Length = sizeof(struct InputEvent);
262 				SendIO((struct IORequest *)game_io);
263 			}
264 
265 		} else {	// Close joystick
266 
267 			// Abort game_io
268 			if (!CheckIO((struct IORequest *)game_io)) {
269 				AbortIO((struct IORequest *)game_io);
270 				WaitIO((struct IORequest *)game_io);
271 			}
272 
273 			// Free game port
274 			if (port_allocated) {
275 				BYTE ctype = GPCT_NOCONTROLLER;
276 				game_io->io_Command = GPD_SETCTYPE;
277 				game_io->io_Data = &ctype;
278 				game_io->io_Length = 1;
279 				DoIO((struct IORequest *)game_io);
280 
281 				port_allocated = false;
282 			}
283 		}
284 }
285 
286 
287 /*
288  *  Poll joystick port, return CIA mask
289  */
290 
poll_joystick(int port)291 uint8 C64::poll_joystick(int port)
292 {
293 	if (port == 0)
294 		return 0xff;
295 
296 	if (game_open && port_allocated) {
297 
298 		// Joystick event arrived?
299 		while (GetMsg(game_port) != NULL) {
300 
301 			// Yes, analyze event
302 			switch (game_event.ie_Code) {
303 				case IECODE_LBUTTON:					// Button pressed
304 					joy_state &= 0xef;
305 					break;
306 
307 				case IECODE_LBUTTON | IECODE_UP_PREFIX:	// Button released
308 					joy_state |= 0x10;
309 					break;
310 
311 				case IECODE_NOBUTTON:					// Joystick moved
312 					if (game_event.ie_X == 1)
313 						joy_state &= 0xf7;				// Right
314 					if (game_event.ie_X == -1)
315 						joy_state &= 0xfb;				// Left
316 					if (game_event.ie_X == 0)
317 						joy_state |= 0x0c;
318 					if (game_event.ie_Y == 1)
319 						joy_state &= 0xfd;				// Down
320 					if (game_event.ie_Y == -1)
321 						joy_state &= 0xfe;				// Up
322 					if (game_event.ie_Y == 0)
323 						joy_state |= 0x03;
324 					break;
325 			}
326 
327 			// Start reading the next event
328 			game_io->io_Command = GPD_READEVENT;
329 			game_io->io_Data = &game_event;
330 			game_io->io_Length = sizeof(struct InputEvent);
331 			SendIO((struct IORequest *)game_io);
332 		}
333 		return joy_state;
334 
335 	} else
336 		return 0xff;
337 }
338 
339 
340 /*
341  * The emulation's main loop
342  */
343 
thread_func(void)344 void C64::thread_func(void)
345 {
346 	while (!quit_thyself) {
347 
348 #ifdef FRODO_SC
349 		// The order of calls is important here
350 		if (TheVIC->EmulateCycle())
351 			TheSID->EmulateLine();
352 		TheCIA1->CheckIRQs();
353 		TheCIA2->CheckIRQs();
354 		TheCIA1->EmulateCycle();
355 		TheCIA2->EmulateCycle();
356 		TheCPU->EmulateCycle();
357 
358 		if (ThePrefs.Emul1541Proc) {
359 			TheCPU1541->CountVIATimers(1);
360 			if (!TheCPU1541->Idle)
361 				TheCPU1541->EmulateCycle();
362 		}
363 		CycleCounter++;
364 #else
365 		// The order of calls is important here
366 		int cycles = TheVIC->EmulateLine();
367 		TheSID->EmulateLine();
368 #if !PRECISE_CIA_CYCLES
369 		TheCIA1->EmulateLine(ThePrefs.CIACycles);
370 		TheCIA2->EmulateLine(ThePrefs.CIACycles);
371 #endif
372 
373 		if (ThePrefs.Emul1541Proc) {
374 			int cycles_1541 = ThePrefs.FloppyCycles;
375 			TheCPU1541->CountVIATimers(cycles_1541);
376 
377 			if (!TheCPU1541->Idle) {
378 				// 1541 processor active, alternately execute
379 				//  6502 and 6510 instructions until both have
380 				//  used up their cycles
381 				while (cycles >= 0 || cycles_1541 >= 0)
382 					if (cycles > cycles_1541)
383 						cycles -= TheCPU->EmulateLine(1);
384 					else
385 						cycles_1541 -= TheCPU1541->EmulateLine(1);
386 			} else
387 				TheCPU->EmulateLine(cycles);
388 		} else
389 			// 1541 processor disabled, only emulate 6510
390 			TheCPU->EmulateLine(cycles);
391 #endif
392 	}
393 }
394