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