ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Be.h
Revision: 1.1
Committed: 2003-07-01T17:28:51Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Log Message:
imported files

File Contents

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