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

# User Rev Content
1 cebix 1.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     }