1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Orginal from Vision-8 Emulator / Copyright (C) 1997-1999 Marcel de Kogel
11 * Modified for Archos by Blueloop (a.wenger@gmx.de)
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 /* Only build for (correct) target */
25 #ifdef HAVE_LCD_BITMAP
29 static const struct plugin_api
* rb
; /* here is a global api struct pointer */
33 #define memset rb->memset
34 #define memcpy rb->memcpy
37 /* #define CHIP8_DEBUG */
39 #if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
40 #define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
43 /****************************************************************************/
44 /** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
45 /** The core is completely generic and can be used outside of Rockbox, **/
46 /** thus the STATIC, EXTERN etc. Please do not modify. **/
47 /****************************************************************************/
48 /** Vision8: CHIP8 emulator *************************************************/
52 /** This file contains the portable CHIP8 emulation engine definitions **/
54 /** Copyright (C) Marcel de Kogel 1997 **/
55 /** You are not allowed to distribute this software commercially **/
56 /** Please, notify me, if you make any changes to this file **/
57 /****************************************************************************/
66 typedef unsigned char byte
; /* sizeof(byte)==1 */
67 typedef unsigned short word
; /* sizeof(word)>=2 */
69 struct chip8_regs_struct
71 byte alg
[16]; /* 16 general registers */
72 byte delay
,sound
; /* delay and sound timer */
73 word i
; /* index register */
74 word pc
; /* program counter */
75 word sp
; /* stack pointer */
78 EXTERN
struct chip8_regs_struct chip8_regs
;
81 #define CHIP8_WIDTH 128
82 #define CHIP8_HEIGHT 64
83 EXTERN byte chip8_super
; /* != 0 if in SCHIP display mode */
85 #define CHIP8_WIDTH 64
86 #define CHIP8_HEIGHT 32
89 EXTERN byte chip8_iperiod
; /* number of opcodes per */
90 /* timeslice (1/50sec.) */
91 EXTERN byte chip8_keys
[16]; /* if 1, key is held down */
92 EXTERN byte chip8_display
[CHIP8_WIDTH
*CHIP8_HEIGHT
];/* 0xff if pixel is set, */
94 EXTERN byte chip8_mem
[4096]; /* machine memory. program */
95 /* is loaded at 0x200 */
96 EXTERN byte chip8_running
; /* if 0, emulation stops */
98 EXTERN
void chip8_execute (void); /* execute chip8_iperiod */
100 EXTERN
void chip8_reset (void); /* reset virtual machine */
101 EXTERN
void chip8 (void); /* start chip8 emulation */
103 EXTERN
void chip8_sound_on (void); /* turn sound on */
104 EXTERN
void chip8_sound_off (void); /* turn sound off */
105 EXTERN
void chip8_interrupt (void); /* update keyboard, */
109 EXTERN byte chip8_trace
; /* if 1, call debugger */
111 EXTERN word chip8_trap
; /* if pc==trap, set trace */
113 EXTERN
void chip8_debug (word opcode
,struct chip8_regs_struct
*regs
);
116 #endif /* __CHIP8_H */
118 /** Vision8: CHIP8 emulator *************************************************/
122 /** This file contains the portable CHIP8 emulation engine **/
123 /** SCHIP emulation (C) Frederic Devernay 2005 **/
125 /** Copyright (C) Marcel de Kogel 1997 **/
126 /** You are not allowed to distribute this software commercially **/
127 /** Please, notify me, if you make any changes to this file **/
128 /****************************************************************************/
131 #define STATIC static
132 #define EXTERN static
133 and include this file for single-object generation
137 #include <stdlib.h> /* for memset, etc. */
144 #define DBG_(_x) ((void)(_x))
146 #define DBG_(_x) ((void)0)
149 STATIC
struct chip8_regs_struct chip8_regs
;
151 static byte chip8_key_pressed
;
152 STATIC byte chip8_keys
[16]; /* if 1, key is held down */
153 STATIC byte chip8_display
[CHIP8_WIDTH
*CHIP8_HEIGHT
]; /* 0xff if pixel is set, */
156 STATIC byte chip8_super
; /* != 0 if in SCHIP display mode */
158 STATIC byte chip8_mem
[4096]; /* machine memory. program */
159 /* is loaded at 0x200 */
161 #define read_mem(a) (chip8_mem[(a)&4095])
162 #define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
164 STATIC byte chip8_iperiod
;
166 STATIC byte chip8_running
; /* Flag for End-of-Emulation */
168 #define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
169 #define get_reg_value(opcode) (*get_reg_offset(opcode))
170 #define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f))
171 #define get_reg_value_2(opcode) (*get_reg_offset_2(opcode))
173 typedef void (*opcode_fn
) (word opcode
);
174 typedef void (*math_fn
) (byte
*reg1
,byte reg2
);
178 static void op_call (word opcode
)
181 write_mem (chip8_regs
.sp
,chip8_regs
.pc
&0xff);
183 write_mem (chip8_regs
.sp
,chip8_regs
.pc
>>8);
184 chip8_regs
.pc
=opcode
;
186 if(chip8_regs
.sp
< 0x1c0)
187 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs
.sp
);
191 static void op_jmp (word opcode
)
193 chip8_regs
.pc
=opcode
;
196 static void op_key (word opcode
)
199 static byte tested
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
201 byte key
, key_value
,cp_value
;
202 if ((opcode
&0xff)==0x9e) /* skp */
204 else if ((opcode
&0xff)==0xa1) /* sknp */
207 DBG_(printf("unhandled key opcode 0x%x\n", opcode
));
210 key
= get_reg_value(opcode
)&0x0f;
214 DBG_(printf("testing key %d\n", key
));
217 key_value
=chip8_keys
[key
];
218 if (cp_value
==key_value
)
222 static void op_skeq_const (word opcode
)
224 if (get_reg_value(opcode
)==(opcode
&0xff))
228 static void op_skne_const (word opcode
)
230 if (get_reg_value(opcode
)!=(opcode
&0xff))
234 static void op_skeq_reg (word opcode
)
236 if (get_reg_value(opcode
)==get_reg_value_2(opcode
))
240 static void op_skne_reg (word opcode
)
242 if (get_reg_value(opcode
)!=get_reg_value_2(opcode
))
246 static void op_mov_const (word opcode
)
248 *get_reg_offset(opcode
)=opcode
&0xff;
251 static void op_add_const (word opcode
)
253 *get_reg_offset(opcode
)+=opcode
&0xff;
256 static void op_mvi (word opcode
)
261 static void op_jmi (word opcode
)
263 chip8_regs
.pc
=opcode
+chip8_regs
.alg
[0];
266 static void op_rand (word opcode
)
268 *get_reg_offset(opcode
)=rand()&(opcode
&0xff);
271 static void math_or (byte
*reg1
,byte reg2
)
276 static void math_mov (byte
*reg1
,byte reg2
)
281 static void math_nop (byte
*reg1
,byte reg2
)
285 DBG_(printf("Warning: math nop!\n"));
288 static void math_and (byte
*reg1
,byte reg2
)
293 static void math_xor (byte
*reg1
,byte reg2
)
298 static void math_add (byte
*reg1
,byte reg2
)
303 chip8_regs
.alg
[15]=tmp
>>8;
306 static void math_sub (byte
*reg1
,byte reg2
)
311 chip8_regs
.alg
[15]=((byte
)(tmp
>>8))+1;
314 static void math_shr (byte
*reg1
,byte reg2
)
317 chip8_regs
.alg
[15]=*reg1
&1;
321 static void math_shl (byte
*reg1
,byte reg2
)
324 chip8_regs
.alg
[15]=*reg1
>>7;
328 static void math_rsb (byte
*reg1
,byte reg2
)
333 chip8_regs
.alg
[15]=((byte
)(tmp
>>8))+1;
337 /* SUPER: scroll down n lines (or half in CHIP8 mode) */
338 static void scroll_down(word opcode
)
340 int n
= opcode
& 0xf;
341 byte
*dst
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
-1;
342 byte
*src
= dst
- n
*CHIP8_WIDTH
;
343 while(src
>= chip8_display
) {
346 while(dst
>= chip8_display
) {
350 /* SUPER: scroll 4 pixels left! */
351 static void scroll_left(void)
353 byte
*dst
= chip8_display
;
355 byte
*eol
= chip8_display
+ CHIP8_WIDTH
;
356 byte
*eoi
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
;
369 static void scroll_right(void)
371 byte
*dst
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
-1;
373 byte
*bol
= chip8_display
+ CHIP8_WIDTH
*(CHIP8_HEIGHT
-1);
374 while(bol
>= chip8_display
) {
388 static void op_system (word opcode
)
390 switch ((byte
)opcode
)
400 DBG_(printf("SUPER: quit the emulator\n"));
404 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
405 memset (chip8_display
,0,sizeof(chip8_display
));
409 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
410 memset (chip8_display
,0,sizeof(chip8_display
));
415 memset (chip8_display
,0,sizeof(chip8_display
));
418 chip8_regs
.pc
=read_mem(chip8_regs
.sp
)<<8;
420 chip8_regs
.pc
+=read_mem(chip8_regs
.sp
);
425 if ((opcode
& 0xF0) == 0xC0)
430 DBG_(printf("unhandled system opcode 0x%x\n", opcode
));
437 static void op_misc (word opcode
)
441 static byte firstwait
= 1;
443 reg
=get_reg_offset(opcode
);
444 switch ((byte
)opcode
)
446 case 0x07: /* gdelay */
447 *reg
=chip8_regs
.delay
;
452 printf("waiting for key press\n");
456 if (chip8_key_pressed
)
457 *reg
=chip8_key_pressed
-1;
461 case 0x15: /* sdelay */
462 chip8_regs
.delay
=*reg
;
464 case 0x18: /* ssound */
465 chip8_regs
.sound
=*reg
;
466 if (chip8_regs
.sound
)
470 chip8_regs
.i
+=(*reg
);
472 case 0x29: /* font */
473 chip8_regs
.i
=((word
)(*reg
&0x0f))*5;
476 case 0x30: /* xfont */
477 chip8_regs
.i
=((word
)(*reg
&0x0f))*10+0x50;
482 for (j
=0;i
>=100;i
-=100)
484 write_mem (chip8_regs
.i
,j
);
485 for (j
=0;i
>=10;i
-=10)
487 write_mem (chip8_regs
.i
+1,j
);
488 write_mem (chip8_regs
.i
+2,i
);
491 for (i
=0,j
=(opcode
>>8)&0x0f; i
<=j
; ++i
)
492 write_mem(chip8_regs
.i
+i
,chip8_regs
.alg
[i
]);
495 for (i
=0,j
=(opcode
>>8)&0x0f; i
<=j
; ++i
)
496 chip8_regs
.alg
[i
]=read_mem(chip8_regs
.i
+i
);
500 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode
>>8)&0x0f));
503 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode
>>8)&0x0f));
507 DBG_(printf("unhandled misc opcode 0x%x\n", opcode
));
512 static void op_sprite (word opcode
)
515 byte n
,x
,x2
,y
,collision
;
517 x
=get_reg_value(opcode
);
518 y
=get_reg_value_2(opcode
);
523 /*printf("SUPER: sprite(%x)\n", opcode);*/
526 q
=chip8_display
+y
*CHIP8_WIDTH
;
532 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
535 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
537 collision
&=(q
[x2
]^=0xff);
538 x2
=(x
+8)&(CHIP8_WIDTH
-1);
540 for (y
=read_mem(p
++);y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
542 collision
&=(q
[x2
]^=0xff);
549 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
551 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
553 collision
&=(q
[x2
]^=0xff);
560 q
=chip8_display
+y
*CHIP8_WIDTH
*2;
565 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
*2)
567 for (y
=read_mem(p
++),x2
=x
*2;y
;y
<<=1,x2
=(x2
+2)&(CHIP8_WIDTH
-1))
571 q
[x2
+CHIP8_WIDTH
]^=0xff;
572 q
[x2
+CHIP8_WIDTH
+1]^=0xff;
573 collision
&= q
[x2
]|q
[x2
+1]|q
[x2
+CHIP8_WIDTH
]|q
[x2
+CHIP8_WIDTH
+1];
580 q
=chip8_display
+y
*CHIP8_WIDTH
;
583 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
585 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
587 collision
&=(q
[x2
]^=0xff);
590 chip8_regs
.alg
[15]=collision
^1;
593 static math_fn math_opcodes
[16]=
613 static void op_math (word opcode
)
615 (*(math_opcodes
[opcode
&0x0f]))
616 (get_reg_offset(opcode
),get_reg_value_2(opcode
));
619 static opcode_fn main_opcodes
[16]=
640 STATIC byte chip8_trace
;
641 STATIC word chip8_trap
;
643 /****************************************************************************/
644 /* This routine is called every opcode when chip8_trace==1. It prints the */
645 /* current register contents and the opcode being executed */
646 /****************************************************************************/
647 STATIC
void chip8_debug (word opcode
,struct chip8_regs_struct
*regs
)
650 byte hextable
[16] = "0123456789ABCDEF";
653 v1
[1] = hextable
[(opcode
>>8)&0x0f];
654 v2
[1] = hextable
[(opcode
>>8)&0x0f];
655 printf ("PC=%04X: %04X - ",regs
->pc
,opcode
);
656 switch (opcode
>>12) {
658 if ((opcode
&0xff0) == 0xc0) {
659 printf ("SCD %01X ; Scroll down n lines",opcode
&0xf);
661 else switch (opcode
&0xfff) {
663 printf ("CLS ; Clear screen");
666 printf ("RET ; Return from subroutine call");
669 printf("SCR ; Scroll right");
672 printf("SCL ; Scroll left");
675 printf("EXIT ; Terminate the interpreter");
678 printf("LOW ; Disable extended screen mode");
681 printf("HIGH ; Enable extended screen mode");
684 printf ("SYS %03X ; Unknown system call",opcode
&0xff);
688 printf ("JP %03X ; Jump to address",opcode
&0xfff);
691 printf ("CALL %03X ; Call subroutine",opcode
&0xfff);
694 printf ("SE %s,%02X ; Skip if register == constant",v1
,opcode
&0xff);
697 printf ("SNE %s,%02X ; Skip if register <> constant",v1
,opcode
&0xff);
700 printf ("SE %s,%s ; Skip if register == register",v1
,v2
);
703 printf ("LD %s,%02X ; Set VX = Byte",v1
,opcode
&0xff);
706 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1
,opcode
&0xff);
709 switch (opcode
&0x0f) {
711 printf ("LD %s,%s ; Set VX = VY, VF updates",v1
,v2
);
714 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1
,v2
);
717 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1
,v2
);
720 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1
,v2
);
723 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1
,v2
);
726 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1
,v2
);
729 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1
,v2
);
732 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1
,v2
);
735 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1
,v2
);
738 printf ("Illegal opcode");
742 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1
,v2
);
745 printf ("LD I,%03X ; Set I = Addr",opcode
&0xfff);
748 printf ("JP V0,%03X ; Jump to Addr + V0",opcode
&0xfff);
751 printf ("RND %s,%02X ; Set VX = random & Byte",v1
,opcode
&0xff);
754 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1
,v2
,opcode
&0x0f);
757 switch (opcode
&0xff) {
759 printf ("SKP %s ; Skip next instruction if key VX down",v1
);
762 printf ("SKNP %s ; Skip next instruction if key VX up",v1
);
765 printf ("%04X ; Illegal opcode", opcode
);
769 switch (opcode
&0xff) {
771 printf ("LD %s,DT ; Set VX = delaytimer",v1
);
774 printf ("LD %s,K ; Set VX = key, wait for keypress",v1
);
777 printf ("LD DT,%s ; Set delaytimer = VX",v1
);
780 printf ("LD ST,%s ; Set soundtimer = VX",v1
);
783 printf ("ADD I,%s ; Set I = I + VX",v1
);
786 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1
);
789 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1
);
792 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1
);
795 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1
);
798 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1
);
801 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1
);
804 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1
);
807 printf ("%04X ; Illegal opcode", opcode
);
811 printf ("\n; Registers: ");
812 for (i
=0;i
<16;++i
) printf ("%02x ",(regs
->alg
[i
])&0xff);
813 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
814 regs
->i
&0xfff,regs
->sp
&0xfff,regs
->delay
&0xff,regs
->sound
&0xff);
818 /****************************************************************************/
819 /* Execute chip8_iperiod opcodes */
820 /****************************************************************************/
821 STATIC
void chip8_execute(void)
826 for (i
= chip8_iperiod
; i
;--i
)
828 /* Fetch the opcode */
829 opcode
=(read_mem(chip8_regs
.pc
)<<8)+read_mem(chip8_regs
.pc
+1);
831 /* Check if trap address has been reached */
832 if ((chip8_regs
.pc
&4095)==chip8_trap
)
834 /* Call the debugger if chip8_trace!=0 */
836 chip8_debug (opcode
,&chip8_regs
);
839 (*(main_opcodes
[opcode
>>12]))(opcode
&0x0fff); /* Emulate this opcode */
842 if (chip8_regs
.delay
)
844 if (chip8_regs
.sound
)
845 if (--chip8_regs
.sound
== 0)
848 /* Update the machine status */
851 for (i
=key_pressed
=0;i
<16;++i
) /* check if a key was first */
852 if (chip8_keys
[i
]) /* pressed */
854 if (key_pressed
&& key_pressed
!=chip8_key_pressed
)
855 chip8_key_pressed
=key_pressed
;
860 /****************************************************************************/
861 /* Reset the virtual chip8 machine */
862 /****************************************************************************/
863 STATIC
void chip8_reset(void)
865 static byte chip8_sprites
[0x50]=
867 0xf9,0x99,0xf2,0x62,0x27,
868 0xf1,0xf8,0xff,0x1f,0x1f,
869 0x99,0xf1,0x1f,0x8f,0x1f,
870 0xf8,0xf9,0xff,0x12,0x44,
871 0xf9,0xf9,0xff,0x9f,0x1f,
872 0xf9,0xf9,0x9e,0x9e,0x9e,
873 0xf8,0x88,0xfe,0x99,0x9e,
874 0xf8,0xf8,0xff,0x8f,0x88,
875 }; /* 4x5 pixel hexadecimal character font patterns */
877 static byte schip_sprites
[10*10]=
879 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
880 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
881 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
882 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
883 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
884 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
885 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
886 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
887 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
888 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
889 }; /* 8x10 pixel font patterns (only 10) */
894 write_mem (i
<<1,chip8_sprites
[i
]&0xf0);
895 write_mem ((i
<<1)+1,chip8_sprites
[i
]<<4);
899 for (i=0; i<100; i++)
900 write_mem (i+0x50,schip_sprites[i]);
902 memcpy(chip8_mem
+0x50, schip_sprites
, 100);
905 memset (chip8_regs
.alg
,0,sizeof(chip8_regs
.alg
));
906 memset (chip8_keys
,0,sizeof(chip8_keys
));
908 memset (chip8_display
,0,sizeof(chip8_display
));
909 chip8_regs
.delay
=chip8_regs
.sound
=chip8_regs
.i
=0;
920 /****************************************************************************/
921 /* Start CHIP8 emulation */
922 /****************************************************************************/
923 STATIC
void chip8 (void)
926 while (chip8_running
==1) chip8_execute ();
929 /****************************************************************************/
930 /** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
931 /****************************************************************************/
933 /* size of the displayed area */
934 #if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
935 #define CHIP8_LCDWIDTH 112
937 #define CHIP8_LCDWIDTH CHIP8_WIDTH
940 #if (LCD_WIDTH > CHIP8_LCDWIDTH)
941 #define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
945 #if (LCD_HEIGHT > CHIP8_HEIGHT)
946 #define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
951 /* variable button definitions */
952 #if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
953 #define CHIP8_OFF BUTTON_OFF
954 #define CHIP8_KEY1 BUTTON_F1
955 #define CHIP8_KEY2 BUTTON_UP
956 #define CHIP8_KEY3 BUTTON_F3
957 #define CHIP8_KEY4 BUTTON_LEFT
958 #define CHIP8_KEY5 BUTTON_PLAY
959 #define CHIP8_KEY6 BUTTON_RIGHT
960 #define CHIP8_KEY7 BUTTON_F2
961 #define CHIP8_KEY8 BUTTON_DOWN
962 #define CHIP8_KEY9 BUTTON_ON
964 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD /* only 9 out of 16 chip8 buttons */
965 #define CHIP8_OFF BUTTON_OFF
966 #define CHIP8_KEY1 BUTTON_F1
967 #define CHIP8_KEY2 BUTTON_UP
968 #define CHIP8_KEY3 BUTTON_F3
969 #define CHIP8_KEY4 BUTTON_LEFT
970 #define CHIP8_KEY5 BUTTON_SELECT
971 #define CHIP8_KEY6 BUTTON_RIGHT
972 #define CHIP8_KEY7 BUTTON_F2
973 #define CHIP8_KEY8 BUTTON_DOWN
974 #define CHIP8_KEY9 BUTTON_ON
976 #elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
977 #define CHIP8_OFF BUTTON_OFF
978 #define CHIP8_KEY2 BUTTON_UP
979 #define CHIP8_KEY4 BUTTON_LEFT
980 #define CHIP8_KEY5 BUTTON_MENU
981 #define CHIP8_KEY6 BUTTON_RIGHT
982 #define CHIP8_KEY8 BUTTON_DOWN
984 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
985 (CONFIG_KEYPAD == IRIVER_H300_PAD)
986 #define CHIP8_OFF BUTTON_OFF
987 #define CHIP8_KEY2 BUTTON_UP
988 #define CHIP8_KEY4 BUTTON_LEFT
989 #define CHIP8_KEY5 BUTTON_SELECT
990 #define CHIP8_KEY6 BUTTON_RIGHT
991 #define CHIP8_KEY8 BUTTON_DOWN
993 #define CHIP8_RC_OFF BUTTON_RC_STOP
995 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
996 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
997 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
998 #define CHIP8_OFF BUTTON_MENU
999 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
1000 #define CHIP8_KEY4 BUTTON_LEFT
1001 #define CHIP8_KEY5 BUTTON_PLAY
1002 #define CHIP8_KEY6 BUTTON_RIGHT
1003 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1005 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
1006 #define CHIP8_OFF BUTTON_POWER
1007 #define CHIP8_KEY2 BUTTON_UP
1008 #define CHIP8_KEY4 BUTTON_LEFT
1009 #define CHIP8_KEY5 BUTTON_SELECT
1010 #define CHIP8_KEY6 BUTTON_RIGHT
1011 #define CHIP8_KEY8 BUTTON_DOWN
1013 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
1014 #define CHIP8_OFF BUTTON_POWER
1015 #define CHIP8_KEY1 BUTTON_MENU
1016 #define CHIP8_KEY2 BUTTON_UP
1017 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1018 #define CHIP8_KEY4 BUTTON_LEFT
1019 #define CHIP8_KEY5 BUTTON_SELECT
1020 #define CHIP8_KEY6 BUTTON_RIGHT
1021 #define CHIP8_KEY7 BUTTON_VOL_UP
1022 #define CHIP8_KEY8 BUTTON_DOWN
1023 #define CHIP8_KEY9 BUTTON_A
1025 #elif CONFIG_KEYPAD == SANSA_E200_PAD
1026 #define CHIP8_OFF BUTTON_POWER
1027 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
1028 #define CHIP8_KEY4 BUTTON_LEFT
1029 #define CHIP8_KEY5 BUTTON_SELECT
1030 #define CHIP8_KEY6 BUTTON_RIGHT
1031 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1033 #elif CONFIG_KEYPAD == SANSA_C200_PAD
1034 #define CHIP8_OFF BUTTON_POWER
1035 #define CHIP8_KEY2 BUTTON_VOL_UP
1036 #define CHIP8_KEY4 BUTTON_LEFT
1037 #define CHIP8_KEY5 BUTTON_SELECT
1038 #define CHIP8_KEY6 BUTTON_RIGHT
1039 #define CHIP8_KEY8 BUTTON_VOL_DOWN
1041 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
1042 #define CHIP8_OFF BUTTON_POWER
1043 #define CHIP8_KEY2 BUTTON_SCROLL_UP
1044 #define CHIP8_KEY4 BUTTON_LEFT
1045 #define CHIP8_KEY5 BUTTON_PLAY
1046 #define CHIP8_KEY6 BUTTON_RIGHT
1047 #define CHIP8_KEY8 BUTTON_SCROLL_DOWN
1049 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
1050 #define CHIP8_OFF BUTTON_BACK
1051 #define CHIP8_KEY1 BUTTON_MENU
1052 #define CHIP8_KEY2 BUTTON_UP
1053 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1054 #define CHIP8_KEY4 BUTTON_LEFT
1055 #define CHIP8_KEY5 BUTTON_SELECT
1056 #define CHIP8_KEY6 BUTTON_RIGHT
1057 #define CHIP8_KEY7 BUTTON_VOL_UP
1058 #define CHIP8_KEY8 BUTTON_DOWN
1059 #define CHIP8_KEY9 BUTTON_PLAY
1061 #elif (CONFIG_KEYPAD == MROBE100_PAD)
1062 #define CHIP8_OFF BUTTON_POWER
1063 #define CHIP8_KEY1 BUTTON_MENU
1064 #define CHIP8_KEY2 BUTTON_UP
1065 #define CHIP8_KEY3 BUTTON_PLAY
1066 #define CHIP8_KEY4 BUTTON_LEFT
1067 #define CHIP8_KEY5 BUTTON_SELECT
1068 #define CHIP8_KEY6 BUTTON_RIGHT
1069 #define CHIP8_KEY7 BUTTON_DISPLAY
1070 #define CHIP8_KEY8 BUTTON_DOWN
1072 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1073 #define CHIP8_OFF BUTTON_RC_REC
1074 #define CHIP8_KEY1 BUTTON_RC_MENU
1075 #define CHIP8_KEY2 BUTTON_RC_VOL_UP
1076 #define CHIP8_KEY3 BUTTON_RC_MODE
1077 #define CHIP8_KEY4 BUTTON_RC_REW
1078 #define CHIP8_KEY5 BUTTON_RC_PLAY
1079 #define CHIP8_KEY6 BUTTON_RC_FF
1080 #define CHIP8_KEY8 BUTTON_RC_VOL_DOWN
1082 #elif (CONFIG_KEYPAD == COWOND2_PAD)
1083 #define CHIP8_OFF BUTTON_POWER
1086 #error No keymap defined!
1089 #ifdef HAVE_TOUCHSCREEN
1091 #define CHIP8_OFF BUTTON_TOPLEFT
1094 #define CHIP8_KEY1 BUTTON_TOPRIGHT
1097 #define CHIP8_KEY2 BUTTON_TOPMIDDLE
1100 #define CHIP8_KEY3 BUTTON_BOTTOMLEFT
1103 #define CHIP8_KEY4 BUTTON_MIDLEFT
1106 #define CHIP8_KEY5 BUTTON_CENTER
1109 #define CHIP8_KEY6 BUTTON_MIDRIGHT
1112 #define CHIP8_KEY7 BUTTON_BOTTOMRIGHT
1115 #define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE
1119 static byte chip8_virtual_keys
[16];
1120 static byte chip8_keymap
[16];
1122 static unsigned long starttimer
; /* Timer value at the beginning */
1123 static unsigned long cycles
; /* Number of update cycles (50Hz) */
1126 static bool is_playing
;
1129 /* one frame of bitswapped mp3 data */
1130 static unsigned char beep
[]={255,
1131 223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
1132 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
1133 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
1134 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
1135 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
1136 252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
1137 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
1138 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
1139 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
1140 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
1141 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
1143 /* callback to request more mp3 data */
1144 void callback(unsigned char** start
, size_t* size
)
1146 *start
= beep
; /* give it the same frame again */
1147 *size
= sizeof(beep
);
1150 /****************************************************************************/
1152 /****************************************************************************/
1153 static void chip8_sound_on (void)
1157 rb
->mp3_play_pause(true); /* kickoff audio */
1161 /****************************************************************************/
1162 /* Turn sound off */
1163 /****************************************************************************/
1164 static void chip8_sound_off (void)
1168 rb
->mp3_play_pause(false); /* pause audio */
1172 /****************************************************************************/
1173 /* Update the display */
1174 /****************************************************************************/
1175 static void chip8_update_display(void)
1180 /* frame buffer in hardware fomat */
1181 unsigned char lcd_framebuf
[CHIP8_HEIGHT
/8][CHIP8_LCDWIDTH
];
1183 for (y
=0;y
<CHIP8_HEIGHT
/8;++y
)
1185 row
= lcd_framebuf
[y
];
1186 for (x
=0, lcd_x
=0;x
<CHIP8_WIDTH
;++x
,++lcd_x
)
1192 if (chip8_display
[x
+(y
*8+i
)*CHIP8_WIDTH
] != 0)
1197 #if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1199 row
[-1] |= w
; /* overlay on */
1206 #if defined(SIMULATOR) || (LCD_DEPTH > 1)
1207 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1208 rb
->lcd_mono_bitmap(lcd_framebuf
[0], CHIP8_X
, CHIP8_Y
, CHIP8_LCDWIDTH
,
1212 rb
->lcd_blit_mono(lcd_framebuf
[0], CHIP8_X
, CHIP8_Y
>>3, CHIP8_LCDWIDTH
,
1213 CHIP8_HEIGHT
>>3, CHIP8_LCDWIDTH
);
1217 static void chip8_keyboard(void)
1220 int button
= rb
->button_get(false);
1226 case CHIP8_OFF
: /* Abort Emulator */
1230 case CHIP8_KEY2
: chip8_virtual_keys
[2] = 1; break;
1231 case CHIP8_KEY2
| BUTTON_REL
: chip8_virtual_keys
[2] = 0; break;
1232 case CHIP8_KEY4
: chip8_virtual_keys
[4] = 1; break;
1233 case CHIP8_KEY4
| BUTTON_REL
: chip8_virtual_keys
[4] = 0; break;
1234 case CHIP8_KEY6
: chip8_virtual_keys
[6] = 1; break;
1235 case CHIP8_KEY6
| BUTTON_REL
: chip8_virtual_keys
[6] = 0; break;
1236 case CHIP8_KEY8
: chip8_virtual_keys
[8] = 1; break;
1237 case CHIP8_KEY8
| BUTTON_REL
: chip8_virtual_keys
[8] = 0; break;
1238 case CHIP8_KEY5
: chip8_virtual_keys
[5] = 1; break;
1239 case CHIP8_KEY5
| BUTTON_REL
: chip8_virtual_keys
[5] = 0; break;
1241 case CHIP8_KEY1
: chip8_virtual_keys
[1] = 1; break;
1242 case CHIP8_KEY1
| BUTTON_REL
: chip8_virtual_keys
[1] = 0; break;
1245 case CHIP8_KEY3
: chip8_virtual_keys
[3] = 1; break;
1246 case CHIP8_KEY3
| BUTTON_REL
: chip8_virtual_keys
[3] = 0; break;
1249 case CHIP8_KEY7
: chip8_virtual_keys
[7] = 1; break;
1250 case CHIP8_KEY7
| BUTTON_REL
: chip8_virtual_keys
[7] = 0; break;
1253 case CHIP8_KEY9
: chip8_virtual_keys
[9] = 1; break;
1254 case CHIP8_KEY9
| BUTTON_REL
: chip8_virtual_keys
[9] = 0; break;
1258 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
1259 chip8_running
= 2; /* indicates stopped because of USB */
1262 for(i
=0; i
<16; i
++) {
1263 chip8_keys
[i
] = chip8_virtual_keys
[chip8_keymap
[i
]];
1267 /****************************************************************************/
1268 /* Update keyboard and display, sync emulation with VDP clock */
1269 /****************************************************************************/
1270 static void chip8_interrupt (void)
1272 unsigned long newtimer
;
1273 unsigned long timer
, runtime
;
1275 chip8_update_display();
1278 runtime
= cycles
* HZ
/ 50;
1279 timer
= starttimer
+ runtime
;
1280 newtimer
= *rb
->current_tick
;
1281 if (TIME_AFTER(timer
, newtimer
))
1283 rb
->sleep(timer
- newtimer
);
1289 starttimer
= newtimer
- runtime
;
1292 static bool chip8_init(const char* file
)
1299 fd
= rb
->open(file
, O_RDONLY
);
1301 rb
->lcd_puts(0, 6, "File Error.");
1304 numread
= rb
->read(fd
, chip8_mem
+0x200, 4096-0x200);
1306 rb
->lcd_puts(0, 6, "I/O Error.");
1311 /* is there a c8k file (chip8 keys) ? */
1312 char c8kname
[MAX_PATH
];
1313 rb
->strcpy(c8kname
, file
);
1314 for(i
=0; i
<16; i
++) {
1315 chip8_virtual_keys
[i
] = 0;
1316 chip8_keymap
[i
] = i
;
1318 len
= rb
->strlen(c8kname
);
1319 c8kname
[len
-2] = '8';
1320 c8kname
[len
-1] = 'k';
1321 fd
= rb
->open(c8kname
, O_RDONLY
);
1323 rb
->lcd_puts(0, 6, "File&Keymap OK.");
1324 numread
= rb
->read(fd
, chip8_keymap
, 16);
1329 rb
->lcd_puts(0, 6, "File OK.");
1331 for(i
=0; i
<16; i
++) {
1332 if (chip8_keymap
[i
] >= '0'
1333 && chip8_keymap
[i
] <= '9')
1334 chip8_keymap
[i
] -= '0';
1335 else if (chip8_keymap
[i
] >= 'A'
1336 && chip8_keymap
[i
] <= 'F')
1337 chip8_keymap
[i
] -= 'A' - 10;
1338 else if (chip8_keymap
[i
] >= 'a'
1339 && chip8_keymap
[i
] <= 'f')
1340 chip8_keymap
[i
] -= 'a' - 10;
1342 chip8_keymap
[i
] %= 16;
1347 bool chip8_run(const char* file
)
1351 rb
->lcd_clear_display();
1352 rb
->lcd_puts(0, 0, "SChip8 Emulator");
1353 rb
->lcd_puts(0, 1, " (c) by ");
1354 rb
->lcd_puts(0, 2, "Marcel de Kogel");
1355 rb
->lcd_puts(0, 3, " Rockbox: ");
1356 rb
->lcd_puts(0, 4, " Blueloop/Fdy ");
1357 rb
->lcd_puts(0, 5, "---------------");
1358 ok
= chip8_init(file
);
1363 rb
->lcd_clear_display();
1364 #if (CHIP8_X > 0) && (CHIP8_Y > 0)
1365 rb
->lcd_drawrect(CHIP8_X
-1,CHIP8_Y
-1,CHIP8_LCDWIDTH
+2,CHIP8_HEIGHT
+2);
1371 is_playing
= rb
->mp3_is_playing(); /* would we disturb playback? */
1372 if (!is_playing
) /* no? then we can make sound */
1374 rb
->mp3_play_data(beep
, sizeof(beep
), callback
);
1377 starttimer
= *rb
->current_tick
;
1384 rb
->splash(HZ
, "Error");
1390 { /* stop it if we used audio */
1391 rb
->mp3_play_stop(); /* Stop audio playback */
1395 if (chip8_running
== 3) {
1396 /* unsupported instruction */
1397 rb
->splash(HZ
, "Error: Unsupported"
1399 " CHIP-8 instruction. (maybe S-CHIP)"
1401 " (S)CHIP-8 instruction."
1411 /***************** Plugin Entry Point *****************/
1413 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
1415 const char* filename
;
1417 rb
= api
; /* copy to global api pointer */
1419 if (parameter
== NULL
)
1421 rb
->splash(HZ
, "Play a .ch8 file!");
1422 return PLUGIN_ERROR
;
1426 filename
= (char*) parameter
;
1429 /* now go ahead and have fun! */
1430 if (chip8_run(filename
))
1431 if (chip8_running
== 0)
1434 return PLUGIN_USB_CONNECTED
;
1436 return PLUGIN_ERROR
;
1438 #endif /* #ifdef HAVE_LCD_BITMAP */