summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/chip8.c1057
1 files changed, 853 insertions, 204 deletions
diff --git a/apps/plugins/chip8.c b/apps/plugins/chip8.c
index 544ee9f959..fab5eab102 100644
--- a/apps/plugins/chip8.c
+++ b/apps/plugins/chip8.c
@@ -21,40 +21,44 @@
21 21
22/* Only build for (correct) target */ 22/* Only build for (correct) target */
23#ifdef HAVE_LCD_BITMAP 23#ifdef HAVE_LCD_BITMAP
24#ifndef SIMULATOR /* not unless lcd_blit() is implemented and mp3_xx stubbed */
25 24
26/* variable button definitions */ 25static struct plugin_api* rb; /* here is a global api struct pointer */
27#if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
28#define CHIP8_KEY1 BUTTON_F1
29#define CHIP8_KEY2 BUTTON_UP
30#define CHIP8_KEY3 BUTTON_F3
31#define CHIP8_KEY4 BUTTON_LEFT
32#define CHIP8_KEY5 BUTTON_PLAY
33#define CHIP8_KEY6 BUTTON_RIGHT
34#define CHIP8_KEY7 BUTTON_F2
35#define CHIP8_KEY8 BUTTON_DOWN
36#define CHIP8_KEY9 BUTTON_ON
37
38#elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
39#define CHIP8_KEY2 BUTTON_UP
40#define CHIP8_KEY4 BUTTON_LEFT
41#define CHIP8_KEY5 BUTTON_MENU
42#define CHIP8_KEY6 BUTTON_RIGHT
43#define CHIP8_KEY8 BUTTON_DOWN
44 26
45#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ 27#define EXTERN static
46 (CONFIG_KEYPAD == IRIVER_H300_PAD) 28#define STATIC static
47#define CHIP8_KEY2 BUTTON_UP 29#define memset rb->memset
48#define CHIP8_KEY4 BUTTON_LEFT 30#define memcpy rb->memcpy
49#define CHIP8_KEY5 BUTTON_SELECT 31#define printf DEBUGF
50#define CHIP8_KEY6 BUTTON_RIGHT 32#define rand rb->rand
51#define CHIP8_KEY8 BUTTON_DOWN 33/* #define CHIP8_DEBUG */
52 34
35#if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64)
36#define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */
53#endif 37#endif
54 38
55static struct plugin_api* rb; /* here is a global api struct pointer */ 39/****************************************************************************/
56unsigned char lcd_framebuf[8][64]; /* frame buffer in hardware fomat */ 40/** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
41/** The core is completely generic and can be used outside of Rockbox, **/
42/** thus the STATIC, EXTERN etc. Please do not modify. **/
43/****************************************************************************/
44/** Vision8: CHIP8 emulator *************************************************/
45/** **/
46/** CHIP8.h **/
47/** **/
48/** This file contains the portable CHIP8 emulation engine definitions **/
49/** **/
50/** Copyright (C) Marcel de Kogel 1997 **/
51/** You are not allowed to distribute this software commercially **/
52/** Please, notify me, if you make any changes to this file **/
53/****************************************************************************/
57 54
55#ifndef __CHIP8_H
56#define __CHIP8_H
57
58#ifndef EXTERN
59#define EXTERN extern
60#endif
61
58typedef unsigned char byte; /* sizeof(byte)==1 */ 62typedef unsigned char byte; /* sizeof(byte)==1 */
59typedef unsigned short word; /* sizeof(word)>=2 */ 63typedef unsigned short word; /* sizeof(word)>=2 */
60 64
@@ -67,21 +71,95 @@ struct chip8_regs_struct
67 word sp; /* stack pointer */ 71 word sp; /* stack pointer */
68}; 72};
69 73
70static struct chip8_regs_struct chip8_regs; 74EXTERN struct chip8_regs_struct chip8_regs;
71 75
72#define chip8_iperiod 10 /* number of opcodes per */ 76#ifdef CHIP8_SUPER
77#define CHIP8_WIDTH 128
78#define CHIP8_HEIGHT 64
79EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */
80#else
81#define CHIP8_WIDTH 64
82#define CHIP8_HEIGHT 32
83#endif
84
85EXTERN byte chip8_iperiod; /* number of opcodes per */
73 /* timeslice (1/50sec.) */ 86 /* timeslice (1/50sec.) */
87EXTERN byte chip8_keys[16]; /* if 1, key is held down */
88EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */
89 /* 0x00 otherwise */
90EXTERN byte chip8_mem[4096]; /* machine memory. program */
91 /* is loaded at 0x200 */
92EXTERN byte chip8_running; /* if 0, emulation stops */
93
94EXTERN void chip8_execute (void); /* execute chip8_iperiod */
95 /* opcodes */
96EXTERN void chip8_reset (void); /* reset virtual machine */
97EXTERN void chip8 (void); /* start chip8 emulation */
98
99EXTERN void chip8_sound_on (void); /* turn sound on */
100EXTERN void chip8_sound_off (void); /* turn sound off */
101EXTERN void chip8_interrupt (void); /* update keyboard, */
102 /* display, etc. */
103
104#ifdef CHIP8_DEBUG
105EXTERN byte chip8_trace; /* if 1, call debugger */
106 /* every opcode */
107EXTERN word chip8_trap; /* if pc==trap, set trace */
108 /* flag */
109EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs);
110#endif
111
112#endif /* __CHIP8_H */
113
114/** Vision8: CHIP8 emulator *************************************************/
115/** **/
116/** CHIP8.c **/
117/** **/
118/** This file contains the portable CHIP8 emulation engine **/
119/** SCHIP emulation (C) Frederic Devernay 2005 **/
120/** **/
121/** Copyright (C) Marcel de Kogel 1997 **/
122/** You are not allowed to distribute this software commercially **/
123/** Please, notify me, if you make any changes to this file **/
124/****************************************************************************/
125
126/* you can
127 #define STATIC static
128 #define EXTERN static
129 and include this file for single-object generation
130*/
131
132#ifndef STATIC
133#include <stdlib.h> /* for memset, etc. */
134#include <string.h>
135#define STATIC
136#endif
137
138#ifdef CHIP8_DEBUG
139#include <stdio.h>
140#define DBG_(_x) ((void)(_x))
141#else
142#define DBG_(_x) ((void)0)
143#endif
144
145STATIC struct chip8_regs_struct chip8_regs;
146
74static byte chip8_key_pressed; 147static byte chip8_key_pressed;
75static byte chip8_keys[16]; /* if 1, key is held down */ 148STATIC byte chip8_keys[16]; /* if 1, key is held down */
76static byte chip8_display[64*32]; /* 0xff if pixel is set, */ 149STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */
77 /* 0x00 otherwise */ 150 /* 0x00 otherwise */
78static byte chip8_mem[4096]; /* machine memory. program */ 151#ifdef CHIP8_SUPER
152STATIC byte chip8_super; /* != 0 if in SCHIP display mode */
153#endif
154STATIC byte chip8_mem[4096]; /* machine memory. program */
79 /* is loaded at 0x200 */ 155 /* is loaded at 0x200 */
80 156
81#define read_mem(a) (chip8_mem[(a)&4095]) 157#define read_mem(a) (chip8_mem[(a)&4095])
82#define write_mem(a,v) (chip8_mem[(a)&4095]=(v)) 158#define write_mem(a,v) (chip8_mem[(a)&4095]=(v))
83 159
84static byte chip8_running; /* Flag for End-of-Emulation */ 160STATIC byte chip8_iperiod;
161
162STATIC byte chip8_running; /* Flag for End-of-Emulation */
85 163
86#define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8)) 164#define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8))
87#define get_reg_value(opcode) (*get_reg_offset(opcode)) 165#define get_reg_value(opcode) (*get_reg_offset(opcode))
@@ -91,46 +169,7 @@ static byte chip8_running; /* Flag for End-of-Emulation */
91typedef void (*opcode_fn) (word opcode); 169typedef void (*opcode_fn) (word opcode);
92typedef void (*math_fn) (byte *reg1,byte reg2); 170typedef void (*math_fn) (byte *reg1,byte reg2);
93 171
94static bool is_playing;
95
96/* one frame of bitswapped mp3 data */
97static unsigned char beep[]={255,
98223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
99 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
100 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
101 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
102 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
103252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
104 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
105 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
106 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
107 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
108111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
109 172
110/* callback to request more mp3 data */
111void callback(unsigned char** start, int* size)
112{
113 *start = beep; /* give it the same frame again */
114 *size = sizeof(beep);
115}
116
117/****************************************************************************/
118/* Turn sound on */
119/****************************************************************************/
120static void chip8_sound_on (void)
121{
122 if (!is_playing)
123 rb->mp3_play_pause(true); /* kickoff audio */
124}
125
126/****************************************************************************/
127/* Turn sound off */
128/****************************************************************************/
129static void chip8_sound_off (void)
130{
131 if (!is_playing)
132 rb->mp3_play_pause(false); /* pause audio */
133}
134 173
135static void op_call (word opcode) 174static void op_call (word opcode)
136{ 175{
@@ -139,6 +178,10 @@ static void op_call (word opcode)
139 chip8_regs.sp--; 178 chip8_regs.sp--;
140 write_mem (chip8_regs.sp,chip8_regs.pc>>8); 179 write_mem (chip8_regs.sp,chip8_regs.pc>>8);
141 chip8_regs.pc=opcode; 180 chip8_regs.pc=opcode;
181#ifdef CHIP8_DEBUG
182 if(chip8_regs.sp < 0x1c0)
183 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp);
184#endif
142} 185}
143 186
144static void op_jmp (word opcode) 187static void op_jmp (word opcode)
@@ -148,14 +191,26 @@ static void op_jmp (word opcode)
148 191
149static void op_key (word opcode) 192static void op_key (word opcode)
150{ 193{
151 byte key_value,cp_value; 194#ifdef CHIP8_DEBUG
152 if ((opcode&0xff)==0x9e) 195 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
196#endif
197 byte key, key_value,cp_value;
198 if ((opcode&0xff)==0x9e) /* skp */
153 cp_value=1; 199 cp_value=1;
154 else if ((opcode&0xff)==0xa1) 200 else if ((opcode&0xff)==0xa1) /* sknp */
155 cp_value=0; 201 cp_value=0;
156 else 202 else {
157 return; 203 DBG_(printf("unhandled key opcode 0x%x\n", opcode));
158 key_value=chip8_keys[get_reg_value(opcode)&0x0f]; 204 return;
205 }
206 key = get_reg_value(opcode)&0x0f;
207#ifdef CHIP8_DEBUG
208 if (!tested[key]) {
209 tested[key] = 1;
210 DBG_(printf("testing key %d\n", key));
211 }
212#endif
213 key_value=chip8_keys[key];
159 if (cp_value==key_value) 214 if (cp_value==key_value)
160 chip8_regs.pc+=2; 215 chip8_regs.pc+=2;
161} 216}
@@ -206,7 +261,7 @@ static void op_jmi (word opcode)
206 261
207static void op_rand (word opcode) 262static void op_rand (word opcode)
208{ 263{
209 *get_reg_offset(opcode)=rb->rand()&(opcode&0xff); 264 *get_reg_offset(opcode)=rand()&(opcode&0xff);
210} 265}
211 266
212static void math_or (byte *reg1,byte reg2) 267static void math_or (byte *reg1,byte reg2)
@@ -223,6 +278,7 @@ static void math_nop (byte *reg1,byte reg2)
223{ 278{
224 (void)reg1; 279 (void)reg1;
225 (void)reg2; 280 (void)reg2;
281 DBG_(printf("Warning: math nop!\n"));
226} 282}
227 283
228static void math_and (byte *reg1,byte reg2) 284static void math_and (byte *reg1,byte reg2)
@@ -273,12 +329,86 @@ static void math_rsb (byte *reg1,byte reg2)
273 chip8_regs.alg[15]=((byte)(tmp>>8))+1; 329 chip8_regs.alg[15]=((byte)(tmp>>8))+1;
274} 330}
275 331
332#ifdef CHIP8_SUPER
333/* SUPER: scroll down n lines (or half in CHIP8 mode) */
334static void scroll_down(word opcode)
335{
336 int n = opcode & 0xf;
337 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
338 byte *src = dst - n*CHIP8_WIDTH;
339 while(src >= chip8_display) {
340 *dst-- = *src--;
341 }
342 while(dst >= chip8_display) {
343 *dst-- = 0;
344 }
345}
346/* SUPER: scroll 4 pixels left! */
347static void scroll_left(void)
348{
349 byte *dst = chip8_display;
350 byte *src = dst;
351 byte *eol = chip8_display + CHIP8_WIDTH;
352 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT;
353 while(eol <= eoi) {
354 src+=4;
355 while(src < eol) {
356 *dst++ = *src++;
357 }
358 *dst++ = 0;
359 *dst++ = 0;
360 *dst++ = 0;
361 *dst++ = 0;
362 eol += CHIP8_WIDTH;
363 }
364}
365static void scroll_right(void)
366{
367 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1;
368 byte *src = dst;
369 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1);
370 while(bol >= chip8_display) {
371 src-=4;
372 while(src >= bol) {
373 *dst-- = *src--;
374 }
375 *dst-- = 0;
376 *dst-- = 0;
377 *dst-- = 0;
378 *dst-- = 0;
379 bol -= CHIP8_WIDTH;
380 }
381}
382#endif
383
276static void op_system (word opcode) 384static void op_system (word opcode)
277{ 385{
278 switch ((byte)opcode) 386 switch ((byte)opcode)
279 { 387 {
388#ifdef CHIP8_SUPER
389 case 0xfb:
390 scroll_right();
391 break;
392 case 0xfc:
393 scroll_left();
394 break;
395 case 0xfd:
396 DBG_(printf("SUPER: quit the emulator\n"));
397 chip8_reset();
398 break;
399 case 0xfe:
400 DBG_(printf("SUPER: set CHIP-8 graphic mode\n"));
401 memset (chip8_display,0,sizeof(chip8_display));
402 chip8_super = 0;
403 break;
404 case 0xff:
405 DBG_(printf("SUPER: set SCHIP graphic mode\n"));
406 memset (chip8_display,0,sizeof(chip8_display));
407 chip8_super = 1;
408 break;
409#endif
280 case 0xe0: 410 case 0xe0:
281 rb->memset (chip8_display,0,sizeof(chip8_display)); 411 memset (chip8_display,0,sizeof(chip8_display));
282 break; 412 break;
283 case 0xee: 413 case 0xee:
284 chip8_regs.pc=read_mem(chip8_regs.sp)<<8; 414 chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
@@ -286,39 +416,64 @@ static void op_system (word opcode)
286 chip8_regs.pc+=read_mem(chip8_regs.sp); 416 chip8_regs.pc+=read_mem(chip8_regs.sp);
287 chip8_regs.sp++; 417 chip8_regs.sp++;
288 break; 418 break;
419 default:
420#ifdef CHIP8_SUPER
421 if ((opcode & 0xF0) == 0xC0)
422 scroll_down(opcode);
423 else
424#endif
425 {
426 DBG_(printf("unhandled system opcode 0x%x\n", opcode));
427 chip8_running = 3;
428 }
429 break;
289 } 430 }
290} 431}
291 432
292static void op_misc (word opcode) 433static void op_misc (word opcode)
293{ 434{
294 byte *reg,i,j; 435 byte *reg,i,j;
436#ifdef CHIP8_DEBUG
437 static byte firstwait = 1;
438#endif
295 reg=get_reg_offset(opcode); 439 reg=get_reg_offset(opcode);
296 switch ((byte)opcode) 440 switch ((byte)opcode)
297 { 441 {
298 case 0x07: 442 case 0x07: /* gdelay */
299 *reg=chip8_regs.delay; 443 *reg=chip8_regs.delay;
300 break; 444 break;
301 case 0x0a: 445 case 0x0a: /* key */
302 if (chip8_key_pressed) 446#ifdef CHIP8_DEBUG
447 if(firstwait) {
448 printf("waiting for key press\n");
449 firstwait = 0;
450 }
451#endif
452 if (chip8_key_pressed)
303 *reg=chip8_key_pressed-1; 453 *reg=chip8_key_pressed-1;
304 else 454 else
305 chip8_regs.pc-=2; 455 chip8_regs.pc-=2;
306 break; 456 break;
307 case 0x15: 457 case 0x15: /* sdelay */
308 chip8_regs.delay=*reg; 458 chip8_regs.delay=*reg;
309 break; 459 break;
310 case 0x18: 460 case 0x18: /* ssound */
311 chip8_regs.sound=*reg; 461 chip8_regs.sound=*reg;
312 if (chip8_regs.sound) 462 if (chip8_regs.sound)
313 chip8_sound_on(); 463 chip8_sound_on();
314 break; 464 break;
315 case 0x1e: 465 case 0x1e: /* adi */
316 chip8_regs.i+=(*reg); 466 chip8_regs.i+=(*reg);
317 break; 467 break;
318 case 0x29: 468 case 0x29: /* font */
319 chip8_regs.i=((word)(*reg&0x0f))*5; 469 chip8_regs.i=((word)(*reg&0x0f))*5;
320 break; 470 break;
321 case 0x33: 471#ifdef CHIP8_SUPER
472 case 0x30: /* xfont */
473 chip8_regs.i=((word)(*reg&0x0f))*10+0x50;
474 break;
475#endif
476 case 0x33: /* bcd */
322 i=*reg; 477 i=*reg;
323 for (j=0;i>=100;i-=100) 478 for (j=0;i>=100;i-=100)
324 j++; 479 j++;
@@ -328,14 +483,25 @@ static void op_misc (word opcode)
328 write_mem (chip8_regs.i+1,j); 483 write_mem (chip8_regs.i+1,j);
329 write_mem (chip8_regs.i+2,i); 484 write_mem (chip8_regs.i+2,i);
330 break; 485 break;
331 case 0x55: 486 case 0x55: /* str */
332 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i) 487 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
333 write_mem(chip8_regs.i+i,chip8_regs.alg[i]); 488 write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
334 break; 489 break;
335 case 0x65: 490 case 0x65: /* ldr */
336 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i) 491 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i)
337 chip8_regs.alg[i]=read_mem(chip8_regs.i+i); 492 chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
338 break; 493 break;
494#ifdef CHIP8_SUPER
495 case 0x75:
496 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f));
497 break;
498 case 0x85:
499 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f));
500 break;
501#endif
502 default:
503 DBG_(printf("unhandled misc opcode 0x%x\n", opcode));
504 break;
339 } 505 }
340} 506}
341 507
@@ -344,18 +510,79 @@ static void op_sprite (word opcode)
344 byte *q; 510 byte *q;
345 byte n,x,x2,y,collision; 511 byte n,x,x2,y,collision;
346 word p; 512 word p;
347 x=get_reg_value(opcode)&63; 513 x=get_reg_value(opcode);
348 y=get_reg_value_2(opcode)&31; 514 y=get_reg_value_2(opcode);
349 p=chip8_regs.i; 515 p=chip8_regs.i;
350 q=chip8_display+y*64;
351 n=opcode&0x0f; 516 n=opcode&0x0f;
517#ifdef CHIP8_SUPER
518 if (chip8_super) {
519 /*printf("SUPER: sprite(%x)\n", opcode);*/
520 x &= 128-1;
521 y &= 64-1;
522 q=chip8_display+y*CHIP8_WIDTH;
523 if(n == 0)
524 { /* 16x16 sprite */
525 n = 16;
526 if (n+y>64)
527 n=64-y;
528 for (collision=1;n;--n,q+=CHIP8_WIDTH)
529 {
530 /* first 8 bits */
531 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
532 if (y&0x80)
533 collision&=(q[x2]^=0xff);
534 x2=(x+8)&(CHIP8_WIDTH-1);
535 /* last 8 bits */
536 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
537 if (y&0x80)
538 collision&=(q[x2]^=0xff);
539 }
540 }
541 else {
542 /* 8xn sprite */
543 if (n+y>64)
544 n=64-y;
545 for (collision=1;n;--n,q+=CHIP8_WIDTH)
546 {
547 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
548 if (y&0x80)
549 collision&=(q[x2]^=0xff);
550 }
551 }
552 }
553 else {
554 x &= 64-1;
555 y &= 32-1;
556 q=chip8_display+y*CHIP8_WIDTH*2;
557 if(n == 0)
558 n = 16;
559 if (n+y>32)
560 n=32-y;
561 for (collision=1;n;--n,q+=CHIP8_WIDTH*2)
562 {
563 for (y=read_mem(p++),x2=x*2;y;y<<=1,x2=(x2+2)&(CHIP8_WIDTH-1))
564 if (y&0x80) {
565 q[x2]^=0xff;
566 q[x2+1]^=0xff;
567 q[x2+CHIP8_WIDTH]^=0xff;
568 q[x2+CHIP8_WIDTH+1]^=0xff;
569 collision &= q[x2]|q[x2+1]|q[x2+CHIP8_WIDTH]|q[x2+CHIP8_WIDTH+1];
570 }
571 }
572 }
573#else
574 x &= 64-1;
575 y &= 32-1;
576 q=chip8_display+y*CHIP8_WIDTH;
352 if (n+y>32) 577 if (n+y>32)
353 n=32-y; 578 n=32-y;
354 for (collision=1;n;--n,q+=64) 579 for (collision=1;n;--n,q+=CHIP8_WIDTH)
355 { 580 {
356 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&63) 581 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1))
357 if (y&0x80) collision&=(q[x2]^=0xff); 582 if (y&0x80)
583 collision&=(q[x2]^=0xff);
358 } 584 }
585#endif
359 chip8_regs.alg[15]=collision^1; 586 chip8_regs.alg[15]=collision^1;
360} 587}
361 588
@@ -405,109 +632,221 @@ static opcode_fn main_opcodes[16]=
405 op_misc 632 op_misc
406}; 633};
407 634
635#ifdef CHIP8_DEBUG
636STATIC byte chip8_trace;
637STATIC word chip8_trap;
638
408/****************************************************************************/ 639/****************************************************************************/
409/* Update the display */ 640/* This routine is called every opcode when chip8_trace==1. It prints the */
641/* current register contents and the opcode being executed */
410/****************************************************************************/ 642/****************************************************************************/
411static void chip8_update_display(void) 643STATIC void chip8_debug (word opcode,struct chip8_regs_struct *regs)
412{ 644{
413 int x,y,i; 645 int i;
414 byte w; 646 byte hextable[16] = "0123456789ABCDEF";
415 byte* row; 647 byte v1[3] = "Vx\0";
416 648 byte v2[3] = "Vx\0";
417 for (y=0;y<=7;++y) /* 32 rows */ 649 v1[1] = hextable[(opcode>>8)&0x0f];
418 { 650 v2[1] = hextable[(opcode>>8)&0x0f];
419 row = lcd_framebuf[y]; 651 printf ("PC=%04X: %04X - ",regs->pc,opcode);
420 for (x=0;x<64;++x) /* 64 columns */ 652 switch (opcode>>12) {
421 { 653 case 0:
422 w = 0; 654 if ((opcode&0xff0) == 0xc0) {
423 for (i=0;i<=3;i++) 655 printf ("SCD %01X ; Scroll down n lines",opcode&0xf);
424 { 656 }
425 w = w >> 2; 657 else switch (opcode&0xfff) {
426 if (chip8_display[x+(y*4+i)*64] != 0) 658 case 0xe0:
427 { 659 printf ("CLS ; Clear screen");
428 w += 128+64; 660 break;
429 } 661 case 0xee:
430 } 662 printf ("RET ; Return from subroutine call");
431 *row++ = w; 663 break;
432 } 664 case 0xfb:
665 printf("SCR ; Scroll right");
666 break;
667 case 0xfc:
668 printf("SCL ; Scroll left");
669 break;
670 case 0xfd:
671 printf("EXIT ; Terminate the interpreter");
672 break;
673 case 0xfe:
674 printf("LOW ; Disable extended screen mode");
675 break;
676 case 0xff:
677 printf("HIGH ; Enable extended screen mode");
678 break;
679 default:
680 printf ("SYS %03X ; Unknown system call",opcode&0xff);
681 }
682 break;
683 case 1:
684 printf ("JP %03X ; Jump to address",opcode&0xfff);
685 break;
686 case 2:
687 printf ("CALL %03X ; Call subroutine",opcode&0xfff);
688 break;
689 case 3:
690 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff);
691 break;
692 case 4:
693 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff);
694 break;
695 case 5:
696 printf ("SE %s,%s ; Skip if register == register",v1,v2);
697 break;
698 case 6:
699 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff);
700 break;
701 case 7:
702 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff);
703 break;
704 case 8:
705 switch (opcode&0x0f) {
706 case 0:
707 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2);
708 break;
709 case 1:
710 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2);
711 break;
712 case 2:
713 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2);
714 break;
715 case 3:
716 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2);
717 break;
718 case 4:
719 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2);
720 break;
721 case 5:
722 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2);
723 break;
724 case 6:
725 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2);
726 break;
727 case 7:
728 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2);
729 break;
730 case 14:
731 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2);
732 break;
733 default:
734 printf ("Illegal opcode");
735 }
736 break;
737 case 9:
738 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2);
739 break;
740 case 10:
741 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff);
742 break;
743 case 11:
744 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff);
745 break;
746 case 12:
747 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff);
748 break;
749 case 13:
750 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f);
751 break;
752 case 14:
753 switch (opcode&0xff) {
754 case 0x9e:
755 printf ("SKP %s ; Skip next instruction if key VX down",v1);
756 break;
757 case 0xa1:
758 printf ("SKNP %s ; Skip next instruction if key VX up",v1);
759 break;
760 default:
761 printf ("%04X ; Illegal opcode", opcode);
762 }
763 break;
764 case 15:
765 switch (opcode&0xff) {
766 case 0x07:
767 printf ("LD %s,DT ; Set VX = delaytimer",v1);
768 break;
769 case 0x0a:
770 printf ("LD %s,K ; Set VX = key, wait for keypress",v1);
771 break;
772 case 0x15:
773 printf ("LD DT,%s ; Set delaytimer = VX",v1);
774 break;
775 case 0x18:
776 printf ("LD ST,%s ; Set soundtimer = VX",v1);
777 break;
778 case 0x1e:
779 printf ("ADD I,%s ; Set I = I + VX",v1);
780 break;
781 case 0x29:
782 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1);
783 break;
784 case 0x30:
785 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1);
786 break;
787 case 0x33:
788 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1);
789 break;
790 case 0x55:
791 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1);
792 break;
793 case 0x65:
794 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1);
795 break;
796 case 0x75:
797 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1);
798 break;
799 case 0x85:
800 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1);
801 break;
802 default:
803 printf ("%04X ; Illegal opcode", opcode);
804 }
805 break;
433 } 806 }
434 rb->lcd_blit(lcd_framebuf[0], 24, 0, 64, 8, 64); 807 printf ("\n; Registers: ");
808 for (i=0;i<16;++i) printf ("%02x ",(regs->alg[i])&0xff);
809 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n",
810 regs->i&0xfff,regs->sp&0xfff,regs->delay&0xff,regs->sound&0xff);
435} 811}
436
437static void chip8_keyboard(void)
438{
439 int button = rb->button_get(false);
440 switch (button)
441 {
442 case BUTTON_OFF: /* Abort Emulator */
443 chip8_running = 0;
444 break;
445
446 case CHIP8_KEY2: chip8_keys[2] = 1; break;
447 case CHIP8_KEY2 | BUTTON_REL: chip8_keys[2] = 0; break;
448 case CHIP8_KEY4: chip8_keys[4] = 1; break;
449 case CHIP8_KEY4 | BUTTON_REL: chip8_keys[4] = 0; break;
450 case CHIP8_KEY6: chip8_keys[6] = 1; break;
451 case CHIP8_KEY6 | BUTTON_REL: chip8_keys[6] = 0; break;
452 case CHIP8_KEY8: chip8_keys[8] = 1; break;
453 case CHIP8_KEY8 | BUTTON_REL: chip8_keys[8] = 0; break;
454 case CHIP8_KEY5: chip8_keys[5] = 1; break;
455 case CHIP8_KEY5 | BUTTON_REL: chip8_keys[5] = 0; break;
456#ifdef CHIP8_KEY1
457 case CHIP8_KEY1: chip8_keys[1] = 1; break;
458 case CHIP8_KEY1 | BUTTON_REL: chip8_keys[1] = 0; break;
459#endif
460#ifdef CHIP8_KEY3
461 case CHIP8_KEY3: chip8_keys[3] = 1; break;
462 case CHIP8_KEY3 | BUTTON_REL: chip8_keys[3] = 0; break;
463#endif
464#ifdef CHIP8_KEY7
465 case CHIP8_KEY7: chip8_keys[7] = 1; break;
466 case CHIP8_KEY7 | BUTTON_REL: chip8_keys[7] = 0; break;
467#endif 812#endif
468#ifdef CHIP8_KEY9
469 case CHIP8_KEY9: chip8_keys[9] = 1; break;
470 case CHIP8_KEY9 | BUTTON_REL: chip8_keys[9] = 0; break;
471#endif
472
473 default:
474 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
475 chip8_running = 2; /* indicates stopped because of USB */
476 break;
477 }
478}
479
480 813
481/****************************************************************************/ 814/****************************************************************************/
482/* Execute chip8_iperiod opcodes */ 815/* Execute chip8_iperiod opcodes */
483/****************************************************************************/ 816/****************************************************************************/
484static void chip8_execute(void) 817STATIC void chip8_execute(void)
485{ 818{
486 byte i; 819 byte i;
487 byte key_pressed=0; 820 byte key_pressed=0;
488 word opcode; 821 word opcode;
489 for (i = chip8_iperiod ; i ;--i) 822 for (i = chip8_iperiod ; i ;--i)
490 { /* Fetch the opcode */ 823 {
824 /* Fetch the opcode */
491 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1); 825 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1);
492 826#ifdef CHIP8_DEBUG
827 /* Check if trap address has been reached */
828 if ((chip8_regs.pc&4095)==chip8_trap)
829 chip8_trace=1;
830 /* Call the debugger if chip8_trace!=0 */
831 if (chip8_trace)
832 chip8_debug (opcode,&chip8_regs);
833#endif
493 chip8_regs.pc+=2; 834 chip8_regs.pc+=2;
494 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */ 835 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */
495 } 836 }
496 /* Update timers */ 837 /* Update timers */
497 if (chip8_regs.delay) 838 if (chip8_regs.delay)
498 --chip8_regs.delay; 839 --chip8_regs.delay;
499
500 if (chip8_regs.sound) 840 if (chip8_regs.sound)
501 if (--chip8_regs.sound == 0) /* Update the machine status */ 841 if (--chip8_regs.sound == 0)
502 chip8_sound_off(); 842 chip8_sound_off();
503 843
504 chip8_update_display(); 844 /* Update the machine status */
505 chip8_keyboard(); 845 chip8_interrupt ();
506 rb->yield(); /* we should regulate the speed by timer query, sleep/yield */
507 846
508 for (i=key_pressed=0;i<16;++i) /* check if a key was first */ 847 for (i=key_pressed=0;i<16;++i) /* check if a key was first */
509 if (chip8_keys[i]) 848 if (chip8_keys[i]) /* pressed */
510 key_pressed=i+1; /* pressed */ 849 key_pressed=i+1;
511 if (key_pressed && key_pressed!=chip8_key_pressed) 850 if (key_pressed && key_pressed!=chip8_key_pressed)
512 chip8_key_pressed=key_pressed; 851 chip8_key_pressed=key_pressed;
513 else 852 else
@@ -517,9 +856,9 @@ static void chip8_execute(void)
517/****************************************************************************/ 856/****************************************************************************/
518/* Reset the virtual chip8 machine */ 857/* Reset the virtual chip8 machine */
519/****************************************************************************/ 858/****************************************************************************/
520static void chip8_reset(void) 859STATIC void chip8_reset(void)
521{ 860{
522 static byte chip8_sprites[16*5]= 861 static byte chip8_sprites[0x50]=
523 { 862 {
524 0xf9,0x99,0xf2,0x62,0x27, 863 0xf9,0x99,0xf2,0x62,0x27,
525 0xf1,0xf8,0xff,0x1f,0x1f, 864 0xf1,0xf8,0xff,0x1f,0x1f,
@@ -529,35 +868,330 @@ static void chip8_reset(void)
529 0xf9,0xf9,0x9e,0x9e,0x9e, 868 0xf9,0xf9,0x9e,0x9e,0x9e,
530 0xf8,0x88,0xfe,0x99,0x9e, 869 0xf8,0x88,0xfe,0x99,0x9e,
531 0xf8,0xf8,0xff,0x8f,0x88, 870 0xf8,0xf8,0xff,0x8f,0x88,
532 }; 871 }; /* 4x5 pixel hexadecimal character font patterns */
872#ifdef CHIP8_SUPER
873 static byte schip_sprites[10*10]=
874 {
875 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */
876 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */
877 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */
878 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */
879 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */
880 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */
881 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */
882 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */
883 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */
884 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */
885 }; /* 8x10 pixel font patterns (only 10) */
886#endif
533 byte i; 887 byte i;
534 for (i=0;i<16*5;++i) 888 for (i=0;i<16*5;++i)
535 { 889 {
536 write_mem (i<<1,chip8_sprites[i]&0xf0); 890 write_mem (i<<1,chip8_sprites[i]&0xf0);
537 write_mem ((i<<1)+1,chip8_sprites[i]<<4); 891 write_mem ((i<<1)+1,chip8_sprites[i]<<4);
538 } 892 }
539 rb->memset (chip8_regs.alg,0,sizeof(chip8_regs.alg)); 893#ifdef CHIP8_SUPER
540 rb->memset (chip8_keys,0,sizeof(chip8_keys)); 894 /*
895 for (i=0; i<100; i++)
896 write_mem (i+0x50,schip_sprites[i]);
897 */
898 memcpy(chip8_mem+0x50, schip_sprites, 100);
899 chip8_super = 0;
900#endif
901 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
902 memset (chip8_keys,0,sizeof(chip8_keys));
541 chip8_key_pressed=0; 903 chip8_key_pressed=0;
542 rb->memset (chip8_display,0,sizeof(chip8_display)); 904 memset (chip8_display,0,sizeof(chip8_display));
543 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0; 905 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
544 chip8_regs.sp=0x1e0; 906 chip8_regs.sp=0x1e0;
545 chip8_regs.pc=0x200; 907 chip8_regs.pc=0x200;
546 chip8_sound_off (); 908 chip8_sound_off ();
547 chip8_running=1; 909 chip8_running=1;
910#ifdef CHIP8_DEBUG
911 chip8_trace=0;
912#endif
913}
914
915
916/****************************************************************************/
917/* Start CHIP8 emulation */
918/****************************************************************************/
919STATIC void chip8 (void)
920{
921 chip8_reset ();
922 while (chip8_running==1) chip8_execute ();
923}
924
925/****************************************************************************/
926/** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/
927/****************************************************************************/
928
929/* size of the displayed area */
930#if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128)
931#define CHIP8_LCDWIDTH 112
932#else
933#define CHIP8_LCDWIDTH CHIP8_WIDTH
934#endif
935
936#if (LCD_WIDTH > CHIP8_LCDWIDTH)
937#define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2)
938#else
939#define CHIP8_X 0
940#endif
941#if (LCD_HEIGHT > CHIP8_HEIGHT)
942#define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3)
943#else
944#define CHIP8_Y 0
945#endif
946
947/* variable button definitions */
948#if CONFIG_KEYPAD == RECORDER_PAD /* only 9 out of 16 chip8 buttons */
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
958
959#elif CONFIG_KEYPAD == ONDIO_PAD /* even more limited */
960#define CHIP8_KEY2 BUTTON_UP
961#define CHIP8_KEY4 BUTTON_LEFT
962#define CHIP8_KEY5 BUTTON_MENU
963#define CHIP8_KEY6 BUTTON_RIGHT
964#define CHIP8_KEY8 BUTTON_DOWN
965
966#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
967 (CONFIG_KEYPAD == IRIVER_H300_PAD)
968#define CHIP8_KEY2 BUTTON_UP
969#define CHIP8_KEY4 BUTTON_LEFT
970#define CHIP8_KEY5 BUTTON_SELECT
971#define CHIP8_KEY6 BUTTON_RIGHT
972#define CHIP8_KEY8 BUTTON_DOWN
973
974#endif
975
976static byte chip8_virtual_keys[16];
977static byte chip8_keymap[16];
978
979static unsigned long starttimer; /* Timer value at the beginning */
980static unsigned long cycles; /* Number of update cycles (50Hz) */
981
982#ifndef SIMULATOR
983static bool is_playing;
984#endif
985
986/* one frame of bitswapped mp3 data */
987static unsigned char beep[]={255,
988223, 28, 35, 0,192,210, 35,226, 72,188,242, 1,128,166, 16, 68,146,252,151, 19,
989 10,180,245,127, 96,184, 3,184, 30, 0,118, 59,128,121,102, 6,212, 0, 97, 6,
990 42, 65, 28,134,192,145, 57, 38,136, 73, 29, 38,132, 15, 21, 70, 91,185, 99,198,
991 15,192, 83, 6, 33,129, 20, 6, 97, 33, 4, 6,245,128, 92, 6, 24, 0, 86, 6,
992 56,129, 44, 24,224, 25, 13, 48, 50, 82,180, 11,251,106,249, 59, 24, 82,175,223,
993252,119, 76,134,120,236,149,250,247,115,254,145,173,174,168,180,255,107,195, 89,
994 24, 25, 48,131,192, 61, 48, 64, 10,176, 49, 64, 1,152, 50, 32, 8,140, 48, 16,
995 5,129, 51,196,187, 41,177, 23,138, 70, 50, 8, 10,242, 48,192, 3,248,226, 0,
996 20,100, 18, 96, 41, 96, 78,102, 7,201,122, 76,119, 20,137, 37,177, 15,132,224,
997 20, 17,191, 67,147,187,116,211, 41,169, 63,172,182,186,217,155,111,140,104,254,
998111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85};
999
1000/* callback to request more mp3 data */
1001void callback(unsigned char** start, int* size)
1002{
1003 *start = beep; /* give it the same frame again */
1004 *size = sizeof(beep);
1005}
1006
1007/****************************************************************************/
1008/* Turn sound on */
1009/****************************************************************************/
1010static void chip8_sound_on (void)
1011{
1012#ifndef SIMULATOR
1013 if (!is_playing)
1014 rb->mp3_play_pause(true); /* kickoff audio */
1015#endif
1016}
1017
1018/****************************************************************************/
1019/* Turn sound off */
1020/****************************************************************************/
1021static void chip8_sound_off (void)
1022{
1023#ifndef SIMULATOR
1024 if (!is_playing)
1025 rb->mp3_play_pause(false); /* pause audio */
1026#endif
1027}
1028
1029/****************************************************************************/
1030/* Update the display */
1031/****************************************************************************/
1032static void chip8_update_display(void)
1033{
1034 int x, lcd_x, y, i;
1035 byte w;
1036 byte* row;
1037 /* frame buffer in hardware fomat */
1038 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH];
1039
1040 for (y=0;y<CHIP8_HEIGHT/8;++y)
1041 {
1042 row = lcd_framebuf[y];
1043 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x)
1044 {
1045 w = 0;
1046 for (i=0;i<8;i++)
1047 {
1048 w = w >> 1;
1049 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0)
1050 {
1051 w += 128;
1052 }
1053 }
1054#if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */
1055 if (x%8 == 1) {
1056 row[-1] |= w; /* overlay on */
1057 }
1058 else
1059#endif
1060 *row++ = w;
1061 }
1062 }
1063#ifdef SIMULATOR
1064 rb->lcd_set_drawmode(DRMODE_SOLID);
1065 rb->lcd_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH, CHIP8_HEIGHT);
1066 rb->lcd_update();
1067#else
1068 rb->lcd_blit(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH, CHIP8_HEIGHT>>3
1069 , CHIP8_LCDWIDTH);
1070#endif
1071}
1072
1073static void chip8_keyboard(void)
1074{
1075 int i;
1076 int button = rb->button_get(false);
1077 switch (button)
1078 {
1079 case BUTTON_OFF: /* Abort Emulator */
1080 chip8_running = 0;
1081 break;
1082
1083 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break;
1084 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break;
1085 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break;
1086 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break;
1087 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break;
1088 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break;
1089 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break;
1090 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break;
1091 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break;
1092 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break;
1093#ifdef CHIP8_KEY1
1094 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break;
1095 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break;
1096#endif
1097#ifdef CHIP8_KEY3
1098 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break;
1099 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break;
1100#endif
1101#ifdef CHIP8_KEY7
1102 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break;
1103 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break;
1104#endif
1105#ifdef CHIP8_KEY9
1106 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break;
1107 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break;
1108#endif
1109
1110 default:
1111 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1112 chip8_running = 2; /* indicates stopped because of USB */
1113 break;
1114 }
1115 for(i=0; i<16; i++) {
1116 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]];
1117 }
1118}
1119
1120/****************************************************************************/
1121/* Update keyboard and display, sync emulation with VDP clock */
1122/****************************************************************************/
1123static void chip8_interrupt (void)
1124{
1125 unsigned long newtimer;
1126 unsigned long timer, runtime;
1127
1128 chip8_update_display();
1129 chip8_keyboard();
1130 cycles ++;
1131 runtime = cycles * HZ / 50;
1132 timer = starttimer + runtime;
1133 newtimer = *rb->current_tick;
1134 if (TIME_AFTER(timer, newtimer))
1135 {
1136 rb->sleep(timer - newtimer);
1137 }
1138 else
1139 {
1140 rb->yield();
1141 }
1142 starttimer = newtimer - runtime;
548} 1143}
549 1144
550static bool chip8_init(char* file) 1145static bool chip8_init(char* file)
551{ 1146{
552 int numread; 1147 int numread;
553 int fd; 1148 int fd;
1149 int len;
1150 int i;
554 1151
555 fd = rb->open(file, O_RDONLY); 1152 fd = rb->open(file, O_RDONLY);
556 if (fd==-1) return false; 1153 if (fd==-1) {
1154 rb->lcd_puts(0, 6, "File Error.");
1155 return false;
1156 }
557 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200); 1157 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200);
558 if (numread==-1) return false; 1158 if (numread==-1) {
1159 rb->lcd_puts(0, 6, "I/O Error.");
1160 return false;
1161 }
559 1162
560 rb->close(fd); 1163 rb->close(fd);
1164 /* is there a c8k file (chip8 keys) ? */
1165 for(i=0; i<16; i++) {
1166 chip8_virtual_keys[i] = 0;
1167 chip8_keymap[i] = i;
1168 }
1169 len = rb->strlen(file);
1170 file[len-2] = '8';
1171 file[len-1] = 'k';
1172 fd = rb->open(file, O_RDONLY);
1173 if (fd!=-1) {
1174 rb->lcd_puts(0, 6, "File&Keymap OK.");
1175 numread = rb->read(fd, chip8_keymap, 16);
1176 rb->close(fd);
1177 }
1178 else
1179 {
1180 rb->lcd_puts(0, 6, "File OK.");
1181 }
1182 for(i=0; i<16; i++) {
1183 if (chip8_keymap[i] >= '0'
1184 && chip8_keymap[i] <= '9')
1185 chip8_keymap[i] -= '0';
1186 else if (chip8_keymap[i] >= 'A'
1187 && chip8_keymap[i] <= 'F')
1188 chip8_keymap[i] -= 'A' - 10;
1189 else if (chip8_keymap[i] >= 'a'
1190 && chip8_keymap[i] <= 'f')
1191 chip8_keymap[i] -= 'a' - 10;
1192 else
1193 chip8_keymap[i] %= 16;
1194 }
561 return true; 1195 return true;
562} 1196}
563 1197
@@ -565,41 +1199,60 @@ bool chip8_run(char* file)
565{ 1199{
566 int ok; 1200 int ok;
567 1201
568 ok = chip8_init(file);
569 if (!ok) {
570 rb->lcd_clear_display();
571 rb->lcd_puts(0, 0, "Error");
572 rb->lcd_update();
573 rb->sleep(HZ);
574 return false;
575 }
576 rb->lcd_clear_display(); 1202 rb->lcd_clear_display();
577 rb->lcd_puts(0, 0, "Chip8 Emulator "); 1203 rb->lcd_puts(0, 0, "SChip8 Emulator");
578 rb->lcd_puts(0, 1, " (c) by "); 1204 rb->lcd_puts(0, 1, " (c) by ");
579 rb->lcd_puts(0, 2, "Marcel de Kogel"); 1205 rb->lcd_puts(0, 2, "Marcel de Kogel");
580 rb->lcd_puts(0, 3, " Archos: "); 1206 rb->lcd_puts(0, 3, " Rockbox: ");
581 rb->lcd_puts(0, 4, " Blueloop "); 1207 rb->lcd_puts(0, 4, " Blueloop/Fdy ");
582 rb->lcd_puts(0, 5, "---------------"); 1208 rb->lcd_puts(0, 5, "---------------");
583 rb->lcd_puts(0, 6, "File OK..."); 1209 ok = chip8_init(file);
584 rb->lcd_update(); 1210 rb->lcd_update();
585 rb->sleep(HZ*1); 1211 rb->sleep(HZ*1);
1212 if (!ok)
1213 return false;
586 rb->lcd_clear_display(); 1214 rb->lcd_clear_display();
587 rb->lcd_drawrect(23,0,66,64); 1215#if (CHIP8_X > 0) && (CHIP8_Y > 0)
1216 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2);
1217#endif
588 rb->lcd_update(); 1218 rb->lcd_update();
589 1219
1220#ifndef SIMULATOR
590 /* init sound */ 1221 /* init sound */
591 is_playing = rb->mp3_is_playing(); /* would we disturb playback? */ 1222 is_playing = rb->mp3_is_playing(); /* would we disturb playback? */
592 if (!is_playing) /* no? then we can make sound */ 1223 if (!is_playing) /* no? then we can make sound */
593 { /* prepare */ 1224 { /* prepare */
594 rb->mp3_play_data(beep, sizeof(beep), callback); 1225 rb->mp3_play_data(beep, sizeof(beep), callback);
595 } 1226 }
1227#endif
1228 starttimer = *rb->current_tick;
596 1229
597 chip8_reset(); 1230 chip8_iperiod=15;
598 while (chip8_running == 1) chip8_execute(); 1231 cycles = 0;
1232 chip8();
599 1233
1234 if (!ok) {
1235 rb->splash(HZ, true, "Error");
1236 return false;
1237 }
1238
1239#ifndef SIMULATOR
600 if (!is_playing) 1240 if (!is_playing)
601 { /* stop it if we used audio */ 1241 { /* stop it if we used audio */
602 rb->mp3_play_stop(); // stop audio ISR 1242 rb->mp3_play_stop(); /* Stop audio playback */
1243 }
1244#endif
1245
1246 if (chip8_running == 3) {
1247 /* unsupported instruction */
1248 rb->splash(HZ, true, "Error: Unsupported"
1249#ifndef CHIP8_SUPER
1250 " CHIP-8 instruction. (maybe S-CHIP)"
1251#else
1252 " (S)CHIP-8 instruction."
1253#endif
1254 );
1255 return false;
603 } 1256 }
604 1257
605 return true; 1258 return true;
@@ -620,9 +1273,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
620 1273
621 if (parameter == NULL) 1274 if (parameter == NULL)
622 { 1275 {
623 rb->lcd_puts(0, 0, "Play .ch8 file!"); 1276 rb->splash(HZ, true, "Play a .ch8 file!");
624 rb->lcd_update();
625 rb->sleep(HZ);
626 return PLUGIN_ERROR; 1277 return PLUGIN_ERROR;
627 } 1278 }
628 else 1279 else
@@ -639,6 +1290,4 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
639 else 1290 else
640 return PLUGIN_ERROR; 1291 return PLUGIN_ERROR;
641} 1292}
642
643#endif /* #ifndef SIMULATOR */
644#endif /* #ifdef HAVE_LCD_BITMAP */ 1293#endif /* #ifdef HAVE_LCD_BITMAP */