ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Be.h
Revision: 1.5
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.4: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * C64_Be.h - Put the pieces together, Be specific stuff
3 *
4 * Frodo (C) 1994-1997,2002-2005 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 <KernelKit.h>
22 #include <device/Joystick.h>
23 #include <device/DigitalPort.h>
24
25 #undef PROFILING
26
27
28 /*
29 * Constructor, system-dependent things
30 */
31
32 void C64::c64_ctor1(void)
33 {
34 joy[0] = joy[1] = NULL;
35 joy_geek_port[0] = joy_geek_port[1] = false;
36 }
37
38 void C64::c64_ctor2(void)
39 {
40 // Initialize joystick variables
41 joy_minx = joy_miny = 32767;
42 joy_maxx = joy_maxy = 0;
43
44 // Initialize semaphores (initially acquired)
45 pause_sem = create_sem(0, "Frodo Pause Semaphore");
46 sound_sync_sem = create_sem(0, "Frodo Sound Sync Semaphore");
47
48 // Preset speedometer start time
49 start_time = system_time();
50 }
51
52
53 /*
54 * Destructor, system-dependent things
55 */
56
57 void C64::c64_dtor(void)
58 {
59 delete_sem(pause_sem);
60 delete_sem(sound_sync_sem);
61 }
62
63
64 /*
65 * Start main emulation thread
66 */
67
68 void C64::Run(void)
69 {
70 // Reset chips
71 TheCPU->Reset();
72 TheSID->Reset();
73 TheCIA1->Reset();
74 TheCIA2->Reset();
75 TheCPU1541->Reset();
76
77 // Patch kernal IEC routines
78 orig_kernal_1d84 = Kernal[0x1d84];
79 orig_kernal_1d85 = Kernal[0x1d85];
80 PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
81
82 // Start the CPU thread
83 the_thread = spawn_thread(thread_invoc, "Frodo 6510", B_URGENT_DISPLAY_PRIORITY, this);
84 thread_running = true;
85 quit_thyself = false;
86 have_a_break = false;
87 resume_thread(the_thread);
88 }
89
90
91 /*
92 * Stop main emulation thread
93 */
94
95 void C64::Quit(void)
96 {
97 long ret;
98
99 // Ask the thread to quit itself if it is running
100 if (thread_running) {
101 if (have_a_break)
102 Resume();
103 quit_thyself = true;
104 wait_for_thread(the_thread, &ret);
105 thread_running = false;
106 }
107 }
108
109
110 /*
111 * Pause main emulation thread
112 */
113
114 void C64::Pause(void)
115 {
116 // Ask the thread to pause and wait for acknowledge
117 if (thread_running && !have_a_break) {
118 have_a_break = true;
119 acquire_sem(pause_sem);
120 TheSID->PauseSound();
121 }
122 }
123
124
125 /*
126 * Resume main emulation thread
127 */
128
129 void C64::Resume(void)
130 {
131 if (thread_running && have_a_break) {
132 have_a_break = false;
133 release_sem(pause_sem);
134 TheSID->ResumeSound();
135 }
136 }
137
138
139 /*
140 * Vertical blank: Poll keyboard and joysticks, update window
141 */
142
143 void C64::VBlank(bool draw_frame)
144 {
145 bigtime_t elapsed_time;
146 long speed_index;
147
148 // To avoid deadlocks on quitting
149 if (quit_thyself) return;
150
151 // Pause requested?
152 if (have_a_break) {
153 release_sem(pause_sem); // Acknowledge pause
154 acquire_sem(pause_sem); // Wait for resume
155 }
156
157 // Poll keyboard
158 TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
159
160 // Poll joysticks
161 TheCIA1->Joystick1 = poll_joystick(0);
162 TheCIA1->Joystick2 = poll_joystick(1);
163
164 if (ThePrefs.JoystickSwap) {
165 uint8 tmp = TheCIA1->Joystick1;
166 TheCIA1->Joystick1 = TheCIA1->Joystick2;
167 TheCIA1->Joystick2 = tmp;
168 }
169
170 // Joystick keyboard emulation
171 if (TheDisplay->NumLock())
172 TheCIA1->Joystick1 &= joykey;
173 else
174 TheCIA1->Joystick2 &= joykey;
175
176 // Count TOD clocks
177 TheCIA1->CountTOD();
178 TheCIA2->CountTOD();
179
180 // Update window if needed
181 if (draw_frame) {
182 TheDisplay->Update();
183
184 // Calculate time between VBlanks, display speedometer
185 elapsed_time = system_time() - start_time;
186 speed_index = 20000 * 100 * ThePrefs.SkipFrames / (elapsed_time + 1);
187
188 // Limit speed to 100% if desired (20ms/frame)
189 // If the SID emulation is on and no frames are skipped, synchronize to the SID
190 if (ThePrefs.LimitSpeed && speed_index > 100) {
191 if (ThePrefs.SIDType == SIDTYPE_DIGITAL && ThePrefs.SkipFrames == 1) {
192 long l;
193 get_sem_count(sound_sync_sem, &l);
194 if (l > 0) // Avoid C64 lagging behind
195 acquire_sem_etc(sound_sync_sem, l+1, 0, 0);
196 else
197 acquire_sem(sound_sync_sem);
198 } else
199 snooze(ThePrefs.SkipFrames * 20000 - elapsed_time);
200 speed_index = 100;
201 }
202
203 start_time = system_time();
204
205 TheDisplay->Speedometer(speed_index);
206 }
207 }
208
209
210 /*
211 * Called by SID after playing 1/50 sec of sound
212 */
213
214 void C64::SoundSync(void)
215 {
216 release_sem(sound_sync_sem);
217 }
218
219
220 /*
221 * Open/close joystick drivers given old and new state of
222 * joystick preferences
223 */
224
225 void C64::open_close_joystick(int port, int oldjoy, int newjoy)
226 {
227 if (oldjoy != newjoy) {
228 joy_minx = joy_miny = 32767; // Reset calibration
229 joy_maxx = joy_maxy = 0;
230 if (joy[port]) {
231 if (joy_geek_port[port]) {
232 ((BDigitalPort *)joy[port])->Close();
233 delete (BDigitalPort *)joy[port];
234 } else {
235 ((BJoystick *)joy[port])->Close();
236 delete (BJoystick *)joy[port];
237 }
238 joy[port] = NULL;
239 }
240 switch (newjoy) {
241 case 1:
242 joy[port] = new BJoystick;
243 ((BJoystick *)joy[port])->Open("joystick1");
244 joy_geek_port[port] = false;
245 break;
246 case 2:
247 joy[port] = new BJoystick;
248 ((BJoystick *)joy[port])->Open("joystick2");
249 joy_geek_port[port] = false;
250 break;
251 case 3:
252 joy[port] = new BDigitalPort;
253 ((BDigitalPort *)joy[port])->Open("DigitalA");
254 joy_geek_port[port] = true;
255 break;
256 case 4:
257 joy[port] = new BDigitalPort;
258 ((BDigitalPort *)joy[port])->Open("DigitalB");
259 joy_geek_port[port] = true;
260 break;
261 }
262 }
263 }
264
265 void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
266 {
267 open_close_joystick(0, oldjoy1, newjoy1);
268 open_close_joystick(1, oldjoy2, newjoy2);
269 }
270
271
272 /*
273 * Poll joystick port, return CIA mask
274 */
275
276 uint8 C64::poll_joystick(int port)
277 {
278 uint8 j = 0xff;
279
280 if (joy[port] == NULL)
281 return j;
282
283 if (joy_geek_port[port]) {
284
285 // GeekPort
286 uint8 val;
287 if (((BDigitalPort *)joy[port])->Read(&val) == 1)
288 j = val | 0xe0;
289
290 } else {
291
292 // Joystick port
293 BJoystick *p = (BJoystick *)joy[port];
294 if (p->Update() != B_ERROR) {
295 if (p->horizontal > joy_maxx)
296 joy_maxx = p->horizontal;
297 if (p->horizontal < joy_minx)
298 joy_minx = p->horizontal;
299 if (p->vertical > joy_maxy)
300 joy_maxy = p->vertical;
301 if (p->vertical < joy_miny)
302 joy_miny = p->vertical;
303
304 if (!p->button1)
305 j &= 0xef; // Button
306
307 if (joy_maxx-joy_minx < 100 || joy_maxy-joy_miny < 100)
308 return j;
309
310 if (p->horizontal < (joy_minx + (joy_maxx-joy_minx)/3))
311 j &= 0xf7; // Right
312 else if (p->horizontal > (joy_minx + 2*(joy_maxx-joy_minx)/3))
313 j &= 0xfb; // Left
314
315 if (p->vertical < (joy_miny + (joy_maxy-joy_miny)/3))
316 j &= 0xfd; // Down
317 else if (p->vertical > (joy_miny + 2*(joy_maxy-joy_miny)/3))
318 j &= 0xfe; // Up
319 }
320 }
321 return j;
322 }
323
324
325 /*
326 * The emulation's main loop
327 */
328
329 long C64::thread_invoc(void *obj)
330 {
331 ((C64 *)obj)->thread_func();
332 return 0;
333 }
334
335 void C64::thread_func(void)
336 {
337 #ifdef PROFILING
338 static bigtime_t vic_time_acc = 0;
339 static bigtime_t sid_time_acc = 0;
340 static bigtime_t cia_time_acc = 0;
341 static bigtime_t cpu_time_acc = 0;
342 #endif
343 #ifdef FRODO_SC
344 while (!quit_thyself) {
345 // The order of calls is important here
346 if (TheVIC->EmulateCycle())
347 TheSID->EmulateLine();
348 TheCIA1->CheckIRQs();
349 TheCIA2->CheckIRQs();
350 TheCIA1->EmulateCycle();
351 TheCIA2->EmulateCycle();
352 TheCPU->EmulateCycle();
353
354 if (ThePrefs.Emul1541Proc) {
355 TheCPU1541->CountVIATimers(1);
356 if (!TheCPU1541->Idle)
357 TheCPU1541->EmulateCycle();
358 }
359 CycleCounter++;
360 #else
361 while (!quit_thyself) {
362 // The order of calls is important here
363 #ifdef PROFILING
364 bigtime_t start_time = system_time();
365 #endif
366 int cycles = TheVIC->EmulateLine();
367 #ifdef PROFILING
368 bigtime_t vic_time = system_time();
369 #endif
370 TheSID->EmulateLine();
371 #ifdef PROFILING
372 bigtime_t sid_time = system_time();
373 #endif
374 #if !PRECISE_CIA_CYCLES
375 TheCIA1->EmulateLine(ThePrefs.CIACycles);
376 TheCIA2->EmulateLine(ThePrefs.CIACycles);
377 #endif
378 #ifdef PROFILING
379 bigtime_t cia_time = system_time();
380 #endif
381
382 if (ThePrefs.Emul1541Proc) {
383 int cycles_1541 = ThePrefs.FloppyCycles;
384 TheCPU1541->CountVIATimers(cycles_1541);
385
386 if (!TheCPU1541->Idle) {
387 // 1541 processor active, alternately execute
388 // 6502 and 6510 instructions until both have
389 // used up their cycles
390 while (cycles >= 0 || cycles_1541 >= 0)
391 if (cycles > cycles_1541)
392 cycles -= TheCPU->EmulateLine(1);
393 else
394 cycles_1541 -= TheCPU1541->EmulateLine(1);
395 } else
396 TheCPU->EmulateLine(cycles);
397 } else
398 // 1541 processor disabled, only emulate 6510
399 TheCPU->EmulateLine(cycles);
400 #ifdef PROFILING
401 bigtime_t cpu_time = system_time();
402 vic_time_acc += vic_time - start_time;
403 sid_time_acc += sid_time - vic_time;
404 cia_time_acc += cia_time - sid_time;
405 cpu_time_acc += cpu_time - cia_time;
406 #endif
407
408 #endif
409 }
410
411 #ifdef PROFILING
412 bigtime_t total_time = vic_time_acc + sid_time_acc + cia_time_acc + cpu_time_acc;
413 printf("VIC: %Ld\n", vic_time_acc * 100 / total_time);
414 printf("SID: %Ld\n", sid_time_acc * 100 / total_time);
415 printf("CIA: %Ld\n", cia_time_acc * 100 / total_time);
416 printf("CPU: %Ld\n", cpu_time_acc * 100 / total_time);
417 #endif
418 }