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

C64_Be.i

Go to the documentation of this file.
00001 /*
00002  *  C64_Be.i - Put the pieces together, Be specific stuff
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  */
00006 
00007 #include <KernelKit.h>
00008 #include <device/Joystick.h>
00009 
00010 #undef PROFILING
00011 
00012 
00013 /*
00014  *  Constructor, system-dependent things
00015  */
00016 
00017 void C64::c64_ctor1(void)
00018 {
00019         joy[0] = new BJoystick();
00020         joy[1] = new BJoystick();
00021 }
00022 
00023 void C64::c64_ctor2(void)
00024 {
00025         // Initialize joystick variables
00026         joy_minx = joy_miny = 32767;
00027         joy_maxx = joy_maxy = 0;
00028 
00029         // Initialize semaphores (initially acquired)
00030         pause_sem = create_sem(0, "Frodo Pause Semaphore");
00031         sound_sync_sem = create_sem(0, "Frodo Sound Sync Semaphore");
00032 
00033         // Preset speedometer start time
00034         start_time = system_time();
00035 }
00036 
00037 
00038 /*
00039  *  Destructor, system-dependent things
00040  */
00041 
00042 void C64::c64_dtor(void)
00043 {
00044         delete_sem(pause_sem);
00045         delete_sem(sound_sync_sem);
00046 
00047         delete joy[0];
00048         delete joy[1];
00049 }
00050 
00051 
00052 /*
00053  *  Start main emulation thread
00054  */
00055 
00056 void C64::Run(void)
00057 {
00058         // Reset chips
00059         TheCPU->Reset();
00060         TheSID->Reset();
00061         TheCIA1->Reset();
00062         TheCIA2->Reset();
00063         TheCPU1541->Reset();
00064 
00065         // Patch kernal IEC routines
00066         orig_kernal_1d84 = Kernal[0x1d84];
00067         orig_kernal_1d85 = Kernal[0x1d85];
00068         PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
00069 
00070         // Start the CPU thread
00071         the_thread = spawn_thread(thread_invoc, "Frodo 6510", B_URGENT_DISPLAY_PRIORITY, this);
00072         thread_running = true;
00073         quit_thyself = false;
00074         have_a_break = false;
00075         resume_thread(the_thread);
00076 }
00077 
00078 
00079 /*
00080  *  Stop main emulation thread
00081  */
00082 
00083 void C64::Quit(void)
00084 {
00085         long ret;
00086 
00087         // Ask the thread to quit itself if it is running
00088         if (thread_running) {
00089                 if (have_a_break)
00090                         Resume();
00091                 quit_thyself = true;
00092                 wait_for_thread(the_thread, &ret);
00093                 thread_running = false;
00094         }
00095 }
00096 
00097 
00098 /*
00099  *  Pause main emulation thread
00100  */
00101 
00102 void C64::Pause(void)
00103 {
00104         // Ask the thread to pause and wait for acknowledge
00105         if (thread_running && !have_a_break) {
00106                 have_a_break = true;
00107                 acquire_sem(pause_sem);
00108                 TheSID->PauseSound();
00109         }
00110 }
00111 
00112 
00113 /*
00114  *  Resume main emulation thread
00115  */
00116 
00117 void C64::Resume(void)
00118 {
00119         if (thread_running && have_a_break) {
00120                 have_a_break = false;
00121                 release_sem(pause_sem);
00122                 TheSID->ResumeSound();
00123         }
00124 }
00125 
00126 
00127 /*
00128  *  Vertical blank: Poll keyboard and joysticks, update window
00129  */
00130 
00131 void C64::VBlank(bool draw_frame)
00132 {
00133         bigtime_t elapsed_time;
00134         long speed_index;
00135 
00136         // To avoid deadlocks on quitting
00137         if (quit_thyself) return;
00138 
00139         // Pause requested?
00140         if (have_a_break) {
00141                 release_sem(pause_sem); // Acknowledge pause
00142                 acquire_sem(pause_sem); // Wait for resume
00143         }
00144 
00145         // Poll keyboard
00146         TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
00147 
00148         // Poll joysticks
00149         TheCIA1->Joystick1 = poll_joystick(0);
00150         TheCIA1->Joystick2 = poll_joystick(1);
00151 
00152         if (ThePrefs.JoystickSwap) {
00153                 uint8 tmp = TheCIA1->Joystick1;
00154                 TheCIA1->Joystick1 = TheCIA1->Joystick2;
00155                 TheCIA1->Joystick2 = tmp;
00156         }
00157 
00158         // Joystick keyboard emulation
00159         if (TheDisplay->NumLock())
00160                 TheCIA1->Joystick1 &= joykey;
00161         else
00162                 TheCIA1->Joystick2 &= joykey;
00163 
00164         // Count TOD clocks
00165         TheCIA1->CountTOD();
00166         TheCIA2->CountTOD();
00167 
00168         // Update window if needed
00169         if (draw_frame) {
00170                 TheDisplay->Update();
00171 
00172                 // Calculate time between VBlanks, display speedometer
00173                 elapsed_time = system_time() - start_time;
00174                 speed_index = 20000 * 100 * ThePrefs.SkipFrames / (elapsed_time + 1);
00175 
00176                 // Limit speed to 100% if desired (20ms/frame)
00177                 // If the SID emulation is on and no frames are skipped, synchronize to the SID
00178                 if (ThePrefs.LimitSpeed && speed_index > 100) {
00179                         if (ThePrefs.SIDType == SIDTYPE_DIGITAL && ThePrefs.SkipFrames == 1) {
00180                                 long l;
00181                                 get_sem_count(sound_sync_sem, &l);
00182                                 if (l > 0)      // Avoid C64 lagging behind
00183                                         acquire_sem_etc(sound_sync_sem, l+1, 0, 0);
00184                                 else
00185                                         acquire_sem(sound_sync_sem);
00186                         } else
00187                                 snooze(ThePrefs.SkipFrames * 20000 - elapsed_time);
00188                         speed_index = 100;
00189                 }
00190 
00191                 start_time = system_time();
00192 
00193                 TheDisplay->Speedometer(speed_index);
00194         }
00195 }
00196 
00197 
00198 /*
00199  *  Called by SID after playing 1/50 sec of sound
00200  */
00201 
00202 void C64::SoundSync(void)
00203 {
00204         release_sem(sound_sync_sem);
00205 }
00206 
00207 
00208 /*
00209  *  Open/close joystick drivers given old and new state of
00210  *  joystick preferences
00211  */
00212 
00213 void C64::open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2)
00214 {
00215         if (oldjoy1 != newjoy1) {
00216                 joy_minx = joy_miny = 32767;    // Reset calibration
00217                 joy_maxx = joy_maxy = 0;
00218                 if (newjoy1)
00219                         joy[0]->Open("joystick2");
00220                 else
00221                         joy[0]->Close();
00222         }
00223 
00224         if (oldjoy2 != newjoy2) {
00225                 joy_minx = joy_miny = 32767;    // Reset calibration
00226                 joy_maxx = joy_maxy = 0;
00227                 if (newjoy2)
00228                         joy[1]->Open("joystick1");
00229                 else
00230                         joy[1]->Close();
00231         }
00232 }
00233 
00234 
00235 /*
00236  *  Poll joystick port, return CIA mask
00237  */
00238 
00239 uint8 C64::poll_joystick(int port)
00240 {
00241         uint8 j = 0xff;
00242 
00243         if (joy[port]->Update() != B_ERROR) {
00244                 if (joy[port]->horizontal > joy_maxx)
00245                         joy_maxx = joy[port]->horizontal;
00246                 if (joy[port]->horizontal < joy_minx)
00247                         joy_minx = joy[port]->horizontal;
00248                 if (joy[port]->vertical > joy_maxy)
00249                         joy_maxy = joy[port]->vertical;
00250                 if (joy[port]->vertical < joy_miny)
00251                         joy_miny = joy[port]->vertical;
00252 
00253                 if (!joy[port]->button1)
00254                         j &= 0xef;                                                      // Button
00255 
00256                 if (joy_maxx-joy_minx < 100 || joy_maxy-joy_miny < 100)
00257                         return j;
00258 
00259                 if (joy[port]->horizontal < (joy_minx + (joy_maxx-joy_minx)/3))
00260                         j &= 0xf7;                                                      // Right
00261                 else if (joy[port]->horizontal > (joy_minx + 2*(joy_maxx-joy_minx)/3))
00262                         j &= 0xfb;                                                      // Left
00263 
00264                 if (joy[port]->vertical < (joy_miny + (joy_maxy-joy_miny)/3))
00265                         j &= 0xfd;                                                      // Down
00266                 else if (joy[port]->vertical > (joy_miny + 2*(joy_maxy-joy_miny)/3))
00267                         j &= 0xfe;                                                      // Up
00268         }
00269         return j;
00270 }
00271 
00272 
00273 /*
00274  * The emulation's main loop
00275  */
00276 
00277 long C64::thread_invoc(void *obj)
00278 {
00279         ((C64 *)obj)->thread_func();
00280         return 0;
00281 }
00282 
00283 void C64::thread_func(void)
00284 {
00285 #ifdef PROFILING
00286 static bigtime_t vic_time_acc = 0;
00287 static bigtime_t sid_time_acc = 0;
00288 static bigtime_t cia_time_acc = 0;
00289 static bigtime_t cpu_time_acc = 0;
00290 #endif
00291 #ifdef FRODO_SC
00292         while (!quit_thyself) {
00293                 // The order of calls is important here
00294                 if (TheVIC->EmulateCycle())
00295                         TheSID->EmulateLine();
00296                 TheCIA1->CheckIRQs();
00297                 TheCIA2->CheckIRQs();
00298                 TheCIA1->EmulateCycle();
00299                 TheCIA2->EmulateCycle();
00300                 TheCPU->EmulateCycle();
00301 
00302                 if (ThePrefs.Emul1541Proc) {
00303                         TheCPU1541->CountVIATimers(1);
00304                         if (!TheCPU1541->Idle)
00305                                 TheCPU1541->EmulateCycle();
00306                 }
00307                 CycleCounter++;
00308 #else
00309         while (!quit_thyself) {
00310                 // The order of calls is important here
00311 #ifdef PROFILING
00312 bigtime_t start_time = system_time();
00313 #endif
00314                 int cycles = TheVIC->EmulateLine();
00315 #ifdef PROFILING
00316 bigtime_t vic_time = system_time();
00317 #endif
00318                 TheSID->EmulateLine();
00319 #ifdef PROFILING
00320 bigtime_t sid_time = system_time();
00321 #endif
00322 #if !PRECISE_CIA_CYCLES
00323                 TheCIA1->EmulateLine(ThePrefs.CIACycles);
00324                 TheCIA2->EmulateLine(ThePrefs.CIACycles);
00325 #endif
00326 #ifdef PROFILING
00327 bigtime_t cia_time = system_time();
00328 #endif
00329 
00330                 if (ThePrefs.Emul1541Proc) {
00331                         int cycles_1541 = ThePrefs.FloppyCycles;
00332                         TheCPU1541->CountVIATimers(cycles_1541);
00333 
00334                         if (!TheCPU1541->Idle) {
00335                                 // 1541 processor active, alternately execute
00336                                 //  6502 and 6510 instructions until both have
00337                                 //  used up their cycles
00338                                 while (cycles >= 0 || cycles_1541 >= 0)
00339                                         if (cycles > cycles_1541)
00340                                                 cycles -= TheCPU->EmulateLine(1);
00341                                         else
00342                                                 cycles_1541 -= TheCPU1541->EmulateLine(1);
00343                         } else
00344                                 TheCPU->EmulateLine(cycles);
00345                 } else
00346                         // 1541 processor disabled, only emulate 6510
00347                         TheCPU->EmulateLine(cycles);
00348 #ifdef PROFILING
00349 bigtime_t cpu_time = system_time();
00350 vic_time_acc += vic_time - start_time;
00351 sid_time_acc += sid_time - vic_time;
00352 cia_time_acc += cia_time - sid_time;
00353 cpu_time_acc += cpu_time - cia_time;
00354 #endif
00355 
00356 #endif
00357         }
00358 
00359 #ifdef PROFILING
00360 bigtime_t total_time = vic_time_acc + sid_time_acc + cia_time_acc + cpu_time_acc;
00361 printf("VIC: %Ld\n", vic_time_acc * 100 / total_time);
00362 printf("SID: %Ld\n", sid_time_acc * 100 / total_time);
00363 printf("CIA: %Ld\n", cia_time_acc * 100 / total_time);
00364 printf("CPU: %Ld\n", cpu_time_acc * 100 / total_time);
00365 #endif
00366 }

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