Commit FS#9607 by Adam Hogan: fix plugin keymaps for Creative Zen Vision:M
[kugel-rb.git] / apps / plugins / chip8.c
blob83bd7262c8091dd97d1164d67a52bfc47c5de23f
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"
24 /* Only build for (correct) target */
25 #ifdef HAVE_LCD_BITMAP
27 PLUGIN_HEADER
29 static const struct plugin_api* rb; /* here is a global api struct pointer */
31 #define EXTERN static
32 #define STATIC static
33 #define memset rb->memset
34 #define memcpy rb->memcpy
35 #define printf DEBUGF
36 #define rand rb->rand
37 /* #define CHIP8_DEBUG */
39 #if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
40 #define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
41 #endif
43 /****************************************************************************/
44 /** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
45 /** The core is completely generic and can be used outside of Rockbox, **/
46 /** thus the STATIC, EXTERN etc. Please do not modify. **/
47 /****************************************************************************/
48 /** Vision8: CHIP8 emulator *************************************************/
49 /** **/
50 /** CHIP8.h **/
51 /** **/
52 /** This file contains the portable CHIP8 emulation engine definitions **/
53 /** **/
54 /** Copyright (C) Marcel de Kogel 1997 **/
55 /** You are not allowed to distribute this software commercially **/
56 /** Please, notify me, if you make any changes to this file **/
57 /****************************************************************************/
59 #ifndef __CHIP8_H
60 #define __CHIP8_H
62 #ifndef EXTERN
63 #define EXTERN extern
64 #endif
66 typedef unsigned char byte; /* sizeof(byte)==1 */
67 typedef unsigned short word; /* sizeof(word)>=2 */
69 struct chip8_regs_struct
71 byte alg[16]; /* 16 general registers */
72 byte delay,sound; /* delay and sound timer */
73 word i; /* index register */
74 word pc; /* program counter */
75 word sp; /* stack pointer */
78 EXTERN struct chip8_regs_struct chip8_regs;
80 #ifdef CHIP8_SUPER
81 #define CHIP8_WIDTH 128
82 #define CHIP8_HEIGHT 64
83 EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */
84 #else
85 #define CHIP8_WIDTH 64
86 #define CHIP8_HEIGHT 32
87 #endif
89 EXTERN byte chip8_iperiod; /* number of opcodes per */
90 /* timeslice (1/50sec.) */
91 EXTERN byte chip8_keys[16]; /* if 1, key is held down */
92 EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */
93 /* 0x00 otherwise */
94 EXTERN byte chip8_mem[4096]; /* machine memory. program */
95 /* is loaded at 0x200 */
96 EXTERN byte chip8_running; /* if 0, emulation stops */
98 EXTERN void chip8_execute (void); /* execute chip8_iperiod */
99 /* opcodes */
100 EXTERN void chip8_reset (void); /* reset virtual machine */
101 EXTERN void chip8 (void); /* start chip8 emulation */
103 EXTERN void chip8_sound_on (void); /* turn sound on */
104 EXTERN void chip8_sound_off (void); /* turn sound off */
105 EXTERN void chip8_interrupt (void); /* update keyboard, */
106 /* display, etc. */
108 #ifdef CHIP8_DEBUG
109 EXTERN byte chip8_trace; /* if 1, call debugger */
110 /* every opcode */
111 EXTERN word chip8_trap; /* if pc==trap, set trace */
112 /* flag */
113 EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs);
114 #endif
116 #endif /* __CHIP8_H */
118 /** Vision8: CHIP8 emulator *************************************************/
119 /** **/
120 /** CHIP8.c **/
121 /** **/
122 /** This file contains the portable CHIP8 emulation engine **/
123 /** SCHIP emulation (C) Frederic Devernay 2005 **/
124 /** **/
125 /** Copyright (C) Marcel de Kogel 1997 **/
126 /** You are not allowed to distribute this software commercially **/
127 /** Please, notify me, if you make any changes to this file **/
128 /****************************************************************************/
130 /* you can
131 #define STATIC static
132 #define EXTERN static
133 and include this file for single-object generation
136 #ifndef STATIC
137 #include <stdlib.h> /* for memset, etc. */
138 #include <string.h>
139 #define STATIC
140 #endif
142 #ifdef CHIP8_DEBUG
143 #include <stdio.h>
144 #define DBG_(_x) ((void)(_x))
145 #else
146 #define DBG_(_x) ((void)0)
147 #endif
149 STATIC struct chip8_regs_struct chip8_regs;
151 static byte chip8_key_pressed;
152 STATIC byte chip8_keys[16]; /* if 1, key is held down */
153 STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */
154 /* 0x00 otherwise */
155 #ifdef CHIP8_SUPER
156 STATIC byte chip8_super; /* != 0 if in SCHIP display mode */
157 #endif
158 STATIC byte chip8_mem[4096]; /* machine memory. program */
159 /* is loaded at 0x200 */
161 #define read_mem(a) (chip8_mem[(a)&4095])
162 #define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
164 STATIC byte chip8_iperiod;
166 STATIC byte chip8_running; /* Flag for End-of-Emulation */
168 #define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
169 #define get_reg_value(opcode) (*get_reg_offset(opcode))
170 #define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f))
171 #define get_reg_value_2(opcode) (*get_reg_offset_2(opcode))
173 typedef void (*opcode_fn) (word opcode);
174 typedef void (*math_fn) (byte *reg1,byte reg2);
178 static void op_call (word opcode)
180 chip8_regs.sp--;
181 write_mem (chip8_regs.sp,chip8_regs.pc&0xff);
182 chip8_regs.sp--;
183 write_mem (chip8_regs.sp,chip8_regs.pc>>8);
184 chip8_regs.pc=opcode;
185 #ifdef CHIP8_DEBUG
186 if(chip8_regs.sp < 0x1c0)
187 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp);
188 #endif
191 static void op_jmp (word opcode)
193 chip8_regs.pc=opcode;
196 static void op_key (word opcode)
198 #ifdef CHIP8_DEBUG
199 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
200 #endif
201 byte key, key_value,cp_value;
202 if ((opcode&0xff)==0x9e) /* skp */
203 cp_value=1;
204 else if ((opcode&0xff)==0xa1) /* sknp */
205 cp_value=0;
206 else {
207 DBG_(printf("unhandled key opcode 0x%x\n", opcode));
208 return;
210 key = get_reg_value(opcode)&0x0f;
211 #ifdef CHIP8_DEBUG
212 if (!tested[key]) {
213 tested[key] = 1;
214 DBG_(printf("testing key %d\n", key));
216 #endif
217 key_value=chip8_keys[key];
218 if (cp_value==key_value)
219 chip8_regs.pc+=2;
222 static void op_skeq_const (word opcode)
224 if (get_reg_value(opcode)==(opcode&0xff))
225 chip8_regs.pc+=2;
228 static void op_skne_const (word opcode)
230 if (get_reg_value(opcode)!=(opcode&0xff))
231 chip8_regs.pc+=2;
234 static void op_skeq_reg (word opcode)
236 if (get_reg_value(opcode)==get_reg_value_2(opcode))
237 chip8_regs.pc+=2;
240 static void op_skne_reg (word opcode)
242 if (get_reg_value(opcode)!=get_reg_value_2(opcode))
243 chip8_regs.pc+=2;
246 static void op_mov_const (word opcode)
248 *get_reg_offset(opcode)=opcode&0xff;
251 static void op_add_const (word opcode)
253 *get_reg_offset(opcode)+=opcode&0xff;
256 static void op_mvi (word opcode)
258 chip8_regs.i=opcode;
261 static void op_jmi (word opcode)
263 chip8_regs.pc=opcode+chip8_regs.alg[0];
266 static void op_rand (word opcode)
268 *get_reg_offset(opcode)=rand()&(opcode&0xff);
271 static void math_or (byte *reg1,byte reg2)
273 *reg1|=reg2;
276 static void math_mov (byte *reg1,byte reg2)
278 *reg1=reg2;
281 static void math_nop (byte *reg1,byte reg2)
283 (void)reg1;
284 (void)reg2;
285 DBG_(printf("Warning: math nop!\n"));
288 static void math_and (byte *reg1,byte reg2)
290 *reg1&=reg2;
293 static void math_xor (byte *reg1,byte reg2)
295 *reg1^=reg2;
298 static void math_add (byte *reg1,byte reg2)
300 word tmp;
301 tmp=*reg1+reg2;
302 *reg1=(byte)tmp;
303 chip8_regs.alg[15]=tmp>>8;
306 static void math_sub (byte *reg1,byte reg2)
308 word tmp;
309 tmp=*reg1-reg2;
310 *reg1=(byte)tmp;
311 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
314 static void math_shr (byte *reg1,byte reg2)
316 (void)reg2;
317 chip8_regs.alg[15]=*reg1&1;
318 *reg1>>=1;
321 static void math_shl (byte *reg1,byte reg2)
323 (void)reg2;
324 chip8_regs.alg[15]=*reg1>>7;
325 *reg1<<=1;
328 static void math_rsb (byte *reg1,byte reg2)
330 word tmp;
331 tmp=reg2-*reg1;
332 *reg1=(byte)tmp;
333 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
336 #ifdef CHIP8_SUPER
337 /* SUPER: scroll down n lines (or half in CHIP8 mode) */
338 static void scroll_down(word opcode)
340 int n = opcode & 0xf;
341 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
342 byte *src = dst - n*CHIP8_WIDTH;
343 while(src >= chip8_display) {
344 *dst-- = *src--;
346 while(dst >= chip8_display) {
347 *dst-- = 0;
350 /* SUPER: scroll 4 pixels left! */
351 static void scroll_left(void)
353 byte *dst = chip8_display;
354 byte *src = dst;
355 byte *eol = chip8_display + CHIP8_WIDTH;
356 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT;
357 while(eol <= eoi) {
358 src+=4;
359 while(src < eol) {
360 *dst++ = *src++;
362 *dst++ = 0;
363 *dst++ = 0;
364 *dst++ = 0;
365 *dst++ = 0;
366 eol += CHIP8_WIDTH;
369 static void scroll_right(void)
371 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
372 byte *src = dst;
373 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1);
374 while(bol >= chip8_display) {
375 src-=4;
376 while(src >= bol) {
377 *dst-- = *src--;
379 *dst-- = 0;
380 *dst-- = 0;
381 *dst-- = 0;
382 *dst-- = 0;
383 bol -= CHIP8_WIDTH;
386 #endif
388 static void op_system (word opcode)
390 switch ((byte)opcode)
392 #ifdef CHIP8_SUPER
393 case 0xfb:
394 scroll_right();
395 break;
396 case 0xfc:
397 scroll_left();
398 break;
399 case 0xfd:
400 DBG_(printf("SUPER: quit the emulator\n"));
401 chip8_reset();
402 break;
403 case 0xfe:
404 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
405 memset (chip8_display,0,sizeof(chip8_display));
406 chip8_super = 0;
407 break;
408 case 0xff:
409 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
410 memset (chip8_display,0,sizeof(chip8_display));
411 chip8_super = 1;
412 break;
413 #endif
414 case 0xe0:
415 memset (chip8_display,0,sizeof(chip8_display));
416 break;
417 case 0xee:
418 chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
419 chip8_regs.sp++;
420 chip8_regs.pc+=read_mem(chip8_regs.sp);
421 chip8_regs.sp++;
422 break;
423 default:
424 #ifdef CHIP8_SUPER
425 if ((opcode & 0xF0) == 0xC0)
426 scroll_down(opcode);
427 else
428 #endif
430 DBG_(printf("unhandled system opcode 0x%x\n", opcode));
431 chip8_running = 3;
433 break;
437 static void op_misc (word opcode)
439 byte *reg,i,j;
440 #ifdef CHIP8_DEBUG
441 static byte firstwait = 1;
442 #endif
443 reg=get_reg_offset(opcode);
444 switch ((byte)opcode)
446 case 0x07: /* gdelay */
447 *reg=chip8_regs.delay;
448 break;
449 case 0x0a: /* key */
450 #ifdef CHIP8_DEBUG
451 if(firstwait) {
452 printf("waiting for key press\n");
453 firstwait = 0;
455 #endif
456 if (chip8_key_pressed)
457 *reg=chip8_key_pressed-1;
458 else
459 chip8_regs.pc-=2;
460 break;
461 case 0x15: /* sdelay */
462 chip8_regs.delay=*reg;
463 break;
464 case 0x18: /* ssound */
465 chip8_regs.sound=*reg;
466 if (chip8_regs.sound)
467 chip8_sound_on();
468 break;
469 case 0x1e: /* adi */
470 chip8_regs.i+=(*reg);
471 break;
472 case 0x29: /* font */
473 chip8_regs.i=((word)(*reg&0x0f))*5;
474 break;
475 #ifdef CHIP8_SUPER
476 case 0x30: /* xfont */
477 chip8_regs.i=((word)(*reg&0x0f))*10+0x50;
478 break;
479 #endif
480 case 0x33: /* bcd */
481 i=*reg;
482 for (j=0;i>=100;i-=100)
483 j++;
484 write_mem (chip8_regs.i,j);
485 for (j=0;i>=10;i-=10)
486 j++;
487 write_mem (chip8_regs.i+1,j);
488 write_mem (chip8_regs.i+2,i);
489 break;
490 case 0x55: /* str */
491 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
492 write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
493 break;
494 case 0x65: /* ldr */
495 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
496 chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
497 break;
498 #ifdef CHIP8_SUPER
499 case 0x75:
500 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f));
501 break;
502 case 0x85:
503 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f));
504 break;
505 #endif
506 default:
507 DBG_(printf("unhandled misc opcode 0x%x\n", opcode));
508 break;
512 static void op_sprite (word opcode)
514 byte *q;
515 byte n,x,x2,y,collision;
516 word p;
517 x=get_reg_value(opcode);
518 y=get_reg_value_2(opcode);
519 p=chip8_regs.i;
520 n=opcode&0x0f;
521 #ifdef CHIP8_SUPER
522 if (chip8_super) {
523 /*printf("SUPER: sprite(%x)\n", opcode);*/
524 x &= 128-1;
525 y &= 64-1;
526 q=chip8_display+y*CHIP8_WIDTH;
527 if(n == 0)
528 { /* 16x16 sprite */
529 n = 16;
530 if (n+y>64)
531 n=64-y;
532 for (collision=1;n;--n,q+=CHIP8_WIDTH)
534 /* first 8 bits */
535 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
536 if (y&0x80)
537 collision&=(q[x2]^=0xff);
538 x2=(x+8)&(CHIP8_WIDTH-1);
539 /* last 8 bits */
540 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
541 if (y&0x80)
542 collision&=(q[x2]^=0xff);
545 else {
546 /* 8xn sprite */
547 if (n+y>64)
548 n=64-y;
549 for (collision=1;n;--n,q+=CHIP8_WIDTH)
551 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
552 if (y&0x80)
553 collision&=(q[x2]^=0xff);
557 else {
558 x &= 64-1;
559 y &= 32-1;
560 q=chip8_display+y*CHIP8_WIDTH*2;
561 if(n == 0)
562 n = 16;
563 if (n+y>32)
564 n=32-y;
565 for (collision=1;n;--n,q+=CHIP8_WIDTH*2)
567 for (y=read_mem(p++),x2=x*2;y;y<<=1,x2=(x2+2)&(CHIP8_WIDTH-1))
568 if (y&0x80) {
569 q[x2]^=0xff;
570 q[x2+1]^=0xff;
571 q[x2+CHIP8_WIDTH]^=0xff;
572 q[x2+CHIP8_WIDTH+1]^=0xff;
573 collision &= q[x2]|q[x2+1]|q[x2+CHIP8_WIDTH]|q[x2+CHIP8_WIDTH+1];
577 #else
578 x &= 64-1;
579 y &= 32-1;
580 q=chip8_display+y*CHIP8_WIDTH;
581 if (n+y>32)
582 n=32-y;
583 for (collision=1;n;--n,q+=CHIP8_WIDTH)
585 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
586 if (y&0x80)
587 collision&=(q[x2]^=0xff);
589 #endif
590 chip8_regs.alg[15]=collision^1;
593 static math_fn math_opcodes[16]=
595 math_mov,
596 math_or,
597 math_and,
598 math_xor,
599 math_add,
600 math_sub,
601 math_shr,
602 math_rsb,
603 math_nop,
604 math_nop,
605 math_nop,
606 math_nop,
607 math_nop,
608 math_nop,
609 math_shl,
610 math_nop
613 static void op_math (word opcode)
615 (*(math_opcodes[opcode&0x0f]))
616 (get_reg_offset(opcode),get_reg_value_2(opcode));
619 static opcode_fn main_opcodes[16]=
621 op_system,
622 op_jmp,
623 op_call,
624 op_skeq_const,
625 op_skne_const,
626 op_skeq_reg,
627 op_mov_const,
628 op_add_const,
629 op_math,
630 op_skne_reg,
631 op_mvi,
632 op_jmi,
633 op_rand,
634 op_sprite,
635 op_key,
636 op_misc
639 #ifdef CHIP8_DEBUG
640 STATIC byte chip8_trace;
641 STATIC word chip8_trap;
643 /****************************************************************************/
644 /* This routine is called every opcode when chip8_trace==1. It prints the */
645 /* current register contents and the opcode being executed */
646 /****************************************************************************/
647 STATIC void chip8_debug (word opcode,struct chip8_regs_struct *regs)
649 int i;
650 byte hextable[16] = "0123456789ABCDEF";
651 byte v1[3] = "Vx\0";
652 byte v2[3] = "Vx\0";
653 v1[1] = hextable[(opcode>>8)&0x0f];
654 v2[1] = hextable[(opcode>>8)&0x0f];
655 printf ("PC=%04X: %04X - ",regs->pc,opcode);
656 switch (opcode>>12) {
657 case 0:
658 if ((opcode&0xff0) == 0xc0) {
659 printf ("SCD %01X ; Scroll down n lines",opcode&0xf);
661 else switch (opcode&0xfff) {
662 case 0xe0:
663 printf ("CLS ; Clear screen");
664 break;
665 case 0xee:
666 printf ("RET ; Return from subroutine call");
667 break;
668 case 0xfb:
669 printf("SCR ; Scroll right");
670 break;
671 case 0xfc:
672 printf("SCL ; Scroll left");
673 break;
674 case 0xfd:
675 printf("EXIT ; Terminate the interpreter");
676 break;
677 case 0xfe:
678 printf("LOW ; Disable extended screen mode");
679 break;
680 case 0xff:
681 printf("HIGH ; Enable extended screen mode");
682 break;
683 default:
684 printf ("SYS %03X ; Unknown system call",opcode&0xff);
686 break;
687 case 1:
688 printf ("JP %03X ; Jump to address",opcode&0xfff);
689 break;
690 case 2:
691 printf ("CALL %03X ; Call subroutine",opcode&0xfff);
692 break;
693 case 3:
694 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff);
695 break;
696 case 4:
697 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff);
698 break;
699 case 5:
700 printf ("SE %s,%s ; Skip if register == register",v1,v2);
701 break;
702 case 6:
703 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff);
704 break;
705 case 7:
706 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff);
707 break;
708 case 8:
709 switch (opcode&0x0f) {
710 case 0:
711 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2);
712 break;
713 case 1:
714 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2);
715 break;
716 case 2:
717 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2);
718 break;
719 case 3:
720 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2);
721 break;
722 case 4:
723 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2);
724 break;
725 case 5:
726 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2);
727 break;
728 case 6:
729 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2);
730 break;
731 case 7:
732 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2);
733 break;
734 case 14:
735 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2);
736 break;
737 default:
738 printf ("Illegal opcode");
740 break;
741 case 9:
742 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2);
743 break;
744 case 10:
745 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff);
746 break;
747 case 11:
748 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff);
749 break;
750 case 12:
751 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff);
752 break;
753 case 13:
754 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f);
755 break;
756 case 14:
757 switch (opcode&0xff) {
758 case 0x9e:
759 printf ("SKP %s ; Skip next instruction if key VX down",v1);
760 break;
761 case 0xa1:
762 printf ("SKNP %s ; Skip next instruction if key VX up",v1);
763 break;
764 default:
765 printf ("%04X ; Illegal opcode", opcode);
767 break;
768 case 15:
769 switch (opcode&0xff) {
770 case 0x07:
771 printf ("LD %s,DT ; Set VX = delaytimer",v1);
772 break;
773 case 0x0a:
774 printf ("LD %s,K ; Set VX = key, wait for keypress",v1);
775 break;
776 case 0x15:
777 printf ("LD DT,%s ; Set delaytimer = VX",v1);
778 break;
779 case 0x18:
780 printf ("LD ST,%s ; Set soundtimer = VX",v1);
781 break;
782 case 0x1e:
783 printf ("ADD I,%s ; Set I = I + VX",v1);
784 break;
785 case 0x29:
786 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1);
787 break;
788 case 0x30:
789 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1);
790 break;
791 case 0x33:
792 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1);
793 break;
794 case 0x55:
795 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1);
796 break;
797 case 0x65:
798 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1);
799 break;
800 case 0x75:
801 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1);
802 break;
803 case 0x85:
804 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1);
805 break;
806 default:
807 printf ("%04X ; Illegal opcode", opcode);
809 break;
811 printf ("\n; Registers: ");
812 for (i=0;i<16;++i) printf ("%02x ",(regs->alg[i])&0xff);
813 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
814 regs->i&0xfff,regs->sp&0xfff,regs->delay&0xff,regs->sound&0xff);
816 #endif
818 /****************************************************************************/
819 /* Execute chip8_iperiod opcodes */
820 /****************************************************************************/
821 STATIC void chip8_execute(void)
823 byte i;
824 byte key_pressed=0;
825 word opcode;
826 for (i = chip8_iperiod ; i ;--i)
828 /* Fetch the opcode */
829 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1);
830 #ifdef CHIP8_DEBUG
831 /* Check if trap address has been reached */
832 if ((chip8_regs.pc&4095)==chip8_trap)
833 chip8_trace=1;
834 /* Call the debugger if chip8_trace!=0 */
835 if (chip8_trace)
836 chip8_debug (opcode,&chip8_regs);
837 #endif
838 chip8_regs.pc+=2;
839 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */
841 /* Update timers */
842 if (chip8_regs.delay)
843 --chip8_regs.delay;
844 if (chip8_regs.sound)
845 if (--chip8_regs.sound == 0)
846 chip8_sound_off();
848 /* Update the machine status */
849 chip8_interrupt ();
851 for (i=key_pressed=0;i<16;++i) /* check if a key was first */
852 if (chip8_keys[i]) /* pressed */
853 key_pressed=i+1;
854 if (key_pressed && key_pressed!=chip8_key_pressed)
855 chip8_key_pressed=key_pressed;
856 else
857 chip8_key_pressed=0;
860 /****************************************************************************/
861 /* Reset the virtual chip8 machine */
862 /****************************************************************************/
863 STATIC void chip8_reset(void)
865 static byte chip8_sprites[0x50]=
867 0xf9,0x99,0xf2,0x62,0x27,
868 0xf1,0xf8,0xff,0x1f,0x1f,
869 0x99,0xf1,0x1f,0x8f,0x1f,
870 0xf8,0xf9,0xff,0x12,0x44,
871 0xf9,0xf9,0xff,0x9f,0x1f,
872 0xf9,0xf9,0x9e,0x9e,0x9e,
873 0xf8,0x88,0xfe,0x99,0x9e,
874 0xf8,0xf8,0xff,0x8f,0x88,
875 }; /* 4x5 pixel hexadecimal character font patterns */
876 #ifdef CHIP8_SUPER
877 static byte schip_sprites[10*10]=
879 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
880 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
881 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
882 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
883 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
884 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
885 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
886 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
887 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
888 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
889 }; /* 8x10 pixel font patterns (only 10) */
890 #endif
891 byte i;
892 for (i=0;i<16*5;++i)
894 write_mem (i<<1,chip8_sprites[i]&0xf0);
895 write_mem ((i<<1)+1,chip8_sprites[i]<<4);
897 #ifdef CHIP8_SUPER
899 for (i=0; i<100; i++)
900 write_mem (i+0x50,schip_sprites[i]);
902 memcpy(chip8_mem+0x50, schip_sprites, 100);
903 chip8_super = 0;
904 #endif
905 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
906 memset (chip8_keys,0,sizeof(chip8_keys));
907 chip8_key_pressed=0;
908 memset (chip8_display,0,sizeof(chip8_display));
909 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
910 chip8_regs.sp=0x1e0;
911 chip8_regs.pc=0x200;
912 chip8_sound_off ();
913 chip8_running=1;
914 #ifdef CHIP8_DEBUG
915 chip8_trace=0;
916 #endif
920 /****************************************************************************/
921 /* Start CHIP8 emulation */
922 /****************************************************************************/
923 STATIC void chip8 (void)
925 chip8_reset ();
926 while (chip8_running==1) chip8_execute ();
929 /****************************************************************************/
930 /** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
931 /****************************************************************************/
933 /* size of the displayed area */
934 #if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
935 #define CHIP8_LCDWIDTH 112
936 #else
937 #define CHIP8_LCDWIDTH CHIP8_WIDTH
938 #endif
940 #if (LCD_WIDTH > CHIP8_LCDWIDTH)
941 #define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
942 #else
943 #define CHIP8_X 0
944 #endif
945 #if (LCD_HEIGHT > CHIP8_HEIGHT)
946 #define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
947 #else
948 #define CHIP8_Y 0
949 #endif
951 /* variable button definitions */
952 #if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
953 #define CHIP8_OFF BUTTON_OFF
954 #define CHIP8_KEY1 BUTTON_F1
955 #define CHIP8_KEY2 BUTTON_UP
956 #define CHIP8_KEY3 BUTTON_F3
957 #define CHIP8_KEY4 BUTTON_LEFT
958 #define CHIP8_KEY5 BUTTON_PLAY
959 #define CHIP8_KEY6 BUTTON_RIGHT
960 #define CHIP8_KEY7 BUTTON_F2
961 #define CHIP8_KEY8 BUTTON_DOWN
962 #define CHIP8_KEY9 BUTTON_ON
964 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD /* only 9 out of 16 chip8 buttons */
965 #define CHIP8_OFF BUTTON_OFF
966 #define CHIP8_KEY1 BUTTON_F1
967 #define CHIP8_KEY2 BUTTON_UP
968 #define CHIP8_KEY3 BUTTON_F3
969 #define CHIP8_KEY4 BUTTON_LEFT
970 #define CHIP8_KEY5 BUTTON_SELECT
971 #define CHIP8_KEY6 BUTTON_RIGHT
972 #define CHIP8_KEY7 BUTTON_F2
973 #define CHIP8_KEY8 BUTTON_DOWN
974 #define CHIP8_KEY9 BUTTON_ON
976 #elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
977 #define CHIP8_OFF BUTTON_OFF
978 #define CHIP8_KEY2 BUTTON_UP
979 #define CHIP8_KEY4 BUTTON_LEFT
980 #define CHIP8_KEY5 BUTTON_MENU
981 #define CHIP8_KEY6 BUTTON_RIGHT
982 #define CHIP8_KEY8 BUTTON_DOWN
984 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
985 (CONFIG_KEYPAD == IRIVER_H300_PAD)
986 #define CHIP8_OFF BUTTON_OFF
987 #define CHIP8_KEY2 BUTTON_UP
988 #define CHIP8_KEY4 BUTTON_LEFT
989 #define CHIP8_KEY5 BUTTON_SELECT
990 #define CHIP8_KEY6 BUTTON_RIGHT
991 #define CHIP8_KEY8 BUTTON_DOWN
993 #define CHIP8_RC_OFF BUTTON_RC_STOP
995 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
996 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
997 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
998 #define CHIP8_OFF BUTTON_MENU
999 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
1000 #define CHIP8_KEY4 BUTTON_LEFT
1001 #define CHIP8_KEY5 BUTTON_PLAY
1002 #define CHIP8_KEY6 BUTTON_RIGHT
1003 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1005 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
1006 #define CHIP8_OFF BUTTON_POWER
1007 #define CHIP8_KEY2 BUTTON_UP
1008 #define CHIP8_KEY4 BUTTON_LEFT
1009 #define CHIP8_KEY5 BUTTON_SELECT
1010 #define CHIP8_KEY6 BUTTON_RIGHT
1011 #define CHIP8_KEY8 BUTTON_DOWN
1013 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
1014 #define CHIP8_OFF BUTTON_POWER
1015 #define CHIP8_KEY1 BUTTON_MENU
1016 #define CHIP8_KEY2 BUTTON_UP
1017 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1018 #define CHIP8_KEY4 BUTTON_LEFT
1019 #define CHIP8_KEY5 BUTTON_SELECT
1020 #define CHIP8_KEY6 BUTTON_RIGHT
1021 #define CHIP8_KEY7 BUTTON_VOL_UP
1022 #define CHIP8_KEY8 BUTTON_DOWN
1023 #define CHIP8_KEY9 BUTTON_A
1025 #elif CONFIG_KEYPAD == SANSA_E200_PAD
1026 #define CHIP8_OFF BUTTON_POWER
1027 #define CHIP8_KEY2 BUTTON_SCROLL_BACK
1028 #define CHIP8_KEY4 BUTTON_LEFT
1029 #define CHIP8_KEY5 BUTTON_SELECT
1030 #define CHIP8_KEY6 BUTTON_RIGHT
1031 #define CHIP8_KEY8 BUTTON_SCROLL_FWD
1033 #elif CONFIG_KEYPAD == SANSA_C200_PAD || CONFIG_KEYPAD == SANSA_CLIP_PAD
1034 #define CHIP8_OFF BUTTON_POWER
1035 #define CHIP8_KEY2 BUTTON_VOL_UP
1036 #define CHIP8_KEY4 BUTTON_LEFT
1037 #define CHIP8_KEY5 BUTTON_SELECT
1038 #define CHIP8_KEY6 BUTTON_RIGHT
1039 #define CHIP8_KEY8 BUTTON_VOL_DOWN
1041 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
1042 #define CHIP8_OFF BUTTON_POWER
1043 #define CHIP8_KEY2 BUTTON_SCROLL_UP
1044 #define CHIP8_KEY4 BUTTON_LEFT
1045 #define CHIP8_KEY5 BUTTON_PLAY
1046 #define CHIP8_KEY6 BUTTON_RIGHT
1047 #define CHIP8_KEY8 BUTTON_SCROLL_DOWN
1049 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
1050 #define CHIP8_OFF BUTTON_BACK
1051 #define CHIP8_KEY1 BUTTON_MENU
1052 #define CHIP8_KEY2 BUTTON_UP
1053 #define CHIP8_KEY3 BUTTON_VOL_DOWN
1054 #define CHIP8_KEY4 BUTTON_LEFT
1055 #define CHIP8_KEY5 BUTTON_SELECT
1056 #define CHIP8_KEY6 BUTTON_RIGHT
1057 #define CHIP8_KEY7 BUTTON_VOL_UP
1058 #define CHIP8_KEY8 BUTTON_DOWN
1059 #define CHIP8_KEY9 BUTTON_PLAY
1061 #elif (CONFIG_KEYPAD == MROBE100_PAD)
1062 #define CHIP8_OFF BUTTON_POWER
1063 #define CHIP8_KEY1 BUTTON_MENU
1064 #define CHIP8_KEY2 BUTTON_UP
1065 #define CHIP8_KEY3 BUTTON_PLAY
1066 #define CHIP8_KEY4 BUTTON_LEFT
1067 #define CHIP8_KEY5 BUTTON_SELECT
1068 #define CHIP8_KEY6 BUTTON_RIGHT
1069 #define CHIP8_KEY7 BUTTON_DISPLAY
1070 #define CHIP8_KEY8 BUTTON_DOWN
1072 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1073 #define CHIP8_OFF BUTTON_RC_REC
1074 #define CHIP8_KEY1 BUTTON_RC_MENU
1075 #define CHIP8_KEY2 BUTTON_RC_VOL_UP
1076 #define CHIP8_KEY3 BUTTON_RC_MODE
1077 #define CHIP8_KEY4 BUTTON_RC_REW
1078 #define CHIP8_KEY5 BUTTON_RC_PLAY
1079 #define CHIP8_KEY6 BUTTON_RC_FF
1080 #define CHIP8_KEY8 BUTTON_RC_VOL_DOWN
1082 #elif (CONFIG_KEYPAD == COWOND2_PAD)
1083 #define CHIP8_OFF BUTTON_POWER
1085 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1086 #define CHIP8_OFF BUTTON_BACK
1087 #define CHIP8_KEY1 BUTTON_MENU
1088 #define CHIP8_KEY2 BUTTON_UP
1089 #define CHIP8_KEY3 BUTTON_CUSTOM
1090 #define CHIP8_KEY4 BUTTON_LEFT
1091 #define CHIP8_KEY5 BUTTON_PLAY
1092 #define CHIP8_KEY6 BUTTON_RIGHT
1093 #define CHIP8_KEY8 BUTTON_DOWN
1095 #else
1096 #error No keymap defined!
1097 #endif
1099 #ifdef HAVE_TOUCHSCREEN
1100 #ifndef CHIP8_OFF
1101 #define CHIP8_OFF BUTTON_TOPLEFT
1102 #endif
1103 #ifndef CHIP8_KEY1
1104 #define CHIP8_KEY1 BUTTON_TOPRIGHT
1105 #endif
1106 #ifndef CHIP8_KEY2
1107 #define CHIP8_KEY2 BUTTON_TOPMIDDLE
1108 #endif
1109 #ifndef CHIP8_KEY3
1110 #define CHIP8_KEY3 BUTTON_BOTTOMLEFT
1111 #endif
1112 #ifndef CHIP8_KEY4
1113 #define CHIP8_KEY4 BUTTON_MIDLEFT
1114 #endif
1115 #ifndef CHIP8_KEY5
1116 #define CHIP8_KEY5 BUTTON_CENTER
1117 #endif
1118 #ifndef CHIP8_KEY6
1119 #define CHIP8_KEY6 BUTTON_MIDRIGHT
1120 #endif
1121 #ifndef CHIP8_KEY7
1122 #define CHIP8_KEY7 BUTTON_BOTTOMRIGHT
1123 #endif
1124 #ifndef CHIP8_KEY8
1125 #define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE
1126 #endif
1127 #endif
1129 static byte chip8_virtual_keys[16];
1130 static byte chip8_keymap[16];
1132 static unsigned long starttimer; /* Timer value at the beginning */
1133 static unsigned long cycles; /* Number of update cycles (50Hz) */
1135 #ifndef SIMULATOR
1136 static bool is_playing;
1137 #endif
1139 /* one frame of bitswapped mp3 data */
1140 static unsigned char beep[]={255,
1141 223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
1142 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
1143 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
1144 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
1145 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
1146 252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
1147 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
1148 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
1149 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
1150 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
1151 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
1153 /* callback to request more mp3 data */
1154 void callback(unsigned char** start, size_t* size)
1156 *start = beep; /* give it the same frame again */
1157 *size = sizeof(beep);
1160 /****************************************************************************/
1161 /* Turn sound on */
1162 /****************************************************************************/
1163 static void chip8_sound_on (void)
1165 #ifndef SIMULATOR
1166 if (!is_playing)
1167 rb->mp3_play_pause(true); /* kickoff audio */
1168 #endif
1171 /****************************************************************************/
1172 /* Turn sound off */
1173 /****************************************************************************/
1174 static void chip8_sound_off (void)
1176 #ifndef SIMULATOR
1177 if (!is_playing)
1178 rb->mp3_play_pause(false); /* pause audio */
1179 #endif
1182 /****************************************************************************/
1183 /* Update the display */
1184 /****************************************************************************/
1185 static void chip8_update_display(void)
1187 int x, lcd_x, y, i;
1188 byte w;
1189 byte* row;
1190 /* frame buffer in hardware fomat */
1191 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH];
1193 for (y=0;y<CHIP8_HEIGHT/8;++y)
1195 row = lcd_framebuf[y];
1196 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x)
1198 w = 0;
1199 for (i=0;i<8;i++)
1201 w = w >> 1;
1202 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0)
1204 w += 128;
1207 #if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1208 if (x%8 == 1) {
1209 row[-1] |= w; /* overlay on */
1211 else
1212 #endif
1213 *row++ = w;
1216 #if defined(SIMULATOR) || (LCD_DEPTH > 1)
1217 rb->lcd_set_drawmode(DRMODE_SOLID);
1218 rb->lcd_mono_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH,
1219 CHIP8_HEIGHT);
1220 rb->lcd_update();
1221 #else
1222 rb->lcd_blit_mono(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH,
1223 CHIP8_HEIGHT>>3, CHIP8_LCDWIDTH);
1224 #endif
1227 static void chip8_keyboard(void)
1229 int i;
1230 int button = rb->button_get(false);
1231 switch (button)
1233 #ifdef CHIP8_RC_OFF
1234 case CHIP8_RC_OFF:
1235 #endif
1236 case CHIP8_OFF: /* Abort Emulator */
1237 chip8_running = 0;
1238 break;
1240 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break;
1241 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break;
1242 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break;
1243 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break;
1244 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break;
1245 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break;
1246 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break;
1247 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break;
1248 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break;
1249 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break;
1250 #ifdef CHIP8_KEY1
1251 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break;
1252 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break;
1253 #endif
1254 #ifdef CHIP8_KEY3
1255 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break;
1256 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break;
1257 #endif
1258 #ifdef CHIP8_KEY7
1259 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break;
1260 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break;
1261 #endif
1262 #ifdef CHIP8_KEY9
1263 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break;
1264 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break;
1265 #endif
1267 default:
1268 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1269 chip8_running = 2; /* indicates stopped because of USB */
1270 break;
1272 for(i=0; i<16; i++) {
1273 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]];
1277 /****************************************************************************/
1278 /* Update keyboard and display, sync emulation with VDP clock */
1279 /****************************************************************************/
1280 static void chip8_interrupt (void)
1282 unsigned long newtimer;
1283 unsigned long timer, runtime;
1285 chip8_update_display();
1286 chip8_keyboard();
1287 cycles ++;
1288 runtime = cycles * HZ / 50;
1289 timer = starttimer + runtime;
1290 newtimer = *rb->current_tick;
1291 if (TIME_AFTER(timer, newtimer))
1293 rb->sleep(timer - newtimer);
1295 else
1297 rb->yield();
1299 starttimer = newtimer - runtime;
1302 static bool chip8_init(const char* file)
1304 int numread;
1305 int fd;
1306 int len;
1307 int i;
1309 fd = rb->open(file, O_RDONLY);
1310 if (fd==-1) {
1311 rb->lcd_puts(0, 6, "File Error.");
1312 return false;
1314 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200);
1315 if (numread==-1) {
1316 rb->lcd_puts(0, 6, "I/O Error.");
1317 return false;
1320 rb->close(fd);
1321 /* is there a c8k file (chip8 keys) ? */
1322 char c8kname[MAX_PATH];
1323 rb->strcpy(c8kname, file);
1324 for(i=0; i<16; i++) {
1325 chip8_virtual_keys[i] = 0;
1326 chip8_keymap[i] = i;
1328 len = rb->strlen(c8kname);
1329 c8kname[len-2] = '8';
1330 c8kname[len-1] = 'k';
1331 fd = rb->open(c8kname, O_RDONLY);
1332 if (fd!=-1) {
1333 rb->lcd_puts(0, 6, "File&Keymap OK.");
1334 numread = rb->read(fd, chip8_keymap, 16);
1335 rb->close(fd);
1337 else
1339 rb->lcd_puts(0, 6, "File OK.");
1341 for(i=0; i<16; i++) {
1342 if (chip8_keymap[i] >= '0'
1343 && chip8_keymap[i] <= '9')
1344 chip8_keymap[i] -= '0';
1345 else if (chip8_keymap[i] >= 'A'
1346 && chip8_keymap[i] <= 'F')
1347 chip8_keymap[i] -= 'A' - 10;
1348 else if (chip8_keymap[i] >= 'a'
1349 && chip8_keymap[i] <= 'f')
1350 chip8_keymap[i] -= 'a' - 10;
1351 else
1352 chip8_keymap[i] %= 16;
1354 return true;
1357 bool chip8_run(const char* file)
1359 int ok;
1361 rb->lcd_clear_display();
1362 rb->lcd_puts(0, 0, "SChip8 Emulator");
1363 rb->lcd_puts(0, 1, " (c) by ");
1364 rb->lcd_puts(0, 2, "Marcel de Kogel");
1365 rb->lcd_puts(0, 3, " Rockbox: ");
1366 rb->lcd_puts(0, 4, " Blueloop/Fdy ");
1367 rb->lcd_puts(0, 5, "---------------");
1368 ok = chip8_init(file);
1369 rb->lcd_update();
1370 rb->sleep(HZ*1);
1371 if (!ok)
1372 return false;
1373 rb->lcd_clear_display();
1374 #if (CHIP8_X > 0) && (CHIP8_Y > 0)
1375 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2);
1376 #endif
1377 rb->lcd_update();
1379 #ifndef SIMULATOR
1380 /* init sound */
1381 is_playing = rb->mp3_is_playing(); /* would we disturb playback? */
1382 if (!is_playing) /* no? then we can make sound */
1383 { /* prepare */
1384 rb->mp3_play_data(beep, sizeof(beep), callback);
1386 #endif
1387 starttimer = *rb->current_tick;
1389 chip8_iperiod=15;
1390 cycles = 0;
1391 chip8();
1393 if (!ok) {
1394 rb->splash(HZ, "Error");
1395 return false;
1398 #ifndef SIMULATOR
1399 if (!is_playing)
1400 { /* stop it if we used audio */
1401 rb->mp3_play_stop(); /* Stop audio playback */
1403 #endif
1405 if (chip8_running == 3) {
1406 /* unsupported instruction */
1407 rb->splash(HZ, "Error: Unsupported"
1408 #ifndef CHIP8_SUPER
1409 " CHIP-8 instruction. (maybe S-CHIP)"
1410 #else
1411 " (S)CHIP-8 instruction."
1412 #endif
1414 return false;
1417 return true;
1421 /***************** Plugin Entry Point *****************/
1423 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1425 const char* filename;
1427 rb = api; /* copy to global api pointer */
1429 if (parameter == NULL)
1431 rb->splash(HZ, "Play a .ch8 file!");
1432 return PLUGIN_ERROR;
1434 else
1436 filename = (char*) parameter;
1439 /* now go ahead and have fun! */
1440 if (chip8_run(filename))
1441 if (chip8_running == 0)
1442 return PLUGIN_OK;
1443 else
1444 return PLUGIN_USB_CONNECTED;
1445 else
1446 return PLUGIN_ERROR;
1448 #endif /* #ifdef HAVE_LCD_BITMAP */