Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

C64_WIN32.i

Go to the documentation of this file.
00001 /*
00002  *  C64_WIN32.i - Put the pieces together, WIN32 specific stuff
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *  WIN32 code by J. Richard Sladkey <jrs@world.std.com>
00006  */
00007 
00008 #include <process.h>
00009 #include "main.h"
00010 
00011 #define FRAME_INTERVAL          (1000/SCREEN_FREQ)      // in milliseconds
00012 #ifdef FRODO_SC
00013 #define SPEEDOMETER_INTERVAL    4000                    // in milliseconds
00014 #else
00015 #define SPEEDOMETER_INTERVAL    1000                    // in milliseconds
00016 #endif
00017 #define JOYSTICK_SENSITIVITY    40                      // % of live range
00018 #define JOYSTICK_MIN            0x0000                  // min value of range
00019 #define JOYSTICK_MAX            0xffff                  // max value of range
00020 #define JOYSTICK_RANGE          (JOYSTICK_MAX - JOYSTICK_MIN)
00021 
00022 static BOOL high_resolution_timer = FALSE;
00023 
00024 /*
00025  *  Constructor, system-dependent things
00026  */
00027 
00028 void C64::c64_ctor1()
00029 {
00030         Debug("C64::c64_ctor1\n");
00031 
00032         // Initialize joystick variables.
00033         joy_state = 0xff;
00034 
00035         // No need to check for state change.
00036         state_change = FALSE;
00037 
00038         // Start the synchronization timer.
00039         timer_semaphore = NULL;
00040         timer_id = NULL;
00041         StartTimer();
00042 }
00043 
00044 void C64::c64_ctor2()
00045 {
00046         Debug("C64::c64_ctor2\n");
00047 }
00048 
00049 
00050 /*
00051  *  Destructor, system-dependent things
00052  */
00053 
00054 void C64::c64_dtor()
00055 {
00056         Debug("C64::c64_dtor\n");
00057 
00058         StopTimer();
00059 }
00060 
00061 
00062 /*
00063  *  Start emulation
00064  */
00065 
00066 void C64::Run()
00067 {
00068         // Reset chips
00069         TheCPU->Reset();
00070         TheSID->Reset();
00071         TheCIA1->Reset();
00072         TheCIA2->Reset();
00073         TheCPU1541->Reset();
00074 
00075         // Patch kernal IEC routines
00076         orig_kernal_1d84 = Kernal[0x1d84];
00077         orig_kernal_1d85 = Kernal[0x1d85];
00078         patch_kernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
00079 
00080         // Start the CPU thread
00081         thread_func();
00082 }
00083 
00084 
00085 /*
00086  *  Stop emulation
00087  */
00088 
00089 void C64::Quit()
00090 {
00091         // Ask the thread to quit itself if it is running
00092         quit_thyself = TRUE;
00093         state_change = TRUE;
00094 }
00095 
00096 
00097 /*
00098  *  Pause emulation
00099  */
00100 
00101 void C64::Pause()
00102 {
00103         StopTimer();
00104         TheSID->PauseSound();
00105         have_a_break = TRUE;
00106         state_change = TRUE;
00107 }
00108 
00109 
00110 /*
00111  *  Resume emulation
00112  */
00113 
00114 void C64::Resume()
00115 {
00116         StartTimer();
00117         TheSID->ResumeSound();
00118         have_a_break = FALSE;
00119 }
00120 
00121 
00122 /*
00123  *  Vertical blank: Poll keyboard and joysticks, update window
00124  */
00125 
00126 void C64::VBlank(bool draw_frame)
00127 {
00128         //Debug("C64::VBlank\n");
00129 
00130         // Poll the keyboard.
00131         TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
00132         // Poll the joysticks.
00133         TheCIA1->Joystick1 = poll_joystick(0);
00134         TheCIA1->Joystick2 = poll_joystick(1);
00135 
00136         if (ThePrefs.JoystickSwap) {
00137                 uint8 tmp = TheCIA1->Joystick1;
00138                 TheCIA1->Joystick1 = TheCIA1->Joystick2;
00139                 TheCIA1->Joystick2 = tmp;
00140         }
00141 
00142         // Joystick keyboard emulation.
00143         if (TheDisplay->NumLock())
00144                 TheCIA1->Joystick1 &= joykey;
00145         else
00146                 TheCIA1->Joystick2 &= joykey;
00147 
00148         // Count TOD clocks.
00149         TheCIA1->CountTOD();
00150         TheCIA2->CountTOD();
00151 
00152 #if 1
00153         // Output a frag.
00154         TheSID->VBlank();
00155 #endif
00156         
00157         if (have_a_break)
00158                 return;
00159 
00160         // Update the window if needed.
00161         frame++;
00162         if (draw_frame) {
00163 
00164                 // Synchronize to the timer if limiting the speed.
00165                 if (ThePrefs.LimitSpeed) {
00166                         if (skipped_frames == 0) {
00167                                 // There is a tiny race condtion here that
00168                                 // could cause a full extra delay cycle.
00169                                 WaitForSingleObject(timer_semaphore, INFINITE);
00170                         }
00171                         else {
00172                                 Debug("*** Skipped a frame! ***\n");
00173                                 skipped_frames = 0;
00174                         }
00175                 }
00176 
00177                 // Perform the actual screen update exactly at the
00178                 // beginning of an interval for the smoothest video.
00179                 TheDisplay->Update();
00180 
00181                 // Compute the speed index and show it in the speedometer.
00182                 DWORD now = timeGetTime();
00183                 int elapsed_time = now - ref_time;
00184                 if (now - ref_time >= SPEEDOMETER_INTERVAL) {
00185                         double speed_index = double(frame * FRAME_INTERVAL * 100 + elapsed_time/2) / elapsed_time;
00186                         TheDisplay->Speedometer((int)speed_index);
00187                         ref_time = now;
00188                         frame = 0;
00189                 }
00190 
00191                 // Make sure our timer is set correctly.
00192                 CheckTimerChange();
00193         }
00194 }
00195 
00196 
00197 void C64::CheckTimerChange()
00198 {
00199         // Make sure the timer interval matches the preferences.
00200         if (!ThePrefs.LimitSpeed && timer_every == 0)
00201                 return;
00202         if (ThePrefs.LimitSpeed && ThePrefs.SkipFrames == timer_every)
00203                 return;
00204         StopTimer();
00205         StartTimer();
00206 }
00207 
00208 /*
00209  *  Open/close joystick drivers given old and new state of
00210  *  joystick preferences
00211  */
00212 
00213 BOOL joystick_open[2];
00214 
00215 void C64::open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2)
00216 {
00217         if (oldjoy1 != newjoy1) {
00218                 joystick_open[0] = FALSE;
00219                 if (newjoy1) {
00220                         JOYINFO joyinfo;
00221                         if (joyGetPos(0, &joyinfo) == JOYERR_NOERROR)
00222                                 joystick_open[0] = TRUE;
00223                 }
00224         }
00225 
00226         if (oldjoy2 != newjoy2) {
00227                 joystick_open[1] = FALSE;
00228                 if (newjoy1) {
00229                         JOYINFO joyinfo;
00230                         if (joyGetPos(1, &joyinfo) == JOYERR_NOERROR)
00231                                 joystick_open[1] = TRUE;
00232                 }
00233         }
00234 
00235         // XXX: Should have our own new prefs!
00236         state_change = TRUE;
00237 }
00238 
00239 
00240 /*
00241  *  Poll joystick port, return CIA mask
00242  */
00243 
00244 uint8 C64::poll_joystick(int port)
00245 {
00246         uint8 j = 0xff;
00247 
00248         if (joystick_open[port]) {
00249                 JOYINFO joyinfo;
00250                 if (joyGetPos(port, &joyinfo) == JOYERR_NOERROR) {
00251                         int x = joyinfo.wXpos;
00252                         int y = joyinfo.wYpos;
00253                         int buttons = joyinfo.wButtons;
00254                         int s1 = JOYSTICK_SENSITIVITY;
00255                         int s2 = 100 - JOYSTICK_SENSITIVITY;
00256                         if (x < JOYSTICK_MIN + s1*JOYSTICK_RANGE/100)
00257                                 j &= 0xfb; // Left
00258                         else if (x > JOYSTICK_MIN + s2*JOYSTICK_RANGE/100)
00259                                 j &= 0xf7; // Right
00260                         if (y < JOYSTICK_MIN + s1*JOYSTICK_RANGE/100)
00261                                 j &= 0xfe; // Up
00262                         else if (y > JOYSTICK_MIN + s2*JOYSTICK_RANGE/100)
00263                                 j &= 0xfd; // Down
00264                         if (buttons & 1)
00265                                 j &= 0xef; // Button
00266                         if (buttons & 2) {
00267                                 Pause();
00268                                 while (joyGetPos(port, &joyinfo) == JOYERR_NOERROR && (joyinfo.wButtons & 2))
00269                                         Sleep(100);
00270                                 Resume();
00271                         }
00272                 }
00273         }
00274 
00275         return j;
00276 }
00277 
00278 void C64::StartTimer()
00279 {
00280         ref_time = timeGetTime();
00281         skipped_frames = 0;
00282         frame = 0;
00283 
00284         if (!ThePrefs.LimitSpeed) {
00285                 timer_every = 0;
00286                 StopTimer();
00287                 return;
00288         }
00289         timer_every = ThePrefs.SkipFrames;
00290 
00291         if (!timer_semaphore) {
00292                 timer_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
00293                 if (!timer_semaphore)
00294                         Debug("CreateSemaphore failed\n");
00295         }
00296 
00297         if (!timer_id) {
00298 
00299                 // Turn on high-resolution times and delays.
00300                 int resolution = FRAME_INTERVAL;
00301                 if (high_resolution_timer) {
00302                         timeBeginPeriod(1);
00303                         resolution = 0;
00304                 }
00305 
00306                 timer_id = timeSetEvent(timer_every*FRAME_INTERVAL, resolution, StaticTimeProc, (DWORD) this, TIME_PERIODIC);
00307                 if (!timer_id)
00308                         Debug("timeSetEvent failed\n");
00309         }
00310 }
00311 
00312 void C64::StopTimer()
00313 {
00314         if (timer_semaphore) {
00315                 CloseHandle(timer_semaphore);
00316                 timer_semaphore = NULL;
00317         }
00318         if (timer_id) {
00319                 timeKillEvent(timer_id);
00320                 timer_id = NULL;
00321 
00322                 // Turn off high-resolution delays.
00323                 if (high_resolution_timer)
00324                         timeEndPeriod(1);
00325         }
00326 
00327 }
00328 
00329 void CALLBACK C64::StaticTimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
00330 {
00331         C64* TheC64 = (C64 *) dwUser;
00332         TheC64->TimeProc(uID);
00333 }
00334 
00335 void C64::TimeProc(UINT id)
00336 {
00337         if (id != timer_id) {
00338                 Debug("TimeProc called for wrong timer id!\n");
00339                 timeKillEvent(id);
00340                 return;
00341         }
00342 
00343         if (!ReleaseSemaphore(timer_semaphore, 1, NULL))
00344                 skipped_frames++;
00345 }
00346 
00347 
00348 /*
00349  * The emulation's main loop
00350  */
00351 
00352 void C64::thread_func()
00353 {
00354         Debug("C64::thread_func\n");
00355 
00356         thread_running = TRUE;
00357 
00358         while (!quit_thyself) {
00359 
00360                 if (have_a_break)
00361                         TheDisplay->WaitUntilActive();
00362 
00363 #ifdef FRODO_SC
00364                 if (ThePrefs.Emul1541Proc)
00365                         EmulateCyclesWith1541();
00366                 else
00367                         EmulateCyclesWithout1541();
00368                 state_change = FALSE;
00369 #else
00370                 // The order of calls is important here
00371                 int cycles = TheVIC->EmulateLine();
00372                 TheSID->EmulateLine();
00373 #if !PRECISE_CIA_CYCLES
00374                 TheCIA1->EmulateLine(ThePrefs.CIACycles);
00375                 TheCIA2->EmulateLine(ThePrefs.CIACycles);
00376 #endif
00377                 if (ThePrefs.Emul1541Proc) {
00378                         int cycles_1541 = ThePrefs.FloppyCycles;
00379                         TheCPU1541->CountVIATimers(cycles_1541);
00380 
00381                         if (!TheCPU1541->Idle) {
00382                                 // 1541 processor active, alternately execute
00383                                 //  6502 and 6510 instructions until both have
00384                                 //  used up their cycles
00385                                 while (cycles >= 0 || cycles_1541 >= 0)
00386                                         if (cycles > cycles_1541)
00387                                                 cycles -= TheCPU->EmulateLine(1);
00388                                         else
00389                                                 cycles_1541 -= TheCPU1541->EmulateLine(1);
00390                         } else
00391                                 TheCPU->EmulateLine(cycles);
00392                 } else
00393                         // 1541 processor disabled, only emulate 6510
00394                         TheCPU->EmulateLine(cycles);
00395 #endif
00396         }
00397 
00398         thread_running = FALSE;
00399 
00400 }
00401 
00402 #ifdef FRODO_SC
00403 
00404 void C64::EmulateCyclesWith1541()
00405 {
00406         thread_running = TRUE;
00407         while (!state_change) {
00408                 // The order of calls is important here
00409                 if (TheVIC->EmulateCycle())
00410                         TheSID->EmulateLine();
00411 #ifndef BATCH_CIA_CYCLES
00412                 TheCIA1->EmulateCycle();
00413                 TheCIA2->EmulateCycle();
00414 #endif
00415                 TheCPU->EmulateCycle();
00416                 TheCPU1541->CountVIATimers(1);
00417                 if (!TheCPU1541->Idle)
00418                         TheCPU1541->EmulateCycle();
00419                 CycleCounter++;
00420         }
00421 }
00422 
00423 void C64::EmulateCyclesWithout1541()
00424 {
00425         thread_running = TRUE;
00426         while (!state_change) {
00427                 // The order of calls is important here
00428                 if (TheVIC->EmulateCycle())
00429                         TheSID->EmulateLine();
00430 #ifndef BATCH_CIA_CYCLES
00431                 TheCIA1->EmulateCycle();
00432                 TheCIA2->EmulateCycle();
00433 #endif
00434                 TheCPU->EmulateCycle();
00435                 CycleCounter++;
00436         }
00437 }
00438 
00439 #endif

Generated on Tue Feb 8 04:07:25 2005 for E32frodo by doxygen 1.3.3