ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Embedded.h
Revision: 1.1
Committed: 2007-01-28T19:18:11Z (17 years, 2 months ago) by berlac
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 berlac 1.1 /*
2     * C64_x.h - Put the pieces together, X specific stuff
3     *
4     * Frodo (C) 1994-1997,2002-2004 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     * Constructor, system-dependent things
121     */
122    
123     void C64::c64_ctor1(void)
124     {
125     // Initialize joystick variables
126     joy_minx[0] = joy_miny[0] = 32767;
127     joy_maxx[0] = joy_maxy[0] = -32768;
128     joy_minx[1] = joy_miny[1] = 32767;
129     joy_maxx[1] = joy_maxy[1] = -32768;
130     }
131    
132     void C64::c64_ctor2(void)
133     {
134     gettimeofday(&tv_start, NULL);
135     }
136    
137    
138     /*
139     * Destructor, system-dependent things
140     */
141    
142     void C64::c64_dtor(void)
143     {
144     }
145    
146    
147     /*
148     * Start main emulation thread
149     */
150    
151     void C64::Run(void)
152     {
153     // Reset chips
154     TheCPU->Reset();
155     TheSID->Reset();
156     TheCIA1->Reset();
157     TheCIA2->Reset();
158     TheCPU1541->Reset();
159    
160     // Patch kernal IEC routines
161     orig_kernal_1d84 = Kernal[0x1d84];
162     orig_kernal_1d85 = Kernal[0x1d85];
163     PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
164    
165     quit_thyself = false;
166     thread_func();
167     }
168    
169    
170     /*
171     * Vertical blank: Poll keyboard and joysticks, update window
172     */
173    
174     void C64::VBlank(bool draw_frame)
175     {
176     // Poll keyboard
177     TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
178     if (TheDisplay->quit_requested)
179     quit_thyself = true;
180    
181     // Poll joysticks
182     TheCIA1->Joystick1 = poll_joystick(0);
183     TheCIA1->Joystick2 = poll_joystick(1);
184    
185     if (ThePrefs.JoystickSwap) {
186     uint8 tmp = TheCIA1->Joystick1;
187     TheCIA1->Joystick1 = TheCIA1->Joystick2;
188     TheCIA1->Joystick2 = tmp;
189     }
190    
191     // Joystick keyboard emulation
192     if (TheDisplay->NumLock())
193     TheCIA1->Joystick1 &= joykey;
194     else
195     TheCIA1->Joystick2 &= joykey;
196    
197     // Count TOD clocks
198     TheCIA1->CountTOD();
199     TheCIA2->CountTOD();
200    
201     // Update window if needed
202     if (draw_frame) {
203     TheDisplay->Update();
204    
205     // Calculate time between VBlanks, display speedometer
206     struct timeval tv;
207     gettimeofday(&tv, NULL);
208     if ((tv.tv_usec -= tv_start.tv_usec) < 0) {
209     tv.tv_usec += 1000000;
210     tv.tv_sec -= 1;
211     }
212     tv.tv_sec -= tv_start.tv_sec;
213     double elapsed_time = (double)tv.tv_sec * 1000000 + tv.tv_usec;
214     speed_index = 20000 / (elapsed_time + 1) * ThePrefs.SkipFrames * 100;
215    
216     // Limit speed to 100% if desired
217     if ((speed_index > 100) && ThePrefs.LimitSpeed) {
218     Delay_usec((unsigned long)(ThePrefs.SkipFrames * 20000 - elapsed_time));
219     speed_index = 100;
220     }
221    
222     gettimeofday(&tv_start, NULL);
223    
224     TheDisplay->Speedometer((int)speed_index);
225     }
226     }
227    
228    
229     /*
230     * The emulation's main loop
231     */
232    
233     void C64::thread_func(void)
234     {
235     int linecnt = 0;
236    
237     #ifdef FRODO_SC
238     while (!quit_thyself) {
239    
240     // The order of calls is important here
241     if (TheVIC->EmulateCycle())
242     TheSID->EmulateLine();
243     TheCIA1->CheckIRQs();
244     TheCIA2->CheckIRQs();
245     TheCIA1->EmulateCycle();
246     TheCIA2->EmulateCycle();
247     TheCPU->EmulateCycle();
248    
249     if (ThePrefs.Emul1541Proc) {
250     TheCPU1541->CountVIATimers(1);
251     if (!TheCPU1541->Idle)
252     TheCPU1541->EmulateCycle();
253     }
254     CycleCounter++;
255     #else
256     while (!quit_thyself) {
257    
258     // The order of calls is important here
259     int cycles = TheVIC->EmulateLine();
260     TheSID->EmulateLine();
261     #if !PRECISE_CIA_CYCLES
262     TheCIA1->EmulateLine(ThePrefs.CIACycles);
263     TheCIA2->EmulateLine(ThePrefs.CIACycles);
264     #endif
265    
266     if (ThePrefs.Emul1541Proc) {
267     int cycles_1541 = ThePrefs.FloppyCycles;
268     TheCPU1541->CountVIATimers(cycles_1541);
269    
270     if (!TheCPU1541->Idle) {
271     // 1541 processor active, alternately execute
272     // 6502 and 6510 instructions until both have
273     // used up their cycles
274     while (cycles >= 0 || cycles_1541 >= 0)
275     if (cycles > cycles_1541)
276     cycles -= TheCPU->EmulateLine(1);
277     else
278     cycles_1541 -= TheCPU1541->EmulateLine(1);
279     } else
280     TheCPU->EmulateLine(cycles);
281     } else
282     // 1541 processor disabled, only emulate 6510
283     TheCPU->EmulateLine(cycles);
284     #endif
285     linecnt++;
286     #if !defined(__svgalib__)
287     if ((linecnt & 0xfff) == 0 && gui) {
288    
289     // check for command from GUI process
290     // fprintf(stderr,":");
291     while (gui->probe()) {
292     char c;
293     if (gui->eread(&c, 1) != 1) {
294     delete gui;
295     gui = 0;
296     fprintf(stderr,"Oops, GUI process died...\n");
297     } else {
298     // fprintf(stderr,"%c",c);
299     switch (c) {
300     case 'q':
301     quit_thyself = true;
302     break;
303     case 'r':
304     Reset();
305     break;
306     case 'p':{
307     Prefs *np = Frodo::reload_prefs();
308     NewPrefs(np);
309     ThePrefs = *np;
310     break;
311     }
312     default:
313     break;
314     }
315     }
316     }
317     }
318     #endif
319     }
320     }