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

# User Rev Content
1 cebix 1.1 /*
2     * C64_Be.h - Put the pieces together, Be specific stuff
3     *
4 cebix 1.5 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 cebix 1.1 *
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 cebix 1.3 #include <device/DigitalPort.h>
24 cebix 1.1
25     #undef PROFILING
26    
27    
28     /*
29     * Constructor, system-dependent things
30     */
31    
32     void C64::c64_ctor1(void)
33     {
34 cebix 1.3 joy[0] = joy[1] = NULL;
35     joy_geek_port[0] = joy_geek_port[1] = false;
36 cebix 1.1 }
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 cebix 1.3 void C64::open_close_joystick(int port, int oldjoy, int newjoy)
226 cebix 1.1 {
227 cebix 1.3 if (oldjoy != newjoy) {
228 cebix 1.1 joy_minx = joy_miny = 32767; // Reset calibration
229     joy_maxx = joy_maxy = 0;
230 cebix 1.3 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 cebix 1.1 }
263 cebix 1.3 }
264 cebix 1.1
265 cebix 1.3 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 cebix 1.1 }
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 cebix 1.3 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 cebix 1.1 }
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     }