ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/C64_Amiga.h
Revision: 1.4
Committed: 2004-01-12T15:13:20Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.3: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * C64_Amiga.h - Put the pieces together, Amiga specific stuff
3 *
4 * Frodo (C) 1994-1997,2002-2004 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 <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 void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2)
231 {
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 }