ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Embedded.h
Revision: 1.2
Committed: 2010-04-21T22:00:13Z (12 years, 7 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -37 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 * 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 #ifdef FRODO_SC
236 while (!quit_thyself) {
237
238 // The order of calls is important here
239 if (TheVIC->EmulateCycle())
240 TheSID->EmulateLine();
241 TheCIA1->CheckIRQs();
242 TheCIA2->CheckIRQs();
243 TheCIA1->EmulateCycle();
244 TheCIA2->EmulateCycle();
245 TheCPU->EmulateCycle();
246
247 if (ThePrefs.Emul1541Proc) {
248 TheCPU1541->CountVIATimers(1);
249 if (!TheCPU1541->Idle)
250 TheCPU1541->EmulateCycle();
251 }
252 CycleCounter++;
253 #else
254 while (!quit_thyself) {
255
256 // The order of calls is important here
257 int cycles = TheVIC->EmulateLine();
258 TheSID->EmulateLine();
259 #if !PRECISE_CIA_CYCLES
260 TheCIA1->EmulateLine(ThePrefs.CIACycles);
261 TheCIA2->EmulateLine(ThePrefs.CIACycles);
262 #endif
263
264 if (ThePrefs.Emul1541Proc) {
265 int cycles_1541 = ThePrefs.FloppyCycles;
266 TheCPU1541->CountVIATimers(cycles_1541);
267
268 if (!TheCPU1541->Idle) {
269 // 1541 processor active, alternately execute
270 // 6502 and 6510 instructions until both have
271 // used up their cycles
272 while (cycles >= 0 || cycles_1541 >= 0)
273 if (cycles > cycles_1541)
274 cycles -= TheCPU->EmulateLine(1);
275 else
276 cycles_1541 -= TheCPU1541->EmulateLine(1);
277 } else
278 TheCPU->EmulateLine(cycles);
279 } else
280 // 1541 processor disabled, only emulate 6510
281 TheCPU->EmulateLine(cycles);
282 #endif
283 }
284 }