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 (19 years, 4 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

# User Rev Content
1 cebix 1.1 /*
2     * C64_WIN32.h - Put the pieces together, WIN32 specific stuff
3     *
4 cebix 1.5 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 cebix 1.1 *
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 cebix 1.3 void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
229 cebix 1.1 {
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