ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Amiga.h
Revision: 1.5
Committed: 2005-06-27T19:55:48Z (19 years, 3 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_Amiga.h - Put the pieces together, Amiga 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 <proto/exec.h>
22     #include <proto/timer.h>
23    
24    
25     // Library bases
26     struct Device *TimerBase;
27    
28    
29     /*
30     * Constructor, system-dependent things
31     */
32    
33     void C64::c64_ctor1(void)
34     {
35     // Open game_io
36     game_port = CreateMsgPort();
37     game_io = (struct IOStdReq *)CreateIORequest(game_port, sizeof(IOStdReq));
38     game_io->io_Message.mn_Node.ln_Type = NT_UNKNOWN;
39     game_open = port_allocated = false;
40     if (!OpenDevice("gameport.device", 1, (struct IORequest *)game_io, 0))
41     game_open = true;
42     }
43    
44     void C64::c64_ctor2(void)
45     {
46     // Initialize joystick variables
47     joy_state = 0xff;
48    
49     // Open timer_io
50     timer_port = CreateMsgPort();
51     timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
52     OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0);
53    
54     // Get timer base
55     TimerBase = timer_io->tr_node.io_Device;
56    
57     // Preset speedometer start time
58     GetSysTime(&start_time);
59     }
60    
61    
62     /*
63     * Destructor, system-dependent things
64     */
65    
66     void C64::c64_dtor(void)
67     {
68     // Stop and delete timer_io
69     if (timer_io != NULL) {
70     if (!CheckIO((struct IORequest *)timer_io))
71     WaitIO((struct IORequest *)timer_io);
72     CloseDevice((struct IORequest *)timer_io);
73     DeleteIORequest((struct IORequest *)timer_io);
74     }
75    
76     if (timer_port != NULL)
77     DeleteMsgPort(timer_port);
78    
79     if (game_open) {
80     if (!CheckIO((struct IORequest *)game_io)) {
81     AbortIO((struct IORequest *)game_io);
82     WaitIO((struct IORequest *)game_io);
83     }
84     CloseDevice((struct IORequest *)game_io);
85     }
86    
87     if (game_io != NULL)
88     DeleteIORequest((struct IORequest *)game_io);
89    
90     if (game_port != NULL)
91     DeleteMsgPort(game_port);
92     }
93    
94    
95     /*
96     * Start emulation
97     */
98    
99     void C64::Run(void)
100     {
101     // Reset chips
102     TheCPU->Reset();
103     TheSID->Reset();
104     TheCIA1->Reset();
105     TheCIA2->Reset();
106     TheCPU1541->Reset();
107    
108     // Patch kernal IEC routines
109     orig_kernal_1d84 = Kernal[0x1d84];
110     orig_kernal_1d85 = Kernal[0x1d85];
111     PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
112    
113     // Start timer_io
114     timer_io->tr_node.io_Command = TR_ADDREQUEST;
115     timer_io->tr_time.tv_secs = 0;
116     timer_io->tr_time.tv_micro = ThePrefs.SkipFrames * 20000; // 20ms per frame
117     SendIO((struct IORequest *)timer_io);
118    
119     // Start the CPU thread
120     thread_running = true;
121     quit_thyself = false;
122     have_a_break = false;
123     thread_func();
124     }
125    
126    
127     /*
128     * Stop emulation
129     */
130    
131     void C64::Quit(void)
132     {
133     // Ask the thread to quit itself if it is running
134     if (thread_running) {
135     quit_thyself = true;
136     thread_running = false;
137     }
138     }
139    
140    
141     /*
142     * Pause emulation
143     */
144    
145     void C64::Pause(void)
146     {
147     TheSID->PauseSound();
148     }
149    
150    
151     /*
152     * Resume emulation
153     */
154    
155     void C64::Resume(void)
156     {
157     TheSID->ResumeSound();
158     }
159    
160    
161     /*
162     * Vertical blank: Poll keyboard and joysticks, update window
163     */
164    
165     void C64::VBlank(bool draw_frame)
166     {
167     struct timeval end_time;
168     long speed_index;
169    
170     // Poll keyboard
171     TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
172    
173     // Poll joysticks
174     TheCIA1->Joystick1 = poll_joystick(0);
175     TheCIA1->Joystick2 = poll_joystick(1);
176    
177     if (ThePrefs.JoystickSwap) {
178     uint8 tmp = TheCIA1->Joystick1;
179     TheCIA1->Joystick1 = TheCIA1->Joystick2;
180     TheCIA1->Joystick2 = tmp;
181     }
182    
183     // Joystick keyboard emulation
184     if (TheDisplay->NumLock())
185     TheCIA1->Joystick1 &= joykey;
186     else
187     TheCIA1->Joystick2 &= joykey;
188    
189     // Count TOD clocks
190     TheCIA1->CountTOD();
191     TheCIA2->CountTOD();
192    
193     // Update window if needed
194     if (draw_frame) {
195     TheDisplay->Update();
196    
197     // Calculate time between VBlanks, display speedometer
198     GetSysTime(&end_time);
199     SubTime(&end_time, &start_time);
200     speed_index = 20000 * 100 * ThePrefs.SkipFrames / (end_time.tv_micro + 1);
201    
202     // Abort timer_io if speed limiter is off
203     if (!ThePrefs.LimitSpeed) {
204     if (!CheckIO((struct IORequest *)timer_io))
205     AbortIO((struct IORequest *)timer_io);
206     } else if (speed_index > 100)
207     speed_index = 100;
208    
209     // Wait for timer_io (limit speed)
210     WaitIO((struct IORequest *)timer_io);
211    
212     // Restart timer_io
213     timer_io->tr_node.io_Command = TR_ADDREQUEST;
214     timer_io->tr_time.tv_secs = 0;
215     timer_io->tr_time.tv_micro = ThePrefs.SkipFrames * 20000; // 20ms per frame
216     SendIO((struct IORequest *)timer_io);
217    
218     GetSysTime(&start_time);
219    
220     TheDisplay->Speedometer(speed_index);
221     }
222     }
223    
224    
225     /*
226     * Open/close joystick drivers given old and new state of
227     * joystick preferences
228     */
229    
230 cebix 1.3 void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
231 cebix 1.1 {
232     if (game_open && (oldjoy2 != newjoy2))
233    
234     if (newjoy2) { // Open joystick
235     joy_state = 0xff;
236     port_allocated = false;
237    
238     // Allocate game port
239     BYTE ctype;
240     Forbid();
241     game_io->io_Command = GPD_ASKCTYPE;
242     game_io->io_Data = &ctype;
243     game_io->io_Length = 1;
244     DoIO((struct IORequest *)game_io);
245    
246     if (ctype != GPCT_NOCONTROLLER)
247     Permit();
248     else {
249     ctype = GPCT_ABSJOYSTICK;
250     game_io->io_Command = GPD_SETCTYPE;
251     game_io->io_Data = &ctype;
252     game_io->io_Length = 1;
253     DoIO((struct IORequest *)game_io);
254     Permit();
255    
256     port_allocated = true;
257    
258     // Set trigger conditions
259     game_trigger.gpt_Keys = GPTF_UPKEYS | GPTF_DOWNKEYS;
260     game_trigger.gpt_Timeout = 65535;
261     game_trigger.gpt_XDelta = 1;
262     game_trigger.gpt_YDelta = 1;
263     game_io->io_Command = GPD_SETTRIGGER;
264     game_io->io_Data = &game_trigger;
265     game_io->io_Length = sizeof(struct GamePortTrigger);
266     DoIO((struct IORequest *)game_io);
267    
268     // Flush device buffer
269     game_io->io_Command = CMD_CLEAR;
270     DoIO((struct IORequest *)game_io);
271    
272     // Start reading joystick events
273     game_io->io_Command = GPD_READEVENT;
274     game_io->io_Data = &game_event;
275     game_io->io_Length = sizeof(struct InputEvent);
276     SendIO((struct IORequest *)game_io);
277     }
278    
279     } else { // Close joystick
280    
281     // Abort game_io
282     if (!CheckIO((struct IORequest *)game_io)) {
283     AbortIO((struct IORequest *)game_io);
284     WaitIO((struct IORequest *)game_io);
285     }
286    
287     // Free game port
288     if (port_allocated) {
289     BYTE ctype = GPCT_NOCONTROLLER;
290     game_io->io_Command = GPD_SETCTYPE;
291     game_io->io_Data = &ctype;
292     game_io->io_Length = 1;
293     DoIO((struct IORequest *)game_io);
294    
295     port_allocated = false;
296     }
297     }
298     }
299    
300    
301     /*
302     * Poll joystick port, return CIA mask
303     */
304    
305     uint8 C64::poll_joystick(int port)
306     {
307     if (port == 0)
308     return 0xff;
309    
310     if (game_open && port_allocated) {
311    
312     // Joystick event arrived?
313     while (GetMsg(game_port) != NULL) {
314    
315     // Yes, analyze event
316     switch (game_event.ie_Code) {
317     case IECODE_LBUTTON: // Button pressed
318     joy_state &= 0xef;
319     break;
320    
321     case IECODE_LBUTTON | IECODE_UP_PREFIX: // Button released
322     joy_state |= 0x10;
323     break;
324    
325     case IECODE_NOBUTTON: // Joystick moved
326     if (game_event.ie_X == 1)
327     joy_state &= 0xf7; // Right
328     if (game_event.ie_X == -1)
329     joy_state &= 0xfb; // Left
330     if (game_event.ie_X == 0)
331     joy_state |= 0x0c;
332     if (game_event.ie_Y == 1)
333     joy_state &= 0xfd; // Down
334     if (game_event.ie_Y == -1)
335     joy_state &= 0xfe; // Up
336     if (game_event.ie_Y == 0)
337     joy_state |= 0x03;
338     break;
339     }
340    
341     // Start reading the next event
342     game_io->io_Command = GPD_READEVENT;
343     game_io->io_Data = &game_event;
344     game_io->io_Length = sizeof(struct InputEvent);
345     SendIO((struct IORequest *)game_io);
346     }
347     return joy_state;
348    
349     } else
350     return 0xff;
351     }
352    
353    
354     /*
355     * The emulation's main loop
356     */
357    
358     void C64::thread_func(void)
359     {
360     while (!quit_thyself) {
361    
362     #ifdef FRODO_SC
363     // The order of calls is important here
364     if (TheVIC->EmulateCycle())
365     TheSID->EmulateLine();
366     TheCIA1->CheckIRQs();
367     TheCIA2->CheckIRQs();
368     TheCIA1->EmulateCycle();
369     TheCIA2->EmulateCycle();
370     TheCPU->EmulateCycle();
371    
372     if (ThePrefs.Emul1541Proc) {
373     TheCPU1541->CountVIATimers(1);
374     if (!TheCPU1541->Idle)
375     TheCPU1541->EmulateCycle();
376     }
377     CycleCounter++;
378     #else
379     // The order of calls is important here
380     int cycles = TheVIC->EmulateLine();
381     TheSID->EmulateLine();
382     #if !PRECISE_CIA_CYCLES
383     TheCIA1->EmulateLine(ThePrefs.CIACycles);
384     TheCIA2->EmulateLine(ThePrefs.CIACycles);
385     #endif
386    
387     if (ThePrefs.Emul1541Proc) {
388     int cycles_1541 = ThePrefs.FloppyCycles;
389     TheCPU1541->CountVIATimers(cycles_1541);
390    
391     if (!TheCPU1541->Idle) {
392     // 1541 processor active, alternately execute
393     // 6502 and 6510 instructions until both have
394     // used up their cycles
395     while (cycles >= 0 || cycles_1541 >= 0)
396     if (cycles > cycles_1541)
397     cycles -= TheCPU->EmulateLine(1);
398     else
399     cycles_1541 -= TheCPU1541->EmulateLine(1);
400     } else
401     TheCPU->EmulateLine(cycles);
402     } else
403     // 1541 processor disabled, only emulate 6510
404     TheCPU->EmulateLine(cycles);
405     #endif
406     }
407     }