A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Orginal from Vision-8 Emulator / Copyright (C) 1997-1999 Marcel de Kogel
11 * Modified for Archos by Blueloop (a.wenger@gmx.de)
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "plugin.h"
23
24
25
26#define EXTERN static
27#define STATIC static
28#define memset rb->memset
29#define memcpy rb->memcpy
30#define printf DEBUGF
31#define rand rb->rand
32/* #define CHIP8_DEBUG */
33
34#if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
35#define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
36#endif
37
38/****************************************************************************/
39/** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
40/** The core is completely generic and can be used outside of Rockbox, **/
41/** thus the STATIC, EXTERN etc. Please do not modify. **/
42/****************************************************************************/
43/** Vision8: CHIP8 emulator *************************************************/
44/** **/
45/** CHIP8.h **/
46/** **/
47/** This file contains the portable CHIP8 emulation engine definitions **/
48/** **/
49/** Copyright (C) Marcel de Kogel 1997 **/
50/** You are not allowed to distribute this software commercially **/
51/** Please, notify me, if you make any changes to this file **/
52/****************************************************************************/
53
54#ifndef __CHIP8_H
55#define __CHIP8_H
56
57#ifndef EXTERN
58#define EXTERN extern
59#endif
60
61typedef unsigned char byte; /* sizeof(byte)==1 */
62typedef unsigned short word; /* sizeof(word)>=2 */
63
64struct chip8_regs_struct
65{
66 byte alg[16]; /* 16 general registers */
67 byte delay,sound; /* delay and sound timer */
68 word i; /* index register */
69 word pc; /* program counter */
70 word sp; /* stack pointer */
71};
72
73EXTERN struct chip8_regs_struct chip8_regs;
74
75#ifdef CHIP8_SUPER
76#define CHIP8_WIDTH 128
77#define CHIP8_HEIGHT 64
78EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */
79#else
80#define CHIP8_WIDTH 64
81#define CHIP8_HEIGHT 32
82#endif
83
84EXTERN byte chip8_iperiod; /* number of opcodes per */
85 /* timeslice (1/50sec.) */
86EXTERN byte chip8_keys[16]; /* if 1, key is held down */
87EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */
88 /* 0x00 otherwise */
89EXTERN byte chip8_mem[4096]; /* machine memory. program */
90 /* is loaded at 0x200 */
91EXTERN byte chip8_running; /* if 0, emulation stops */
92
93EXTERN void chip8_execute (void); /* execute chip8_iperiod */
94 /* opcodes */
95EXTERN void chip8_reset (void); /* reset virtual machine */
96EXTERN void chip8 (void); /* start chip8 emulation */
97
98EXTERN void chip8_sound_on (void); /* turn sound on */
99EXTERN void chip8_sound_off (void); /* turn sound off */
100EXTERN void chip8_interrupt (void); /* update keyboard, */
101 /* display, etc. */
102
103#ifdef CHIP8_DEBUG
104EXTERN byte chip8_trace; /* if 1, call debugger */
105 /* every opcode */
106EXTERN word chip8_trap; /* if pc==trap, set trace */
107 /* flag */
108EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs);
109#endif
110
111#endif /* __CHIP8_H */
112
113/** Vision8: CHIP8 emulator *************************************************/
114/** **/
115/** CHIP8.c **/
116/** **/
117/** This file contains the portable CHIP8 emulation engine **/
118/** SCHIP emulation (C) Frederic Devernay 2005 **/
119/** **/
120/** Copyright (C) Marcel de Kogel 1997 **/
121/** You are not allowed to distribute this software commercially **/
122/** Please, notify me, if you make any changes to this file **/
123/****************************************************************************/
124
125/* you can
126 #define STATIC static
127 #define EXTERN static
128 and include this file for single-object generation
129*/
130
131#ifndef STATIC
132#include <stdlib.h> /* for memset, etc. */
133#include <string.h>
134#define STATIC
135#endif
136
137#ifdef CHIP8_DEBUG
138#include <stdio.h>
139#define DBG_(_x) ((void)(_x))
140#else
141#define DBG_(_x) ((void)0)
142#endif
143
144STATIC struct chip8_regs_struct chip8_regs;
145
146static byte chip8_key_pressed;
147STATIC byte chip8_keys[16]; /* if 1, key is held down */
148STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */
149 /* 0x00 otherwise */
150#ifdef CHIP8_SUPER
151STATIC byte chip8_super; /* != 0 if in SCHIP display mode */
152#endif
153STATIC byte chip8_mem[4096]; /* machine memory. program */
154 /* is loaded at 0x200 */
155
156#define read_mem(a) (chip8_mem[(a)&4095])
157#define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
158
159STATIC byte chip8_iperiod;
160
161STATIC byte chip8_running; /* Flag for End-of-Emulation */
162
163#define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
164#define get_reg_value(opcode) (*get_reg_offset(opcode))
165#define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f))
166#define get_reg_value_2(opcode) (*get_reg_offset_2(opcode))
167
168typedef void (*opcode_fn) (word opcode);
169typedef void (*math_fn) (byte *reg1,byte reg2);
170
171
172
173static void op_call (word opcode)
174{
175 chip8_regs.sp--;
176 write_mem (chip8_regs.sp,chip8_regs.pc&0xff);
177 chip8_regs.sp--;
178 write_mem (chip8_regs.sp,chip8_regs.pc>>8);
179 chip8_regs.pc=opcode;
180#ifdef CHIP8_DEBUG
181 if(chip8_regs.sp < 0x1c0)
182 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp);
183#endif
184}
185
186static void op_jmp (word opcode)
187{
188 chip8_regs.pc=opcode;
189}
190
191static void op_key (word opcode)
192{
193#ifdef CHIP8_DEBUG
194 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
195#endif
196 byte key, key_value,cp_value;
197 if ((opcode&0xff)==0x9e) /* skp */
198 cp_value=1;
199 else if ((opcode&0xff)==0xa1) /* sknp */
200 cp_value=0;
201 else {
202 DBG_(printf("unhandled key opcode 0x%x\n", opcode));
203 return;
204 }
205 key = get_reg_value(opcode)&0x0f;
206#ifdef CHIP8_DEBUG
207 if (!tested[key]) {
208 tested[key] = 1;
209 DBG_(printf("testing key %d\n", key));
210 }
211#endif
212 key_value=chip8_keys[key];
213 if (cp_value==key_value)
214 chip8_regs.pc+=2;
215}
216
217static void op_skeq_const (word opcode)
218{
219 if (get_reg_value(opcode)==(opcode&0xff))
220 chip8_regs.pc+=2;
221}
222
223static void op_skne_const (word opcode)
224{
225 if (get_reg_value(opcode)!=(opcode&0xff))
226 chip8_regs.pc+=2;
227}
228
229static void op_skeq_reg (word opcode)
230{
231 if (get_reg_value(opcode)==get_reg_value_2(opcode))
232 chip8_regs.pc+=2;
233}
234
235static void op_skne_reg (word opcode)
236{
237 if (get_reg_value(opcode)!=get_reg_value_2(opcode))
238 chip8_regs.pc+=2;
239}
240
241static void op_mov_const (word opcode)
242{
243 *get_reg_offset(opcode)=opcode&0xff;
244}
245
246static void op_add_const (word opcode)
247{
248 *get_reg_offset(opcode)+=opcode&0xff;
249}
250
251static void op_mvi (word opcode)
252{
253 chip8_regs.i=opcode;
254}
255
256static void op_jmi (word opcode)
257{
258 chip8_regs.pc=opcode+chip8_regs.alg[0];
259}
260
261static void op_rand (word opcode)
262{
263 *get_reg_offset(opcode)=rand()&(opcode&0xff);
264}
265
266static void math_or (byte *reg1,byte reg2)
267{
268 *reg1|=reg2;
269}
270
271static void math_mov (byte *reg1,byte reg2)
272{
273 *reg1=reg2;
274}
275
276static void math_nop (byte *reg1,byte reg2)
277{
278 (void)reg1;
279 (void)reg2;
280 DBG_(printf("Warning: math nop!\n"));
281}
282
283static void math_and (byte *reg1,byte reg2)
284{
285 *reg1&=reg2;
286}
287
288static void math_xor (byte *reg1,byte reg2)
289{
290 *reg1^=reg2;
291}
292
293static void math_add (byte *reg1,byte reg2)
294{
295 word tmp;
296 tmp=*reg1+reg2;
297 *reg1=(byte)tmp;
298 chip8_regs.alg[15]=tmp>>8;
299}
300
301static void math_sub (byte *reg1,byte reg2)
302{
303 word tmp;
304 tmp=*reg1-reg2;
305 *reg1=(byte)tmp;
306 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
307}
308
309static void math_shr (byte *reg1,byte reg2)
310{
311 (void)reg2;
312 chip8_regs.alg[15]=*reg1&1;
313 *reg1>>=1;
314}
315
316static void math_shl (byte *reg1,byte reg2)
317{
318 (void)reg2;
319 chip8_regs.alg[15]=*reg1>>7;
320 *reg1<<=1;
321}
322
323static void math_rsb (byte *reg1,byte reg2)
324{
325 word tmp;
326 tmp=reg2-*reg1;
327 *reg1=(byte)tmp;
328 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
329}
330
331#ifdef CHIP8_SUPER
332/* SUPER: scroll down n lines (or half in CHIP8 mode) */
333static void scroll_down(word opcode)
334{
335 int n = opcode & 0xf;
336 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
337 byte *src = dst - n*CHIP8_WIDTH;
338 while(src >= chip8_display) {
339 *dst-- = *src--;
340 }
341 while(dst >= chip8_display) {
342 *dst-- = 0;
343 }
344}
345/* SUPER: scroll 4 pixels left! */
346static void scroll_left(void)
347{
348 byte *dst = chip8_display;
349 byte *src = dst;
350 byte *eol = chip8_display + CHIP8_WIDTH;
351 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT;
352 while(eol <= eoi) {
353 src+=4;
354 while(src < eol) {
355 *dst++ = *src++;
356 }
357 *dst++ = 0;
358 *dst++ = 0;
359 *dst++ = 0;
360 *dst++ = 0;
361 eol += CHIP8_WIDTH;
362 }
363}
364static void scroll_right(void)
365{
366 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
367 byte *src = dst;
368 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1);
369 while(bol >= chip8_display) {
370 src-=4;
371 while(src >= bol) {
372 *dst-- = *src--;
373 }
374 *dst-- = 0;
375 *dst-- = 0;
376 *dst-- = 0;
377 *dst-- = 0;
378 bol -= CHIP8_WIDTH;
379 }
380}
381#endif
382
383static void op_system (word opcode)
384{
385 switch ((byte)opcode)
386 {
387#ifdef CHIP8_SUPER
388 case 0xfb:
389 scroll_right();
390 break;
391 case 0xfc:
392 scroll_left();
393 break;
394 case 0xfd:
395 DBG_(printf("SUPER: quit the emulator\n"));
396 chip8_reset();
397 break;
398 case 0xfe:
399 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
400 memset (chip8_display,0,sizeof(chip8_display));
401 chip8_super = 0;
402 break;
403 case 0xff:
404 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
405 memset (chip8_display,0,sizeof(chip8_display));
406 chip8_super = 1;
407 break;
408#endif
409 case 0xe0:
410 memset (chip8_display,0,sizeof(chip8_display));
411 break;
412 case 0xee:
413 chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
414 chip8_regs.sp++;
415 chip8_regs.pc+=read_mem(chip8_regs.sp);
416 chip8_regs.sp++;
417 break;
418 default:
419#ifdef CHIP8_SUPER
420 if ((opcode & 0xF0) == 0xC0)
421 scroll_down(opcode);
422 else
423#endif
424 {
425 DBG_(printf("unhandled system opcode 0x%x\n", opcode));
426 chip8_running = 3;
427 }
428 break;
429 }
430}
431
432static void op_misc (word opcode)
433{
434 byte *reg,i,j;
435#ifdef CHIP8_DEBUG
436 static byte firstwait = 1;
437#endif
438 reg=get_reg_offset(opcode);
439 switch ((byte)opcode)
440 {
441 case 0x07: /* gdelay */
442 *reg=chip8_regs.delay;
443 break;
444 case 0x0a: /* key */
445#ifdef CHIP8_DEBUG
446 if(firstwait) {
447 printf("waiting for key press\n");
448 firstwait = 0;
449 }
450#endif
451 if (chip8_key_pressed)
452 *reg=chip8_key_pressed-1;
453 else
454 chip8_regs.pc-=2;
455 break;
456 case 0x15: /* sdelay */
457 chip8_regs.delay=*reg;
458 break;
459 case 0x18: /* ssound */
460 chip8_regs.sound=*reg;
461 if (chip8_regs.sound)
462 chip8_sound_on();
463 break;
464 case 0x1e: /* adi */
465 chip8_regs.i+=(*reg);
466 break;
467 case 0x29: /* font */
468 chip8_regs.i=((word)(*reg&0x0f))*5;
469 break;
470#ifdef CHIP8_SUPER
471 case 0x30: /* xfont */
472 chip8_regs.i=((word)(*reg&0x0f))*10+0x50;
473 break;
474#endif
475 case 0x33: /* bcd */
476 i=*reg;
477 for (j=0;i>=100;i-=100)
478 j++;
479 write_mem (chip8_regs.i,j);
480 for (j=0;i>=10;i-=10)
481 j++;
482 write_mem (chip8_regs.i+1,j);
483 write_mem (chip8_regs.i+2,i);
484 break;
485 case 0x55: /* str */
486 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
487 write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
488 break;
489 case 0x65: /* ldr */
490 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
491 chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
492 break;
493#ifdef CHIP8_SUPER
494 case 0x75:
495 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f));
496 break;
497 case 0x85:
498 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f));
499 break;
500#endif
501 default:
502 DBG_(printf("unhandled misc opcode 0x%x\n", opcode));
503 break;
504 }
505}
506
507static void op_sprite (word opcode)
508{
509 byte *q;
510 byte n,x,x2,y,collision;
511 word p;
512 x=get_reg_value(opcode);
513 y=get_reg_value_2(opcode);
514 p=chip8_regs.i;
515 n=opcode&0x0f;
516#ifdef CHIP8_SUPER
517 if (chip8_super) {
518 /*printf("SUPER: sprite(%x)\n", opcode);*/
519 x &= 128-1;
520 y &= 64-1;
521 q=chip8_display+y*CHIP8_WIDTH;
522 if(n == 0)
523 { /* 16x16 sprite */
524 n = 16;
525 if (n+y>64)
526 n=64-y;
527 for (collision=1;n;--n,q+=CHIP8_WIDTH)
528 {
529 /* first 8 bits */
530 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
531 if (y&0x80)
532 collision&=(q[x2]^=0xff);
533 x2=(x+8)&(CHIP8_WIDTH-1);
534 /* last 8 bits */
535 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
536 if (y&0x80)
537 collision&=(q[x2]^=0xff);
538 }
539 }
540 else {
541 /* 8xn sprite */
542 if (n+y>64)
543 n=64-y;
544 for (collision=1;n;--n,q+=CHIP8_WIDTH)
545 {
546 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
547 if (y&0x80)
548 collision&=(q[x2]^=0xff);
549 }
550 }
551 }
552 else {
553 x &= 64-1;
554 y &= 32-1;
555 q=chip8_display+y*CHIP8_WIDTH*2;
556 if(n == 0)
557 n = 16;
558 if (n+y>32)
559 n=32-y;
560 for (collision=1;n;--n,q+=CHIP8_WIDTH*2)
561 {
562 for (y=read_mem(p++),x2=x*2;y;y<<=1,x2=(x2+2)&(CHIP8_WIDTH-1))
563 if (y&0x80) {
564 q[x2]^=0xff;
565 q[x2+1]^=0xff;
566 q[x2+CHIP8_WIDTH]^=0xff;
567 q[x2+CHIP8_WIDTH+1]^=0xff;
568 collision &= q[x2]|q[x2+1]|q[x2+CHIP8_WIDTH]|q[x2+CHIP8_WIDTH+1];
569 }
570 }
571 }
572#else
573 x &= 64-1;
574 y &= 32-1;
575 q=chip8_display+y*CHIP8_WIDTH;
576 if (n+y>32)
577 n=32-y;
578 for (collision=1;n;--n,q+=CHIP8_WIDTH)
579 {
580 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
581 if (y&0x80)
582 collision&=(q[x2]^=0xff);
583 }
584#endif
585 chip8_regs.alg[15]=collision^1;
586}
587
588static const math_fn math_opcodes[16]=
589{
590 math_mov,
591 math_or,
592 math_and,
593 math_xor,
594 math_add,
595 math_sub,
596 math_shr,
597 math_rsb,
598 math_nop,
599 math_nop,
600 math_nop,
601 math_nop,
602 math_nop,
603 math_nop,
604 math_shl,
605 math_nop
606};
607
608static void op_math (word opcode)
609{
610 (*(math_opcodes[opcode&0x0f]))
611 (get_reg_offset(opcode),get_reg_value_2(opcode));
612}
613
614static const opcode_fn main_opcodes[16]=
615{
616 op_system,
617 op_jmp,
618 op_call,
619 op_skeq_const,
620 op_skne_const,
621 op_skeq_reg,
622 op_mov_const,
623 op_add_const,
624 op_math,
625 op_skne_reg,
626 op_mvi,
627 op_jmi,
628 op_rand,
629 op_sprite,
630 op_key,
631 op_misc
632};
633
634#ifdef CHIP8_DEBUG
635STATIC byte chip8_trace;
636STATIC word chip8_trap;
637
638/****************************************************************************/
639/* This routine is called every opcode when chip8_trace==1. It prints the */
640/* current register contents and the opcode being executed */
641/****************************************************************************/
642STATIC void chip8_debug (word opcode,struct chip8_regs_struct *regs)
643{
644 int i;
645 static const byte hextable[16] = "0123456789ABCDEF";
646 byte v1[3] = "Vx\0";
647 byte v2[3] = "Vx\0";
648 v1[1] = hextable[(opcode>>8)&0x0f];
649 v2[1] = hextable[(opcode>>8)&0x0f];
650 printf ("PC=%04X: %04X - ",regs->pc,opcode);
651 switch (opcode>>12) {
652 case 0:
653 if ((opcode&0xff0) == 0xc0) {
654 printf ("SCD %01X ; Scroll down n lines",opcode&0xf);
655 }
656 else switch (opcode&0xfff) {
657 case 0xe0:
658 printf ("CLS ; Clear screen");
659 break;
660 case 0xee:
661 printf ("RET ; Return from subroutine call");
662 break;
663 case 0xfb:
664 printf("SCR ; Scroll right");
665 break;
666 case 0xfc:
667 printf("SCL ; Scroll left");
668 break;
669 case 0xfd:
670 printf("EXIT ; Terminate the interpreter");
671 break;
672 case 0xfe:
673 printf("LOW ; Disable extended screen mode");
674 break;
675 case 0xff:
676 printf("HIGH ; Enable extended screen mode");
677 break;
678 default:
679 printf ("SYS %03X ; Unknown system call",opcode&0xff);
680 }
681 break;
682 case 1:
683 printf ("JP %03X ; Jump to address",opcode&0xfff);
684 break;
685 case 2:
686 printf ("CALL %03X ; Call subroutine",opcode&0xfff);
687 break;
688 case 3:
689 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff);
690 break;
691 case 4:
692 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff);
693 break;
694 case 5:
695 printf ("SE %s,%s ; Skip if register == register",v1,v2);
696 break;
697 case 6:
698 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff);
699 break;
700 case 7:
701 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff);
702 break;
703 case 8:
704 switch (opcode&0x0f) {
705 case 0:
706 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2);
707 break;
708 case 1:
709 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2);
710 break;
711 case 2:
712 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2);
713 break;
714 case 3:
715 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2);
716 break;
717 case 4:
718 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2);
719 break;
720 case 5:
721 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2);
722 break;
723 case 6:
724 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2);
725 break;
726 case 7:
727 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2);
728 break;
729 case 14:
730 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2);
731 break;
732 default:
733 printf ("Illegal opcode");
734 }
735 break;
736 case 9:
737 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2);
738 break;
739 case 10:
740 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff);
741 break;
742 case 11:
743 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff);
744 break;
745 case 12:
746 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff);
747 break;
748 case 13:
749 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f);
750 break;
751 case 14:
752 switch (opcode&0xff) {
753 case 0x9e:
754 printf ("SKP %s ; Skip next instruction if key VX down",v1);
755 break;
756 case 0xa1:
757 printf ("SKNP %s ; Skip next instruction if key VX up",v1);
758 break;
759 default:
760 printf ("%04X ; Illegal opcode", opcode);
761 }
762 break;
763 case 15:
764 switch (opcode&0xff) {
765 case 0x07:
766 printf ("LD %s,DT ; Set VX = delaytimer",v1);
767 break;
768 case 0x0a:
769 printf ("LD %s,K ; Set VX = key, wait for keypress",v1);
770 break;
771 case 0x15:
772 printf ("LD DT,%s ; Set delaytimer = VX",v1);
773 break;
774 case 0x18:
775 printf ("LD ST,%s ; Set soundtimer = VX",v1);
776 break;
777 case 0x1e:
778 printf ("ADD I,%s ; Set I = I + VX",v1);
779 break;
780 case 0x29:
781 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1);
782 break;
783 case 0x30:
784 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1);
785 break;
786 case 0x33:
787 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1);
788 break;
789 case 0x55:
790 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1);
791 break;
792 case 0x65:
793 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1);
794 break;
795 case 0x75:
796 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1);
797 break;
798 case 0x85:
799 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1);
800 break;
801 default:
802 printf ("%04X ; Illegal opcode", opcode);
803 }
804 break;
805 }
806 printf ("\n; Registers: ");
807 for (i=0;i<16;++i) printf ("%02x ",(regs->alg[i])&0xff);
808 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
809 regs->i&0xfff,regs->sp&0xfff,regs->delay&0xff,regs->sound&0xff);
810}
811#endif
812
813/****************************************************************************/
814/* Execute chip8_iperiod opcodes */
815/****************************************************************************/
816STATIC void chip8_execute(void)
817{
818 byte i;
819 byte key_pressed=0;
820 word opcode;
821 for (i = chip8_iperiod ; i ;--i)
822 {
823 /* Fetch the opcode */
824 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1);
825#ifdef CHIP8_DEBUG
826 /* Check if trap address has been reached */
827 if ((chip8_regs.pc&4095)==chip8_trap)
828 chip8_trace=1;
829 /* Call the debugger if chip8_trace!=0 */
830 if (chip8_trace)
831 chip8_debug (opcode,&chip8_regs);
832#endif
833 chip8_regs.pc+=2;
834 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */
835 }
836 /* Update timers */
837 if (chip8_regs.delay)
838 --chip8_regs.delay;
839 if (chip8_regs.sound)
840 if (--chip8_regs.sound == 0)
841 chip8_sound_off();
842
843 /* Update the machine status */
844 chip8_interrupt ();
845
846 for (i=key_pressed=0;i<16;++i) /* check if a key was first */
847 if (chip8_keys[i]) /* pressed */
848 key_pressed=i+1;
849 if (key_pressed && key_pressed!=chip8_key_pressed)
850 chip8_key_pressed=key_pressed;
851 else
852 chip8_key_pressed=0;
853}
854
855/****************************************************************************/
856/* Reset the virtual chip8 machine */
857/****************************************************************************/
858STATIC void chip8_reset(void)
859{
860 static const byte chip8_sprites[0x50]=
861 {
862 0xf9,0x99,0xf2,0x62,0x27,
863 0xf1,0xf8,0xff,0x1f,0x1f,
864 0x99,0xf1,0x1f,0x8f,0x1f,
865 0xf8,0xf9,0xff,0x12,0x44,
866 0xf9,0xf9,0xff,0x9f,0x1f,
867 0xf9,0xf9,0x9e,0x9e,0x9e,
868 0xf8,0x88,0xfe,0x99,0x9e,
869 0xf8,0xf8,0xff,0x8f,0x88,
870 }; /* 4x5 pixel hexadecimal character font patterns */
871#ifdef CHIP8_SUPER
872 static const byte schip_sprites[10*10]=
873 {
874 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
875 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
876 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
877 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
878 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
879 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
880 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
881 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
882 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
883 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
884 }; /* 8x10 pixel font patterns (only 10) */
885#endif
886 byte i;
887 for (i=0;i<16*5;++i)
888 {
889 write_mem (i<<1,chip8_sprites[i]&0xf0);
890 write_mem ((i<<1)+1,chip8_sprites[i]<<4);
891 }
892#ifdef CHIP8_SUPER
893 /*
894 for (i=0; i<100; i++)
895 write_mem (i+0x50,schip_sprites[i]);
896 */
897 memcpy(chip8_mem+0x50, schip_sprites, 100);
898 chip8_super = 0;
899#endif
900 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
901 memset (chip8_keys,0,sizeof(chip8_keys));
902 chip8_key_pressed=0;
903 memset (chip8_display,0,sizeof(chip8_display));
904 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
905 chip8_regs.sp=0x1e0;
906 chip8_regs.pc=0x200;
907 chip8_sound_off ();
908 chip8_running=1;
909#ifdef CHIP8_DEBUG
910 chip8_trace=0;
911#endif
912}
913
914
915/****************************************************************************/
916/* Start CHIP8 emulation */
917/****************************************************************************/
918STATIC void chip8 (void)
919{
920 chip8_reset ();
921 while (chip8_running==1) chip8_execute ();
922}
923
924/****************************************************************************/
925/** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
926/****************************************************************************/
927
928/* size of the displayed area */
929#if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
930#define CHIP8_LCDWIDTH 112
931#else
932#define CHIP8_LCDWIDTH CHIP8_WIDTH
933#endif
934
935#if (LCD_WIDTH > CHIP8_LCDWIDTH)
936#define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
937#else
938#define CHIP8_X 0
939#endif
940#if (LCD_HEIGHT > CHIP8_HEIGHT)
941#define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
942#else
943#define CHIP8_Y 0
944#endif
945
946/* variable button definitions */
947#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
948 (CONFIG_KEYPAD == IRIVER_H300_PAD)
949#define CHIP8_OFF BUTTON_OFF
950#define CHIP8_KEY2 BUTTON_UP
951#define CHIP8_KEY4 BUTTON_LEFT
952#define CHIP8_KEY5 BUTTON_SELECT
953#define CHIP8_KEY6 BUTTON_RIGHT
954#define CHIP8_KEY8 BUTTON_DOWN
955
956#define CHIP8_RC_OFF BUTTON_RC_STOP
957
958#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
959 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
960 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
961#define CHIP8_OFF BUTTON_MENU
962#define CHIP8_KEY2 BUTTON_SCROLL_BACK
963#define CHIP8_KEY4 BUTTON_LEFT
964#define CHIP8_KEY5 BUTTON_PLAY
965#define CHIP8_KEY6 BUTTON_RIGHT
966#define CHIP8_KEY8 BUTTON_SCROLL_FWD
967
968#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
969#define CHIP8_OFF BUTTON_POWER
970#define CHIP8_KEY2 BUTTON_UP
971#define CHIP8_KEY4 BUTTON_LEFT
972#define CHIP8_KEY5 BUTTON_SELECT
973#define CHIP8_KEY6 BUTTON_RIGHT
974#define CHIP8_KEY8 BUTTON_DOWN
975
976#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
977#define CHIP8_OFF BUTTON_POWER
978#define CHIP8_KEY1 BUTTON_MENU
979#define CHIP8_KEY2 BUTTON_UP
980#define CHIP8_KEY3 BUTTON_VOL_DOWN
981#define CHIP8_KEY4 BUTTON_LEFT
982#define CHIP8_KEY5 BUTTON_SELECT
983#define CHIP8_KEY6 BUTTON_RIGHT
984#define CHIP8_KEY7 BUTTON_VOL_UP
985#define CHIP8_KEY8 BUTTON_DOWN
986#define CHIP8_KEY9 BUTTON_A
987
988#elif CONFIG_KEYPAD == SANSA_E200_PAD || \
989 CONFIG_KEYPAD == SANSA_FUZE_PAD
990#define CHIP8_OFF BUTTON_POWER
991#define CHIP8_KEY2 BUTTON_SCROLL_BACK
992#define CHIP8_KEY4 BUTTON_LEFT
993#define CHIP8_KEY5 BUTTON_SELECT
994#define CHIP8_KEY6 BUTTON_RIGHT
995#define CHIP8_KEY8 BUTTON_SCROLL_FWD
996
997#elif CONFIG_KEYPAD == SANSA_C200_PAD || \
998CONFIG_KEYPAD == SANSA_CLIP_PAD || \
999CONFIG_KEYPAD == SANSA_M200_PAD
1000#define CHIP8_OFF BUTTON_POWER
1001#define CHIP8_KEY2 BUTTON_UP
1002#define CHIP8_KEY4 BUTTON_LEFT
1003#define CHIP8_KEY5 BUTTON_SELECT
1004#define CHIP8_KEY6 BUTTON_RIGHT
1005#define CHIP8_KEY8 BUTTON_DOWN
1006
1007#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
1008#define CHIP8_OFF BUTTON_POWER
1009#define CHIP8_KEY2 BUTTON_SCROLL_UP
1010#define CHIP8_KEY4 BUTTON_LEFT
1011#define CHIP8_KEY5 BUTTON_PLAY
1012#define CHIP8_KEY6 BUTTON_RIGHT
1013#define CHIP8_KEY8 BUTTON_SCROLL_DOWN
1014
1015#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
1016#define CHIP8_OFF BUTTON_BACK
1017#define CHIP8_KEY1 BUTTON_MENU
1018#define CHIP8_KEY2 BUTTON_UP
1019#define CHIP8_KEY3 BUTTON_VOL_DOWN
1020#define CHIP8_KEY4 BUTTON_LEFT
1021#define CHIP8_KEY5 BUTTON_SELECT
1022#define CHIP8_KEY6 BUTTON_RIGHT
1023#define CHIP8_KEY7 BUTTON_VOL_UP
1024#define CHIP8_KEY8 BUTTON_DOWN
1025#define CHIP8_KEY9 BUTTON_PLAY
1026
1027#elif (CONFIG_KEYPAD == MROBE100_PAD)
1028#define CHIP8_OFF BUTTON_POWER
1029#define CHIP8_KEY1 BUTTON_MENU
1030#define CHIP8_KEY2 BUTTON_UP
1031#define CHIP8_KEY3 BUTTON_PLAY
1032#define CHIP8_KEY4 BUTTON_LEFT
1033#define CHIP8_KEY5 BUTTON_SELECT
1034#define CHIP8_KEY6 BUTTON_RIGHT
1035#define CHIP8_KEY7 BUTTON_DISPLAY
1036#define CHIP8_KEY8 BUTTON_DOWN
1037
1038#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1039#define CHIP8_OFF BUTTON_RC_REC
1040#define CHIP8_KEY1 BUTTON_RC_MENU
1041#define CHIP8_KEY2 BUTTON_RC_VOL_UP
1042#define CHIP8_KEY3 BUTTON_RC_MODE
1043#define CHIP8_KEY4 BUTTON_RC_REW
1044#define CHIP8_KEY5 BUTTON_RC_PLAY
1045#define CHIP8_KEY6 BUTTON_RC_FF
1046#define CHIP8_KEY8 BUTTON_RC_VOL_DOWN
1047
1048#elif (CONFIG_KEYPAD == COWON_D2_PAD)
1049#define CHIP8_OFF BUTTON_POWER
1050
1051#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1052#define CHIP8_OFF BUTTON_BACK
1053#define CHIP8_KEY1 BUTTON_MENU
1054#define CHIP8_KEY2 BUTTON_UP
1055#define CHIP8_KEY3 BUTTON_CUSTOM
1056#define CHIP8_KEY4 BUTTON_LEFT
1057#define CHIP8_KEY5 BUTTON_PLAY
1058#define CHIP8_KEY6 BUTTON_RIGHT
1059#define CHIP8_KEY8 BUTTON_DOWN
1060
1061#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
1062#define CHIP8_OFF BUTTON_POWER
1063#define CHIP8_KEY1 BUTTON_VOL_UP
1064#define CHIP8_KEY2 BUTTON_UP
1065#define CHIP8_KEY3 BUTTON_VOL_DOWN
1066#define CHIP8_KEY4 BUTTON_BACK
1067#define CHIP8_KEY5 BUTTON_PLAY
1068#define CHIP8_KEY6 BUTTON_MENU
1069#define CHIP8_KEY8 BUTTON_DOWN
1070
1071#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1072#define CHIP8_OFF BUTTON_POWER
1073#define CHIP8_KEY1 BUTTON_MENU
1074#define CHIP8_KEY2 BUTTON_UP
1075#define CHIP8_KEY3 BUTTON_VOL_DOWN
1076#define CHIP8_KEY4 BUTTON_LEFT
1077#define CHIP8_KEY5 BUTTON_SELECT
1078#define CHIP8_KEY6 BUTTON_RIGHT
1079#define CHIP8_KEY7 BUTTON_VOL_UP
1080#define CHIP8_KEY8 BUTTON_DOWN
1081#define CHIP8_KEY9 BUTTON_VIEW
1082
1083#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
1084#define CHIP8_OFF BUTTON_POWER
1085#define CHIP8_KEY1 BUTTON_PREV
1086#define CHIP8_KEY2 BUTTON_PLAY
1087#define CHIP8_KEY3 BUTTON_NEXT
1088#define CHIP8_KEY4 BUTTON_LEFT
1089#define CHIP8_KEY5 BUTTON_UP
1090#define CHIP8_KEY6 BUTTON_RIGHT
1091#define CHIP8_KEY7 BUTTON_MENU
1092#define CHIP8_KEY8 BUTTON_DOWN
1093#define CHIP8_KEY9 BUTTON_VIEW
1094#define CHIP8_KEY0 BUTTON_VOL_DOWN
1095
1096#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
1097#define CHIP8_OFF BUTTON_POWER
1098#define CHIP8_KEY1 BUTTON_LEFT
1099#define CHIP8_KEY2 BUTTON_UP
1100#define CHIP8_KEY3 BUTTON_RIGHT
1101#define CHIP8_KEY4 BUTTON_PREV
1102#define CHIP8_KEY5 BUTTON_PLAY
1103#define CHIP8_KEY6 BUTTON_NEXT
1104#define CHIP8_KEY7 BUTTON_MENU
1105#define CHIP8_KEY8 BUTTON_DOWN
1106#define CHIP8_KEY9 BUTTON_VOL_UP
1107#define CHIP8_KEY0 BUTTON_VOL_DOWN
1108
1109#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
1110CONFIG_KEYPAD == ONDAVX777_PAD || \
1111CONFIG_KEYPAD == MROBE500_PAD
1112#define CHIP8_OFF BUTTON_POWER
1113
1114#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \
1115 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
1116#define CHIP8_OFF BUTTON_REW
1117#define CHIP8_KEY0 BUTTON_FFWD
1118#define CHIP8_KEY2 BUTTON_UP
1119#define CHIP8_KEY4 BUTTON_LEFT
1120#define CHIP8_KEY5 BUTTON_PLAY
1121#define CHIP8_KEY6 BUTTON_RIGHT
1122#define CHIP8_KEY8 BUTTON_DOWN
1123
1124#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
1125#define CHIP8_OFF BUTTON_REC
1126#define CHIP8_KEY2 BUTTON_UP
1127#define CHIP8_KEY4 BUTTON_PREV
1128#define CHIP8_KEY5 BUTTON_OK
1129#define CHIP8_KEY6 BUTTON_NEXT
1130#define CHIP8_KEY8 BUTTON_DOWN
1131
1132#elif CONFIG_KEYPAD == MPIO_HD200_PAD
1133
1134#define CHIP8_OFF (BUTTON_REC|BUTTON_PLAY)
1135#define CHIP8_KEY1 BUTTON_REW
1136#define CHIP8_KEY2 BUTTON_FF
1137#define CHIP8_KEY3 BUTTON_FUNC
1138#define CHIP8_KEY4 BUTTON_REC
1139#define CHIP8_KEY5 BUTTON_PLAY
1140#define CHIP8_KEY6 BUTTON_VOL_DOWN
1141#define CHIP8_KEY8 BUTTON_VOL_UP
1142
1143#elif CONFIG_KEYPAD == MPIO_HD300_PAD
1144
1145#define CHIP8_OFF (BUTTON_MENU|BUTTON_REPEAT)
1146#define CHIP8_KEY1 BUTTON_REW
1147#define CHIP8_KEY2 BUTTON_FF
1148#define CHIP8_KEY3 BUTTON_MENU
1149#define CHIP8_KEY4 BUTTON_ENTER
1150#define CHIP8_KEY5 BUTTON_REC
1151#define CHIP8_KEY6 BUTTON_PLAY
1152#define CHIP8_KEY7 BUTTON_UP
1153#define CHIP8_KEY8 BUTTON_DOWN
1154
1155#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
1156
1157#define CHIP8_OFF BUTTON_POWER
1158#define CHIP8_KEY0 BUTTON_VOL_DOWN
1159#define CHIP8_KEY1 BUTTON_BACK
1160#define CHIP8_KEY2 BUTTON_UP
1161#define CHIP8_KEY3 BUTTON_PLAYPAUSE
1162#define CHIP8_KEY4 BUTTON_LEFT
1163#define CHIP8_KEY5 BUTTON_SELECT
1164#define CHIP8_KEY6 BUTTON_RIGHT
1165#define CHIP8_KEY7 BUTTON_BOTTOMLEFT
1166#define CHIP8_KEY8 BUTTON_DOWN
1167#define CHIP8_KEY9 BUTTON_BOTTOMRIGHT
1168#define CHIP8_KEYA BUTTON_VOL_UP
1169
1170#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
1171
1172#define CHIP8_OFF BUTTON_POWER
1173#define CHIP8_KEY1 BUTTON_LEFT
1174#define CHIP8_KEY2 BUTTON_UP
1175#define CHIP8_KEY3 BUTTON_RIGHT
1176#define CHIP8_KEY4 BUTTON_DOWN
1177#define CHIP8_KEY5 BUTTON_NEXT
1178#define CHIP8_KEY6 BUTTON_PREV
1179#define CHIP8_KEY7 BUTTON_SELECT
1180#define CHIP8_KEY8 BUTTON_VOL_DOWN
1181#define CHIP8_KEY9 BUTTON_VOL_UP
1182
1183#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
1184#define CHIP8_OFF (BUTTON_BACK|BUTTON_REPEAT)
1185#define CHIP8_KEY1 BUTTON_MENU
1186#define CHIP8_KEY2 BUTTON_UP
1187#define CHIP8_KEY3 BUTTON_DOWN
1188#define CHIP8_KEY4 BUTTON_LEFT
1189#define CHIP8_KEY5 BUTTON_SELECT
1190#define CHIP8_KEY6 BUTTON_RIGHT
1191#define CHIP8_KEY7 BUTTON_BACK
1192#define CHIP8_KEY8 BUTTON_POWER
1193#define CHIP8_KEY9 BUTTON_USER
1194
1195#elif (CONFIG_KEYPAD == HM60X_PAD)
1196#define CHIP8_OFF BUTTON_POWER
1197#define CHIP8_KEY2 BUTTON_UP
1198#define CHIP8_KEY4 BUTTON_DOWN
1199#define CHIP8_KEY5 BUTTON_SELECT
1200#define CHIP8_KEY6 BUTTON_RIGHT
1201#define CHIP8_KEY8 BUTTON_LEFT
1202
1203#elif (CONFIG_KEYPAD == SONY_NWZ_PAD)
1204#define CHIP8_OFF BUTTON_BACK
1205#define CHIP8_KEY2 BUTTON_UP
1206#define CHIP8_KEY4 BUTTON_DOWN
1207#define CHIP8_KEY5 BUTTON_PLAY
1208#define CHIP8_KEY6 BUTTON_RIGHT
1209#define CHIP8_KEY8 BUTTON_LEFT
1210
1211#elif (CONFIG_KEYPAD == CREATIVE_ZEN_PAD)
1212#define CHIP8_OFF BUTTON_BACK
1213#define CHIP8_KEY2 BUTTON_UP
1214#define CHIP8_KEY4 BUTTON_DOWN
1215#define CHIP8_KEY5 BUTTON_SELECT
1216#define CHIP8_KEY6 BUTTON_RIGHT
1217#define CHIP8_KEY8 BUTTON_LEFT
1218
1219#elif (CONFIG_KEYPAD == HM801_PAD)
1220#define CHIP8_OFF (BUTTON_POWER|BUTTON_SELECT)
1221#define CHIP8_KEY1 BUTTON_PREV
1222#define CHIP8_KEY2 BUTTON_UP
1223#define CHIP8_KEY3 BUTTON_DOWN
1224#define CHIP8_KEY4 BUTTON_LEFT
1225#define CHIP8_KEY5 BUTTON_SELECT
1226#define CHIP8_KEY6 BUTTON_RIGHT
1227#define CHIP8_KEY7 BUTTON_NEXT
1228#define CHIP8_KEY8 BUTTON_PLAY
1229#define CHIP8_KEY9 BUTTON_POWER
1230
1231#elif (CONFIG_KEYPAD == DX50_PAD)
1232#define CHIP8_OFF BUTTON_POWER
1233
1234#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
1235#define CHIP8_OFF BUTTON_POWER
1236#define CHIP8_KEY1 BUTTON_TOPLEFT
1237#define CHIP8_KEY2 BUTTON_TOPMIDDLE
1238#define CHIP8_KEY3 BUTTON_TOPRIGHT
1239#define CHIP8_KEY4 BUTTON_MIDLEFT
1240#define CHIP8_KEY5 BUTTON_CENTER
1241#define CHIP8_KEY6 BUTTON_MIDRIGHT
1242#define CHIP8_KEY7 BUTTON_BOTTOMLEFT
1243#define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE
1244#define CHIP8_KEY9 BUTTON_BOTTOMRIGHT
1245
1246#elif (CONFIG_KEYPAD == AGPTEK_ROCKER_PAD)
1247#define CHIP8_OFF BUTTON_POWER
1248#define CHIP8_KEY2 BUTTON_UP
1249#define CHIP8_KEY4 BUTTON_DOWN
1250#define CHIP8_KEY5 BUTTON_SELECT
1251#define CHIP8_KEY6 BUTTON_RIGHT
1252#define CHIP8_KEY8 BUTTON_LEFT
1253
1254#elif CONFIG_KEYPAD == XDUOO_X3_PAD || CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
1255#define CHIP8_OFF BUTTON_POWER
1256#define CHIP8_KEY2 BUTTON_HOME
1257#define CHIP8_KEY4 BUTTON_PREV
1258#define CHIP8_KEY5 BUTTON_PLAY
1259#define CHIP8_KEY6 BUTTON_NEXT
1260#define CHIP8_KEY8 BUTTON_OPTION
1261
1262#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
1263#define CHIP8_OFF BUTTON_POWER
1264#define CHIP8_KEY2 BUTTON_HOME
1265#define CHIP8_KEY4 BUTTON_PREV
1266#define CHIP8_KEY5 BUTTON_PLAY
1267#define CHIP8_KEY6 BUTTON_NEXT
1268#define CHIP8_KEY8 BUTTON_OPTION
1269
1270#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
1271#define CHIP8_OFF BUTTON_POWER
1272#define CHIP8_KEY2 BUTTON_NEXT
1273#define CHIP8_KEY4 BUTTON_HOME
1274#define CHIP8_KEY5 BUTTON_VOL_UP
1275#define CHIP8_KEY6 BUTTON_VOL_DOWN
1276#define CHIP8_KEY8 BUTTON_PREV
1277
1278#elif CONFIG_KEYPAD == EROSQ_PAD
1279#define CHIP8_OFF BUTTON_POWER
1280#define CHIP8_KEY2 BUTTON_NEXT
1281#define CHIP8_KEY4 BUTTON_MENU
1282#define CHIP8_KEY5 BUTTON_PLAY
1283#define CHIP8_KEY6 BUTTON_BACK
1284#define CHIP8_KEY8 BUTTON_PREV
1285
1286#elif CONFIG_KEYPAD == FIIO_M3K_PAD
1287#define CHIP8_OFF BUTTON_POWER
1288#define CHIP8_KEY2 BUTTON_MENU
1289#define CHIP8_KEY4 BUTTON_LEFT
1290#define CHIP8_KEY5 BUTTON_SELECT
1291#define CHIP8_KEY6 BUTTON_RIGHT
1292#define CHIP8_KEY8 BUTTON_BACK
1293
1294#elif CONFIG_KEYPAD == SDL_PAD
1295/* use touchscreen */
1296#elif (CONFIG_KEYPAD == MA_PAD)
1297#define CHIP8_OFF BUTTON_BACK
1298#define CHIP8_KEY2 BUTTON_UP
1299#define CHIP8_KEY4 BUTTON_DOWN
1300#define CHIP8_KEY5 BUTTON_PLAY
1301#define CHIP8_KEY6 BUTTON_RIGHT
1302#define CHIP8_KEY8 BUTTON_LEFT
1303
1304#elif CONFIG_KEYPAD == RG_NANO_PAD
1305#define CHIP8_OFF BUTTON_START
1306#define CHIP8_KEY1 BUTTON_Y
1307#define CHIP8_KEY2 BUTTON_A
1308#define CHIP8_KEY3 BUTTON_X
1309#define CHIP8_KEY4 BUTTON_LEFT
1310#define CHIP8_KEY5 BUTTON_UP
1311#define CHIP8_KEY6 BUTTON_RIGHT
1312#define CHIP8_KEY7 BUTTON_B
1313#define CHIP8_KEY8 BUTTON_DOWN
1314#define CHIP8_KEY9 BUTTON_R
1315#define CHIP8_KEY0 BUTTON_L
1316
1317#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
1318/* use touchscreen */
1319
1320#else
1321#error No keymap defined!
1322#endif
1323
1324#ifdef HAVE_TOUCHSCREEN
1325#ifndef CHIP8_OFF
1326#define CHIP8_OFF BUTTON_TOPLEFT
1327#endif
1328#ifndef CHIP8_KEY1
1329#define CHIP8_KEY1 BUTTON_TOPRIGHT
1330#endif
1331#ifndef CHIP8_KEY2
1332#define CHIP8_KEY2 BUTTON_TOPMIDDLE
1333#endif
1334#ifndef CHIP8_KEY3
1335#define CHIP8_KEY3 BUTTON_BOTTOMLEFT
1336#endif
1337#ifndef CHIP8_KEY4
1338#define CHIP8_KEY4 BUTTON_MIDLEFT
1339#endif
1340#ifndef CHIP8_KEY5
1341#define CHIP8_KEY5 BUTTON_CENTER
1342#endif
1343#ifndef CHIP8_KEY6
1344#define CHIP8_KEY6 BUTTON_MIDRIGHT
1345#endif
1346#ifndef CHIP8_KEY7
1347#define CHIP8_KEY7 BUTTON_BOTTOMRIGHT
1348#endif
1349#ifndef CHIP8_KEY8
1350#define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE
1351#endif
1352#endif
1353
1354static byte chip8_virtual_keys[16];
1355static byte chip8_keymap[16];
1356
1357static unsigned long starttimer; /* Timer value at the beginning */
1358static unsigned long cycles; /* Number of update cycles (50Hz) */
1359
1360/****************************************************************************/
1361/* Turn sound on */
1362/****************************************************************************/
1363static void chip8_sound_on (void)
1364{
1365}
1366
1367/****************************************************************************/
1368/* Turn sound off */
1369/****************************************************************************/
1370static void chip8_sound_off (void)
1371{
1372}
1373
1374/****************************************************************************/
1375/* Update the display */
1376/****************************************************************************/
1377static void chip8_update_display(void)
1378{
1379 int x, lcd_x, y, i;
1380 byte w;
1381 byte* row;
1382 /* frame buffer in hardware fomat */
1383 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH];
1384
1385 for (y=0;y<CHIP8_HEIGHT/8;++y)
1386 {
1387 row = lcd_framebuf[y];
1388 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x)
1389 {
1390 w = 0;
1391 for (i=0;i<8;i++)
1392 {
1393 w = w >> 1;
1394 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0)
1395 {
1396 w += 128;
1397 }
1398 }
1399#if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1400 if (x%8 == 1) {
1401 row[-1] |= w; /* overlay on */
1402 }
1403 else
1404#endif
1405 *row++ = w;
1406 }
1407 }
1408#if (CONFIG_PLATFORM & PLATFORM_HOSTED) || (LCD_DEPTH >= 4)
1409 rb->lcd_set_drawmode(DRMODE_SOLID);
1410 rb->lcd_mono_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH,
1411 CHIP8_HEIGHT);
1412 rb->lcd_update();
1413#else
1414 rb->lcd_blit_mono(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH,
1415 CHIP8_HEIGHT>>3, CHIP8_LCDWIDTH);
1416#endif
1417}
1418
1419static void chip8_keyboard(void)
1420{
1421 int i;
1422 int button = rb->button_get(false);
1423 switch (button)
1424 {
1425#ifdef CHIP8_RC_OFF
1426 case CHIP8_RC_OFF:
1427#endif
1428 case CHIP8_OFF: /* Abort Emulator */
1429 chip8_running = 0;
1430 break;
1431
1432 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break;
1433 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break;
1434 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break;
1435 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break;
1436 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break;
1437 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break;
1438 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break;
1439 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break;
1440 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break;
1441 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break;
1442#ifdef CHIP8_KEY1
1443 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break;
1444 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break;
1445#endif
1446#ifdef CHIP8_KEY3
1447 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break;
1448 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break;
1449#endif
1450#ifdef CHIP8_KEY7
1451 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break;
1452 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break;
1453#endif
1454#ifdef CHIP8_KEY9
1455 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break;
1456 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break;
1457#endif
1458#ifdef CHIP8_KEYA
1459 case CHIP8_KEYA: chip8_virtual_keys[10] = 1; break;
1460 case CHIP8_KEYA | BUTTON_REL: chip8_virtual_keys[10] = 0; break;
1461#endif
1462
1463 default:
1464 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1465 chip8_running = 2; /* indicates stopped because of USB */
1466 break;
1467 }
1468 for(i=0; i<16; i++) {
1469 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]];
1470 }
1471}
1472
1473/****************************************************************************/
1474/* Update keyboard and display, sync emulation with VDP clock */
1475/****************************************************************************/
1476static void chip8_interrupt (void)
1477{
1478 unsigned long current_tick;
1479 unsigned long timer, runtime;
1480
1481 chip8_update_display();
1482 chip8_keyboard();
1483 cycles ++;
1484 runtime = cycles * HZ / 50;
1485 timer = starttimer + runtime;
1486 current_tick = *rb->current_tick;
1487 if (TIME_AFTER(timer, current_tick))
1488 {
1489 rb->sleep(timer - current_tick);
1490 }
1491 else
1492 {
1493 rb->yield();
1494 }
1495}
1496
1497static bool chip8_init(const char* file)
1498{
1499 int numread;
1500 int fd;
1501 int len;
1502 int i;
1503
1504 fd = rb->open(file, O_RDONLY);
1505 if (fd < 0) {
1506 rb->lcd_puts(0, 6, "File Error.");
1507 return false;
1508 }
1509 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200);
1510 rb->close(fd);
1511 if (numread==-1) {
1512 rb->lcd_puts(0, 6, "I/O Error.");
1513 return false;
1514 }
1515
1516 /* is there a c8k file (chip8 keys) ? */
1517 char c8kname[MAX_PATH];
1518 rb->strcpy(c8kname, file);
1519 for(i=0; i<16; i++) {
1520 chip8_virtual_keys[i] = 0;
1521 chip8_keymap[i] = i;
1522 }
1523 len = rb->strlen(c8kname);
1524 c8kname[len-2] = '8';
1525 c8kname[len-1] = 'k';
1526 fd = rb->open(c8kname, O_RDONLY);
1527 if (fd >= 0) {
1528 rb->lcd_puts(0, 6, "File&Keymap OK.");
1529 numread = rb->read(fd, chip8_keymap, 16);
1530 rb->close(fd);
1531 }
1532 else
1533 {
1534 rb->lcd_puts(0, 6, "File OK.");
1535 }
1536 for(i=0; i<16; i++) {
1537 if (chip8_keymap[i] >= '0'
1538 && chip8_keymap[i] <= '9')
1539 chip8_keymap[i] -= '0';
1540 else if (chip8_keymap[i] >= 'A'
1541 && chip8_keymap[i] <= 'F')
1542 chip8_keymap[i] -= 'A' - 10;
1543 else if (chip8_keymap[i] >= 'a'
1544 && chip8_keymap[i] <= 'f')
1545 chip8_keymap[i] -= 'a' - 10;
1546 else
1547 chip8_keymap[i] %= 16;
1548 }
1549 return true;
1550}
1551
1552static bool chip8_run(const char* file)
1553{
1554 int ok;
1555
1556 rb->lcd_clear_display();
1557 rb->lcd_puts(0, 0, "SChip8 Emulator");
1558 rb->lcd_puts(0, 1, " (c) by ");
1559 rb->lcd_puts(0, 2, "Marcel de Kogel");
1560 rb->lcd_puts(0, 3, " Rockbox: ");
1561 rb->lcd_puts(0, 4, " Blueloop/Fdy ");
1562 rb->lcd_puts(0, 5, "---------------");
1563 ok = chip8_init(file);
1564 rb->lcd_update();
1565 rb->sleep(HZ*1);
1566 if (!ok)
1567 return false;
1568 rb->lcd_clear_display();
1569#if (CHIP8_X > 0) && (CHIP8_Y > 0)
1570 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2);
1571#endif
1572 rb->lcd_update();
1573 starttimer = *rb->current_tick;
1574
1575 chip8_iperiod=15;
1576 cycles = 0;
1577 chip8();
1578
1579 if (chip8_running == 3) {
1580 /* unsupported instruction */
1581 rb->splash(HZ, "Error: Unsupported"
1582#ifndef CHIP8_SUPER
1583 " CHIP-8 instruction. (maybe S-CHIP)"
1584#else
1585 " (S)CHIP-8 instruction."
1586#endif
1587 );
1588 return false;
1589 }
1590
1591 return true;
1592}
1593
1594
1595/***************** Plugin Entry Point *****************/
1596
1597enum plugin_status plugin_start(const void* parameter)
1598{
1599 const char* filename;
1600
1601 if (parameter == NULL)
1602 {
1603 rb->splash(HZ, "Play a .ch8 file!");
1604 return PLUGIN_ERROR;
1605 }
1606 else
1607 {
1608 filename = (char*) parameter;
1609 }
1610
1611 /* now go ahead and have fun! */
1612 if (chip8_run(filename))
1613 if (chip8_running == 0)
1614 return PLUGIN_OK;
1615 else
1616 return PLUGIN_USB_CONNECTED;
1617 else
1618 return PLUGIN_ERROR;
1619}