ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_x.h
Revision: 1.3
Committed: 2003-07-01T19:14:08Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
TkGui.tcl renamed to Frodo_GUI.tcl, which is now expected and installed in
/usr/bin

File Contents

# Content
1 /*
2 * C64_x.h - Put the pieces together, X specific stuff
3 *
4 * Frodo (C) 1994-1997,2002-2003 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", BINDIR "Frodo_GUI.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 }