ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_x.h
Revision: 1.8
Committed: 2005-06-27T19:55:48Z (19 years, 3 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.7: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * C64_x.h - Put the pieces together, X specific stuff
3 *
4 * Frodo (C) 1994-1997,2002-2005 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 #ifdef __linux__
99 // select() timing is much more accurate under Linux
100 static void Delay_usec(unsigned long usec)
101 {
102 int was_error;
103 struct timeval tv;
104
105 tv.tv_sec = 0;
106 tv.tv_usec = usec;
107 do {
108 errno = 0;
109 was_error = select(0, NULL, NULL, NULL, &tv);
110 } while (was_error && (errno == EINTR));
111 }
112 #else
113 static void Delay_usec(unsigned long usec)
114 {
115 usleep(usec);
116 }
117 #endif
118
119
120 /*
121 * Constructor, system-dependent things
122 */
123
124 void C64::c64_ctor1(void)
125 {
126 // Initialize joystick variables
127 joy_minx[0] = joy_miny[0] = 32767;
128 joy_maxx[0] = joy_maxy[0] = -32768;
129 joy_minx[1] = joy_miny[1] = 32767;
130 joy_maxx[1] = joy_maxy[1] = -32768;
131
132 // we need to create a potential GUI subprocess here, because we don't want
133 // it to inherit file-descriptors (such as for the audio-device and alike..)
134 #if defined(__svgalib__)
135 gui = 0;
136 #else
137 // try to start up Tk gui.
138 gui = new CmdPipe("wish", BINDIR "Frodo_GUI.tcl");
139 if (gui) {
140 if (gui->fail) {
141 delete gui; gui = 0;
142 }
143 }
144 // wait until the GUI process responds (if it does...)
145 if (gui) {
146 if (5 != gui->ewrite("ping\n",5)) {
147 delete gui; gui = 0;
148 } else {
149 char c;
150 fd_set set;
151 FD_ZERO(&set);
152 FD_SET(gui->get_read_fd(), &set);
153 struct timeval tv;
154 tv.tv_usec = 0;
155 tv.tv_sec = 5;
156 // Use the following commented line for HP-UX < 10.20
157 // if (select(FD_SETSIZE, (int *)&set, (int *)NULL, (int *)NULL, &tv) <= 0) {
158 if (select(FD_SETSIZE, &set, NULL, NULL, &tv) <= 0) {
159 delete gui; gui = 0;
160 } else {
161 if (1 != gui->eread(&c, 1)) {
162 delete gui; gui = 0;
163 } else {
164 if (c != 'o') {
165 delete gui; gui = 0;
166 }
167 }
168 }
169 }
170 }
171 #endif // __svgalib__
172 }
173
174 void C64::c64_ctor2(void)
175 {
176 #ifndef __svgalib__
177 if (!gui) {
178 fprintf(stderr,"Alas, master, no preferences window will be available.\n"
179 "If you wish to see one, make sure the 'wish' interpreter\n"
180 "(Tk version >= 4.1) is installed in your path.\n"
181 "You can still use Frodo, though. Use F10 to quit, \n"
182 "F11 to cause an NMI and F12 to reset the C64.\n"
183 "You can change the preferences by editing ~/.frodorc\n");
184 }
185 #endif // SVGAlib
186
187 gettimeofday(&tv_start, NULL);
188 }
189
190
191 /*
192 * Destructor, system-dependent things
193 */
194
195 void C64::c64_dtor(void)
196 {
197 }
198
199
200 /*
201 * Start main emulation thread
202 */
203
204 void C64::Run(void)
205 {
206 // Reset chips
207 TheCPU->Reset();
208 TheSID->Reset();
209 TheCIA1->Reset();
210 TheCIA2->Reset();
211 TheCPU1541->Reset();
212
213 // Patch kernal IEC routines
214 orig_kernal_1d84 = Kernal[0x1d84];
215 orig_kernal_1d85 = Kernal[0x1d85];
216 PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
217
218 quit_thyself = false;
219 thread_func();
220 }
221
222
223 /*
224 * Vertical blank: Poll keyboard and joysticks, update window
225 */
226
227 void C64::VBlank(bool draw_frame)
228 {
229 // Poll keyboard
230 TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
231 if (TheDisplay->quit_requested)
232 quit_thyself = true;
233
234 // Poll joysticks
235 TheCIA1->Joystick1 = poll_joystick(0);
236 TheCIA1->Joystick2 = poll_joystick(1);
237
238 if (ThePrefs.JoystickSwap) {
239 uint8 tmp = TheCIA1->Joystick1;
240 TheCIA1->Joystick1 = TheCIA1->Joystick2;
241 TheCIA1->Joystick2 = tmp;
242 }
243
244 // Joystick keyboard emulation
245 if (TheDisplay->NumLock())
246 TheCIA1->Joystick1 &= joykey;
247 else
248 TheCIA1->Joystick2 &= joykey;
249
250 // Count TOD clocks
251 TheCIA1->CountTOD();
252 TheCIA2->CountTOD();
253
254 // Update window if needed
255 if (draw_frame) {
256 TheDisplay->Update();
257
258 // Calculate time between VBlanks, display speedometer
259 struct timeval tv;
260 gettimeofday(&tv, NULL);
261 if ((tv.tv_usec -= tv_start.tv_usec) < 0) {
262 tv.tv_usec += 1000000;
263 tv.tv_sec -= 1;
264 }
265 tv.tv_sec -= tv_start.tv_sec;
266 double elapsed_time = (double)tv.tv_sec * 1000000 + tv.tv_usec;
267 speed_index = 20000 / (elapsed_time + 1) * ThePrefs.SkipFrames * 100;
268
269 // Limit speed to 100% if desired
270 if ((speed_index > 100) && ThePrefs.LimitSpeed) {
271 Delay_usec((unsigned long)(ThePrefs.SkipFrames * 20000 - elapsed_time));
272 speed_index = 100;
273 }
274
275 gettimeofday(&tv_start, NULL);
276
277 TheDisplay->Speedometer((int)speed_index);
278 }
279 }
280
281
282 /*
283 * The emulation's main loop
284 */
285
286 void C64::thread_func(void)
287 {
288 int linecnt = 0;
289
290 #ifdef FRODO_SC
291 while (!quit_thyself) {
292
293 // The order of calls is important here
294 if (TheVIC->EmulateCycle())
295 TheSID->EmulateLine();
296 TheCIA1->CheckIRQs();
297 TheCIA2->CheckIRQs();
298 TheCIA1->EmulateCycle();
299 TheCIA2->EmulateCycle();
300 TheCPU->EmulateCycle();
301
302 if (ThePrefs.Emul1541Proc) {
303 TheCPU1541->CountVIATimers(1);
304 if (!TheCPU1541->Idle)
305 TheCPU1541->EmulateCycle();
306 }
307 CycleCounter++;
308 #else
309 while (!quit_thyself) {
310
311 // The order of calls is important here
312 int cycles = TheVIC->EmulateLine();
313 TheSID->EmulateLine();
314 #if !PRECISE_CIA_CYCLES
315 TheCIA1->EmulateLine(ThePrefs.CIACycles);
316 TheCIA2->EmulateLine(ThePrefs.CIACycles);
317 #endif
318
319 if (ThePrefs.Emul1541Proc) {
320 int cycles_1541 = ThePrefs.FloppyCycles;
321 TheCPU1541->CountVIATimers(cycles_1541);
322
323 if (!TheCPU1541->Idle) {
324 // 1541 processor active, alternately execute
325 // 6502 and 6510 instructions until both have
326 // used up their cycles
327 while (cycles >= 0 || cycles_1541 >= 0)
328 if (cycles > cycles_1541)
329 cycles -= TheCPU->EmulateLine(1);
330 else
331 cycles_1541 -= TheCPU1541->EmulateLine(1);
332 } else
333 TheCPU->EmulateLine(cycles);
334 } else
335 // 1541 processor disabled, only emulate 6510
336 TheCPU->EmulateLine(cycles);
337 #endif
338 linecnt++;
339 #if !defined(__svgalib__)
340 if ((linecnt & 0xfff) == 0 && gui) {
341
342 // check for command from GUI process
343 // fprintf(stderr,":");
344 while (gui->probe()) {
345 char c;
346 if (gui->eread(&c, 1) != 1) {
347 delete gui;
348 gui = 0;
349 fprintf(stderr,"Oops, GUI process died...\n");
350 } else {
351 // fprintf(stderr,"%c",c);
352 switch (c) {
353 case 'q':
354 quit_thyself = true;
355 break;
356 case 'r':
357 Reset();
358 break;
359 case 'p':{
360 Prefs *np = Frodo::reload_prefs();
361 NewPrefs(np);
362 ThePrefs = *np;
363 break;
364 }
365 default:
366 break;
367 }
368 }
369 }
370 }
371 #endif
372 }
373 #if !defined(__svgalib__)
374 if (gui) {
375 gui->ewrite("quit\n",5);
376 }
377 #endif
378 }