ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_WIN32.h
Revision: 1.5
Committed: 2005-06-27T19:55:48Z (17 years, 5 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.4: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * C64_WIN32.h - Put the pieces together, WIN32 specific stuff
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 <process.h>
22 #include "main.h"
23
24 #define FRAME_INTERVAL (1000/SCREEN_FREQ) // in milliseconds
25 #ifdef FRODO_SC
26 #define SPEEDOMETER_INTERVAL 4000 // in milliseconds
27 #else
28 #define SPEEDOMETER_INTERVAL 1000 // in milliseconds
29 #endif
30 #define JOYSTICK_SENSITIVITY 40 // % of live range
31 #define JOYSTICK_MIN 0x0000 // min value of range
32 #define JOYSTICK_MAX 0xffff // max value of range
33 #define JOYSTICK_RANGE (JOYSTICK_MAX - JOYSTICK_MIN)
34
35 static BOOL high_resolution_timer = FALSE;
36
37 /*
38 * Constructor, system-dependent things
39 */
40
41 void C64::c64_ctor1()
42 {
43 Debug("C64::c64_ctor1\n");
44
45 // Initialize joystick variables.
46 joy_state = 0xff;
47
48 // No need to check for state change.
49 state_change = FALSE;
50
51 // Start the synchronization timer.
52 timer_semaphore = NULL;
53 timer_id = NULL;
54 StartTimer();
55 }
56
57 void C64::c64_ctor2()
58 {
59 Debug("C64::c64_ctor2\n");
60 }
61
62
63 /*
64 * Destructor, system-dependent things
65 */
66
67 void C64::c64_dtor()
68 {
69 Debug("C64::c64_dtor\n");
70
71 StopTimer();
72 }
73
74
75 /*
76 * Start emulation
77 */
78
79 void C64::Run()
80 {
81 // Reset chips
82 TheCPU->Reset();
83 TheSID->Reset();
84 TheCIA1->Reset();
85 TheCIA2->Reset();
86 TheCPU1541->Reset();
87
88 // Patch kernal IEC routines
89 orig_kernal_1d84 = Kernal[0x1d84];
90 orig_kernal_1d85 = Kernal[0x1d85];
91 patch_kernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
92
93 // Start the CPU thread
94 thread_func();
95 }
96
97
98 /*
99 * Stop emulation
100 */
101
102 void C64::Quit()
103 {
104 // Ask the thread to quit itself if it is running
105 quit_thyself = TRUE;
106 state_change = TRUE;
107 }
108
109
110 /*
111 * Pause emulation
112 */
113
114 void C64::Pause()
115 {
116 StopTimer();
117 TheSID->PauseSound();
118 have_a_break = TRUE;
119 state_change = TRUE;
120 }
121
122
123 /*
124 * Resume emulation
125 */
126
127 void C64::Resume()
128 {
129 StartTimer();
130 TheSID->ResumeSound();
131 have_a_break = FALSE;
132 }
133
134
135 /*
136 * Vertical blank: Poll keyboard and joysticks, update window
137 */
138
139 void C64::VBlank(bool draw_frame)
140 {
141 //Debug("C64::VBlank\n");
142
143 // Poll the keyboard.
144 TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
145 // Poll the joysticks.
146 TheCIA1->Joystick1 = poll_joystick(0);
147 TheCIA1->Joystick2 = poll_joystick(1);
148
149 if (ThePrefs.JoystickSwap) {
150 uint8 tmp = TheCIA1->Joystick1;
151 TheCIA1->Joystick1 = TheCIA1->Joystick2;
152 TheCIA1->Joystick2 = tmp;
153 }
154
155 // Joystick keyboard emulation.
156 if (TheDisplay->NumLock())
157 TheCIA1->Joystick1 &= joykey;
158 else
159 TheCIA1->Joystick2 &= joykey;
160
161 // Count TOD clocks.
162 TheCIA1->CountTOD();
163 TheCIA2->CountTOD();
164
165 #if 1
166 // Output a frag.
167 TheSID->VBlank();
168 #endif
169
170 if (have_a_break)
171 return;
172
173 // Update the window if needed.
174 frame++;
175 if (draw_frame) {
176
177 // Synchronize to the timer if limiting the speed.
178 if (ThePrefs.LimitSpeed) {
179 if (skipped_frames == 0) {
180 // There is a tiny race condtion here that
181 // could cause a full extra delay cycle.
182 WaitForSingleObject(timer_semaphore, INFINITE);
183 }
184 else {
185 Debug("*** Skipped a frame! ***\n");
186 skipped_frames = 0;
187 }
188 }
189
190 // Perform the actual screen update exactly at the
191 // beginning of an interval for the smoothest video.
192 TheDisplay->Update();
193
194 // Compute the speed index and show it in the speedometer.
195 DWORD now = timeGetTime();
196 int elapsed_time = now - ref_time;
197 if (now - ref_time >= SPEEDOMETER_INTERVAL) {
198 double speed_index = double(frame * FRAME_INTERVAL * 100 + elapsed_time/2) / elapsed_time;
199 TheDisplay->Speedometer((int)speed_index);
200 ref_time = now;
201 frame = 0;
202 }
203
204 // Make sure our timer is set correctly.
205 CheckTimerChange();
206 }
207 }
208
209
210 void C64::CheckTimerChange()
211 {
212 // Make sure the timer interval matches the preferences.
213 if (!ThePrefs.LimitSpeed && timer_every == 0)
214 return;
215 if (ThePrefs.LimitSpeed && ThePrefs.SkipFrames == timer_every)
216 return;
217 StopTimer();
218 StartTimer();
219 }
220
221 /*
222 * Open/close joystick drivers given old and new state of
223 * joystick preferences
224 */
225
226 BOOL joystick_open[2];
227
228 void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
229 {
230 if (oldjoy1 != newjoy1) {
231 joystick_open[0] = FALSE;
232 if (newjoy1) {
233 JOYINFO joyinfo;
234 if (joyGetPos(0, &joyinfo) == JOYERR_NOERROR)
235 joystick_open[0] = TRUE;
236 }
237 }
238
239 if (oldjoy2 != newjoy2) {
240 joystick_open[1] = FALSE;
241 if (newjoy1) {
242 JOYINFO joyinfo;
243 if (joyGetPos(1, &joyinfo) == JOYERR_NOERROR)
244 joystick_open[1] = TRUE;
245 }
246 }
247
248 // XXX: Should have our own new prefs!
249 state_change = TRUE;
250 }
251
252
253 /*
254 * Poll joystick port, return CIA mask
255 */
256
257 uint8 C64::poll_joystick(int port)
258 {
259 uint8 j = 0xff;
260
261 if (joystick_open[port]) {
262 JOYINFO joyinfo;
263 if (joyGetPos(port, &joyinfo) == JOYERR_NOERROR) {
264 int x = joyinfo.wXpos;
265 int y = joyinfo.wYpos;
266 int buttons = joyinfo.wButtons;
267 int s1 = JOYSTICK_SENSITIVITY;
268 int s2 = 100 - JOYSTICK_SENSITIVITY;
269 if (x < JOYSTICK_MIN + s1*JOYSTICK_RANGE/100)
270 j &= 0xfb; // Left
271 else if (x > JOYSTICK_MIN + s2*JOYSTICK_RANGE/100)
272 j &= 0xf7; // Right
273 if (y < JOYSTICK_MIN + s1*JOYSTICK_RANGE/100)
274 j &= 0xfe; // Up
275 else if (y > JOYSTICK_MIN + s2*JOYSTICK_RANGE/100)
276 j &= 0xfd; // Down
277 if (buttons & 1)
278 j &= 0xef; // Button
279 if (buttons & 2) {
280 Pause();
281 while (joyGetPos(port, &joyinfo) == JOYERR_NOERROR && (joyinfo.wButtons & 2))
282 Sleep(100);
283 Resume();
284 }
285 }
286 }
287
288 return j;
289 }
290
291 void C64::StartTimer()
292 {
293 ref_time = timeGetTime();
294 skipped_frames = 0;
295 frame = 0;
296
297 if (!ThePrefs.LimitSpeed) {
298 timer_every = 0;
299 StopTimer();
300 return;
301 }
302 timer_every = ThePrefs.SkipFrames;
303
304 if (!timer_semaphore) {
305 timer_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
306 if (!timer_semaphore)
307 Debug("CreateSemaphore failed\n");
308 }
309
310 if (!timer_id) {
311
312 // Turn on high-resolution times and delays.
313 int resolution = FRAME_INTERVAL;
314 if (high_resolution_timer) {
315 timeBeginPeriod(1);
316 resolution = 0;
317 }
318
319 timer_id = timeSetEvent(timer_every*FRAME_INTERVAL, resolution, StaticTimeProc, (DWORD) this, TIME_PERIODIC);
320 if (!timer_id)
321 Debug("timeSetEvent failed\n");
322 }
323 }
324
325 void C64::StopTimer()
326 {
327 if (timer_semaphore) {
328 CloseHandle(timer_semaphore);
329 timer_semaphore = NULL;
330 }
331 if (timer_id) {
332 timeKillEvent(timer_id);
333 timer_id = NULL;
334
335 // Turn off high-resolution delays.
336 if (high_resolution_timer)
337 timeEndPeriod(1);
338 }
339
340 }
341
342 void CALLBACK C64::StaticTimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
343 {
344 C64* TheC64 = (C64 *) dwUser;
345 TheC64->TimeProc(uID);
346 }
347
348 void C64::TimeProc(UINT id)
349 {
350 if (id != timer_id) {
351 Debug("TimeProc called for wrong timer id!\n");
352 timeKillEvent(id);
353 return;
354 }
355
356 if (!ReleaseSemaphore(timer_semaphore, 1, NULL))
357 skipped_frames++;
358 }
359
360
361 /*
362 * The emulation's main loop
363 */
364
365 void C64::thread_func()
366 {
367 Debug("C64::thread_func\n");
368
369 thread_running = TRUE;
370
371 while (!quit_thyself) {
372
373 if (have_a_break)
374 TheDisplay->WaitUntilActive();
375
376 #ifdef FRODO_SC
377 if (ThePrefs.Emul1541Proc)
378 EmulateCyclesWith1541();
379 else
380 EmulateCyclesWithout1541();
381 state_change = FALSE;
382 #else
383 // The order of calls is important here
384 int cycles = TheVIC->EmulateLine();
385 TheSID->EmulateLine();
386 #if !PRECISE_CIA_CYCLES
387 TheCIA1->EmulateLine(ThePrefs.CIACycles);
388 TheCIA2->EmulateLine(ThePrefs.CIACycles);
389 #endif
390 if (ThePrefs.Emul1541Proc) {
391 int cycles_1541 = ThePrefs.FloppyCycles;
392 TheCPU1541->CountVIATimers(cycles_1541);
393
394 if (!TheCPU1541->Idle) {
395 // 1541 processor active, alternately execute
396 // 6502 and 6510 instructions until both have
397 // used up their cycles
398 while (cycles >= 0 || cycles_1541 >= 0)
399 if (cycles > cycles_1541)
400 cycles -= TheCPU->EmulateLine(1);
401 else
402 cycles_1541 -= TheCPU1541->EmulateLine(1);
403 } else
404 TheCPU->EmulateLine(cycles);
405 } else
406 // 1541 processor disabled, only emulate 6510
407 TheCPU->EmulateLine(cycles);
408 #endif
409 }
410
411 thread_running = FALSE;
412
413 }
414
415 #ifdef FRODO_SC
416
417 void C64::EmulateCyclesWith1541()
418 {
419 thread_running = TRUE;
420 while (!state_change) {
421 // The order of calls is important here
422 if (TheVIC->EmulateCycle())
423 TheSID->EmulateLine();
424 #ifndef BATCH_CIA_CYCLES
425 TheCIA1->EmulateCycle();
426 TheCIA2->EmulateCycle();
427 #endif
428 TheCPU->EmulateCycle();
429 TheCPU1541->CountVIATimers(1);
430 if (!TheCPU1541->Idle)
431 TheCPU1541->EmulateCycle();
432 CycleCounter++;
433 }
434 }
435
436 void C64::EmulateCyclesWithout1541()
437 {
438 thread_running = TRUE;
439 while (!state_change) {
440 // The order of calls is important here
441 if (TheVIC->EmulateCycle())
442 TheSID->EmulateLine();
443 #ifndef BATCH_CIA_CYCLES
444 TheCIA1->EmulateCycle();
445 TheCIA2->EmulateCycle();
446 #endif
447 TheCPU->EmulateCycle();
448 CycleCounter++;
449 }
450 }
451
452 #endif