Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / chip8.c
blob0f7e24b551bbc09f0de66548d69962905e397419
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
20 #include "plugin.h"
22 /* Only build for (correct) target */
23 #ifdef HAVE_LCD_BITMAP
25 PLUGIN_HEADER
27 static struct plugin_api* rb; /* here is a global api struct pointer */
29 #define EXTERN static
30 #define STATIC static
31 #define memset rb->memset
32 #define memcpy rb->memcpy
33 #define printf DEBUGF
34 #define rand rb->rand
35 /* #define CHIP8_DEBUG */
37 #if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
38 #define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
39 #endif
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 *************************************************/
47 /** **/
48 /** CHIP8.h **/
49 /** **/
50 /** This file contains the portable CHIP8 emulation engine definitions **/
51 /** **/
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 /****************************************************************************/
57 #ifndef __CHIP8_H
58 #define __CHIP8_H
60 #ifndef EXTERN
61 #define EXTERN extern
62 #endif
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;
78 #ifdef CHIP8_SUPER
79 #define CHIP8_WIDTH 128
80 #define CHIP8_HEIGHT 64
81 EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */
82 #else
83 #define CHIP8_WIDTH 64
84 #define CHIP8_HEIGHT 32
85 #endif
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, */
91 /* 0x00 otherwise */
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 */
97 /* opcodes */
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, */
104 /* display, etc. */
106 #ifdef CHIP8_DEBUG
107 EXTERN byte chip8_trace; /* if 1, call debugger */
108 /* every opcode */
109 EXTERN word chip8_trap; /* if pc==trap, set trace */
110 /* flag */
111 EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs);
112 #endif
114 #endif /* __CHIP8_H */
116 /** Vision8: CHIP8 emulator *************************************************/
117 /** **/
118 /** CHIP8.c **/
119 /** **/
120 /** This file contains the portable CHIP8 emulation engine **/
121 /** SCHIP emulation (C) Frederic Devernay 2005 **/
122 /** **/
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 /****************************************************************************/
128 /* you can
129 #define STATIC static
130 #define EXTERN static
131 and include this file for single-object generation
134 #ifndef STATIC
135 #include <stdlib.h> /* for memset, etc. */
136 #include <string.h>
137 #define STATIC
138 #endif
140 #ifdef CHIP8_DEBUG
141 #include <stdio.h>
142 #define DBG_(_x) ((void)(_x))
143 #else
144 #define DBG_(_x) ((void)0)
145 #endif
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, */
152 /* 0x00 otherwise */
153 #ifdef CHIP8_SUPER
154 STATIC byte chip8_super; /* != 0 if in SCHIP display mode */
155 #endif
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)
178 chip8_regs.sp--;
179 write_mem (chip8_regs.sp,chip8_regs.pc&0xff);
180 chip8_regs.sp--;
181 write_mem (chip8_regs.sp,chip8_regs.pc>>8);
182 chip8_regs.pc=opcode;
183 #ifdef CHIP8_DEBUG
184 if(chip8_regs.sp < 0x1c0)
185 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp);
186 #endif
189 static void op_jmp (word opcode)
191 chip8_regs.pc=opcode;
194 static void op_key (word opcode)
196 #ifdef CHIP8_DEBUG
197 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
198 #endif
199 byte key, key_value,cp_value;
200 if ((opcode&0xff)==0x9e) /* skp */
201 cp_value=1;
202 else if ((opcode&0xff)==0xa1) /* sknp */
203 cp_value=0;
204 else {
205 DBG_(printf("unhandled key opcode 0x%x\n", opcode));
206 return;
208 key = get_reg_value(opcode)&0x0f;
209 #ifdef CHIP8_DEBUG
210 if (!tested[key]) {
211 tested[key] = 1;
212 DBG_(printf("testing key %d\n", key));
214 #endif
215 key_value=chip8_keys[key];
216 if (cp_value==key_value)
217 chip8_regs.pc+=2;
220 static void op_skeq_const (word opcode)
222 if (get_reg_value(opcode)==(opcode&0xff))
223 chip8_regs.pc+=2;
226 static void op_skne_const (word opcode)
228 if (get_reg_value(opcode)!=(opcode&0xff))
229 chip8_regs.pc+=2;
232 static void op_skeq_reg (word opcode)
234 if (get_reg_value(opcode)==get_reg_value_2(opcode))
235 chip8_regs.pc+=2;
238 static void op_skne_reg (word opcode)
240 if (get_reg_value(opcode)!=get_reg_value_2(opcode))
241 chip8_regs.pc+=2;
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)
256 chip8_regs.i=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)
271 *reg1|=reg2;
274 static void math_mov (byte *reg1,byte reg2)
276 *reg1=reg2;
279 static void math_nop (byte *reg1,byte reg2)
281 (void)reg1;
282 (void)reg2;
283 DBG_(printf("Warning: math nop!\n"));
286 static void math_and (byte *reg1,byte reg2)
288 *reg1&=reg2;
291 static void math_xor (byte *reg1,byte reg2)
293 *reg1^=reg2;
296 static void math_add (byte *reg1,byte reg2)
298 word tmp;
299 tmp=*reg1+reg2;
300 *reg1=(byte)tmp;
301 chip8_regs.alg[15]=tmp>>8;
304 static void math_sub (byte *reg1,byte reg2)
306 word tmp;
307 tmp=*reg1-reg2;
308 *reg1=(byte)tmp;
309 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
312 static void math_shr (byte *reg1,byte reg2)
314 (void)reg2;
315 chip8_regs.alg[15]=*reg1&1;
316 *reg1>>=1;
319 static void math_shl (byte *reg1,byte reg2)
321 (void)reg2;
322 chip8_regs.alg[15]=*reg1>>7;
323 *reg1<<=1;
326 static void math_rsb (byte *reg1,byte reg2)
328 word tmp;
329 tmp=reg2-*reg1;
330 *reg1=(byte)tmp;
331 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
334 #ifdef CHIP8_SUPER
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) {
342 *dst-- = *src--;
344 while(dst >= chip8_display) {
345 *dst-- = 0;
348 /* SUPER: scroll 4 pixels left! */
349 static void scroll_left(void)
351 byte *dst = chip8_display;
352 byte *src = dst;
353 byte *eol = chip8_display + CHIP8_WIDTH;
354 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT;
355 while(eol <= eoi) {
356 src+=4;
357 while(src < eol) {
358 *dst++ = *src++;
360 *dst++ = 0;
361 *dst++ = 0;
362 *dst++ = 0;
363 *dst++ = 0;
364 eol += CHIP8_WIDTH;
367 static void scroll_right(void)
369 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
370 byte *src = dst;
371 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1);
372 while(bol >= chip8_display) {
373 src-=4;
374 while(src >= bol) {
375 *dst-- = *src--;
377 *dst-- = 0;
378 *dst-- = 0;
379 *dst-- = 0;
380 *dst-- = 0;
381 bol -= CHIP8_WIDTH;
384 #endif
386 static void op_system (word opcode)
388 switch ((byte)opcode)
390 #ifdef CHIP8_SUPER
391 case 0xfb:
392 scroll_right();
393 break;
394 case 0xfc:
395 scroll_left();
396 break;
397 case 0xfd:
398 DBG_(printf("SUPER: quit the emulator\n"));
399 chip8_reset();
400 break;
401 case 0xfe:
402 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
403 memset (chip8_display,0,sizeof(chip8_display));
404 chip8_super = 0;
405 break;
406 case 0xff:
407 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
408 memset (chip8_display,0,sizeof(chip8_display));
409 chip8_super = 1;
410 break;
411 #endif
412 case 0xe0:
413 memset (chip8_display,0,sizeof(chip8_display));
414 break;
415 case 0xee:
416 chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
417 chip8_regs.sp++;
418 chip8_regs.pc+=read_mem(chip8_regs.sp);
419 chip8_regs.sp++;
420 break;
421 default:
422 #ifdef CHIP8_SUPER
423 if ((opcode & 0xF0) == 0xC0)
424 scroll_down(opcode);
425 else
426 #endif
428 DBG_(printf("unhandled system opcode 0x%x\n", opcode));
429 chip8_running = 3;
431 break;
435 static void op_misc (word opcode)
437 byte *reg,i,j;
438 #ifdef CHIP8_DEBUG
439 static byte firstwait = 1;
440 #endif
441 reg=get_reg_offset(opcode);
442 switch ((byte)opcode)
444 case 0x07: /* gdelay */
445 *reg=chip8_regs.delay;
446 break;
447 case 0x0a: /* key */
448 #ifdef CHIP8_DEBUG
449 if(firstwait) {
450 printf("waiting for key press\n");
451 firstwait = 0;
453 #endif
454 if (chip8_key_pressed)
455 *reg=chip8_key_pressed-1;
456 else
457 chip8_regs.pc-=2;
458 break;
459 case 0x15: /* sdelay */
460 chip8_regs.delay=*reg;
461 break;
462 case 0x18: /* ssound */
463 chip8_regs.sound=*reg;
464 if (chip8_regs.sound)
465 chip8_sound_on();
466 break;
467 case 0x1e: /* adi */
468 chip8_regs.i+=(*reg);
469 break;
470 case 0x29: /* font */
471 chip8_regs.i=((word)(*reg&0x0f))*5;
472 break;
473 #ifdef CHIP8_SUPER
474 case 0x30: /* xfont */
475 chip8_regs.i=((word)(*reg&0x0f))*10+0x50;
476 break;
477 #endif
478 case 0x33: /* bcd */
479 i=*reg;
480 for (j=0;i>=100;i-=100)
481 j++;
482 write_mem (chip8_regs.i,j);
483 for (j=0;i>=10;i-=10)
484 j++;
485 write_mem (chip8_regs.i+1,j);
486 write_mem (chip8_regs.i+2,i);
487 break;
488 case 0x55: /* str */
489 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
490 write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
491 break;
492 case 0x65: /* ldr */
493 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
494 chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
495 break;
496 #ifdef CHIP8_SUPER
497 case 0x75:
498 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f));
499 break;
500 case 0x85:
501 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f));
502 break;
503 #endif
504 default:
505 DBG_(printf("unhandled misc opcode 0x%x\n", opcode));
506 break;
510 static void op_sprite (word opcode)
512 byte *q;
513 byte n,x,x2,y,collision;
514 word p;
515 x=get_reg_value(opcode);
516 y=get_reg_value_2(opcode);
517 p=chip8_regs.i;
518 n=opcode&0x0f;
519 #ifdef CHIP8_SUPER
520 if (chip8_super) {
521 /*printf("SUPER: sprite(%x)\n", opcode);*/
522 x &= 128-1;
523 y &= 64-1;
524 q=chip8_display+y*CHIP8_WIDTH;
525 if(n == 0)
526 { /* 16x16 sprite */
527 n = 16;
528 if (n+y>64)
529 n=64-y;
530 for (collision=1;n;--n,q+=CHIP8_WIDTH)
532 /* first 8 bits */
533 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
534 if (y&0x80)
535 collision&=(q[x2]^=0xff);
536 x2=(x+8)&(CHIP8_WIDTH-1);
537 /* last 8 bits */
538 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
539 if (y&0x80)
540 collision&=(q[x2]^=0xff);
543 else {
544 /* 8xn sprite */
545 if (n+y>64)
546 n=64-y;
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))
550 if (y&0x80)
551 collision&=(q[x2]^=0xff);
555 else {
556 x &= 64-1;
557 y &= 32-1;
558 q=chip8_display+y*CHIP8_WIDTH*2;
559 if(n == 0)
560 n = 16;
561 if (n+y>32)
562 n=32-y;
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))
566 if (y&0x80) {
567 q[x2]^=0xff;
568 q[x2+1]^=0xff;
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];
575 #else
576 x &= 64-1;
577 y &= 32-1;
578 q=chip8_display+y*CHIP8_WIDTH;
579 if (n+y>32)
580 n=32-y;
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))
584 if (y&0x80)
585 collision&=(q[x2]^=0xff);
587 #endif
588 chip8_regs.alg[15]=collision^1;
591 static math_fn math_opcodes[16]=
593 math_mov,
594 math_or,
595 math_and,
596 math_xor,
597 math_add,
598 math_sub,
599 math_shr,
600 math_rsb,
601 math_nop,
602 math_nop,
603 math_nop,
604 math_nop,
605 math_nop,
606 math_nop,
607 math_shl,
608 math_nop
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]=
619 op_system,
620 op_jmp,
621 op_call,
622 op_skeq_const,
623 op_skne_const,
624 op_skeq_reg,
625 op_mov_const,
626 op_add_const,
627 op_math,
628 op_skne_reg,
629 op_mvi,
630 op_jmi,
631 op_rand,
632 op_sprite,
633 op_key,
634 op_misc
637 #ifdef CHIP8_DEBUG
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)
647 int i;
648 byte hextable[16] = "0123456789ABCDEF";
649 byte v1[3] = "Vx\0";
650 byte v2[3] = "Vx\0";
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) {
655 case 0:
656 if ((opcode&0xff0) == 0xc0) {
657 printf ("SCD %01X ; Scroll down n lines",opcode&0xf);
659 else switch (opcode&0xfff) {
660 case 0xe0:
661 printf ("CLS ; Clear screen");
662 break;
663 case 0xee:
664 printf ("RET ; Return from subroutine call");
665 break;
666 case 0xfb:
667 printf("SCR ; Scroll right");
668 break;
669 case 0xfc:
670 printf("SCL ; Scroll left");
671 break;
672 case 0xfd:
673 printf("EXIT ; Terminate the interpreter");
674 break;
675 case 0xfe:
676 printf("LOW ; Disable extended screen mode");
677 break;
678 case 0xff:
679 printf("HIGH ; Enable extended screen mode");
680 break;
681 default:
682 printf ("SYS %03X ; Unknown system call",opcode&0xff);
684 break;
685 case 1:
686 printf ("JP %03X ; Jump to address",opcode&0xfff);
687 break;
688 case 2:
689 printf ("CALL %03X ; Call subroutine",opcode&0xfff);
690 break;
691 case 3:
692 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff);
693 break;
694 case 4:
695 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff);
696 break;
697 case 5:
698 printf ("SE %s,%s ; Skip if register == register",v1,v2);
699 break;
700 case 6:
701 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff);
702 break;
703 case 7:
704 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff);
705 break;
706 case 8:
707 switch (opcode&0x0f) {
708 case 0:
709 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2);
710 break;
711 case 1:
712 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2);
713 break;
714 case 2:
715 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2);
716 break;
717 case 3:
718 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2);
719 break;
720 case 4:
721 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2);
722 break;
723 case 5:
724 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2);
725 break;
726 case 6:
727 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2);
728 break;
729 case 7:
730 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2);
731 break;
732 case 14:
733 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2);
734 break;
735 default:
736 printf ("Illegal opcode");
738 break;
739 case 9:
740 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2);
741 break;
742 case 10:
743 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff);
744 break;
745 case 11:
746 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff);
747 break;
748 case 12:
749 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff);
750 break;
751 case 13:
752 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f);
753 break;
754 case 14:
755 switch (opcode&0xff) {
756 case 0x9e:
757 printf ("SKP %s ; Skip next instruction if key VX down",v1);
758 break;
759 case 0xa1:
760 printf ("SKNP %s ; Skip next instruction if key VX up",v1);
761 break;
762 default:
763 printf ("%04X ; Illegal opcode", opcode);
765 break;
766 case 15:
767 switch (opcode&0xff) {
768 case 0x07:
769 printf ("LD %s,DT ; Set VX = delaytimer",v1);
770 break;
771 case 0x0a:
772 printf ("LD %s,K ; Set VX = key, wait for keypress",v1);
773 break;
774 case 0x15:
775 printf ("LD DT,%s ; Set delaytimer = VX",v1);
776 break;
777 case 0x18:
778 printf ("LD ST,%s ; Set soundtimer = VX",v1);
779 break;
780 case 0x1e:
781 printf ("ADD I,%s ; Set I = I + VX",v1);
782 break;
783 case 0x29:
784 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1);
785 break;
786 case 0x30:
787 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1);
788 break;
789 case 0x33:
790 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1);
791 break;
792 case 0x55:
793 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1);
794 break;
795 case 0x65:
796 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1);
797 break;
798 case 0x75:
799 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1);
800 break;
801 case 0x85:
802 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1);
803 break;
804 default:
805 printf ("%04X ; Illegal opcode", opcode);
807 break;
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);
814 #endif
816 /****************************************************************************/
817 /* Execute chip8_iperiod opcodes */
818 /****************************************************************************/
819 STATIC void chip8_execute(void)
821 byte i;
822 byte key_pressed=0;
823 word opcode;
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);
828 #ifdef CHIP8_DEBUG
829 /* Check if trap address has been reached */
830 if ((chip8_regs.pc&4095)==chip8_trap)
831 chip8_trace=1;
832 /* Call the debugger if chip8_trace!=0 */
833 if (chip8_trace)
834 chip8_debug (opcode,&chip8_regs);
835 #endif
836 chip8_regs.pc+=2;
837 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */
839 /* Update timers */
840 if (chip8_regs.delay)
841 --chip8_regs.delay;
842 if (chip8_regs.sound)
843 if (--chip8_regs.sound == 0)
844 chip8_sound_off();
846 /* Update the machine status */
847 chip8_interrupt ();
849 for (i=key_pressed=0;i<16;++i) /* check if a key was first */
850 if (chip8_keys[i]) /* pressed */
851 key_pressed=i+1;
852 if (key_pressed && key_pressed!=chip8_key_pressed)
853 chip8_key_pressed=key_pressed;
854 else
855 chip8_key_pressed=0;
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 */
874 #ifdef CHIP8_SUPER
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) */
888 #endif
889 byte i;
890 for (i=0;i<16*5;++i)
892 write_mem (i<<1,chip8_sprites[i]&0xf0);
893 write_mem ((i<<1)+1,chip8_sprites[i]<<4);
895 #ifdef CHIP8_SUPER
897 for (i=0; i<100; i++)
898 write_mem (i+0x50,schip_sprites[i]);
900 memcpy(chip8_mem+0x50, schip_sprites, 100);
901 chip8_super = 0;
902 #endif
903 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
904 memset (chip8_keys,0,sizeof(chip8_keys));
905 chip8_key_pressed=0;
906 memset (chip8_display,0,sizeof(chip8_display));
907 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
908 chip8_regs.sp=0x1e0;
909 chip8_regs.pc=0x200;
910 chip8_sound_off ();
911 chip8_running=1;
912 #ifdef CHIP8_DEBUG
913 chip8_trace=0;
914 #endif
918 /****************************************************************************/
919 /* Start CHIP8 emulation */
920 /****************************************************************************/
921 STATIC void chip8 (void)
923 chip8_reset ();
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
934 #else
935 #define CHIP8_LCDWIDTH CHIP8_WIDTH
936 #endif
938 #if (LCD_WIDTH > CHIP8_LCDWIDTH)
939 #define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
940 #else
941 #define CHIP8_X 0
942 #endif
943 #if (LCD_HEIGHT > CHIP8_HEIGHT)
944 #define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
945 #else
946 #define CHIP8_Y 0
947 #endif
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_BACK
1026 #define CHIP8_KEY4 BUTTON_LEFT
1027 #define CHIP8_KEY5 BUTTON_SELECT
1028 #define CHIP8_KEY6 BUTTON_RIGHT
1029 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
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
1047 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
1048 #define CHIP8_OFF BUTTON_BACK
1049 #define CHIP8_KEY1 BUTTON_MENU
1050 #define CHIP8_KEY2 BUTTON_UP
1051 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1052 #define CHIP8_KEY4 BUTTON_LEFT
1053 #define CHIP8_KEY5 BUTTON_SELECT
1054 #define CHIP8_KEY6 BUTTON_RIGHT
1055 #define CHIP8_KEY7 BUTTON_VOL_UP
1056 #define CHIP8_KEY8 BUTTON_DOWN
1057 #define CHIP8_KEY9 BUTTON_PLAY
1059 #elif (CONFIG_KEYPAD == MROBE100_PAD)
1060 #define CHIP8_OFF BUTTON_POWER
1061 #define CHIP8_KEY1 BUTTON_MENU
1062 #define CHIP8_KEY2 BUTTON_UP
1063 #define CHIP8_KEY3 BUTTON_PLAY
1064 #define CHIP8_KEY4 BUTTON_LEFT
1065 #define CHIP8_KEY5 BUTTON_SELECT
1066 #define CHIP8_KEY6 BUTTON_RIGHT
1067 #define CHIP8_KEY7 BUTTON_DISPLAY
1068 #define CHIP8_KEY8 BUTTON_DOWN
1070 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1071 #define CHIP8_OFF BUTTON_RC_REC
1072 #define CHIP8_KEY1 BUTTON_RC_MENU
1073 #define CHIP8_KEY2 BUTTON_RC_VOL_UP
1074 #define CHIP8_KEY3 BUTTON_RC_MODE
1075 #define CHIP8_KEY4 BUTTON_RC_REW
1076 #define CHIP8_KEY5 BUTTON_RC_PLAY
1077 #define CHIP8_KEY6 BUTTON_RC_FF
1078 #define CHIP8_KEY8 BUTTON_RC_VOL_DOWN
1080 #elif (CONFIG_KEYPAD == COWOND2_PAD)
1081 #define CHIP8_OFF BUTTON_POWER
1082 #define CHIP8_KEY2 BUTTON_DOWN
1083 #define CHIP8_KEY4 BUTTON_LEFT
1084 #define CHIP8_KEY5 BUTTON_SELECT
1085 #define CHIP8_KEY6 BUTTON_RIGHT
1086 #define CHIP8_KEY8 BUTTON_UP
1088 #else
1089 #error No keymap defined!
1090 #endif
1092 static byte chip8_virtual_keys[16];
1093 static byte chip8_keymap[16];
1095 static unsigned long starttimer; /* Timer value at the beginning */
1096 static unsigned long cycles; /* Number of update cycles (50Hz) */
1098 #ifndef SIMULATOR
1099 static bool is_playing;
1100 #endif
1102 /* one frame of bitswapped mp3 data */
1103 static unsigned char beep[]={255,
1104 223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
1105 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
1106 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
1107 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
1108 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
1109 252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
1110 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
1111 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
1112 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
1113 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
1114 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
1116 /* callback to request more mp3 data */
1117 void callback(unsigned char** start, size_t* size)
1119 *start = beep; /* give it the same frame again */
1120 *size = sizeof(beep);
1123 /****************************************************************************/
1124 /* Turn sound on */
1125 /****************************************************************************/
1126 static void chip8_sound_on (void)
1128 #ifndef SIMULATOR
1129 if (!is_playing)
1130 rb->mp3_play_pause(true); /* kickoff audio */
1131 #endif
1134 /****************************************************************************/
1135 /* Turn sound off */
1136 /****************************************************************************/
1137 static void chip8_sound_off (void)
1139 #ifndef SIMULATOR
1140 if (!is_playing)
1141 rb->mp3_play_pause(false); /* pause audio */
1142 #endif
1145 /****************************************************************************/
1146 /* Update the display */
1147 /****************************************************************************/
1148 static void chip8_update_display(void)
1150 int x, lcd_x, y, i;
1151 byte w;
1152 byte* row;
1153 /* frame buffer in hardware fomat */
1154 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH];
1156 for (y=0;y<CHIP8_HEIGHT/8;++y)
1158 row = lcd_framebuf[y];
1159 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x)
1161 w = 0;
1162 for (i=0;i<8;i++)
1164 w = w >> 1;
1165 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0)
1167 w += 128;
1170 #if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1171 if (x%8 == 1) {
1172 row[-1] |= w; /* overlay on */
1174 else
1175 #endif
1176 *row++ = w;
1179 #if defined(SIMULATOR) || (LCD_DEPTH > 1)
1180 rb->lcd_set_drawmode(DRMODE_SOLID);
1181 rb->lcd_mono_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH,
1182 CHIP8_HEIGHT);
1183 rb->lcd_update();
1184 #else
1185 rb->lcd_blit_mono(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH,
1186 CHIP8_HEIGHT>>3, CHIP8_LCDWIDTH);
1187 #endif
1190 static void chip8_keyboard(void)
1192 int i;
1193 int button = rb->button_get(false);
1194 switch (button)
1196 #ifdef CHIP8_RC_OFF
1197 case CHIP8_RC_OFF:
1198 #endif
1199 case CHIP8_OFF: /* Abort Emulator */
1200 chip8_running = 0;
1201 break;
1203 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break;
1204 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break;
1205 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break;
1206 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break;
1207 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break;
1208 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break;
1209 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break;
1210 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break;
1211 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break;
1212 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break;
1213 #ifdef CHIP8_KEY1
1214 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break;
1215 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break;
1216 #endif
1217 #ifdef CHIP8_KEY3
1218 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break;
1219 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break;
1220 #endif
1221 #ifdef CHIP8_KEY7
1222 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break;
1223 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break;
1224 #endif
1225 #ifdef CHIP8_KEY9
1226 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break;
1227 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break;
1228 #endif
1230 default:
1231 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1232 chip8_running = 2; /* indicates stopped because of USB */
1233 break;
1235 for(i=0; i<16; i++) {
1236 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]];
1240 /****************************************************************************/
1241 /* Update keyboard and display, sync emulation with VDP clock */
1242 /****************************************************************************/
1243 static void chip8_interrupt (void)
1245 unsigned long newtimer;
1246 unsigned long timer, runtime;
1248 chip8_update_display();
1249 chip8_keyboard();
1250 cycles ++;
1251 runtime = cycles * HZ / 50;
1252 timer = starttimer + runtime;
1253 newtimer = *rb->current_tick;
1254 if (TIME_AFTER(timer, newtimer))
1256 rb->sleep(timer - newtimer);
1258 else
1260 rb->yield();
1262 starttimer = newtimer - runtime;
1265 static bool chip8_init(char* file)
1267 int numread;
1268 int fd;
1269 int len;
1270 int i;
1272 fd = rb->open(file, O_RDONLY);
1273 if (fd==-1) {
1274 rb->lcd_puts(0, 6, "File Error.");
1275 return false;
1277 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200);
1278 if (numread==-1) {
1279 rb->lcd_puts(0, 6, "I/O Error.");
1280 return false;
1283 rb->close(fd);
1284 /* is there a c8k file (chip8 keys) ? */
1285 for(i=0; i<16; i++) {
1286 chip8_virtual_keys[i] = 0;
1287 chip8_keymap[i] = i;
1289 len = rb->strlen(file);
1290 file[len-2] = '8';
1291 file[len-1] = 'k';
1292 fd = rb->open(file, O_RDONLY);
1293 if (fd!=-1) {
1294 rb->lcd_puts(0, 6, "File&Keymap OK.");
1295 numread = rb->read(fd, chip8_keymap, 16);
1296 rb->close(fd);
1298 else
1300 rb->lcd_puts(0, 6, "File OK.");
1302 for(i=0; i<16; i++) {
1303 if (chip8_keymap[i] >= '0'
1304 && chip8_keymap[i] <= '9')
1305 chip8_keymap[i] -= '0';
1306 else if (chip8_keymap[i] >= 'A'
1307 && chip8_keymap[i] <= 'F')
1308 chip8_keymap[i] -= 'A' - 10;
1309 else if (chip8_keymap[i] >= 'a'
1310 && chip8_keymap[i] <= 'f')
1311 chip8_keymap[i] -= 'a' - 10;
1312 else
1313 chip8_keymap[i] %= 16;
1315 return true;
1318 bool chip8_run(char* file)
1320 int ok;
1322 rb->lcd_clear_display();
1323 rb->lcd_puts(0, 0, "SChip8 Emulator");
1324 rb->lcd_puts(0, 1, " (c) by ");
1325 rb->lcd_puts(0, 2, "Marcel de Kogel");
1326 rb->lcd_puts(0, 3, " Rockbox: ");
1327 rb->lcd_puts(0, 4, " Blueloop/Fdy ");
1328 rb->lcd_puts(0, 5, "---------------");
1329 ok = chip8_init(file);
1330 rb->lcd_update();
1331 rb->sleep(HZ*1);
1332 if (!ok)
1333 return false;
1334 rb->lcd_clear_display();
1335 #if (CHIP8_X > 0) && (CHIP8_Y > 0)
1336 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2);
1337 #endif
1338 rb->lcd_update();
1340 #ifndef SIMULATOR
1341 /* init sound */
1342 is_playing = rb->mp3_is_playing(); /* would we disturb playback? */
1343 if (!is_playing) /* no? then we can make sound */
1344 { /* prepare */
1345 rb->mp3_play_data(beep, sizeof(beep), callback);
1347 #endif
1348 starttimer = *rb->current_tick;
1350 chip8_iperiod=15;
1351 cycles = 0;
1352 chip8();
1354 if (!ok) {
1355 rb->splash(HZ, "Error");
1356 return false;
1359 #ifndef SIMULATOR
1360 if (!is_playing)
1361 { /* stop it if we used audio */
1362 rb->mp3_play_stop(); /* Stop audio playback */
1364 #endif
1366 if (chip8_running == 3) {
1367 /* unsupported instruction */
1368 rb->splash(HZ, "Error: Unsupported"
1369 #ifndef CHIP8_SUPER
1370 " CHIP-8 instruction. (maybe S-CHIP)"
1371 #else
1372 " (S)CHIP-8 instruction."
1373 #endif
1375 return false;
1378 return true;
1382 /***************** Plugin Entry Point *****************/
1384 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1386 char* filename;
1388 rb = api; /* copy to global api pointer */
1390 if (parameter == NULL)
1392 rb->splash(HZ, "Play a .ch8 file!");
1393 return PLUGIN_ERROR;
1395 else
1397 filename = (char*) parameter;
1400 /* now go ahead and have fun! */
1401 if (chip8_run(filename))
1402 if (chip8_running == 0)
1403 return PLUGIN_OK;
1404 else
1405 return PLUGIN_USB_CONNECTED;
1406 else
1407 return PLUGIN_ERROR;
1409 #endif /* #ifdef HAVE_LCD_BITMAP */