Prepare new maemo release
[maemo-rb.git] / apps / plugins / chip8.c
blob2585c49ff2ec18dff6161568e5c84a99912fde9b
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 * 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 ****************************************************************************/
22 #include "plugin.h"
26 #define EXTERN static
27 #define STATIC static
28 #define memset rb->memset
29 #define memcpy rb->memcpy
30 #define printf DEBUGF
31 #define rand rb->rand
32 /* #define CHIP8_DEBUG */
34 #if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
35 #define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
36 #endif
38 /****************************************************************************/
39 /** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
40 /** The core is completely generic and can be used outside of Rockbox, **/
41 /** thus the STATIC, EXTERN etc. Please do not modify. **/
42 /****************************************************************************/
43 /** Vision8: CHIP8 emulator *************************************************/
44 /** **/
45 /** CHIP8.h **/
46 /** **/
47 /** This file contains the portable CHIP8 emulation engine definitions **/
48 /** **/
49 /** Copyright (C) Marcel de Kogel 1997 **/
50 /** You are not allowed to distribute this software commercially **/
51 /** Please, notify me, if you make any changes to this file **/
52 /****************************************************************************/
54 #ifndef __CHIP8_H
55 #define __CHIP8_H
57 #ifndef EXTERN
58 #define EXTERN extern
59 #endif
61 typedef unsigned char byte; /* sizeof(byte)==1 */
62 typedef unsigned short word; /* sizeof(word)>=2 */
64 struct chip8_regs_struct
66 byte alg[16]; /* 16 general registers */
67 byte delay,sound; /* delay and sound timer */
68 word i; /* index register */
69 word pc; /* program counter */
70 word sp; /* stack pointer */
73 EXTERN struct chip8_regs_struct chip8_regs;
75 #ifdef CHIP8_SUPER
76 #define CHIP8_WIDTH 128
77 #define CHIP8_HEIGHT 64
78 EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */
79 #else
80 #define CHIP8_WIDTH 64
81 #define CHIP8_HEIGHT 32
82 #endif
84 EXTERN byte chip8_iperiod; /* number of opcodes per */
85 /* timeslice (1/50sec.) */
86 EXTERN byte chip8_keys[16]; /* if 1, key is held down */
87 EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */
88 /* 0x00 otherwise */
89 EXTERN byte chip8_mem[4096]; /* machine memory. program */
90 /* is loaded at 0x200 */
91 EXTERN byte chip8_running; /* if 0, emulation stops */
93 EXTERN void chip8_execute (void); /* execute chip8_iperiod */
94 /* opcodes */
95 EXTERN void chip8_reset (void); /* reset virtual machine */
96 EXTERN void chip8 (void); /* start chip8 emulation */
98 EXTERN void chip8_sound_on (void); /* turn sound on */
99 EXTERN void chip8_sound_off (void); /* turn sound off */
100 EXTERN void chip8_interrupt (void); /* update keyboard, */
101 /* display, etc. */
103 #ifdef CHIP8_DEBUG
104 EXTERN byte chip8_trace; /* if 1, call debugger */
105 /* every opcode */
106 EXTERN word chip8_trap; /* if pc==trap, set trace */
107 /* flag */
108 EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs);
109 #endif
111 #endif /* __CHIP8_H */
113 /** Vision8: CHIP8 emulator *************************************************/
114 /** **/
115 /** CHIP8.c **/
116 /** **/
117 /** This file contains the portable CHIP8 emulation engine **/
118 /** SCHIP emulation (C) Frederic Devernay 2005 **/
119 /** **/
120 /** Copyright (C) Marcel de Kogel 1997 **/
121 /** You are not allowed to distribute this software commercially **/
122 /** Please, notify me, if you make any changes to this file **/
123 /****************************************************************************/
125 /* you can
126 #define STATIC static
127 #define EXTERN static
128 and include this file for single-object generation
131 #ifndef STATIC
132 #include <stdlib.h> /* for memset, etc. */
133 #include <string.h>
134 #define STATIC
135 #endif
137 #ifdef CHIP8_DEBUG
138 #include <stdio.h>
139 #define DBG_(_x) ((void)(_x))
140 #else
141 #define DBG_(_x) ((void)0)
142 #endif
144 STATIC struct chip8_regs_struct chip8_regs;
146 static byte chip8_key_pressed;
147 STATIC byte chip8_keys[16]; /* if 1, key is held down */
148 STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */
149 /* 0x00 otherwise */
150 #ifdef CHIP8_SUPER
151 STATIC byte chip8_super; /* != 0 if in SCHIP display mode */
152 #endif
153 STATIC byte chip8_mem[4096]; /* machine memory. program */
154 /* is loaded at 0x200 */
156 #define read_mem(a) (chip8_mem[(a)&4095])
157 #define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
159 STATIC byte chip8_iperiod;
161 STATIC byte chip8_running; /* Flag for End-of-Emulation */
163 #define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
164 #define get_reg_value(opcode) (*get_reg_offset(opcode))
165 #define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f))
166 #define get_reg_value_2(opcode) (*get_reg_offset_2(opcode))
168 typedef void (*opcode_fn) (word opcode);
169 typedef void (*math_fn) (byte *reg1,byte reg2);
173 static void op_call (word opcode)
175 chip8_regs.sp--;
176 write_mem (chip8_regs.sp,chip8_regs.pc&0xff);
177 chip8_regs.sp--;
178 write_mem (chip8_regs.sp,chip8_regs.pc>>8);
179 chip8_regs.pc=opcode;
180 #ifdef CHIP8_DEBUG
181 if(chip8_regs.sp < 0x1c0)
182 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp);
183 #endif
186 static void op_jmp (word opcode)
188 chip8_regs.pc=opcode;
191 static void op_key (word opcode)
193 #ifdef CHIP8_DEBUG
194 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
195 #endif
196 byte key, key_value,cp_value;
197 if ((opcode&0xff)==0x9e) /* skp */
198 cp_value=1;
199 else if ((opcode&0xff)==0xa1) /* sknp */
200 cp_value=0;
201 else {
202 DBG_(printf("unhandled key opcode 0x%x\n", opcode));
203 return;
205 key = get_reg_value(opcode)&0x0f;
206 #ifdef CHIP8_DEBUG
207 if (!tested[key]) {
208 tested[key] = 1;
209 DBG_(printf("testing key %d\n", key));
211 #endif
212 key_value=chip8_keys[key];
213 if (cp_value==key_value)
214 chip8_regs.pc+=2;
217 static void op_skeq_const (word opcode)
219 if (get_reg_value(opcode)==(opcode&0xff))
220 chip8_regs.pc+=2;
223 static void op_skne_const (word opcode)
225 if (get_reg_value(opcode)!=(opcode&0xff))
226 chip8_regs.pc+=2;
229 static void op_skeq_reg (word opcode)
231 if (get_reg_value(opcode)==get_reg_value_2(opcode))
232 chip8_regs.pc+=2;
235 static void op_skne_reg (word opcode)
237 if (get_reg_value(opcode)!=get_reg_value_2(opcode))
238 chip8_regs.pc+=2;
241 static void op_mov_const (word opcode)
243 *get_reg_offset(opcode)=opcode&0xff;
246 static void op_add_const (word opcode)
248 *get_reg_offset(opcode)+=opcode&0xff;
251 static void op_mvi (word opcode)
253 chip8_regs.i=opcode;
256 static void op_jmi (word opcode)
258 chip8_regs.pc=opcode+chip8_regs.alg[0];
261 static void op_rand (word opcode)
263 *get_reg_offset(opcode)=rand()&(opcode&0xff);
266 static void math_or (byte *reg1,byte reg2)
268 *reg1|=reg2;
271 static void math_mov (byte *reg1,byte reg2)
273 *reg1=reg2;
276 static void math_nop (byte *reg1,byte reg2)
278 (void)reg1;
279 (void)reg2;
280 DBG_(printf("Warning: math nop!\n"));
283 static void math_and (byte *reg1,byte reg2)
285 *reg1&=reg2;
288 static void math_xor (byte *reg1,byte reg2)
290 *reg1^=reg2;
293 static void math_add (byte *reg1,byte reg2)
295 word tmp;
296 tmp=*reg1+reg2;
297 *reg1=(byte)tmp;
298 chip8_regs.alg[15]=tmp>>8;
301 static void math_sub (byte *reg1,byte reg2)
303 word tmp;
304 tmp=*reg1-reg2;
305 *reg1=(byte)tmp;
306 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
309 static void math_shr (byte *reg1,byte reg2)
311 (void)reg2;
312 chip8_regs.alg[15]=*reg1&1;
313 *reg1>>=1;
316 static void math_shl (byte *reg1,byte reg2)
318 (void)reg2;
319 chip8_regs.alg[15]=*reg1>>7;
320 *reg1<<=1;
323 static void math_rsb (byte *reg1,byte reg2)
325 word tmp;
326 tmp=reg2-*reg1;
327 *reg1=(byte)tmp;
328 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
331 #ifdef CHIP8_SUPER
332 /* SUPER: scroll down n lines (or half in CHIP8 mode) */
333 static void scroll_down(word opcode)
335 int n = opcode & 0xf;
336 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
337 byte *src = dst - n*CHIP8_WIDTH;
338 while(src >= chip8_display) {
339 *dst-- = *src--;
341 while(dst >= chip8_display) {
342 *dst-- = 0;
345 /* SUPER: scroll 4 pixels left! */
346 static void scroll_left(void)
348 byte *dst = chip8_display;
349 byte *src = dst;
350 byte *eol = chip8_display + CHIP8_WIDTH;
351 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT;
352 while(eol <= eoi) {
353 src+=4;
354 while(src < eol) {
355 *dst++ = *src++;
357 *dst++ = 0;
358 *dst++ = 0;
359 *dst++ = 0;
360 *dst++ = 0;
361 eol += CHIP8_WIDTH;
364 static void scroll_right(void)
366 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
367 byte *src = dst;
368 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1);
369 while(bol >= chip8_display) {
370 src-=4;
371 while(src >= bol) {
372 *dst-- = *src--;
374 *dst-- = 0;
375 *dst-- = 0;
376 *dst-- = 0;
377 *dst-- = 0;
378 bol -= CHIP8_WIDTH;
381 #endif
383 static void op_system (word opcode)
385 switch ((byte)opcode)
387 #ifdef CHIP8_SUPER
388 case 0xfb:
389 scroll_right();
390 break;
391 case 0xfc:
392 scroll_left();
393 break;
394 case 0xfd:
395 DBG_(printf("SUPER: quit the emulator\n"));
396 chip8_reset();
397 break;
398 case 0xfe:
399 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
400 memset (chip8_display,0,sizeof(chip8_display));
401 chip8_super = 0;
402 break;
403 case 0xff:
404 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
405 memset (chip8_display,0,sizeof(chip8_display));
406 chip8_super = 1;
407 break;
408 #endif
409 case 0xe0:
410 memset (chip8_display,0,sizeof(chip8_display));
411 break;
412 case 0xee:
413 chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
414 chip8_regs.sp++;
415 chip8_regs.pc+=read_mem(chip8_regs.sp);
416 chip8_regs.sp++;
417 break;
418 default:
419 #ifdef CHIP8_SUPER
420 if ((opcode & 0xF0) == 0xC0)
421 scroll_down(opcode);
422 else
423 #endif
425 DBG_(printf("unhandled system opcode 0x%x\n", opcode));
426 chip8_running = 3;
428 break;
432 static void op_misc (word opcode)
434 byte *reg,i,j;
435 #ifdef CHIP8_DEBUG
436 static byte firstwait = 1;
437 #endif
438 reg=get_reg_offset(opcode);
439 switch ((byte)opcode)
441 case 0x07: /* gdelay */
442 *reg=chip8_regs.delay;
443 break;
444 case 0x0a: /* key */
445 #ifdef CHIP8_DEBUG
446 if(firstwait) {
447 printf("waiting for key press\n");
448 firstwait = 0;
450 #endif
451 if (chip8_key_pressed)
452 *reg=chip8_key_pressed-1;
453 else
454 chip8_regs.pc-=2;
455 break;
456 case 0x15: /* sdelay */
457 chip8_regs.delay=*reg;
458 break;
459 case 0x18: /* ssound */
460 chip8_regs.sound=*reg;
461 if (chip8_regs.sound)
462 chip8_sound_on();
463 break;
464 case 0x1e: /* adi */
465 chip8_regs.i+=(*reg);
466 break;
467 case 0x29: /* font */
468 chip8_regs.i=((word)(*reg&0x0f))*5;
469 break;
470 #ifdef CHIP8_SUPER
471 case 0x30: /* xfont */
472 chip8_regs.i=((word)(*reg&0x0f))*10+0x50;
473 break;
474 #endif
475 case 0x33: /* bcd */
476 i=*reg;
477 for (j=0;i>=100;i-=100)
478 j++;
479 write_mem (chip8_regs.i,j);
480 for (j=0;i>=10;i-=10)
481 j++;
482 write_mem (chip8_regs.i+1,j);
483 write_mem (chip8_regs.i+2,i);
484 break;
485 case 0x55: /* str */
486 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
487 write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
488 break;
489 case 0x65: /* ldr */
490 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
491 chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
492 break;
493 #ifdef CHIP8_SUPER
494 case 0x75:
495 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f));
496 break;
497 case 0x85:
498 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f));
499 break;
500 #endif
501 default:
502 DBG_(printf("unhandled misc opcode 0x%x\n", opcode));
503 break;
507 static void op_sprite (word opcode)
509 byte *q;
510 byte n,x,x2,y,collision;
511 word p;
512 x=get_reg_value(opcode);
513 y=get_reg_value_2(opcode);
514 p=chip8_regs.i;
515 n=opcode&0x0f;
516 #ifdef CHIP8_SUPER
517 if (chip8_super) {
518 /*printf("SUPER: sprite(%x)\n", opcode);*/
519 x &= 128-1;
520 y &= 64-1;
521 q=chip8_display+y*CHIP8_WIDTH;
522 if(n == 0)
523 { /* 16x16 sprite */
524 n = 16;
525 if (n+y>64)
526 n=64-y;
527 for (collision=1;n;--n,q+=CHIP8_WIDTH)
529 /* first 8 bits */
530 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
531 if (y&0x80)
532 collision&=(q[x2]^=0xff);
533 x2=(x+8)&(CHIP8_WIDTH-1);
534 /* last 8 bits */
535 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
536 if (y&0x80)
537 collision&=(q[x2]^=0xff);
540 else {
541 /* 8xn sprite */
542 if (n+y>64)
543 n=64-y;
544 for (collision=1;n;--n,q+=CHIP8_WIDTH)
546 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
547 if (y&0x80)
548 collision&=(q[x2]^=0xff);
552 else {
553 x &= 64-1;
554 y &= 32-1;
555 q=chip8_display+y*CHIP8_WIDTH*2;
556 if(n == 0)
557 n = 16;
558 if (n+y>32)
559 n=32-y;
560 for (collision=1;n;--n,q+=CHIP8_WIDTH*2)
562 for (y=read_mem(p++),x2=x*2;y;y<<=1,x2=(x2+2)&(CHIP8_WIDTH-1))
563 if (y&0x80) {
564 q[x2]^=0xff;
565 q[x2+1]^=0xff;
566 q[x2+CHIP8_WIDTH]^=0xff;
567 q[x2+CHIP8_WIDTH+1]^=0xff;
568 collision &= q[x2]|q[x2+1]|q[x2+CHIP8_WIDTH]|q[x2+CHIP8_WIDTH+1];
572 #else
573 x &= 64-1;
574 y &= 32-1;
575 q=chip8_display+y*CHIP8_WIDTH;
576 if (n+y>32)
577 n=32-y;
578 for (collision=1;n;--n,q+=CHIP8_WIDTH)
580 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
581 if (y&0x80)
582 collision&=(q[x2]^=0xff);
584 #endif
585 chip8_regs.alg[15]=collision^1;
588 static const math_fn math_opcodes[16]=
590 math_mov,
591 math_or,
592 math_and,
593 math_xor,
594 math_add,
595 math_sub,
596 math_shr,
597 math_rsb,
598 math_nop,
599 math_nop,
600 math_nop,
601 math_nop,
602 math_nop,
603 math_nop,
604 math_shl,
605 math_nop
608 static void op_math (word opcode)
610 (*(math_opcodes[opcode&0x0f]))
611 (get_reg_offset(opcode),get_reg_value_2(opcode));
614 static const opcode_fn main_opcodes[16]=
616 op_system,
617 op_jmp,
618 op_call,
619 op_skeq_const,
620 op_skne_const,
621 op_skeq_reg,
622 op_mov_const,
623 op_add_const,
624 op_math,
625 op_skne_reg,
626 op_mvi,
627 op_jmi,
628 op_rand,
629 op_sprite,
630 op_key,
631 op_misc
634 #ifdef CHIP8_DEBUG
635 STATIC byte chip8_trace;
636 STATIC word chip8_trap;
638 /****************************************************************************/
639 /* This routine is called every opcode when chip8_trace==1. It prints the */
640 /* current register contents and the opcode being executed */
641 /****************************************************************************/
642 STATIC void chip8_debug (word opcode,struct chip8_regs_struct *regs)
644 int i;
645 static const byte hextable[16] = "0123456789ABCDEF";
646 byte v1[3] = "Vx\0";
647 byte v2[3] = "Vx\0";
648 v1[1] = hextable[(opcode>>8)&0x0f];
649 v2[1] = hextable[(opcode>>8)&0x0f];
650 printf ("PC=%04X: %04X - ",regs->pc,opcode);
651 switch (opcode>>12) {
652 case 0:
653 if ((opcode&0xff0) == 0xc0) {
654 printf ("SCD %01X ; Scroll down n lines",opcode&0xf);
656 else switch (opcode&0xfff) {
657 case 0xe0:
658 printf ("CLS ; Clear screen");
659 break;
660 case 0xee:
661 printf ("RET ; Return from subroutine call");
662 break;
663 case 0xfb:
664 printf("SCR ; Scroll right");
665 break;
666 case 0xfc:
667 printf("SCL ; Scroll left");
668 break;
669 case 0xfd:
670 printf("EXIT ; Terminate the interpreter");
671 break;
672 case 0xfe:
673 printf("LOW ; Disable extended screen mode");
674 break;
675 case 0xff:
676 printf("HIGH ; Enable extended screen mode");
677 break;
678 default:
679 printf ("SYS %03X ; Unknown system call",opcode&0xff);
681 break;
682 case 1:
683 printf ("JP %03X ; Jump to address",opcode&0xfff);
684 break;
685 case 2:
686 printf ("CALL %03X ; Call subroutine",opcode&0xfff);
687 break;
688 case 3:
689 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff);
690 break;
691 case 4:
692 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff);
693 break;
694 case 5:
695 printf ("SE %s,%s ; Skip if register == register",v1,v2);
696 break;
697 case 6:
698 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff);
699 break;
700 case 7:
701 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff);
702 break;
703 case 8:
704 switch (opcode&0x0f) {
705 case 0:
706 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2);
707 break;
708 case 1:
709 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2);
710 break;
711 case 2:
712 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2);
713 break;
714 case 3:
715 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2);
716 break;
717 case 4:
718 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2);
719 break;
720 case 5:
721 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2);
722 break;
723 case 6:
724 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2);
725 break;
726 case 7:
727 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2);
728 break;
729 case 14:
730 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2);
731 break;
732 default:
733 printf ("Illegal opcode");
735 break;
736 case 9:
737 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2);
738 break;
739 case 10:
740 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff);
741 break;
742 case 11:
743 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff);
744 break;
745 case 12:
746 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff);
747 break;
748 case 13:
749 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f);
750 break;
751 case 14:
752 switch (opcode&0xff) {
753 case 0x9e:
754 printf ("SKP %s ; Skip next instruction if key VX down",v1);
755 break;
756 case 0xa1:
757 printf ("SKNP %s ; Skip next instruction if key VX up",v1);
758 break;
759 default:
760 printf ("%04X ; Illegal opcode", opcode);
762 break;
763 case 15:
764 switch (opcode&0xff) {
765 case 0x07:
766 printf ("LD %s,DT ; Set VX = delaytimer",v1);
767 break;
768 case 0x0a:
769 printf ("LD %s,K ; Set VX = key, wait for keypress",v1);
770 break;
771 case 0x15:
772 printf ("LD DT,%s ; Set delaytimer = VX",v1);
773 break;
774 case 0x18:
775 printf ("LD ST,%s ; Set soundtimer = VX",v1);
776 break;
777 case 0x1e:
778 printf ("ADD I,%s ; Set I = I + VX",v1);
779 break;
780 case 0x29:
781 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1);
782 break;
783 case 0x30:
784 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1);
785 break;
786 case 0x33:
787 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1);
788 break;
789 case 0x55:
790 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1);
791 break;
792 case 0x65:
793 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1);
794 break;
795 case 0x75:
796 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1);
797 break;
798 case 0x85:
799 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1);
800 break;
801 default:
802 printf ("%04X ; Illegal opcode", opcode);
804 break;
806 printf ("\n; Registers: ");
807 for (i=0;i<16;++i) printf ("%02x ",(regs->alg[i])&0xff);
808 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
809 regs->i&0xfff,regs->sp&0xfff,regs->delay&0xff,regs->sound&0xff);
811 #endif
813 /****************************************************************************/
814 /* Execute chip8_iperiod opcodes */
815 /****************************************************************************/
816 STATIC void chip8_execute(void)
818 byte i;
819 byte key_pressed=0;
820 word opcode;
821 for (i = chip8_iperiod ; i ;--i)
823 /* Fetch the opcode */
824 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1);
825 #ifdef CHIP8_DEBUG
826 /* Check if trap address has been reached */
827 if ((chip8_regs.pc&4095)==chip8_trap)
828 chip8_trace=1;
829 /* Call the debugger if chip8_trace!=0 */
830 if (chip8_trace)
831 chip8_debug (opcode,&chip8_regs);
832 #endif
833 chip8_regs.pc+=2;
834 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */
836 /* Update timers */
837 if (chip8_regs.delay)
838 --chip8_regs.delay;
839 if (chip8_regs.sound)
840 if (--chip8_regs.sound == 0)
841 chip8_sound_off();
843 /* Update the machine status */
844 chip8_interrupt ();
846 for (i=key_pressed=0;i<16;++i) /* check if a key was first */
847 if (chip8_keys[i]) /* pressed */
848 key_pressed=i+1;
849 if (key_pressed && key_pressed!=chip8_key_pressed)
850 chip8_key_pressed=key_pressed;
851 else
852 chip8_key_pressed=0;
855 /****************************************************************************/
856 /* Reset the virtual chip8 machine */
857 /****************************************************************************/
858 STATIC void chip8_reset(void)
860 static const byte chip8_sprites[0x50]=
862 0xf9,0x99,0xf2,0x62,0x27,
863 0xf1,0xf8,0xff,0x1f,0x1f,
864 0x99,0xf1,0x1f,0x8f,0x1f,
865 0xf8,0xf9,0xff,0x12,0x44,
866 0xf9,0xf9,0xff,0x9f,0x1f,
867 0xf9,0xf9,0x9e,0x9e,0x9e,
868 0xf8,0x88,0xfe,0x99,0x9e,
869 0xf8,0xf8,0xff,0x8f,0x88,
870 }; /* 4x5 pixel hexadecimal character font patterns */
871 #ifdef CHIP8_SUPER
872 static const byte schip_sprites[10*10]=
874 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
875 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
876 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
877 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
878 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
879 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
880 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
881 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
882 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
883 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
884 }; /* 8x10 pixel font patterns (only 10) */
885 #endif
886 byte i;
887 for (i=0;i<16*5;++i)
889 write_mem (i<<1,chip8_sprites[i]&0xf0);
890 write_mem ((i<<1)+1,chip8_sprites[i]<<4);
892 #ifdef CHIP8_SUPER
894 for (i=0; i<100; i++)
895 write_mem (i+0x50,schip_sprites[i]);
897 memcpy(chip8_mem+0x50, schip_sprites, 100);
898 chip8_super = 0;
899 #endif
900 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
901 memset (chip8_keys,0,sizeof(chip8_keys));
902 chip8_key_pressed=0;
903 memset (chip8_display,0,sizeof(chip8_display));
904 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
905 chip8_regs.sp=0x1e0;
906 chip8_regs.pc=0x200;
907 chip8_sound_off ();
908 chip8_running=1;
909 #ifdef CHIP8_DEBUG
910 chip8_trace=0;
911 #endif
915 /****************************************************************************/
916 /* Start CHIP8 emulation */
917 /****************************************************************************/
918 STATIC void chip8 (void)
920 chip8_reset ();
921 while (chip8_running==1) chip8_execute ();
924 /****************************************************************************/
925 /** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
926 /****************************************************************************/
928 /* size of the displayed area */
929 #if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
930 #define CHIP8_LCDWIDTH 112
931 #else
932 #define CHIP8_LCDWIDTH CHIP8_WIDTH
933 #endif
935 #if (LCD_WIDTH > CHIP8_LCDWIDTH)
936 #define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
937 #else
938 #define CHIP8_X 0
939 #endif
940 #if (LCD_HEIGHT > CHIP8_HEIGHT)
941 #define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
942 #else
943 #define CHIP8_Y 0
944 #endif
946 /* variable button definitions */
947 #if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
948 #define CHIP8_OFF BUTTON_OFF
949 #define CHIP8_KEY1 BUTTON_F1
950 #define CHIP8_KEY2 BUTTON_UP
951 #define CHIP8_KEY3 BUTTON_F3
952 #define CHIP8_KEY4 BUTTON_LEFT
953 #define CHIP8_KEY5 BUTTON_PLAY
954 #define CHIP8_KEY6 BUTTON_RIGHT
955 #define CHIP8_KEY7 BUTTON_F2
956 #define CHIP8_KEY8 BUTTON_DOWN
957 #define CHIP8_KEY9 BUTTON_ON
959 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD /* only 9 out of 16 chip8 buttons */
960 #define CHIP8_OFF BUTTON_OFF
961 #define CHIP8_KEY1 BUTTON_F1
962 #define CHIP8_KEY2 BUTTON_UP
963 #define CHIP8_KEY3 BUTTON_F3
964 #define CHIP8_KEY4 BUTTON_LEFT
965 #define CHIP8_KEY5 BUTTON_SELECT
966 #define CHIP8_KEY6 BUTTON_RIGHT
967 #define CHIP8_KEY7 BUTTON_F2
968 #define CHIP8_KEY8 BUTTON_DOWN
969 #define CHIP8_KEY9 BUTTON_ON
971 #elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
972 #define CHIP8_OFF BUTTON_OFF
973 #define CHIP8_KEY2 BUTTON_UP
974 #define CHIP8_KEY4 BUTTON_LEFT
975 #define CHIP8_KEY5 BUTTON_MENU
976 #define CHIP8_KEY6 BUTTON_RIGHT
977 #define CHIP8_KEY8 BUTTON_DOWN
979 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
980 (CONFIG_KEYPAD == IRIVER_H300_PAD)
981 #define CHIP8_OFF BUTTON_OFF
982 #define CHIP8_KEY2 BUTTON_UP
983 #define CHIP8_KEY4 BUTTON_LEFT
984 #define CHIP8_KEY5 BUTTON_SELECT
985 #define CHIP8_KEY6 BUTTON_RIGHT
986 #define CHIP8_KEY8 BUTTON_DOWN
988 #define CHIP8_RC_OFF BUTTON_RC_STOP
990 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
991 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
992 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
993 #define CHIP8_OFF BUTTON_MENU
994 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
995 #define CHIP8_KEY4 BUTTON_LEFT
996 #define CHIP8_KEY5 BUTTON_PLAY
997 #define CHIP8_KEY6 BUTTON_RIGHT
998 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1000 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
1001 #define CHIP8_OFF BUTTON_POWER
1002 #define CHIP8_KEY2 BUTTON_UP
1003 #define CHIP8_KEY4 BUTTON_LEFT
1004 #define CHIP8_KEY5 BUTTON_SELECT
1005 #define CHIP8_KEY6 BUTTON_RIGHT
1006 #define CHIP8_KEY8 BUTTON_DOWN
1008 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
1009 #define CHIP8_OFF BUTTON_POWER
1010 #define CHIP8_KEY1 BUTTON_MENU
1011 #define CHIP8_KEY2 BUTTON_UP
1012 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1013 #define CHIP8_KEY4 BUTTON_LEFT
1014 #define CHIP8_KEY5 BUTTON_SELECT
1015 #define CHIP8_KEY6 BUTTON_RIGHT
1016 #define CHIP8_KEY7 BUTTON_VOL_UP
1017 #define CHIP8_KEY8 BUTTON_DOWN
1018 #define CHIP8_KEY9 BUTTON_A
1020 #elif CONFIG_KEYPAD == SANSA_E200_PAD || \
1021 CONFIG_KEYPAD == SANSA_FUZE_PAD
1022 #define CHIP8_OFF BUTTON_POWER
1023 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
1024 #define CHIP8_KEY4 BUTTON_LEFT
1025 #define CHIP8_KEY5 BUTTON_SELECT
1026 #define CHIP8_KEY6 BUTTON_RIGHT
1027 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1029 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
1030 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
1031 CONFIG_KEYPAD == SANSA_M200_PAD
1032 #define CHIP8_OFF BUTTON_POWER
1033 #define CHIP8_KEY2 BUTTON_UP
1034 #define CHIP8_KEY4 BUTTON_LEFT
1035 #define CHIP8_KEY5 BUTTON_SELECT
1036 #define CHIP8_KEY6 BUTTON_RIGHT
1037 #define CHIP8_KEY8 BUTTON_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 == COWON_D2_PAD)
1081 #define CHIP8_OFF BUTTON_POWER
1083 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1084 #define CHIP8_OFF BUTTON_BACK
1085 #define CHIP8_KEY1 BUTTON_MENU
1086 #define CHIP8_KEY2 BUTTON_UP
1087 #define CHIP8_KEY3 BUTTON_CUSTOM
1088 #define CHIP8_KEY4 BUTTON_LEFT
1089 #define CHIP8_KEY5 BUTTON_PLAY
1090 #define CHIP8_KEY6 BUTTON_RIGHT
1091 #define CHIP8_KEY8 BUTTON_DOWN
1093 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1094 #define CHIP8_OFF BUTTON_POWER
1095 #define CHIP8_KEY1 BUTTON_MENU
1096 #define CHIP8_KEY2 BUTTON_UP
1097 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1098 #define CHIP8_KEY4 BUTTON_LEFT
1099 #define CHIP8_KEY5 BUTTON_SELECT
1100 #define CHIP8_KEY6 BUTTON_RIGHT
1101 #define CHIP8_KEY7 BUTTON_VOL_UP
1102 #define CHIP8_KEY8 BUTTON_DOWN
1103 #define CHIP8_KEY9 BUTTON_VIEW
1105 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
1106 #define CHIP8_OFF BUTTON_POWER
1107 #define CHIP8_KEY1 BUTTON_PREV
1108 #define CHIP8_KEY2 BUTTON_PLAY
1109 #define CHIP8_KEY3 BUTTON_NEXT
1110 #define CHIP8_KEY4 BUTTON_LEFT
1111 #define CHIP8_KEY5 BUTTON_UP
1112 #define CHIP8_KEY6 BUTTON_RIGHT
1113 #define CHIP8_KEY7 BUTTON_MENU
1114 #define CHIP8_KEY8 BUTTON_DOWN
1115 #define CHIP8_KEY9 BUTTON_VIEW
1116 #define CHIP8_KEY0 BUTTON_VOL_DOWN
1118 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
1119 #define CHIP8_OFF BUTTON_POWER
1120 #define CHIP8_KEY1 BUTTON_LEFT
1121 #define CHIP8_KEY2 BUTTON_UP
1122 #define CHIP8_KEY3 BUTTON_RIGHT
1123 #define CHIP8_KEY4 BUTTON_PREV
1124 #define CHIP8_KEY5 BUTTON_PLAY
1125 #define CHIP8_KEY6 BUTTON_NEXT
1126 #define CHIP8_KEY7 BUTTON_MENU
1127 #define CHIP8_KEY8 BUTTON_DOWN
1128 #define CHIP8_KEY9 BUTTON_VOL_UP
1129 #define CHIP8_KEY0 BUTTON_VOL_DOWN
1131 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
1132 CONFIG_KEYPAD == ONDAVX777_PAD || \
1133 CONFIG_KEYPAD == MROBE500_PAD
1134 #define CHIP8_OFF BUTTON_POWER
1136 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
1137 #define CHIP8_OFF BUTTON_REC
1138 #define CHIP8_KEY2 BUTTON_UP
1139 #define CHIP8_KEY4 BUTTON_LEFT
1140 #define CHIP8_KEY5 BUTTON_PLAY
1141 #define CHIP8_KEY6 BUTTON_RIGHT
1142 #define CHIP8_KEY8 BUTTON_DOWN
1144 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
1145 #define CHIP8_OFF BUTTON_REC
1146 #define CHIP8_KEY2 BUTTON_UP
1147 #define CHIP8_KEY4 BUTTON_PREV
1148 #define CHIP8_KEY5 BUTTON_OK
1149 #define CHIP8_KEY6 BUTTON_NEXT
1150 #define CHIP8_KEY8 BUTTON_DOWN
1152 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
1154 #define CHIP8_OFF (BUTTON_REC|BUTTON_PLAY)
1155 #define CHIP8_KEY1 BUTTON_REW
1156 #define CHIP8_KEY2 BUTTON_FF
1157 #define CHIP8_KEY3 BUTTON_FUNC
1158 #define CHIP8_KEY4 BUTTON_REC
1159 #define CHIP8_KEY5 BUTTON_PLAY
1160 #define CHIP8_KEY6 BUTTON_VOL_DOWN
1161 #define CHIP8_KEY8 BUTTON_VOL_UP
1163 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
1165 #define CHIP8_OFF (BUTTON_MENU|BUTTON_REPEAT)
1166 #define CHIP8_KEY1 BUTTON_REW
1167 #define CHIP8_KEY2 BUTTON_FF
1168 #define CHIP8_KEY3 BUTTON_MENU
1169 #define CHIP8_KEY4 BUTTON_ENTER
1170 #define CHIP8_KEY5 BUTTON_REC
1171 #define CHIP8_KEY6 BUTTON_PLAY
1172 #define CHIP8_KEY7 BUTTON_UP
1173 #define CHIP8_KEY8 BUTTON_DOWN
1175 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
1177 #define CHIP8_OFF BUTTON_POWER
1178 #define CHIP8_KEY1 BUTTON_LEFT
1179 #define CHIP8_KEY2 BUTTON_UP
1180 #define CHIP8_KEY3 BUTTON_RIGHT
1181 #define CHIP8_KEY4 BUTTON_DOWN
1182 #define CHIP8_KEY5 BUTTON_PLAYPAUSE
1183 #define CHIP8_KEY6 BUTTON_BACK
1184 #define CHIP8_KEY7 BUTTON_SELECT
1185 #define CHIP8_KEY8 BUTTON_VOL_DOWN
1186 #define CHIP8_KEY9 BUTTON_VOL_UP
1188 #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
1190 #define CHIP8_OFF BUTTON_POWER
1191 #define CHIP8_KEY1 BUTTON_LEFT
1192 #define CHIP8_KEY2 BUTTON_UP
1193 #define CHIP8_KEY3 BUTTON_RIGHT
1194 #define CHIP8_KEY4 BUTTON_DOWN
1195 #define CHIP8_KEY5 BUTTON_NEXT
1196 #define CHIP8_KEY6 BUTTON_PREV
1197 #define CHIP8_KEY7 BUTTON_SELECT
1198 #define CHIP8_KEY8 BUTTON_VOL_DOWN
1199 #define CHIP8_KEY9 BUTTON_VOL_UP
1201 #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
1202 #define CHIP8_OFF (BUTTON_BACK|BUTTON_REPEAT)
1203 #define CHIP8_KEY1 BUTTON_MENU
1204 #define CHIP8_KEY2 BUTTON_UP
1205 #define CHIP8_KEY3 BUTTON_DOWN
1206 #define CHIP8_KEY4 BUTTON_LEFT
1207 #define CHIP8_KEY5 BUTTON_SELECT
1208 #define CHIP8_KEY6 BUTTON_RIGHT
1209 #define CHIP8_KEY7 BUTTON_BACK
1210 #define CHIP8_KEY8 BUTTON_POWER
1211 #define CHIP8_KEY9 BUTTON_USER
1213 #elif (CONFIG_KEYPAD == HM60X_PAD)
1214 #define CHIP8_OFF BUTTON_POWER
1215 #define CHIP8_KEY2 BUTTON_UP
1216 #define CHIP8_KEY4 BUTTON_DOWN
1217 #define CHIP8_KEY5 BUTTON_SELECT
1218 #define CHIP8_KEY6 BUTTON_RIGHT
1219 #define CHIP8_KEY8 BUTTON_LEFT
1221 #elif (CONFIG_KEYPAD == HM801_PAD)
1222 #define CHIP8_OFF (BUTTON_POWER|BUTTON_SELECT)
1223 #define CHIP8_KEY1 BUTTON_PREV
1224 #define CHIP8_KEY2 BUTTON_UP
1225 #define CHIP8_KEY3 BUTTON_DOWN
1226 #define CHIP8_KEY4 BUTTON_LEFT
1227 #define CHIP8_KEY5 BUTTON_SELECT
1228 #define CHIP8_KEY6 BUTTON_RIGHT
1229 #define CHIP8_KEY7 BUTTON_NEXT
1230 #define CHIP8_KEY8 BUTTON_PLAY
1231 #define CHIP8_KEY9 BUTTON_POWER
1233 #else
1234 #error No keymap defined!
1235 #endif
1237 #ifdef HAVE_TOUCHSCREEN
1238 #ifndef CHIP8_OFF
1239 #define CHIP8_OFF BUTTON_TOPLEFT
1240 #endif
1241 #ifndef CHIP8_KEY1
1242 #define CHIP8_KEY1 BUTTON_TOPRIGHT
1243 #endif
1244 #ifndef CHIP8_KEY2
1245 #define CHIP8_KEY2 BUTTON_TOPMIDDLE
1246 #endif
1247 #ifndef CHIP8_KEY3
1248 #define CHIP8_KEY3 BUTTON_BOTTOMLEFT
1249 #endif
1250 #ifndef CHIP8_KEY4
1251 #define CHIP8_KEY4 BUTTON_MIDLEFT
1252 #endif
1253 #ifndef CHIP8_KEY5
1254 #define CHIP8_KEY5 BUTTON_CENTER
1255 #endif
1256 #ifndef CHIP8_KEY6
1257 #define CHIP8_KEY6 BUTTON_MIDRIGHT
1258 #endif
1259 #ifndef CHIP8_KEY7
1260 #define CHIP8_KEY7 BUTTON_BOTTOMRIGHT
1261 #endif
1262 #ifndef CHIP8_KEY8
1263 #define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE
1264 #endif
1265 #endif
1267 static byte chip8_virtual_keys[16];
1268 static byte chip8_keymap[16];
1270 static unsigned long starttimer; /* Timer value at the beginning */
1271 static unsigned long cycles; /* Number of update cycles (50Hz) */
1273 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1274 static bool is_playing;
1276 /* one frame of bitswapped mp3 data */
1277 static unsigned char beep[]={255,
1278 223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
1279 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
1280 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
1281 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
1282 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
1283 252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
1284 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
1285 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
1286 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
1287 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
1288 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
1290 /* callback to request more mp3 data */
1291 static void callback(const void** start, size_t* size)
1293 *start = beep; /* give it the same frame again */
1294 *size = sizeof(beep);
1296 #endif /* PLATFORM_NATIVE */
1298 /****************************************************************************/
1299 /* Turn sound on */
1300 /****************************************************************************/
1301 static void chip8_sound_on (void)
1303 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1304 if (!is_playing)
1305 rb->mp3_play_pause(true); /* kickoff audio */
1306 #endif
1309 /****************************************************************************/
1310 /* Turn sound off */
1311 /****************************************************************************/
1312 static void chip8_sound_off (void)
1314 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1315 if (!is_playing)
1316 rb->mp3_play_pause(false); /* pause audio */
1317 #endif
1320 /****************************************************************************/
1321 /* Update the display */
1322 /****************************************************************************/
1323 static void chip8_update_display(void)
1325 int x, lcd_x, y, i;
1326 byte w;
1327 byte* row;
1328 /* frame buffer in hardware fomat */
1329 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH];
1331 for (y=0;y<CHIP8_HEIGHT/8;++y)
1333 row = lcd_framebuf[y];
1334 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x)
1336 w = 0;
1337 for (i=0;i<8;i++)
1339 w = w >> 1;
1340 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0)
1342 w += 128;
1345 #if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1346 if (x%8 == 1) {
1347 row[-1] |= w; /* overlay on */
1349 else
1350 #endif
1351 *row++ = w;
1354 #if (CONFIG_PLATFORM & PLATFORM_HOSTED) || (LCD_DEPTH >= 4)
1355 rb->lcd_set_drawmode(DRMODE_SOLID);
1356 rb->lcd_mono_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH,
1357 CHIP8_HEIGHT);
1358 rb->lcd_update();
1359 #else
1360 rb->lcd_blit_mono(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH,
1361 CHIP8_HEIGHT>>3, CHIP8_LCDWIDTH);
1362 #endif
1365 static void chip8_keyboard(void)
1367 int i;
1368 int button = rb->button_get(false);
1369 switch (button)
1371 #ifdef CHIP8_RC_OFF
1372 case CHIP8_RC_OFF:
1373 #endif
1374 case CHIP8_OFF: /* Abort Emulator */
1375 chip8_running = 0;
1376 break;
1378 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break;
1379 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break;
1380 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break;
1381 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break;
1382 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break;
1383 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break;
1384 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break;
1385 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break;
1386 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break;
1387 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break;
1388 #ifdef CHIP8_KEY1
1389 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break;
1390 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break;
1391 #endif
1392 #ifdef CHIP8_KEY3
1393 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break;
1394 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break;
1395 #endif
1396 #ifdef CHIP8_KEY7
1397 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break;
1398 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break;
1399 #endif
1400 #ifdef CHIP8_KEY9
1401 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break;
1402 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break;
1403 #endif
1405 default:
1406 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1407 chip8_running = 2; /* indicates stopped because of USB */
1408 break;
1410 for(i=0; i<16; i++) {
1411 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]];
1415 /****************************************************************************/
1416 /* Update keyboard and display, sync emulation with VDP clock */
1417 /****************************************************************************/
1418 static void chip8_interrupt (void)
1420 unsigned long current_tick;
1421 unsigned long timer, runtime;
1423 chip8_update_display();
1424 chip8_keyboard();
1425 cycles ++;
1426 runtime = cycles * HZ / 50;
1427 timer = starttimer + runtime;
1428 current_tick = *rb->current_tick;
1429 if (TIME_AFTER(timer, current_tick))
1431 rb->sleep(timer - current_tick);
1433 else
1435 rb->yield();
1439 static bool chip8_init(const char* file)
1441 int numread;
1442 int fd;
1443 int len;
1444 int i;
1446 fd = rb->open(file, O_RDONLY);
1447 if (fd < 0) {
1448 rb->lcd_puts(0, 6, "File Error.");
1449 return false;
1451 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200);
1452 rb->close(fd);
1453 if (numread==-1) {
1454 rb->lcd_puts(0, 6, "I/O Error.");
1455 return false;
1458 /* is there a c8k file (chip8 keys) ? */
1459 char c8kname[MAX_PATH];
1460 rb->strcpy(c8kname, file);
1461 for(i=0; i<16; i++) {
1462 chip8_virtual_keys[i] = 0;
1463 chip8_keymap[i] = i;
1465 len = rb->strlen(c8kname);
1466 c8kname[len-2] = '8';
1467 c8kname[len-1] = 'k';
1468 fd = rb->open(c8kname, O_RDONLY);
1469 if (fd >= 0) {
1470 rb->lcd_puts(0, 6, "File&Keymap OK.");
1471 numread = rb->read(fd, chip8_keymap, 16);
1472 rb->close(fd);
1474 else
1476 rb->lcd_puts(0, 6, "File OK.");
1478 for(i=0; i<16; i++) {
1479 if (chip8_keymap[i] >= '0'
1480 && chip8_keymap[i] <= '9')
1481 chip8_keymap[i] -= '0';
1482 else if (chip8_keymap[i] >= 'A'
1483 && chip8_keymap[i] <= 'F')
1484 chip8_keymap[i] -= 'A' - 10;
1485 else if (chip8_keymap[i] >= 'a'
1486 && chip8_keymap[i] <= 'f')
1487 chip8_keymap[i] -= 'a' - 10;
1488 else
1489 chip8_keymap[i] %= 16;
1491 return true;
1494 static bool chip8_run(const char* file)
1496 int ok;
1498 rb->lcd_clear_display();
1499 rb->lcd_puts(0, 0, "SChip8 Emulator");
1500 rb->lcd_puts(0, 1, " (c) by ");
1501 rb->lcd_puts(0, 2, "Marcel de Kogel");
1502 rb->lcd_puts(0, 3, " Rockbox: ");
1503 rb->lcd_puts(0, 4, " Blueloop/Fdy ");
1504 rb->lcd_puts(0, 5, "---------------");
1505 ok = chip8_init(file);
1506 rb->lcd_update();
1507 rb->sleep(HZ*1);
1508 if (!ok)
1509 return false;
1510 rb->lcd_clear_display();
1511 #if (CHIP8_X > 0) && (CHIP8_Y > 0)
1512 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2);
1513 #endif
1514 rb->lcd_update();
1516 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1517 /* init sound */
1518 is_playing = rb->mp3_is_playing(); /* would we disturb playback? */
1519 if (!is_playing) /* no? then we can make sound */
1520 { /* prepare */
1521 rb->mp3_play_data(beep, sizeof(beep), callback);
1523 #endif
1524 starttimer = *rb->current_tick;
1526 chip8_iperiod=15;
1527 cycles = 0;
1528 chip8();
1530 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1531 if (!is_playing)
1532 { /* stop it if we used audio */
1533 rb->mp3_play_stop(); /* Stop audio playback */
1535 #endif
1537 if (chip8_running == 3) {
1538 /* unsupported instruction */
1539 rb->splash(HZ, "Error: Unsupported"
1540 #ifndef CHIP8_SUPER
1541 " CHIP-8 instruction. (maybe S-CHIP)"
1542 #else
1543 " (S)CHIP-8 instruction."
1544 #endif
1546 return false;
1549 return true;
1553 /***************** Plugin Entry Point *****************/
1555 enum plugin_status plugin_start(const void* parameter)
1557 const char* filename;
1559 if (parameter == NULL)
1561 rb->splash(HZ, "Play a .ch8 file!");
1562 return PLUGIN_ERROR;
1564 else
1566 filename = (char*) parameter;
1569 /* now go ahead and have fun! */
1570 if (chip8_run(filename))
1571 if (chip8_running == 0)
1572 return PLUGIN_OK;
1573 else
1574 return PLUGIN_USB_CONNECTED;
1575 else
1576 return PLUGIN_ERROR;