1 /*
2  * atari_ps2.c - Sony PlayStation 2 port code
3  *
4  * Copyright (c) 2005 Troy Ayers and Piotr Fusik
5  * Copyright (c) 2005-2014 Atari800 development team (see DOC/CREDITS)
6  *
7  * This file is part of the Atari800 emulator project which emulates
8  * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
9  *
10  * Atari800 is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Atari800 is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Atari800; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24 			//TODO: map the following keys
25 			//control <>: (suits)
26 			//akey_clear
27 			//AKEY_BREAK
28 			//all ALT+key shortcut keys
29 			//Atari OPTION key (temple of apshai, others?)
30 			//keyboard repeat (when shift nor control pressed)
31 			//mouse support
32 			//autodetect pal vs ntsc
33 			//allow user to map own keyboard keys to controller
34 			//enable cdfs, hdd, mass, and host support.
35 
36 #include "config.h"
37 #include <stdio.h>
38 #include <string.h>
39 #include <tamtypes.h>
40 #include <loadfile.h>
41 #include <fileio.h>
42 #include <sifcmd.h>
43 #include <sifrpc.h>
44 #include <kernel.h>
45 #include <debug.h>
46 #include <libmc.h>
47 #include <libkbd.h>
48 #include <libpad.h>
49 #include <gsKit.h>
50 #include <dmaKit.h>
51 
52 #include "atari.h"
53 #include "colours.h"
54 #include "input.h"
55 #include "akey.h"
56 #include "log.h"
57 #include "monitor.h"
58 #include "screen.h"
59 #include "ui.h"
60 #include "util.h"
61 
62 //#ifdef SOUND
63 #include <audsrv.h>
64 #include "pokeysnd.h"
65 #include "sound.h"
66 extern unsigned char audsrv[];
67 extern unsigned int size_audsrv;
68 //#endif
69 
70 // define to use T0 and T1 timers
71 #define USE_TIMERS
72 extern unsigned char usbd[];
73 extern unsigned int size_usbd;
74 
75 extern unsigned char ps2kbd[];
76 extern unsigned int size_ps2kbd;
77 
78 static GSGLOBAL *gsGlobal = NULL;
79 
80 static int clut[256] __attribute__((aligned(16)));
81 
82 //int PS2KbdCAPS = 0;
83 int PS2KbdSHIFT = 0;
84 int PS2KbdCONTROL = 0;
85 int PS2KbdALT = 0;
86 
87 #define PAD_PORT 0
88 #define PAD_SLOT 0
89 
90 static char padBuf[256] __attribute__((aligned(64)));
91 
92 #ifdef USE_TIMERS
93 
94 /* We use T0 for PLATFORM_Time() and T1 for PLATFORM_Sleep().
95    Note that both timers are just 16-bit. */
96 
97 #define T0_COUNT  (*(volatile unsigned long *) 0x10000000)
98 #define T0_MODE   (*(volatile unsigned long *) 0x10000010)
99 #define T0_COMP   (*(volatile unsigned long *) 0x10000020)
100 #define T1_COUNT  (*(volatile unsigned long *) 0x10000800)
101 #define T1_MODE   (*(volatile unsigned long *) 0x10000810)
102 #define T1_COMP   (*(volatile unsigned long *) 0x10000820)
103 
104 #define INTC_TIM0 9
105 #define INTC_TIM1 10
106 
107 static int t0_interrupt_id = -1;
108 static int t1_interrupt_id = -1;
109 
110 /* The range of int is enough for about 7 years
111    of continuous running. */
112 static volatile int timer_interrupt_ticks = 0;
113 
114 static int sleeping_thread_id = 0;
115 
t0_interrupt_handler(int ca)116 static int t0_interrupt_handler(int ca)
117 {
118 	timer_interrupt_ticks++;
119 	T0_MODE |= 0x800; // clear overflow status
120 	// __asm__ volatile("sync.l; ei"); // XXX: necessary?
121 	return -1; // XXX: or 0? what does it mean?
122 }
123 
t1_interrupt_handler(int ca)124 static int t1_interrupt_handler(int ca)
125 {
126 	iWakeupThread(sleeping_thread_id);
127 	T1_MODE = 0; // disable
128 	// __asm__ volatile("sync.l; ei"); // XXX: necessary?
129 	return -1; // XXX: or 0? what does it mean?
130 }
131 
timer_initialize(void)132 static void timer_initialize(void)
133 {
134 	T0_MODE = 0; // disable
135 	t0_interrupt_id = AddIntcHandler(INTC_TIM0, t0_interrupt_handler, 0);
136 	EnableIntc(INTC_TIM0);
137 	T0_COUNT = 0;
138 	T0_MODE = 0x002  // 576000 Hz clock
139 			+ 0x080  // start counting
140 			+ 0x200; // generate interrupt on overflow
141 
142 	T1_MODE = 0; // disable
143 	t1_interrupt_id = AddIntcHandler(INTC_TIM1, t1_interrupt_handler, 0);
144 	EnableIntc(INTC_TIM1);
145 }
146 
timer_shutdown(void)147 static void timer_shutdown(void)
148 {
149 	T0_MODE = 0;
150 	if (t0_interrupt_id >= 0) {
151 		DisableIntc(INTC_TIM0);
152 		RemoveIntcHandler(INTC_TIM0, t0_interrupt_id);
153 		t0_interrupt_id = -1;
154 	}
155 	T1_MODE = 0;
156 	if (t1_interrupt_id >= 0) {
157 		DisableIntc(INTC_TIM1);
158 		RemoveIntcHandler(INTC_TIM1, t1_interrupt_id);
159 		t1_interrupt_id = -1;
160 	}
161 }
162 
163 #endif /* USE_TIMERS */
164 
PLATFORM_Time(void)165 double PLATFORM_Time(void)
166 {
167 #ifdef USE_TIMERS
168 	/* AFAIK, multiplication is faster than division,
169 	   on every CPU architecture */
170 	return (timer_interrupt_ticks * 65536.0 + T0_COUNT) * (1.0 / 576000);
171 #else
172 	static double fake_timer = 0;
173 	return fake_timer++;
174 #endif
175 }
176 
177 /* this PLATFORM_Sleep() supports times only up to 0.11 sec,
178    which is enough for Atari800 purposes */
179 
180 /* void PLATFORM_Sleep(double s)
181 {
182 #ifdef USE_TIMERS
183 	unsigned long count = 65536 - (unsigned long) (s * 576000);
184 	// do nothing if s is less than one T1 tick
185 	if (count >= 65536)
186 		return;
187 	sleeping_thread_id = GetThreadId();
188 	T1_COUNT = count;
189 	T1_MODE = 0x002  // 576000 Hz clock
190 			+ 0x080  // start counting
191 			+ 0x200; // generate interrupt on overflow
192 //	SleepThread();
193 #endif
194 }
195 */
196 //volatile int locked = 1;
197 
198 //void wakeup(s32 id, u16 time, void *arg)
199 //{
200 //        locked = 0;
201 //}
202 //
203 //void PLATFORM_Sleep(double s)
204 //{
205 //
206 //        /* 15734 is around 1 second on NTSC */
207 //	/* is about 1ms? */
208 //        SetAlarm(15734 * s, wakeup, 0);
209 //        while (locked);
210 //	locked = 1;
211 //}
PLATFORM_Sleep(double s)212 void PLATFORM_Sleep(double s)
213 {
214 
215 	if (UI_is_active){
216 	        int i,ret;
217 	        for (i=0;i<s * 100.0;i++){
218 
219 			ee_sema_t sema;
220 	                sema.attr = 0;
221 	                sema.count = 0;
222 	                sema.init_count = 0;
223 	                sema.max_count = 1;
224 	                ret = CreateSema(&sema);
225 	                if (ret <= 0) {
226 	                        //could not create sema, strange!  continue anyway.
227 	                        return;
228 	                }
229 
230 	                iSignalSema(ret);
231 	                WaitSema(ret);
232 	                DeleteSema(ret);
233 	        }
234 	}
235 }
236 
237 
loadModules(void)238 void loadModules(void)
239 {
240 	int ret;
241 	//init_scr();
242 
243 	ret = SifLoadModule("rom0:SIO2MAN", 0, NULL);
244 	if (ret < 0) {
245 		Log_print("Sio2man loading failed: %d", ret);
246 		SleepThread();
247 	}
248 
249 //	Log_print("mcman");
250 	SifLoadModule("rom0:MCMAN", 0, NULL);
251 
252 //	Log_print("mcserv");
253 	SifLoadModule("rom0:MCSERV", 0, NULL);
254 
255 //	Log_print("padman");
256 	ret = SifLoadModule("rom0:PADMAN", 0, NULL);
257 	if (ret < 0) {
258 		Log_print("Padman loading failed: %d", ret);
259 		SleepThread();
260 	}
261 
262 	mcInit(MC_TYPE_MC);
263 
264 //	cdinit(1);
265 	SifInitRpc(0);
266 
267 	SifExecModuleBuffer(usbd, size_usbd, 0, NULL, &ret);
268 	SifExecModuleBuffer(ps2kbd, size_ps2kbd, 0, NULL, &ret);
269 
270 	if (PS2KbdInit() == 0) {
271 		Log_print("Failed to Init Keyboard.");
272 	}
273 	PS2KbdSetReadmode(PS2KBD_READMODE_RAW);
274 
275 #ifdef SOUND
276 	ret = SifLoadModule("rom0:LIBSD", 0, NULL);
277 
278 	ret = SifExecModuleBuffer(audsrv, size_audsrv, 0, NULL, &ret);
279 #endif
280 
281 }
282 
PLATFORM_Initialise(int * argc,char * argv[])283 int PLATFORM_Initialise(int *argc, char *argv[])
284 {
285 	// Swap Red and Blue components
286 	int i;
287 	for (i = 0; i < 256; i++) {
288 		int c = Colours_table[i];
289 //		clut[i] = (c >> 16) + (c & 0xff00) + ((c & 0xff) << 16);
290 		// swap bits 3 and 4 to workaround a bug in gsKit
291 		clut[(i ^ i * 2) & 16 ? i ^ 24 : i] = (c >> 16) + (c & 0xff00) + ((c & 0xff) << 16);
292 	}
293 	// Clear debug from screen
294 	init_scr();
295 	// Initialize graphics
296 	gsGlobal = gsKit_init_global(GS_MODE_NTSC);
297 	dmaKit_init(D_CTRL_RELE_ON, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC,
298 	            D_CTRL_STD_OFF, D_CTRL_RCYC_8);
299 	dmaKit_chan_init(DMA_CHANNEL_GIF);
300 	gsGlobal->PSM = GS_PSM_CT32;
301 	gsGlobal->Test->ZTE = 0;
302 	gsKit_init_screen(gsGlobal);
303 	// Init joypad
304 	padInit(0);
305 	padPortOpen(PAD_PORT, PAD_SLOT, padBuf);
306 #ifdef USE_TIMERS
307 	timer_initialize();
308 #endif
309 #ifdef SOUND
310 	if (!Sound_Initialise(argc, argv))
311 		return FALSE;
312 #endif
313 
314 	return TRUE;
315 }
316 
PLATFORM_Exit(int run_monitor)317 int PLATFORM_Exit(int run_monitor)
318 {
319 	// TODO: shutdown graphics mode
320 	Log_flushlog();
321 #if 0
322 	if (run_monitor && MONITOR_Run()) {
323 		// TODO: reinitialize graphics mode
324 		return TRUE;
325 	}
326 #endif
327 #ifdef USE_TIMERS
328 	timer_shutdown();
329 #endif
330 /* TODO Sound_Exit should not be called here! It only stays here now because
331    the next step restarts the PS2 without ever returning from this function to
332    Atari800_Exit, so the call to Sound_Exit located in the latter function is
333    never invoked. So, should the LoadExecPS2call below get removed, so should
334    this call to Sound_Exit. */
335 #ifdef SOUND
336 	Sound_Exit();
337 #endif
338 //zzz temp exit procedure
339 //Hard coded to go back to ulaunch
340 	fioExit();
341 	SifExitRpc();
342 	LoadExecPS2("mc0:/BOOT/BOOT.ELF", 0, NULL);
343 //zzz end
344 	return FALSE;
345 }
346 
PLATFORM_DisplayScreen(void)347 void PLATFORM_DisplayScreen(void)
348 {
349 	GSTEXTURE tex;
350 	tex.Width = Screen_WIDTH;
351 	tex.Height = Screen_HEIGHT;
352 	tex.PSM = GS_PSM_T8;
353 	tex.Mem = (UBYTE *) Screen_atari;
354 	tex.Clut = clut;
355 	tex.Vram = 0x200000;
356 	tex.VramClut = 0x280000;
357 	tex.Filter = GS_FILTER_LINEAR;
358 	// TODO: upload clut just once
359 	gsKit_texture_upload(gsGlobal, &tex);
360 	gsKit_prim_sprite_texture(gsGlobal, &tex, 0, 0, 32, 0, 640, 480, 32 + 320, 240, 0, 0x80808080);
361 #if 0
362 	gsKit_sync_flip(gsGlobal);
363 #else
364 	// flip without vsync
365 	// this is a copy of gsKit_sync_flip() code with just gsKit_vsync() call removed
366 	GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192,
367 		gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 );
368 	gsGlobal->ActiveBuffer ^= 1;
369 	gsGlobal->PrimContext ^= 1;
370 	gsGlobal->EvenOrOdd = ((GSREG *) GS_CSR)->FIELD;
371 	gsKit_setactive(gsGlobal);
372 #endif
373 
374 }
375 
PadButtons(void)376 static int PadButtons(void)
377 {
378 	struct padButtonStatus buttons;
379 	for (;;) {
380 		int ret = padGetState(PAD_PORT, PAD_SLOT);
381 		if (ret == PAD_STATE_STABLE || ret == PAD_STATE_FINDCTP1)
382 			break;
383 		if (ret == PAD_STATE_DISCONN)
384 			return 0;
385 	}
386 	padRead(PAD_PORT, PAD_SLOT, &buttons);
387 	return ~buttons.btns;
388 }
389 
PLATFORM_Keyboard(void)390 int PLATFORM_Keyboard(void)
391 {
392 	int new_pad = PadButtons();
393 	PS2KbdRawKey key;
394 	INPUT_key_consol = INPUT_CONSOL_NONE;
395 
396 	if (UI_is_active) {
397 		if (new_pad & PAD_CROSS)
398 			return AKEY_RETURN;
399 		if (new_pad & PAD_CIRCLE)
400 			return AKEY_ESCAPE;
401 		if (new_pad & PAD_LEFT)
402 			return AKEY_LEFT;
403 		if (new_pad & PAD_RIGHT)
404 			return AKEY_RIGHT;
405 		if (new_pad & PAD_UP)
406 			return AKEY_UP;
407 		if (new_pad & PAD_DOWN)
408 			return AKEY_DOWN;
409 		if (new_pad & PAD_L1)
410 		    return AKEY_COLDSTART;
411 		if (new_pad & PAD_R1)
412 			return AKEY_WARMSTART;
413 	}
414 	//PAD_CROSS is used for PLATFORM_TRIG().
415 	if (new_pad & PAD_TRIANGLE)
416 		return AKEY_UI;
417 	if (new_pad & PAD_SQUARE)
418 		return AKEY_SPACE;
419 	if (new_pad & PAD_CIRCLE)
420 		return AKEY_RETURN;
421 	if (new_pad & PAD_L1)
422 		return AKEY_COLDSTART;
423 	if (new_pad & PAD_R1)
424 		return AKEY_WARMSTART;
425 	if (Atari800_machine_type == Atari800_MACHINE_5200) {
426 		if (new_pad & PAD_START)
427 			return AKEY_5200_START;
428 	}
429 	else {
430 		if (new_pad & PAD_START)
431 			INPUT_key_consol ^= INPUT_CONSOL_START;
432 		if (new_pad & PAD_SELECT)
433 			INPUT_key_consol ^= INPUT_CONSOL_SELECT;
434 		if (new_pad & PAD_CROSS)
435 			return AKEY_HELP;
436 	}
437 if (Atari800_machine_type != Atari800_MACHINE_5200 || UI_is_active) {
438 
439 	while (PS2KbdReadRaw(&key) != 0) {
440 		if (key.state == PS2KBD_RAWKEY_DOWN) {
441 			switch (key.key) {
442 			case EOF:
443 				Atari800_Exit(FALSE);
444 				exit(0);
445 			    break;
446 			case 0x28:
447 				return AKEY_RETURN;
448 			case 0x29:
449 				return AKEY_ESCAPE;
450 			case 0x2A:
451 				return AKEY_BACKSPACE;
452 			case 0x2B:
453 				return AKEY_TAB;
454 			case 0x2C:
455 				return AKEY_SPACE;
456 			case 0x46://Print Screen Button
457 				return AKEY_SCREENSHOT;
458 			case 0x4F:
459 			    return AKEY_RIGHT;
460 			case 0x50:
461 			    return AKEY_LEFT;
462 			case 0x51:
463 			    return AKEY_DOWN;
464 			case 0x52:
465 			    return AKEY_UP;
466 			case 0x58:
467 			    return AKEY_RETURN;
468 
469 			case 0xE0:
470 				PS2KbdCONTROL = 1;
471 				return AKEY_NONE;
472 			case 0xE4:
473 				PS2KbdCONTROL = 1;
474 				return AKEY_NONE;
475 			case 0xE1:
476 				PS2KbdSHIFT = 1;
477 				return AKEY_NONE;
478 			case 0xE2:
479 				PS2KbdALT = 1;
480 				return AKEY_NONE;
481 			case 0xE5:
482 				PS2KbdSHIFT = 1;
483 				return AKEY_NONE;
484 			case 0xE6:
485 				PS2KbdALT = 1;
486 				return AKEY_NONE;
487 			default:
488 				break;
489 			}
490 		}
491 
492 		if ((key.state == PS2KBD_RAWKEY_DOWN) && !PS2KbdSHIFT && !PS2KbdALT) {
493 			switch (key.key) {
494 			case 0x1E:
495 				return AKEY_1;
496 			case 0X1F:
497 				return AKEY_2;
498 			case 0x20:
499 				return AKEY_3;
500 			case 0x21:
501 				return AKEY_4;
502 			case 0x22:
503 				return AKEY_5;
504 			case 0x23:
505 				return AKEY_6;
506 			case 0x24:
507 				return AKEY_7;
508 			case 0x25:
509 				return AKEY_8;
510 			case 0x26:
511 				return AKEY_9;
512 			case 0x27:
513 				return AKEY_0;
514 			case 0x2D:
515 				return AKEY_MINUS;
516 			case 0x2E:
517 				return AKEY_EQUAL;
518 			case 0x2F:
519 				return AKEY_BRACKETLEFT;
520 			case 0x30:
521 				return AKEY_BRACKETRIGHT;
522 			case 0x31:
523 				return AKEY_BACKSLASH;
524 			case 0x33:
525 				return AKEY_SEMICOLON;
526 			case 0x34:
527 				return AKEY_QUOTE;
528 			case 0x35:
529 				return AKEY_ATARI;
530 			case 0x36:
531 				return AKEY_COMMA;
532 			case 0x37:
533 				return AKEY_FULLSTOP;
534 			case 0x38:
535 				return AKEY_SLASH;
536 			case 0x3A://F1
537 				return AKEY_UI;
538 			case 0x3E://F5
539 				return AKEY_WARMSTART;
540 			case 0x42://F9
541 				return AKEY_EXIT;
542 			case 0x43://F10
543 				return AKEY_SCREENSHOT;
544 			default:
545 				break;
546 			}
547 		}
548 		if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdSHIFT && !PS2KbdCONTROL && !PS2KbdALT) {
549 			switch (key.key) {
550 			case 0x4:
551 				return AKEY_A;
552 			case 0x5:
553 				return AKEY_B;
554 			case 0x6:
555 				return AKEY_C;
556 			case 0x7:
557 				return AKEY_D;
558 			case 0x8:
559 				return AKEY_E;
560 			case 0x9:
561 				return AKEY_F;
562 			case 0xA:
563 				return AKEY_G;
564 			case 0xB:
565 				return AKEY_H;
566 			case 0xC:
567 				return AKEY_I;
568 			case 0xD:
569 				return AKEY_J;
570 			case 0xE:
571 				return AKEY_K;
572 			case 0xF:
573 				return AKEY_L;
574 			case 0x10:
575 				return AKEY_M;
576 			case 0x11:
577 				return AKEY_N;
578 			case 0x12:
579 				return AKEY_O;
580 			case 0x13:
581 				return AKEY_P;
582 			case 0x14:
583 				return AKEY_Q;
584 			case 0x15:
585 				return AKEY_R;
586 			case 0x16:
587 				return AKEY_S;
588 			case 0x17:
589 				return AKEY_T;
590 			case 0x18:
591 				return AKEY_U;
592 			case 0x19:
593 				return AKEY_V;
594 			case 0x1A:
595 				return AKEY_W;
596 			case 0x1B:
597 				return AKEY_X;
598 			case 0x1C:
599 				return AKEY_Y;
600 			case 0x1D:
601 				return AKEY_Z;
602 			case 0x1E:
603 				return AKEY_EXCLAMATION;
604 			case 0X1F:
605 				return AKEY_AT;
606 			case 0x20:
607 				return AKEY_HASH;
608 			case 0x21:
609 				return AKEY_DOLLAR;
610 			case 0x22:
611 				return AKEY_PERCENT;
612 			case 0x23:
613 //				return AKEY_CIRCUMFLEX;
614 				return AKEY_CARET;
615 			case 0x24:
616 				return AKEY_AMPERSAND;
617 			case 0x25:
618 				return AKEY_ASTERISK;
619 			case 0x26:
620 				return AKEY_PARENLEFT;
621 			case 0x27:
622 				return AKEY_PARENRIGHT;
623 			case 0x2B:
624 				return AKEY_SETTAB;
625 			case 0x2D:
626 				return AKEY_UNDERSCORE;
627 			case 0x2E:
628 				return AKEY_PLUS;
629 			case 0x31:
630 				return AKEY_BAR;
631 			case 0x33:
632 				return AKEY_COLON;
633 			case 0x34:
634 				return AKEY_DBLQUOTE;
635 			case 0x36:
636 				return AKEY_LESS;
637 			case 0x37:
638 				return AKEY_GREATER;
639 			case 0x38:
640 				return AKEY_QUESTION;
641 			case 0x3E://Shift+F5
642 				return AKEY_COLDSTART;
643 			case 0x43://Shift+F10
644 				return AKEY_SCREENSHOT_INTERLACE;
645 			case 0x49://Shift+Insert key
646 				return AKEY_INSERT_LINE;
647 			case 0x4C://Shift+Backspace Key
648 				return AKEY_DELETE_LINE;
649 			default:
650 				break;
651 			}
652 		}
653 		if ((key.state == PS2KBD_RAWKEY_DOWN) && !PS2KbdSHIFT && !PS2KbdCONTROL && !PS2KbdALT) {
654 			switch (key.key) {
655 			case 0x4:
656 				return AKEY_a;
657 			case 0x5:
658 				return AKEY_b;
659 			case 0x6:
660 				return AKEY_c;
661 			case 0x7:
662 				return AKEY_d;
663 			case 0x8:
664 				return AKEY_e;
665 			case 0x9:
666 				return AKEY_f;
667 			case 0xA:
668 				return AKEY_g;
669 			case 0xB:
670 				return AKEY_h;
671 			case 0xC:
672 				return AKEY_i;
673 			case 0xD:
674 				return AKEY_j;
675 			case 0xE:
676 				return AKEY_k;
677 			case 0xF:
678 				return AKEY_l;
679 			case 0x10:
680 				return AKEY_m;
681 			case 0x11:
682 				return AKEY_n;
683 			case 0x12:
684 				return AKEY_o;
685 			case 0x13:
686 				return AKEY_p;
687 			case 0x14:
688 				return AKEY_q;
689 			case 0x15:
690 				return AKEY_r;
691 			case 0x16:
692 				return AKEY_s;
693 			case 0x17:
694 				return AKEY_t;
695 			case 0x18:
696 				return AKEY_u;
697 			case 0x19:
698 				return AKEY_v;
699 			case 0x1A:
700 				return AKEY_w;
701 			case 0x1B:
702 				return AKEY_x;
703 			case 0x1C:
704 				return AKEY_y;
705 			case 0x1D:
706 				return AKEY_z;
707 			case 0x49:
708 				return AKEY_INSERT_CHAR;
709 			case 0x4C:
710 				return AKEY_DELETE_CHAR;
711 			default:
712 				break;
713 			}
714 		}
715 		if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdCONTROL && !PS2KbdALT) {
716 			switch(key.key) {
717 			case 0x4:
718 				return AKEY_CTRL_a;
719 			case 0x5:
720 				return AKEY_CTRL_b;
721 			case 0x6:
722 				return AKEY_CTRL_c;
723 			case 0x7:
724 				return AKEY_CTRL_d;
725 			case 0x8:
726 				return AKEY_CTRL_e;
727 			case 0x9:
728 				return AKEY_CTRL_f;
729 			case 0xA:
730 				return AKEY_CTRL_g;
731 			case 0xB:
732 				return AKEY_CTRL_h;
733 			case 0xC:
734 				return AKEY_CTRL_i;
735 			case 0xD:
736 				return AKEY_CTRL_j;
737 			case 0xE:
738 				return AKEY_CTRL_k;
739 			case 0xF:
740 				return AKEY_CTRL_l;
741 			case 0x10:
742 				return AKEY_CTRL_m;
743 			case 0x11:
744 				return AKEY_CTRL_n;
745 			case 0x12:
746 				return AKEY_CTRL_o;
747 			case 0x13:
748 				return AKEY_CTRL_p;
749 			case 0x14:
750 				return AKEY_CTRL_q;
751 			case 0x15:
752 				return AKEY_CTRL_r;
753 			case 0x16:
754 				return AKEY_CTRL_s;
755 			case 0x17:
756 				return AKEY_CTRL_t;
757 			case 0x18:
758 				return AKEY_CTRL_u;
759 			case 0x19:
760 				return AKEY_CTRL_v;
761 			case 0x1A:
762 				return AKEY_CTRL_w;
763 			case 0x1B:
764 				return AKEY_CTRL_x;
765 			case 0x1C:
766 				return AKEY_CTRL_y;
767 			case 0x1D:
768 				return AKEY_CTRL_z;
769 			case 0x1E:
770 				return AKEY_CTRL_1;
771 			case 0x1F:
772 				return AKEY_CTRL_2;
773 			case 0x20:
774 				return AKEY_CTRL_3;
775 			case 0x21:
776 				return AKEY_CTRL_4;
777 			case 0x22:
778 				return AKEY_CTRL_5;
779 			case 0x23:
780 				return AKEY_CTRL_6;
781 			case 0x24:
782 				return AKEY_CTRL_7;
783 			case 0x25:
784 				return AKEY_CTRL_8;
785 			case 0x26:
786 				return AKEY_CTRL_9;
787 			case 0x27:
788 				return AKEY_CTRL_0;
789 			case 0x2B:
790 				return AKEY_CLRTAB;
791 			case 0x33:
792 				return AKEY_SEMICOLON | AKEY_CTRL;
793 			case 0x36:
794 				return AKEY_LESS | AKEY_CTRL;
795 			case 0x37:
796 				return AKEY_GREATER | AKEY_CTRL;
797 			default:
798 				break;
799 			}
800 		}
801 		if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdALT) {
802 			switch(key.key) {
803 			//case dcr ylsa
804 			case 0x7:
805 				UI_alt_function = UI_MENU_DISK;
806 				return AKEY_UI;
807 			case 0x6:
808 				UI_alt_function = UI_MENU_CARTRIDGE;
809 				return AKEY_UI;
810 			case 0x15:
811 				UI_alt_function = UI_MENU_RUN;
812 				return AKEY_UI;
813 			case 0x1C:
814 				UI_alt_function = UI_MENU_SYSTEM;
815 				return AKEY_UI;
816 			case 0xF:
817 				UI_alt_function = UI_MENU_LOADSTATE;
818 				return AKEY_UI;
819 			case 0x16:
820 				UI_alt_function = UI_MENU_SAVESTATE;
821 				return AKEY_UI;
822 			case 0x17:
823 				UI_alt_function = UI_MENU_CASSETTE;
824 				return AKEY_UI;
825 			case 0x4:
826 				UI_alt_function = UI_MENU_ABOUT;
827 				return AKEY_UI;
828 			default:
829 				break;
830 			}
831 		}
832 
833 
834 		if (key.state == PS2KBD_RAWKEY_UP) {
835 			switch (key.key) {
836 			case 0x39:
837 
838 			return AKEY_CAPSTOGGLE;
839 			case 0xE0:
840 				PS2KbdCONTROL = 0;
841 				return AKEY_NONE;
842 			case 0xE4:
843 				PS2KbdCONTROL = 0;
844 				return AKEY_NONE;
845 			case 0xE1:
846 				PS2KbdSHIFT = 0;
847 				return AKEY_NONE;
848 			case 0xE2:
849 				PS2KbdALT = 0;
850 				return AKEY_NONE;
851 			case 0xE5:
852 				PS2KbdSHIFT = 0;
853 				return AKEY_NONE;
854 			case 0xE6:
855 				PS2KbdALT = 0;
856 				return AKEY_NONE;
857 			default:
858 				break;
859 			}
860 		}
861 	}
862 }
863 	return AKEY_NONE;
864 }
865 
PLATFORM_PORT(int num)866 int PLATFORM_PORT(int num)
867 {
868 	int ret = 0xff;
869 	if (num == 0) {
870 		int pad = PadButtons();
871 		if (pad & PAD_LEFT)
872 			ret &= 0xf0 | INPUT_STICK_LEFT;
873 		if (pad & PAD_RIGHT)
874 			ret &= 0xf0 | INPUT_STICK_RIGHT;
875 		if (pad & PAD_UP)
876 			ret &= 0xf0 | INPUT_STICK_FORWARD;
877 		if (pad & PAD_DOWN)
878 			ret &= 0xf0 | INPUT_STICK_BACK;
879 	}
880 	return ret;
881 }
882 
PLATFORM_TRIG(int num)883 int PLATFORM_TRIG(int num)
884 {
885 	if (num == 0 && PadButtons() & PAD_CROSS)
886 		return 0;
887 	return 1;
888 }
889 
890 char dir_path[FILENAME_MAX];
891 
892 static int dir_n;
893 static int dir_i;
894 
895 // XXX: use followup calls to get directory entries one-by-one?
896 
897 #define MAX_FILES_PER_DIR 1000
898 
899 static mcTable mcDir[MAX_FILES_PER_DIR];
900 
Atari_OpenDir(const char * filename)901 int Atari_OpenDir(const char *filename)
902 {
903 	// TODO: support other devices
904 	if (strncmp(filename, "mc0:/", 5) != 0)
905 		return FALSE;
906 	dir_n = mcGetDir(0, 0, filename + 4, 0 /* followup flag */, MAX_FILES_PER_DIR, mcDir);
907 	mcSync(0,NULL,&dir_n);
908 	if (dir_n < 0)
909 		return FALSE;
910 	dir_i = 0;
911 	// XXX: does it know (and needs to know) that "mc0:/" is a root directory?
912 	Util_splitpath(filename, dir_path, NULL);
913 	return TRUE;
914 }
915 
Atari_ReadDir(char * fullpath,char * filename,int * isdir,int * readonly,int * size,char * timetext)916 int Atari_ReadDir(char *fullpath, char *filename, int *isdir,
917                   int *readonly, int *size, char *timetext)
918 {
919 	const mcTable *p;
920 	if (dir_i >= dir_n)
921 		return FALSE;
922 	p = mcDir + dir_i;
923 	if (fullpath != NULL)
924 		Util_catpath(fullpath, dir_path, p->name);
925 	if (filename != NULL)
926 		strcpy(filename, p->name);
927 	if (isdir != NULL)
928 		*isdir = (p->attrFile & MC_ATTR_SUBDIR) ? TRUE : FALSE;
929 	if (readonly != NULL)
930 		*readonly = (p->attrFile & MC_ATTR_WRITEABLE) ? FALSE : TRUE; // XXX: MC_ATTR_PROTECTED ?
931 	if (size != NULL)
932 		*size = (int) (p->fileSizeByte);
933 	if (timetext != NULL) {
934 		// FIXME: adjust from GMT to local time
935 		int hour = p->_modify.hour;
936 		char ampm = 'a';
937 		if (hour >= 12) {
938 			hour -= 12;
939 			ampm = 'p';
940 		}
941 		if (hour == 0)
942 			hour = 12;
943 		sprintf(timetext, "%2d-%02d-%02d %2d:%02d%c",
944 			p->_modify.month, p->_modify.day, p->_modify.year % 100, hour, p->_modify.sec, ampm);
945 	}
946 	dir_i++;
947 	return TRUE;
948 }
949 
950 #ifdef SOUND
951 
Sound_Initialise(int * argc,char * argv[])952 int Sound_Initialise(int *argc, char *argv[])
953 {
954 	if (audsrv_init() != 0)
955 		Log_print("failed to initialize audsrv: %s", audsrv_get_error_string());
956 	else {
957 		struct audsrv_fmt_t format;
958 		format.bits = 8;
959 		format.freq = 44100;
960 		format.channels = 1;
961 		audsrv_set_format(&format);
962 		audsrv_set_volume(MAX_VOLUME);
963 		POKEYSND_Init(POKEYSND_FREQ_17_EXACT, 44100, 1, 0);
964 	}
965 	return TRUE;
966 }
967 
Sound_Exit(void)968 void Sound_Exit(void)
969 {
970 	audsrv_quit();
971 }
972 
Sound_Update(void)973 void Sound_Update(void)
974 {
975 	static char buffer[44100 / 50];
976 	unsigned int nsamples = (Atari800_tv_mode == Atari800_TV_NTSC) ? (44100 / 60) : (44100 / 50);
977 	POKEYSND_Process(buffer, nsamples);
978 	audsrv_wait_audio(nsamples);
979 	audsrv_play_audio(buffer, nsamples);
980 }
981 
Sound_Pause(void)982 void Sound_Pause(void)
983 {
984 	audsrv_stop_audio();
985 }
986 
Sound_Continue(void)987 void Sound_Continue(void)
988 {
989 	if (audsrv_init() != 0)
990 		Log_print("failed to initialize audsrv: %s", audsrv_get_error_string());
991 	else {
992 		struct audsrv_fmt_t format;
993 		format.bits = 8;
994 		format.freq = 44100;
995 		format.channels = 1;
996 		audsrv_set_format(&format);
997 		audsrv_set_volume(MAX_VOLUME);
998 	}
999 }
1000 
1001 #endif /* SOUND */
1002 
main(int argc,char ** argv)1003 int main(int argc, char **argv)
1004 {
1005 	loadModules();
1006 	/* initialise Atari800 core */
1007 	if (!Atari800_Initialise(&argc, argv))
1008 		return 3;
1009 
1010 	/* main loop */
1011 	for (;;) {
1012 		INPUT_key_code = PLATFORM_Keyboard();
1013 		Atari800_Frame();
1014 		if (Atari800_display_screen){
1015 			PLATFORM_DisplayScreen();}
1016 	}
1017 }
1018