ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_x.h
Revision: 1.9
Committed: 2010-04-21T21:59:24Z (12 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +25 -93 lines
Log Message:
removed Tcl/Tk GUI

File Contents

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