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 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
22 /* Only build for (correct) target */
23 #ifdef HAVE_LCD_BITMAP
27 static struct plugin_api
* rb
; /* here is a global api struct pointer */
31 #define memset rb->memset
32 #define memcpy rb->memcpy
35 /* #define CHIP8_DEBUG */
37 #if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
38 #define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
41 /****************************************************************************/
42 /** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
43 /** The core is completely generic and can be used outside of Rockbox, **/
44 /** thus the STATIC, EXTERN etc. Please do not modify. **/
45 /****************************************************************************/
46 /** Vision8: CHIP8 emulator *************************************************/
50 /** This file contains the portable CHIP8 emulation engine definitions **/
52 /** Copyright (C) Marcel de Kogel 1997 **/
53 /** You are not allowed to distribute this software commercially **/
54 /** Please, notify me, if you make any changes to this file **/
55 /****************************************************************************/
64 typedef unsigned char byte
; /* sizeof(byte)==1 */
65 typedef unsigned short word
; /* sizeof(word)>=2 */
67 struct chip8_regs_struct
69 byte alg
[16]; /* 16 general registers */
70 byte delay
,sound
; /* delay and sound timer */
71 word i
; /* index register */
72 word pc
; /* program counter */
73 word sp
; /* stack pointer */
76 EXTERN
struct chip8_regs_struct chip8_regs
;
79 #define CHIP8_WIDTH 128
80 #define CHIP8_HEIGHT 64
81 EXTERN byte chip8_super
; /* != 0 if in SCHIP display mode */
83 #define CHIP8_WIDTH 64
84 #define CHIP8_HEIGHT 32
87 EXTERN byte chip8_iperiod
; /* number of opcodes per */
88 /* timeslice (1/50sec.) */
89 EXTERN byte chip8_keys
[16]; /* if 1, key is held down */
90 EXTERN byte chip8_display
[CHIP8_WIDTH
*CHIP8_HEIGHT
];/* 0xff if pixel is set, */
92 EXTERN byte chip8_mem
[4096]; /* machine memory. program */
93 /* is loaded at 0x200 */
94 EXTERN byte chip8_running
; /* if 0, emulation stops */
96 EXTERN
void chip8_execute (void); /* execute chip8_iperiod */
98 EXTERN
void chip8_reset (void); /* reset virtual machine */
99 EXTERN
void chip8 (void); /* start chip8 emulation */
101 EXTERN
void chip8_sound_on (void); /* turn sound on */
102 EXTERN
void chip8_sound_off (void); /* turn sound off */
103 EXTERN
void chip8_interrupt (void); /* update keyboard, */
107 EXTERN byte chip8_trace
; /* if 1, call debugger */
109 EXTERN word chip8_trap
; /* if pc==trap, set trace */
111 EXTERN
void chip8_debug (word opcode
,struct chip8_regs_struct
*regs
);
114 #endif /* __CHIP8_H */
116 /** Vision8: CHIP8 emulator *************************************************/
120 /** This file contains the portable CHIP8 emulation engine **/
121 /** SCHIP emulation (C) Frederic Devernay 2005 **/
123 /** Copyright (C) Marcel de Kogel 1997 **/
124 /** You are not allowed to distribute this software commercially **/
125 /** Please, notify me, if you make any changes to this file **/
126 /****************************************************************************/
129 #define STATIC static
130 #define EXTERN static
131 and include this file for single-object generation
135 #include <stdlib.h> /* for memset, etc. */
142 #define DBG_(_x) ((void)(_x))
144 #define DBG_(_x) ((void)0)
147 STATIC
struct chip8_regs_struct chip8_regs
;
149 static byte chip8_key_pressed
;
150 STATIC byte chip8_keys
[16]; /* if 1, key is held down */
151 STATIC byte chip8_display
[CHIP8_WIDTH
*CHIP8_HEIGHT
]; /* 0xff if pixel is set, */
154 STATIC byte chip8_super
; /* != 0 if in SCHIP display mode */
156 STATIC byte chip8_mem
[4096]; /* machine memory. program */
157 /* is loaded at 0x200 */
159 #define read_mem(a) (chip8_mem[(a)&4095])
160 #define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
162 STATIC byte chip8_iperiod
;
164 STATIC byte chip8_running
; /* Flag for End-of-Emulation */
166 #define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
167 #define get_reg_value(opcode) (*get_reg_offset(opcode))
168 #define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f))
169 #define get_reg_value_2(opcode) (*get_reg_offset_2(opcode))
171 typedef void (*opcode_fn
) (word opcode
);
172 typedef void (*math_fn
) (byte
*reg1
,byte reg2
);
176 static void op_call (word opcode
)
179 write_mem (chip8_regs
.sp
,chip8_regs
.pc
&0xff);
181 write_mem (chip8_regs
.sp
,chip8_regs
.pc
>>8);
182 chip8_regs
.pc
=opcode
;
184 if(chip8_regs
.sp
< 0x1c0)
185 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs
.sp
);
189 static void op_jmp (word opcode
)
191 chip8_regs
.pc
=opcode
;
194 static void op_key (word opcode
)
197 static byte tested
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
199 byte key
, key_value
,cp_value
;
200 if ((opcode
&0xff)==0x9e) /* skp */
202 else if ((opcode
&0xff)==0xa1) /* sknp */
205 DBG_(printf("unhandled key opcode 0x%x\n", opcode
));
208 key
= get_reg_value(opcode
)&0x0f;
212 DBG_(printf("testing key %d\n", key
));
215 key_value
=chip8_keys
[key
];
216 if (cp_value
==key_value
)
220 static void op_skeq_const (word opcode
)
222 if (get_reg_value(opcode
)==(opcode
&0xff))
226 static void op_skne_const (word opcode
)
228 if (get_reg_value(opcode
)!=(opcode
&0xff))
232 static void op_skeq_reg (word opcode
)
234 if (get_reg_value(opcode
)==get_reg_value_2(opcode
))
238 static void op_skne_reg (word opcode
)
240 if (get_reg_value(opcode
)!=get_reg_value_2(opcode
))
244 static void op_mov_const (word opcode
)
246 *get_reg_offset(opcode
)=opcode
&0xff;
249 static void op_add_const (word opcode
)
251 *get_reg_offset(opcode
)+=opcode
&0xff;
254 static void op_mvi (word opcode
)
259 static void op_jmi (word opcode
)
261 chip8_regs
.pc
=opcode
+chip8_regs
.alg
[0];
264 static void op_rand (word opcode
)
266 *get_reg_offset(opcode
)=rand()&(opcode
&0xff);
269 static void math_or (byte
*reg1
,byte reg2
)
274 static void math_mov (byte
*reg1
,byte reg2
)
279 static void math_nop (byte
*reg1
,byte reg2
)
283 DBG_(printf("Warning: math nop!\n"));
286 static void math_and (byte
*reg1
,byte reg2
)
291 static void math_xor (byte
*reg1
,byte reg2
)
296 static void math_add (byte
*reg1
,byte reg2
)
301 chip8_regs
.alg
[15]=tmp
>>8;
304 static void math_sub (byte
*reg1
,byte reg2
)
309 chip8_regs
.alg
[15]=((byte
)(tmp
>>8))+1;
312 static void math_shr (byte
*reg1
,byte reg2
)
315 chip8_regs
.alg
[15]=*reg1
&1;
319 static void math_shl (byte
*reg1
,byte reg2
)
322 chip8_regs
.alg
[15]=*reg1
>>7;
326 static void math_rsb (byte
*reg1
,byte reg2
)
331 chip8_regs
.alg
[15]=((byte
)(tmp
>>8))+1;
335 /* SUPER: scroll down n lines (or half in CHIP8 mode) */
336 static void scroll_down(word opcode
)
338 int n
= opcode
& 0xf;
339 byte
*dst
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
-1;
340 byte
*src
= dst
- n
*CHIP8_WIDTH
;
341 while(src
>= chip8_display
) {
344 while(dst
>= chip8_display
) {
348 /* SUPER: scroll 4 pixels left! */
349 static void scroll_left(void)
351 byte
*dst
= chip8_display
;
353 byte
*eol
= chip8_display
+ CHIP8_WIDTH
;
354 byte
*eoi
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
;
367 static void scroll_right(void)
369 byte
*dst
= chip8_display
+ CHIP8_WIDTH
*CHIP8_HEIGHT
-1;
371 byte
*bol
= chip8_display
+ CHIP8_WIDTH
*(CHIP8_HEIGHT
-1);
372 while(bol
>= chip8_display
) {
386 static void op_system (word opcode
)
388 switch ((byte
)opcode
)
398 DBG_(printf("SUPER: quit the emulator\n"));
402 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
403 memset (chip8_display
,0,sizeof(chip8_display
));
407 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
408 memset (chip8_display
,0,sizeof(chip8_display
));
413 memset (chip8_display
,0,sizeof(chip8_display
));
416 chip8_regs
.pc
=read_mem(chip8_regs
.sp
)<<8;
418 chip8_regs
.pc
+=read_mem(chip8_regs
.sp
);
423 if ((opcode
& 0xF0) == 0xC0)
428 DBG_(printf("unhandled system opcode 0x%x\n", opcode
));
435 static void op_misc (word opcode
)
439 static byte firstwait
= 1;
441 reg
=get_reg_offset(opcode
);
442 switch ((byte
)opcode
)
444 case 0x07: /* gdelay */
445 *reg
=chip8_regs
.delay
;
450 printf("waiting for key press\n");
454 if (chip8_key_pressed
)
455 *reg
=chip8_key_pressed
-1;
459 case 0x15: /* sdelay */
460 chip8_regs
.delay
=*reg
;
462 case 0x18: /* ssound */
463 chip8_regs
.sound
=*reg
;
464 if (chip8_regs
.sound
)
468 chip8_regs
.i
+=(*reg
);
470 case 0x29: /* font */
471 chip8_regs
.i
=((word
)(*reg
&0x0f))*5;
474 case 0x30: /* xfont */
475 chip8_regs
.i
=((word
)(*reg
&0x0f))*10+0x50;
480 for (j
=0;i
>=100;i
-=100)
482 write_mem (chip8_regs
.i
,j
);
483 for (j
=0;i
>=10;i
-=10)
485 write_mem (chip8_regs
.i
+1,j
);
486 write_mem (chip8_regs
.i
+2,i
);
489 for (i
=0,j
=(opcode
>>8)&0x0f; i
<=j
; ++i
)
490 write_mem(chip8_regs
.i
+i
,chip8_regs
.alg
[i
]);
493 for (i
=0,j
=(opcode
>>8)&0x0f; i
<=j
; ++i
)
494 chip8_regs
.alg
[i
]=read_mem(chip8_regs
.i
+i
);
498 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode
>>8)&0x0f));
501 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode
>>8)&0x0f));
505 DBG_(printf("unhandled misc opcode 0x%x\n", opcode
));
510 static void op_sprite (word opcode
)
513 byte n
,x
,x2
,y
,collision
;
515 x
=get_reg_value(opcode
);
516 y
=get_reg_value_2(opcode
);
521 /*printf("SUPER: sprite(%x)\n", opcode);*/
524 q
=chip8_display
+y
*CHIP8_WIDTH
;
530 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
533 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
535 collision
&=(q
[x2
]^=0xff);
536 x2
=(x
+8)&(CHIP8_WIDTH
-1);
538 for (y
=read_mem(p
++);y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
540 collision
&=(q
[x2
]^=0xff);
547 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
549 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
551 collision
&=(q
[x2
]^=0xff);
558 q
=chip8_display
+y
*CHIP8_WIDTH
*2;
563 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
*2)
565 for (y
=read_mem(p
++),x2
=x
*2;y
;y
<<=1,x2
=(x2
+2)&(CHIP8_WIDTH
-1))
569 q
[x2
+CHIP8_WIDTH
]^=0xff;
570 q
[x2
+CHIP8_WIDTH
+1]^=0xff;
571 collision
&= q
[x2
]|q
[x2
+1]|q
[x2
+CHIP8_WIDTH
]|q
[x2
+CHIP8_WIDTH
+1];
578 q
=chip8_display
+y
*CHIP8_WIDTH
;
581 for (collision
=1;n
;--n
,q
+=CHIP8_WIDTH
)
583 for (y
=read_mem(p
++),x2
=x
;y
;y
<<=1,x2
=(x2
+1)&(CHIP8_WIDTH
-1))
585 collision
&=(q
[x2
]^=0xff);
588 chip8_regs
.alg
[15]=collision
^1;
591 static math_fn math_opcodes
[16]=
611 static void op_math (word opcode
)
613 (*(math_opcodes
[opcode
&0x0f]))
614 (get_reg_offset(opcode
),get_reg_value_2(opcode
));
617 static opcode_fn main_opcodes
[16]=
638 STATIC byte chip8_trace
;
639 STATIC word chip8_trap
;
641 /****************************************************************************/
642 /* This routine is called every opcode when chip8_trace==1. It prints the */
643 /* current register contents and the opcode being executed */
644 /****************************************************************************/
645 STATIC
void chip8_debug (word opcode
,struct chip8_regs_struct
*regs
)
648 byte hextable
[16] = "0123456789ABCDEF";
651 v1
[1] = hextable
[(opcode
>>8)&0x0f];
652 v2
[1] = hextable
[(opcode
>>8)&0x0f];
653 printf ("PC=%04X: %04X - ",regs
->pc
,opcode
);
654 switch (opcode
>>12) {
656 if ((opcode
&0xff0) == 0xc0) {
657 printf ("SCD %01X ; Scroll down n lines",opcode
&0xf);
659 else switch (opcode
&0xfff) {
661 printf ("CLS ; Clear screen");
664 printf ("RET ; Return from subroutine call");
667 printf("SCR ; Scroll right");
670 printf("SCL ; Scroll left");
673 printf("EXIT ; Terminate the interpreter");
676 printf("LOW ; Disable extended screen mode");
679 printf("HIGH ; Enable extended screen mode");
682 printf ("SYS %03X ; Unknown system call",opcode
&0xff);
686 printf ("JP %03X ; Jump to address",opcode
&0xfff);
689 printf ("CALL %03X ; Call subroutine",opcode
&0xfff);
692 printf ("SE %s,%02X ; Skip if register == constant",v1
,opcode
&0xff);
695 printf ("SNE %s,%02X ; Skip if register <> constant",v1
,opcode
&0xff);
698 printf ("SE %s,%s ; Skip if register == register",v1
,v2
);
701 printf ("LD %s,%02X ; Set VX = Byte",v1
,opcode
&0xff);
704 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1
,opcode
&0xff);
707 switch (opcode
&0x0f) {
709 printf ("LD %s,%s ; Set VX = VY, VF updates",v1
,v2
);
712 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1
,v2
);
715 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1
,v2
);
718 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1
,v2
);
721 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1
,v2
);
724 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1
,v2
);
727 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1
,v2
);
730 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1
,v2
);
733 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1
,v2
);
736 printf ("Illegal opcode");
740 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1
,v2
);
743 printf ("LD I,%03X ; Set I = Addr",opcode
&0xfff);
746 printf ("JP V0,%03X ; Jump to Addr + V0",opcode
&0xfff);
749 printf ("RND %s,%02X ; Set VX = random & Byte",v1
,opcode
&0xff);
752 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1
,v2
,opcode
&0x0f);
755 switch (opcode
&0xff) {
757 printf ("SKP %s ; Skip next instruction if key VX down",v1
);
760 printf ("SKNP %s ; Skip next instruction if key VX up",v1
);
763 printf ("%04X ; Illegal opcode", opcode
);
767 switch (opcode
&0xff) {
769 printf ("LD %s,DT ; Set VX = delaytimer",v1
);
772 printf ("LD %s,K ; Set VX = key, wait for keypress",v1
);
775 printf ("LD DT,%s ; Set delaytimer = VX",v1
);
778 printf ("LD ST,%s ; Set soundtimer = VX",v1
);
781 printf ("ADD I,%s ; Set I = I + VX",v1
);
784 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1
);
787 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1
);
790 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1
);
793 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1
);
796 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1
);
799 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1
);
802 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1
);
805 printf ("%04X ; Illegal opcode", opcode
);
809 printf ("\n; Registers: ");
810 for (i
=0;i
<16;++i
) printf ("%02x ",(regs
->alg
[i
])&0xff);
811 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
812 regs
->i
&0xfff,regs
->sp
&0xfff,regs
->delay
&0xff,regs
->sound
&0xff);
816 /****************************************************************************/
817 /* Execute chip8_iperiod opcodes */
818 /****************************************************************************/
819 STATIC
void chip8_execute(void)
824 for (i
= chip8_iperiod
; i
;--i
)
826 /* Fetch the opcode */
827 opcode
=(read_mem(chip8_regs
.pc
)<<8)+read_mem(chip8_regs
.pc
+1);
829 /* Check if trap address has been reached */
830 if ((chip8_regs
.pc
&4095)==chip8_trap
)
832 /* Call the debugger if chip8_trace!=0 */
834 chip8_debug (opcode
,&chip8_regs
);
837 (*(main_opcodes
[opcode
>>12]))(opcode
&0x0fff); /* Emulate this opcode */
840 if (chip8_regs
.delay
)
842 if (chip8_regs
.sound
)
843 if (--chip8_regs
.sound
== 0)
846 /* Update the machine status */
849 for (i
=key_pressed
=0;i
<16;++i
) /* check if a key was first */
850 if (chip8_keys
[i
]) /* pressed */
852 if (key_pressed
&& key_pressed
!=chip8_key_pressed
)
853 chip8_key_pressed
=key_pressed
;
858 /****************************************************************************/
859 /* Reset the virtual chip8 machine */
860 /****************************************************************************/
861 STATIC
void chip8_reset(void)
863 static byte chip8_sprites
[0x50]=
865 0xf9,0x99,0xf2,0x62,0x27,
866 0xf1,0xf8,0xff,0x1f,0x1f,
867 0x99,0xf1,0x1f,0x8f,0x1f,
868 0xf8,0xf9,0xff,0x12,0x44,
869 0xf9,0xf9,0xff,0x9f,0x1f,
870 0xf9,0xf9,0x9e,0x9e,0x9e,
871 0xf8,0x88,0xfe,0x99,0x9e,
872 0xf8,0xf8,0xff,0x8f,0x88,
873 }; /* 4x5 pixel hexadecimal character font patterns */
875 static byte schip_sprites
[10*10]=
877 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
878 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
879 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
880 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
881 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
882 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
883 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
884 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
885 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
886 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
887 }; /* 8x10 pixel font patterns (only 10) */
892 write_mem (i
<<1,chip8_sprites
[i
]&0xf0);
893 write_mem ((i
<<1)+1,chip8_sprites
[i
]<<4);
897 for (i=0; i<100; i++)
898 write_mem (i+0x50,schip_sprites[i]);
900 memcpy(chip8_mem
+0x50, schip_sprites
, 100);
903 memset (chip8_regs
.alg
,0,sizeof(chip8_regs
.alg
));
904 memset (chip8_keys
,0,sizeof(chip8_keys
));
906 memset (chip8_display
,0,sizeof(chip8_display
));
907 chip8_regs
.delay
=chip8_regs
.sound
=chip8_regs
.i
=0;
918 /****************************************************************************/
919 /* Start CHIP8 emulation */
920 /****************************************************************************/
921 STATIC
void chip8 (void)
924 while (chip8_running
==1) chip8_execute ();
927 /****************************************************************************/
928 /** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
929 /****************************************************************************/
931 /* size of the displayed area */
932 #if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
933 #define CHIP8_LCDWIDTH 112
935 #define CHIP8_LCDWIDTH CHIP8_WIDTH
938 #if (LCD_WIDTH > CHIP8_LCDWIDTH)
939 #define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
943 #if (LCD_HEIGHT > CHIP8_HEIGHT)
944 #define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
949 /* variable button definitions */
950 #if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
951 #define CHIP8_OFF BUTTON_OFF
952 #define CHIP8_KEY1 BUTTON_F1
953 #define CHIP8_KEY2 BUTTON_UP
954 #define CHIP8_KEY3 BUTTON_F3
955 #define CHIP8_KEY4 BUTTON_LEFT
956 #define CHIP8_KEY5 BUTTON_PLAY
957 #define CHIP8_KEY6 BUTTON_RIGHT
958 #define CHIP8_KEY7 BUTTON_F2
959 #define CHIP8_KEY8 BUTTON_DOWN
960 #define CHIP8_KEY9 BUTTON_ON
962 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD /* only 9 out of 16 chip8 buttons */
963 #define CHIP8_OFF BUTTON_OFF
964 #define CHIP8_KEY1 BUTTON_F1
965 #define CHIP8_KEY2 BUTTON_UP
966 #define CHIP8_KEY3 BUTTON_F3
967 #define CHIP8_KEY4 BUTTON_LEFT
968 #define CHIP8_KEY5 BUTTON_SELECT
969 #define CHIP8_KEY6 BUTTON_RIGHT
970 #define CHIP8_KEY7 BUTTON_F2
971 #define CHIP8_KEY8 BUTTON_DOWN
972 #define CHIP8_KEY9 BUTTON_ON
974 #elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
975 #define CHIP8_OFF BUTTON_OFF
976 #define CHIP8_KEY2 BUTTON_UP
977 #define CHIP8_KEY4 BUTTON_LEFT
978 #define CHIP8_KEY5 BUTTON_MENU
979 #define CHIP8_KEY6 BUTTON_RIGHT
980 #define CHIP8_KEY8 BUTTON_DOWN
982 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
983 (CONFIG_KEYPAD == IRIVER_H300_PAD)
984 #define CHIP8_OFF BUTTON_OFF
985 #define CHIP8_KEY2 BUTTON_UP
986 #define CHIP8_KEY4 BUTTON_LEFT
987 #define CHIP8_KEY5 BUTTON_SELECT
988 #define CHIP8_KEY6 BUTTON_RIGHT
989 #define CHIP8_KEY8 BUTTON_DOWN
991 #define CHIP8_RC_OFF BUTTON_RC_STOP
993 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
994 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
995 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
996 #define CHIP8_OFF BUTTON_MENU
997 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
998 #define CHIP8_KEY4 BUTTON_LEFT
999 #define CHIP8_KEY5 BUTTON_PLAY
1000 #define CHIP8_KEY6 BUTTON_RIGHT
1001 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1003 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
1004 #define CHIP8_OFF BUTTON_POWER
1005 #define CHIP8_KEY2 BUTTON_UP
1006 #define CHIP8_KEY4 BUTTON_LEFT
1007 #define CHIP8_KEY5 BUTTON_SELECT
1008 #define CHIP8_KEY6 BUTTON_RIGHT
1009 #define CHIP8_KEY8 BUTTON_DOWN
1011 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
1012 #define CHIP8_OFF BUTTON_POWER
1013 #define CHIP8_KEY1 BUTTON_MENU
1014 #define CHIP8_KEY2 BUTTON_UP
1015 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1016 #define CHIP8_KEY4 BUTTON_LEFT
1017 #define CHIP8_KEY5 BUTTON_SELECT
1018 #define CHIP8_KEY6 BUTTON_RIGHT
1019 #define CHIP8_KEY7 BUTTON_VOL_UP
1020 #define CHIP8_KEY8 BUTTON_DOWN
1021 #define CHIP8_KEY9 BUTTON_A
1023 #elif CONFIG_KEYPAD == SANSA_E200_PAD
1024 #define CHIP8_OFF BUTTON_POWER
1025 #define CHIP8_KEY2 BUTTON_SCROLL_UP
1026 #define CHIP8_KEY4 BUTTON_LEFT
1027 #define CHIP8_KEY5 BUTTON_SELECT
1028 #define CHIP8_KEY6 BUTTON_RIGHT
1029 #define CHIP8_KEY8 BUTTON_SCROLL_DOWN
1031 #elif CONFIG_KEYPAD == SANSA_C200_PAD
1032 #define CHIP8_OFF BUTTON_POWER
1033 #define CHIP8_KEY2 BUTTON_VOL_UP
1034 #define CHIP8_KEY4 BUTTON_LEFT
1035 #define CHIP8_KEY5 BUTTON_SELECT
1036 #define CHIP8_KEY6 BUTTON_RIGHT
1037 #define CHIP8_KEY8 BUTTON_VOL_DOWN
1039 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
1040 #define CHIP8_OFF BUTTON_POWER
1041 #define CHIP8_KEY2 BUTTON_SCROLL_UP
1042 #define CHIP8_KEY4 BUTTON_LEFT
1043 #define CHIP8_KEY5 BUTTON_PLAY
1044 #define CHIP8_KEY6 BUTTON_RIGHT
1045 #define CHIP8_KEY8 BUTTON_SCROLL_DOWN
1049 static byte chip8_virtual_keys
[16];
1050 static byte chip8_keymap
[16];
1052 static unsigned long starttimer
; /* Timer value at the beginning */
1053 static unsigned long cycles
; /* Number of update cycles (50Hz) */
1056 static bool is_playing
;
1059 /* one frame of bitswapped mp3 data */
1060 static unsigned char beep
[]={255,
1061 223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
1062 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
1063 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
1064 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
1065 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
1066 252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
1067 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
1068 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
1069 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
1070 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
1071 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
1073 /* callback to request more mp3 data */
1074 void callback(unsigned char** start
, size_t* size
)
1076 *start
= beep
; /* give it the same frame again */
1077 *size
= sizeof(beep
);
1080 /****************************************************************************/
1082 /****************************************************************************/
1083 static void chip8_sound_on (void)
1087 rb
->mp3_play_pause(true); /* kickoff audio */
1091 /****************************************************************************/
1092 /* Turn sound off */
1093 /****************************************************************************/
1094 static void chip8_sound_off (void)
1098 rb
->mp3_play_pause(false); /* pause audio */
1102 /****************************************************************************/
1103 /* Update the display */
1104 /****************************************************************************/
1105 static void chip8_update_display(void)
1110 /* frame buffer in hardware fomat */
1111 unsigned char lcd_framebuf
[CHIP8_HEIGHT
/8][CHIP8_LCDWIDTH
];
1113 for (y
=0;y
<CHIP8_HEIGHT
/8;++y
)
1115 row
= lcd_framebuf
[y
];
1116 for (x
=0, lcd_x
=0;x
<CHIP8_WIDTH
;++x
,++lcd_x
)
1122 if (chip8_display
[x
+(y
*8+i
)*CHIP8_WIDTH
] != 0)
1127 #if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1129 row
[-1] |= w
; /* overlay on */
1136 #if defined(SIMULATOR) || (LCD_DEPTH > 1)
1137 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1138 rb
->lcd_mono_bitmap(lcd_framebuf
[0], CHIP8_X
, CHIP8_Y
, CHIP8_LCDWIDTH
, CHIP8_HEIGHT
);
1141 rb
->lcd_blit(lcd_framebuf
[0], CHIP8_X
, CHIP8_Y
>>3, CHIP8_LCDWIDTH
, CHIP8_HEIGHT
>>3
1146 static void chip8_keyboard(void)
1149 int button
= rb
->button_get(false);
1155 case CHIP8_OFF
: /* Abort Emulator */
1159 case CHIP8_KEY2
: chip8_virtual_keys
[2] = 1; break;
1160 case CHIP8_KEY2
| BUTTON_REL
: chip8_virtual_keys
[2] = 0; break;
1161 case CHIP8_KEY4
: chip8_virtual_keys
[4] = 1; break;
1162 case CHIP8_KEY4
| BUTTON_REL
: chip8_virtual_keys
[4] = 0; break;
1163 case CHIP8_KEY6
: chip8_virtual_keys
[6] = 1; break;
1164 case CHIP8_KEY6
| BUTTON_REL
: chip8_virtual_keys
[6] = 0; break;
1165 case CHIP8_KEY8
: chip8_virtual_keys
[8] = 1; break;
1166 case CHIP8_KEY8
| BUTTON_REL
: chip8_virtual_keys
[8] = 0; break;
1167 case CHIP8_KEY5
: chip8_virtual_keys
[5] = 1; break;
1168 case CHIP8_KEY5
| BUTTON_REL
: chip8_virtual_keys
[5] = 0; break;
1170 case CHIP8_KEY1
: chip8_virtual_keys
[1] = 1; break;
1171 case CHIP8_KEY1
| BUTTON_REL
: chip8_virtual_keys
[1] = 0; break;
1174 case CHIP8_KEY3
: chip8_virtual_keys
[3] = 1; break;
1175 case CHIP8_KEY3
| BUTTON_REL
: chip8_virtual_keys
[3] = 0; break;
1178 case CHIP8_KEY7
: chip8_virtual_keys
[7] = 1; break;
1179 case CHIP8_KEY7
| BUTTON_REL
: chip8_virtual_keys
[7] = 0; break;
1182 case CHIP8_KEY9
: chip8_virtual_keys
[9] = 1; break;
1183 case CHIP8_KEY9
| BUTTON_REL
: chip8_virtual_keys
[9] = 0; break;
1187 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
1188 chip8_running
= 2; /* indicates stopped because of USB */
1191 for(i
=0; i
<16; i
++) {
1192 chip8_keys
[i
] = chip8_virtual_keys
[chip8_keymap
[i
]];
1196 /****************************************************************************/
1197 /* Update keyboard and display, sync emulation with VDP clock */
1198 /****************************************************************************/
1199 static void chip8_interrupt (void)
1201 unsigned long newtimer
;
1202 unsigned long timer
, runtime
;
1204 chip8_update_display();
1207 runtime
= cycles
* HZ
/ 50;
1208 timer
= starttimer
+ runtime
;
1209 newtimer
= *rb
->current_tick
;
1210 if (TIME_AFTER(timer
, newtimer
))
1212 rb
->sleep(timer
- newtimer
);
1218 starttimer
= newtimer
- runtime
;
1221 static bool chip8_init(char* file
)
1228 fd
= rb
->open(file
, O_RDONLY
);
1230 rb
->lcd_puts(0, 6, "File Error.");
1233 numread
= rb
->read(fd
, chip8_mem
+0x200, 4096-0x200);
1235 rb
->lcd_puts(0, 6, "I/O Error.");
1240 /* is there a c8k file (chip8 keys) ? */
1241 for(i
=0; i
<16; i
++) {
1242 chip8_virtual_keys
[i
] = 0;
1243 chip8_keymap
[i
] = i
;
1245 len
= rb
->strlen(file
);
1248 fd
= rb
->open(file
, O_RDONLY
);
1250 rb
->lcd_puts(0, 6, "File&Keymap OK.");
1251 numread
= rb
->read(fd
, chip8_keymap
, 16);
1256 rb
->lcd_puts(0, 6, "File OK.");
1258 for(i
=0; i
<16; i
++) {
1259 if (chip8_keymap
[i
] >= '0'
1260 && chip8_keymap
[i
] <= '9')
1261 chip8_keymap
[i
] -= '0';
1262 else if (chip8_keymap
[i
] >= 'A'
1263 && chip8_keymap
[i
] <= 'F')
1264 chip8_keymap
[i
] -= 'A' - 10;
1265 else if (chip8_keymap
[i
] >= 'a'
1266 && chip8_keymap
[i
] <= 'f')
1267 chip8_keymap
[i
] -= 'a' - 10;
1269 chip8_keymap
[i
] %= 16;
1274 bool chip8_run(char* file
)
1278 rb
->lcd_clear_display();
1279 rb
->lcd_puts(0, 0, "SChip8 Emulator");
1280 rb
->lcd_puts(0, 1, " (c) by ");
1281 rb
->lcd_puts(0, 2, "Marcel de Kogel");
1282 rb
->lcd_puts(0, 3, " Rockbox: ");
1283 rb
->lcd_puts(0, 4, " Blueloop/Fdy ");
1284 rb
->lcd_puts(0, 5, "---------------");
1285 ok
= chip8_init(file
);
1290 rb
->lcd_clear_display();
1291 #if (CHIP8_X > 0) && (CHIP8_Y > 0)
1292 rb
->lcd_drawrect(CHIP8_X
-1,CHIP8_Y
-1,CHIP8_LCDWIDTH
+2,CHIP8_HEIGHT
+2);
1298 is_playing
= rb
->mp3_is_playing(); /* would we disturb playback? */
1299 if (!is_playing
) /* no? then we can make sound */
1301 rb
->mp3_play_data(beep
, sizeof(beep
), callback
);
1304 starttimer
= *rb
->current_tick
;
1311 rb
->splash(HZ
, "Error");
1317 { /* stop it if we used audio */
1318 rb
->mp3_play_stop(); /* Stop audio playback */
1322 if (chip8_running
== 3) {
1323 /* unsupported instruction */
1324 rb
->splash(HZ
, "Error: Unsupported"
1326 " CHIP-8 instruction. (maybe S-CHIP)"
1328 " (S)CHIP-8 instruction."
1338 /***************** Plugin Entry Point *****************/
1340 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
1344 rb
= api
; /* copy to global api pointer */
1346 if (parameter
== NULL
)
1348 rb
->splash(HZ
, "Play a .ch8 file!");
1349 return PLUGIN_ERROR
;
1353 filename
= (char*) parameter
;
1356 /* now go ahead and have fun! */
1357 if (chip8_run(filename
))
1358 if (chip8_running
== 0)
1361 return PLUGIN_USB_CONNECTED
;
1363 return PLUGIN_ERROR
;
1365 #endif /* #ifdef HAVE_LCD_BITMAP */