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

# Content
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 }