ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_x.h
Revision: 1.1
Committed: 2003-07-01T17:28:51Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Log Message:
imported files

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * C64_x.h - Put the pieces together, X specific stuff
3     *
4     * Frodo (C) 1994-1997,2002 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 "main.h"
22    
23    
24     static struct timeval tv_start;
25    
26     #ifndef HAVE_USLEEP
27     /*
28     * NAME:
29     * usleep -- This is the precision timer for Test Set
30     * Automation. It uses the select(2) system
31     * call to delay for the desired number of
32     * micro-seconds. This call returns ZERO
33     * (which is usually ignored) on successful
34     * completion, -1 otherwise.
35     *
36     * ALGORITHM:
37     * 1) We range check the passed in microseconds and log a
38     * warning message if appropriate. We then return without
39     * delay, flagging an error.
40     * 2) Load the Seconds and micro-seconds portion of the
41     * interval timer structure.
42     * 3) Call select(2) with no file descriptors set, just the
43     * timer, this results in either delaying the proper
44     * ammount of time or being interupted early by a signal.
45     *
46     * HISTORY:
47     * Added when the need for a subsecond timer was evident.
48     *
49     * AUTHOR:
50     * Michael J. Dyer Telephone: AT&T 414.647.4044
51     * General Electric Medical Systems GE DialComm 8 *767.4044
52     * P.O. Box 414 Mail Stop 12-27 Sect'y AT&T 414.647.4584
53     * Milwaukee, Wisconsin USA 53201 8 *767.4584
54     * internet: mike@sherlock.med.ge.com GEMS WIZARD e-mail: DYER
55     */
56    
57     #include <unistd.h>
58     #include <stdlib.h>
59     #include <stdio.h>
60     #include <errno.h>
61     #include <time.h>
62     #include <sys/time.h>
63     #include <sys/param.h>
64     #include <sys/types.h>
65    
66     int usleep(unsigned long int microSeconds)
67     {
68     unsigned int Seconds, uSec;
69     int nfds, readfds, writefds, exceptfds;
70     struct timeval Timer;
71    
72     nfds = readfds = writefds = exceptfds = 0;
73    
74     if( (microSeconds == (unsigned long) 0)
75     || microSeconds > (unsigned long) 4000000 )
76     {
77     errno = ERANGE; /* value out of range */
78     perror( "usleep time out of range ( 0 -> 4000000 ) " );
79     return -1;
80     }
81    
82     Seconds = microSeconds / (unsigned long) 1000000;
83     uSec = microSeconds % (unsigned long) 1000000;
84    
85     Timer.tv_sec = Seconds;
86     Timer.tv_usec = uSec;
87    
88     if( select( nfds, &readfds, &writefds, &exceptfds, &Timer ) < 0 )
89     {
90     perror( "usleep (select) failed" );
91     return -1;
92     }
93    
94     return 0;
95     }
96     #endif
97    
98    
99     /*
100     * Constructor, system-dependent things
101     */
102    
103     void C64::c64_ctor1(void)
104     {
105     // Initialize joystick variables
106     joyfd[0] = joyfd[1] = -1;
107     joy_minx = joy_miny = 32767;
108     joy_maxx = joy_maxy = -32768;
109    
110     // we need to create a potential GUI subprocess here, because we don't want
111     // it to inherit file-descriptors (such as for the audio-device and alike..)
112     #if defined(__svgalib__)
113     gui = 0;
114     #else
115     // try to start up Tk gui.
116     gui = new CmdPipe("wish", "TkGui.tcl");
117     if (gui) {
118     if (gui->fail) {
119     delete gui; gui = 0;
120     }
121     }
122     // wait until the GUI process responds (if it does...)
123     if (gui) {
124     if (5 != gui->ewrite("ping\n",5)) {
125     delete gui; gui = 0;
126     } else {
127     char c;
128     fd_set set;
129     FD_ZERO(&set);
130     FD_SET(gui->get_read_fd(), &set);
131     struct timeval tv;
132     tv.tv_usec = 0;
133     tv.tv_sec = 5;
134     // Use the following commented line for HP-UX < 10.20
135     // if (select(FD_SETSIZE, (int *)&set, (int *)NULL, (int *)NULL, &tv) <= 0) {
136     if (select(FD_SETSIZE, &set, NULL, NULL, &tv) <= 0) {
137     delete gui; gui = 0;
138     } else {
139     if (1 != gui->eread(&c, 1)) {
140     delete gui; gui = 0;
141     } else {
142     if (c != 'o') {
143     delete gui; gui = 0;
144     }
145     }
146     }
147     }
148     }
149     #endif // __svgalib__
150     }
151    
152     void C64::c64_ctor2(void)
153     {
154     #ifndef __svgalib__
155     if (!gui) {
156     fprintf(stderr,"Alas, master, no preferences window will be available.\n"
157     "If you wish to see one, make sure the 'wish' interpreter\n"
158     "(Tk version >= 4.1) is installed in your path.\n"
159     "You can still use Frodo, though. Use F10 to quit, \n"
160     "F11 to cause an NMI and F12 to reset the C64.\n"
161     "You can change the preferences by editing ~/.frodorc\n");
162     }
163     #endif // SVGAlib
164    
165     gettimeofday(&tv_start, NULL);
166     }
167    
168    
169     /*
170     * Destructor, system-dependent things
171     */
172    
173     void C64::c64_dtor(void)
174     {
175     }
176    
177    
178     /*
179     * Start main emulation thread
180     */
181    
182     void C64::Run(void)
183     {
184     // Reset chips
185     TheCPU->Reset();
186     TheSID->Reset();
187     TheCIA1->Reset();
188     TheCIA2->Reset();
189     TheCPU1541->Reset();
190    
191     // Patch kernal IEC routines
192     orig_kernal_1d84 = Kernal[0x1d84];
193     orig_kernal_1d85 = Kernal[0x1d85];
194     PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
195    
196     quit_thyself = false;
197     thread_func();
198     }
199    
200    
201     /*
202     * Vertical blank: Poll keyboard and joysticks, update window
203     */
204    
205     void C64::VBlank(bool draw_frame)
206     {
207     // Poll keyboard
208     TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
209     if (TheDisplay->quit_requested)
210     quit_thyself = true;
211    
212     // Poll joysticks
213     TheCIA1->Joystick1 = poll_joystick(0);
214     TheCIA1->Joystick2 = poll_joystick(1);
215    
216     if (ThePrefs.JoystickSwap) {
217     uint8 tmp = TheCIA1->Joystick1;
218     TheCIA1->Joystick1 = TheCIA1->Joystick2;
219     TheCIA1->Joystick2 = tmp;
220     }
221    
222     // Joystick keyboard emulation
223     if (TheDisplay->NumLock())
224     TheCIA1->Joystick1 &= joykey;
225     else
226     TheCIA1->Joystick2 &= joykey;
227    
228     // Count TOD clocks
229     TheCIA1->CountTOD();
230     TheCIA2->CountTOD();
231    
232     // Update window if needed
233     if (draw_frame) {
234     TheDisplay->Update();
235    
236     // Calculate time between VBlanks, display speedometer
237     struct timeval tv;
238     gettimeofday(&tv, NULL);
239     if ((tv.tv_usec -= tv_start.tv_usec) < 0) {
240     tv.tv_usec += 1000000;
241     tv.tv_sec -= 1;
242     }
243     tv.tv_sec -= tv_start.tv_sec;
244     double elapsed_time = (double)tv.tv_sec * 1000000 + tv.tv_usec;
245     speed_index = 20000 / (elapsed_time + 1) * ThePrefs.SkipFrames * 100;
246    
247     // Limit speed to 100% if desired
248     if ((speed_index > 100) && ThePrefs.LimitSpeed) {
249     usleep((unsigned long)(ThePrefs.SkipFrames * 20000 - elapsed_time));
250     speed_index = 100;
251     }
252    
253     gettimeofday(&tv_start, NULL);
254    
255     TheDisplay->Speedometer((int)speed_index);
256     }
257     }
258    
259    
260     /*
261     * Open/close joystick drivers given old and new state of
262     * joystick preferences
263     */
264    
265     void C64::open_close_joysticks(bool oldjoy1, bool oldjoy2, bool newjoy1, bool newjoy2)
266     {
267     #ifdef HAVE_LINUX_JOYSTICK_H
268     if (oldjoy1 != newjoy1) {
269     joy_minx = joy_miny = 32767; // Reset calibration
270     joy_maxx = joy_maxy = -32768;
271     if (newjoy1) {
272     joyfd[0] = open("/dev/js0", O_RDONLY);
273     if (joyfd[0] < 0)
274     fprintf(stderr, "Couldn't open joystick 1\n");
275     } else {
276     close(joyfd[0]);
277     joyfd[0] = -1;
278     }
279     }
280    
281     if (oldjoy2 != newjoy2) {
282     joy_minx = joy_miny = 32767; // Reset calibration
283     joy_maxx = joy_maxy = -32768;
284     if (newjoy2) {
285     joyfd[1] = open("/dev/js1", O_RDONLY);
286     if (joyfd[1] < 0)
287     fprintf(stderr, "Couldn't open joystick 2\n");
288     } else {
289     close(joyfd[1]);
290     joyfd[1] = -1;
291     }
292     }
293     #endif
294     }
295    
296    
297     /*
298     * Poll joystick port, return CIA mask
299     */
300    
301     uint8 C64::poll_joystick(int port)
302     {
303     #ifdef HAVE_LINUX_JOYSTICK_H
304     JS_DATA_TYPE js;
305     uint8 j = 0xff;
306    
307     if (joyfd[port] >= 0) {
308     if (read(joyfd[port], &js, JS_RETURN) == JS_RETURN) {
309     if (js.x > joy_maxx)
310     joy_maxx = js.x;
311     if (js.x < joy_minx)
312     joy_minx = js.x;
313     if (js.y > joy_maxy)
314     joy_maxy = js.y;
315     if (js.y < joy_miny)
316     joy_miny = js.y;
317    
318     if (joy_maxx-joy_minx < 100 || joy_maxy-joy_miny < 100)
319     return 0xff;
320    
321     if (js.x < (joy_minx + (joy_maxx-joy_minx)/3))
322     j &= 0xfb; // Left
323     else if (js.x > (joy_minx + 2*(joy_maxx-joy_minx)/3))
324     j &= 0xf7; // Right
325    
326     if (js.y < (joy_miny + (joy_maxy-joy_miny)/3))
327     j &= 0xfe; // Up
328     else if (js.y > (joy_miny + 2*(joy_maxy-joy_miny)/3))
329     j &= 0xfd; // Down
330    
331     if (js.buttons & 1)
332     j &= 0xef; // Button
333     }
334     }
335     return j;
336     #else
337     return 0xff;
338     #endif
339     }
340    
341    
342     /*
343     * The emulation's main loop
344     */
345    
346     void C64::thread_func(void)
347     {
348     int linecnt = 0;
349    
350     #ifdef FRODO_SC
351     while (!quit_thyself) {
352    
353     // The order of calls is important here
354     if (TheVIC->EmulateCycle())
355     TheSID->EmulateLine();
356     TheCIA1->CheckIRQs();
357     TheCIA2->CheckIRQs();
358     TheCIA1->EmulateCycle();
359     TheCIA2->EmulateCycle();
360     TheCPU->EmulateCycle();
361    
362     if (ThePrefs.Emul1541Proc) {
363     TheCPU1541->CountVIATimers(1);
364     if (!TheCPU1541->Idle)
365     TheCPU1541->EmulateCycle();
366     }
367     CycleCounter++;
368     #else
369     while (!quit_thyself) {
370    
371     // The order of calls is important here
372     int cycles = TheVIC->EmulateLine();
373     TheSID->EmulateLine();
374     #if !PRECISE_CIA_CYCLES
375     TheCIA1->EmulateLine(ThePrefs.CIACycles);
376     TheCIA2->EmulateLine(ThePrefs.CIACycles);
377     #endif
378    
379     if (ThePrefs.Emul1541Proc) {
380     int cycles_1541 = ThePrefs.FloppyCycles;
381     TheCPU1541->CountVIATimers(cycles_1541);
382    
383     if (!TheCPU1541->Idle) {
384     // 1541 processor active, alternately execute
385     // 6502 and 6510 instructions until both have
386     // used up their cycles
387     while (cycles >= 0 || cycles_1541 >= 0)
388     if (cycles > cycles_1541)
389     cycles -= TheCPU->EmulateLine(1);
390     else
391     cycles_1541 -= TheCPU1541->EmulateLine(1);
392     } else
393     TheCPU->EmulateLine(cycles);
394     } else
395     // 1541 processor disabled, only emulate 6510
396     TheCPU->EmulateLine(cycles);
397     #endif
398     linecnt++;
399     #if !defined(__svgalib__)
400     if ((linecnt & 0xfff) == 0 && gui) {
401    
402     // check for command from GUI process
403     // fprintf(stderr,":");
404     while (gui->probe()) {
405     char c;
406     if (gui->eread(&c, 1) != 1) {
407     delete gui;
408     gui = 0;
409     fprintf(stderr,"Oops, GUI process died...\n");
410     } else {
411     // fprintf(stderr,"%c",c);
412     switch (c) {
413     case 'q':
414     quit_thyself = true;
415     break;
416     case 'r':
417     Reset();
418     break;
419     case 'p':{
420     Prefs *np = Frodo::reload_prefs();
421     NewPrefs(np);
422     ThePrefs = *np;
423     break;
424     }
425     default:
426     break;
427     }
428     }
429     }
430     }
431     #endif
432     }
433     #if !defined(__svgalib__)
434     if (gui) {
435     gui->ewrite("quit\n",5);
436     }
437     #endif
438     }