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 (13 years, 11 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

# Content
1 /*
2 * C64_x.h - Put the pieces together, X specific stuff
3 *
4 * Frodo Copyright (C) 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
133 void C64::c64_ctor2(void)
134 {
135 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
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 Delay_usec((unsigned long)(ThePrefs.SkipFrames * 20000 - elapsed_time));
225 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 }
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 }