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

C64_x.i

Go to the documentation of this file.
00001 /*
00002  *  C64_x.i - Put the pieces together, X specific stuff
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *  Unix stuff by Bernd Schmidt/Lutz Vieweg
00006  */
00007 
00008 #include "main.h"
00009 
00010 
00011 static struct timeval tv_start;
00012 
00013 #ifndef HAVE_USLEEP
00014 /*
00015  *  NAME:
00016  *      usleep     -- This is the precision timer for Test Set
00017  *                    Automation. It uses the select(2) system
00018  *                    call to delay for the desired number of
00019  *                    micro-seconds. This call returns ZERO
00020  *                    (which is usually ignored) on successful
00021  *                    completion, -1 otherwise.
00022  *
00023  *  ALGORITHM:
00024  *      1) We range check the passed in microseconds and log a
00025  *         warning message if appropriate. We then return without
00026  *         delay, flagging an error.
00027  *      2) Load the Seconds and micro-seconds portion of the
00028  *         interval timer structure.
00029  *      3) Call select(2) with no file descriptors set, just the
00030  *         timer, this results in either delaying the proper
00031  *         ammount of time or being interupted early by a signal.
00032  *
00033  *  HISTORY:
00034  *      Added when the need for a subsecond timer was evident.
00035  *
00036  *  AUTHOR:
00037  *      Michael J. Dyer                   Telephone:   AT&T 414.647.4044
00038  *      General Electric Medical Systems        GE DialComm  8 *767.4044
00039  *      P.O. Box 414  Mail Stop 12-27         Sect'y   AT&T 414.647.4584
00040  *      Milwaukee, Wisconsin  USA 53201                      8 *767.4584
00041  *      internet:  mike@sherlock.med.ge.com     GEMS WIZARD e-mail: DYER
00042  */
00043 
00044 #include <unistd.h>
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <errno.h>
00048 #include <time.h>
00049 #include <sys/time.h>
00050 #include <sys/param.h>
00051 #include <sys/types.h>
00052 
00053 int usleep(unsigned long int microSeconds)
00054 {
00055         unsigned int            Seconds, uSec;
00056         int                     nfds, readfds, writefds, exceptfds;
00057         struct  timeval         Timer;
00058 
00059         nfds = readfds = writefds = exceptfds = 0;
00060 
00061         if( (microSeconds == (unsigned long) 0)
00062                 || microSeconds > (unsigned long) 4000000 )
00063         {
00064                 errno = ERANGE;         /* value out of range */
00065                 perror( "usleep time out of range ( 0 -> 4000000 ) " );
00066                 return -1;
00067         }
00068 
00069         Seconds = microSeconds / (unsigned long) 1000000;
00070         uSec    = microSeconds % (unsigned long) 1000000;
00071 
00072         Timer.tv_sec            = Seconds;
00073         Timer.tv_usec           = uSec;
00074 
00075         if( select( nfds, &readfds, &writefds, &exceptfds, &Timer ) < 0 )
00076         {
00077                 perror( "usleep (select) failed" );
00078                 return -1;
00079         }
00080 
00081         return 0;
00082 }
00083 #endif
00084 
00085 
00086 /*
00087  *  Constructor, system-dependent things
00088  */
00089 
00090 void C64::c64_ctor1(void)
00091 {
00092         // Initialize joystick variables
00093         joyfd[0] = joyfd[1] = -1;
00094         joy_minx = joy_miny = 32767;
00095         joy_maxx = joy_maxy = -32768;
00096 
00097         // we need to create a potential GUI subprocess here, because we don't want
00098         // it to inherit file-descriptors (such as for the audio-device and alike..)
00099 #if defined(__svgalib__)
00100         gui = 0;
00101 #else
00102         // try to start up Tk gui.
00103         gui = new CmdPipe("wish", "TkGui.tcl");
00104         if (gui) {
00105                 if (gui->fail) {
00106                         delete gui; gui = 0;
00107                 }
00108         }
00109         // wait until the GUI process responds (if it does...)
00110         if (gui) {
00111                 if (5 != gui->ewrite("ping\n",5)) {
00112                         delete gui; gui = 0;
00113                 } else {
00114                         char c;
00115                         fd_set set;
00116                         FD_ZERO(&set);
00117                         FD_SET(gui->get_read_fd(), &set);
00118                         struct timeval tv;
00119                         tv.tv_usec = 0;
00120                         tv.tv_sec = 5;
00121 // Use the following commented line for HP-UX < 10.20
00122 //                      if (select(FD_SETSIZE, (int *)&set, (int *)NULL, (int *)NULL, &tv) <= 0) {
00123                         if (select(FD_SETSIZE, &set, NULL, NULL, &tv) <= 0) {
00124                                 delete gui; gui = 0;
00125                         } else {
00126                                 if (1 != gui->eread(&c, 1)) {
00127                                         delete gui; gui = 0;
00128                                 } else {
00129                                         if (c != 'o') {
00130                                                 delete gui; gui = 0;
00131                                         }
00132                                 }
00133                         }
00134                 }
00135         }
00136 #endif // __svgalib__
00137 }
00138 
00139 void C64::c64_ctor2(void)
00140 {
00141 #ifndef  __svgalib__  
00142    if (!gui) {
00143         fprintf(stderr,"Alas, master, no preferences window will be available.\n"
00144                        "If you wish to see one, make sure the 'wish' interpreter\n"
00145                        "(Tk version >= 4.1) is installed in your path.\n"
00146                        "You can still use Frodo, though. Use F10 to quit, \n"
00147                        "F11 to cause an NMI and F12 to reset the C64.\n"
00148                        "You can change the preferences by editing ~/.frodorc\n");
00149    }
00150 #endif // SVGAlib
00151   
00152         gettimeofday(&tv_start, NULL);
00153 }
00154 
00155 
00156 /*
00157  *  Destructor, system-dependent things
00158  */
00159 
00160 void C64::c64_dtor(void)
00161 {
00162 }
00163 
00164 
00165 /*
00166  *  Start main emulation thread
00167  */
00168 
00169 void C64::Run(void)
00170 {
00171         // Reset chips
00172         TheCPU->Reset();
00173         TheSID->Reset();
00174         TheCIA1->Reset();
00175         TheCIA2->Reset();
00176         TheCPU1541->Reset();
00177 
00178         // Patch kernal IEC routines
00179         orig_kernal_1d84 = Kernal[0x1d84];
00180         orig_kernal_1d85 = Kernal[0x1d85];
00181         PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
00182 
00183         quit_thyself = false;
00184         thread_func();
00185 }
00186 
00187 
00188 /*
00189  *  Vertical blank: Poll keyboard and joysticks, update window
00190  */
00191 
00192 void C64::VBlank(bool draw_frame)
00193 {
00194         // Poll keyboard
00195         TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
00196         if (TheDisplay->quit_requested)
00197                 quit_thyself = true;
00198 
00199         // Poll joysticks
00200         TheCIA1->Joystick1 = poll_joystick(0);
00201         TheCIA1->Joystick2 = poll_joystick(1);
00202 
00203         if (ThePrefs.JoystickSwap) {
00204                 uint8 tmp = TheCIA1->Joystick1;
00205                 TheCIA1->Joystick1 = TheCIA1->Joystick2;
00206                 TheCIA1->Joystick2 = tmp;
00207         }
00208 
00209         // Joystick keyboard emulation
00210         if (TheDisplay->NumLock())
00211                 TheCIA1->Joystick1 &= joykey;
00212         else
00213                 TheCIA1->Joystick2 &= joykey;
00214        
00215         // Count TOD clocks
00216         TheCIA1->CountTOD();
00217         TheCIA2->CountTOD();
00218 
00219         // Update window if needed
00220         if (draw_frame) {
00221         TheDisplay->Update();
00222 
00223                 // Calculate time between VBlanks, display speedometer
00224                 struct timeval tv;
00225                 gettimeofday(&tv, NULL);
00226                 if ((tv.tv_usec -= tv_start.tv_usec) < 0) {
00227                         tv.tv_usec += 1000000;
00228                         tv.tv_sec -= 1;
00229                 }
00230                 tv.tv_sec -= tv_start.tv_sec;
00231                 double elapsed_time = (double)tv.tv_sec * 1000000 + tv.tv_usec;
00232                 speed_index = 20000 / (elapsed_time + 1) * ThePrefs.SkipFrames * 100;
00233 
00234                 // Limit speed to 100% if desired
00235                 if ((speed_index > 100) && ThePrefs.LimitSpeed) {
00236                         usleep((unsigned long)(ThePrefs.SkipFrames * 20000 - elapsed_time));
00237                         speed_index = 100;
00238                 }
00239 
00240                 gettimeofday(&tv_start, NULL);
00241 
00242                 TheDisplay->Speedometer((int)speed_index);
00243         }
00244 }
00245 
00246 
00247 /*
00248  *  Open/close joystick drivers given old and new state of
00249  *  joystick preferences
00250  */
00251 
00252 void C64::open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2)
00253 {
00254 #ifdef HAVE_LINUX_JOYSTICK_H
00255         if (oldjoy1 != newjoy1) {
00256                 joy_minx = joy_miny = 32767;    // Reset calibration
00257                 joy_maxx = joy_maxy = -32768;
00258                 if (newjoy1) {
00259                         joyfd[0] = open("/dev/js0", O_RDONLY);
00260                         if (joyfd[0] < 0)
00261                                 fprintf(stderr, "Couldn't open joystick 1\n");
00262                 } else {
00263                         close(joyfd[0]);
00264                         joyfd[0] = -1;
00265                 }
00266         }
00267 
00268         if (oldjoy2 != newjoy2) {
00269                 joy_minx = joy_miny = 32767;    // Reset calibration
00270                 joy_maxx = joy_maxy = -32768;
00271                 if (newjoy2) {
00272                         joyfd[1] = open("/dev/js1", O_RDONLY);
00273                         if (joyfd[1] < 0)
00274                                 fprintf(stderr, "Couldn't open joystick 2\n");
00275                 } else {
00276                         close(joyfd[1]);
00277                         joyfd[1] = -1;
00278                 }
00279         }
00280 #endif
00281 }
00282 
00283 
00284 /*
00285  *  Poll joystick port, return CIA mask
00286  */
00287 
00288 uint8 C64::poll_joystick(int port)
00289 {
00290 #ifdef HAVE_LINUX_JOYSTICK_H
00291         JS_DATA_TYPE js;
00292         uint8 j = 0xff;
00293 
00294         if (joyfd[port] >= 0) {
00295                 if (read(joyfd[port], &js, JS_RETURN) == JS_RETURN) {
00296                         if (js.x > joy_maxx)
00297                                 joy_maxx = js.x;
00298                         if (js.x < joy_minx)
00299                                 joy_minx = js.x;
00300                         if (js.y > joy_maxy)
00301                                 joy_maxy = js.y;
00302                         if (js.y < joy_miny)
00303                                 joy_miny = js.y;
00304 
00305                         if (joy_maxx-joy_minx < 100 || joy_maxy-joy_miny < 100)
00306                                 return 0xff;
00307 
00308                         if (js.x < (joy_minx + (joy_maxx-joy_minx)/3))
00309                                 j &= 0xfb;                                                      // Left
00310                         else if (js.x > (joy_minx + 2*(joy_maxx-joy_minx)/3))
00311                                 j &= 0xf7;                                                      // Right
00312 
00313                         if (js.y < (joy_miny + (joy_maxy-joy_miny)/3))
00314                                 j &= 0xfe;                                                      // Up
00315                         else if (js.y > (joy_miny + 2*(joy_maxy-joy_miny)/3))
00316                                 j &= 0xfd;                                                      // Down
00317 
00318                         if (js.buttons & 1)
00319                                 j &= 0xef;                                                      // Button
00320                 }
00321         }
00322         return j;
00323 #else
00324         return 0xff;
00325 #endif
00326 }
00327 
00328 
00329 /*
00330  * The emulation's main loop
00331  */
00332 
00333 void C64::thread_func(void)
00334 {
00335         int linecnt = 0;
00336 
00337 #ifdef FRODO_SC
00338         while (!quit_thyself) {
00339 
00340                 // The order of calls is important here
00341                 if (TheVIC->EmulateCycle())
00342                         TheSID->EmulateLine();
00343                 TheCIA1->CheckIRQs();
00344                 TheCIA2->CheckIRQs();
00345                 TheCIA1->EmulateCycle();
00346                 TheCIA2->EmulateCycle();
00347                 TheCPU->EmulateCycle();
00348 
00349                 if (ThePrefs.Emul1541Proc) {
00350                         TheCPU1541->CountVIATimers(1);
00351                         if (!TheCPU1541->Idle)
00352                                 TheCPU1541->EmulateCycle();
00353                 }
00354                 CycleCounter++;
00355 #else
00356         while (!quit_thyself) {
00357 
00358                 // The order of calls is important here
00359                 int cycles = TheVIC->EmulateLine();
00360                 TheSID->EmulateLine();
00361 #if !PRECISE_CIA_CYCLES
00362                 TheCIA1->EmulateLine(ThePrefs.CIACycles);
00363                 TheCIA2->EmulateLine(ThePrefs.CIACycles);
00364 #endif
00365 
00366                 if (ThePrefs.Emul1541Proc) {
00367                         int cycles_1541 = ThePrefs.FloppyCycles;
00368                         TheCPU1541->CountVIATimers(cycles_1541);
00369 
00370                         if (!TheCPU1541->Idle) {
00371                                 // 1541 processor active, alternately execute
00372                                 //  6502 and 6510 instructions until both have
00373                                 //  used up their cycles
00374                                 while (cycles >= 0 || cycles_1541 >= 0)
00375                                         if (cycles > cycles_1541)
00376                                                 cycles -= TheCPU->EmulateLine(1);
00377                                         else
00378                                                 cycles_1541 -= TheCPU1541->EmulateLine(1);
00379                         } else
00380                                 TheCPU->EmulateLine(cycles);
00381                 } else
00382                         // 1541 processor disabled, only emulate 6510
00383                         TheCPU->EmulateLine(cycles);
00384 #endif
00385                 linecnt++;
00386 #if !defined(__svgalib__)
00387                 if ((linecnt & 0xfff) == 0 && gui) {
00388 
00389                         // check for command from GUI process
00390                 // fprintf(stderr,":");
00391                         while (gui->probe()) {
00392                                 char c;
00393                                 if (gui->eread(&c, 1) != 1) {
00394                                         delete gui;
00395                                         gui = 0;
00396                                         fprintf(stderr,"Oops, GUI process died...\n");
00397                                 } else {
00398                // fprintf(stderr,"%c",c);
00399                                         switch (c) {
00400                                                 case 'q':
00401                                                         quit_thyself = true;
00402                                                         break;
00403                                                 case 'r':
00404                                                         Reset();
00405                                                         break;
00406                                                 case 'p':{
00407                                                         Prefs *np = Frodo::reload_prefs();
00408                                                         NewPrefs(np);
00409                                                         ThePrefs = *np;
00410                                                         break;
00411                                                 }
00412                                                 default:
00413                                                         break;
00414                                         }
00415                                 }
00416                         }
00417                 }
00418 #endif
00419         }
00420 #if !defined(__svgalib__)
00421         if (gui) {
00422                 gui->ewrite("quit\n",5);
00423         }
00424 #endif
00425 }

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