diff options
-rw-r--r-- | apps/plugins/chip8.c | 1057 | ||||
-rw-r--r-- | docs/CREDITS | 1 |
2 files changed, 854 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 */ | 25 | static 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 | ||
55 | static struct plugin_api* rb; /* here is a global api struct pointer */ | 39 | /****************************************************************************/ |
56 | unsigned 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 | |||
58 | typedef unsigned char byte; /* sizeof(byte)==1 */ | 62 | typedef unsigned char byte; /* sizeof(byte)==1 */ |
59 | typedef unsigned short word; /* sizeof(word)>=2 */ | 63 | typedef 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 | ||
70 | static struct chip8_regs_struct chip8_regs; | 74 | EXTERN 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 | ||
79 | EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */ | ||
80 | #else | ||
81 | #define CHIP8_WIDTH 64 | ||
82 | #define CHIP8_HEIGHT 32 | ||
83 | #endif | ||
84 | |||
85 | EXTERN byte chip8_iperiod; /* number of opcodes per */ | ||
73 | /* timeslice (1/50sec.) */ | 86 | /* timeslice (1/50sec.) */ |
87 | EXTERN byte chip8_keys[16]; /* if 1, key is held down */ | ||
88 | EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */ | ||
89 | /* 0x00 otherwise */ | ||
90 | EXTERN byte chip8_mem[4096]; /* machine memory. program */ | ||
91 | /* is loaded at 0x200 */ | ||
92 | EXTERN byte chip8_running; /* if 0, emulation stops */ | ||
93 | |||
94 | EXTERN void chip8_execute (void); /* execute chip8_iperiod */ | ||
95 | /* opcodes */ | ||
96 | EXTERN void chip8_reset (void); /* reset virtual machine */ | ||
97 | EXTERN void chip8 (void); /* start chip8 emulation */ | ||
98 | |||
99 | EXTERN void chip8_sound_on (void); /* turn sound on */ | ||
100 | EXTERN void chip8_sound_off (void); /* turn sound off */ | ||
101 | EXTERN void chip8_interrupt (void); /* update keyboard, */ | ||
102 | /* display, etc. */ | ||
103 | |||
104 | #ifdef CHIP8_DEBUG | ||
105 | EXTERN byte chip8_trace; /* if 1, call debugger */ | ||
106 | /* every opcode */ | ||
107 | EXTERN word chip8_trap; /* if pc==trap, set trace */ | ||
108 | /* flag */ | ||
109 | EXTERN 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 | |||
145 | STATIC struct chip8_regs_struct chip8_regs; | ||
146 | |||
74 | static byte chip8_key_pressed; | 147 | static byte chip8_key_pressed; |
75 | static byte chip8_keys[16]; /* if 1, key is held down */ | 148 | STATIC byte chip8_keys[16]; /* if 1, key is held down */ |
76 | static byte chip8_display[64*32]; /* 0xff if pixel is set, */ | 149 | STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */ |
77 | /* 0x00 otherwise */ | 150 | /* 0x00 otherwise */ |
78 | static byte chip8_mem[4096]; /* machine memory. program */ | 151 | #ifdef CHIP8_SUPER |
152 | STATIC byte chip8_super; /* != 0 if in SCHIP display mode */ | ||
153 | #endif | ||
154 | STATIC 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 | ||
84 | static byte chip8_running; /* Flag for End-of-Emulation */ | 160 | STATIC byte chip8_iperiod; |
161 | |||
162 | STATIC 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 */ | |||
91 | typedef void (*opcode_fn) (word opcode); | 169 | typedef void (*opcode_fn) (word opcode); |
92 | typedef void (*math_fn) (byte *reg1,byte reg2); | 170 | typedef void (*math_fn) (byte *reg1,byte reg2); |
93 | 171 | ||
94 | static bool is_playing; | ||
95 | |||
96 | /* one frame of bitswapped mp3 data */ | ||
97 | static unsigned char beep[]={255, | ||
98 | 223, 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, | ||
103 | 252,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, | ||
108 | 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85}; | ||
109 | 172 | ||
110 | /* callback to request more mp3 data */ | ||
111 | void 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 | /****************************************************************************/ | ||
120 | static 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 | /****************************************************************************/ | ||
129 | static void chip8_sound_off (void) | ||
130 | { | ||
131 | if (!is_playing) | ||
132 | rb->mp3_play_pause(false); /* pause audio */ | ||
133 | } | ||
134 | 173 | ||
135 | static void op_call (word opcode) | 174 | static 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 | ||
144 | static void op_jmp (word opcode) | 187 | static void op_jmp (word opcode) |
@@ -148,14 +191,26 @@ static void op_jmp (word opcode) | |||
148 | 191 | ||
149 | static void op_key (word opcode) | 192 | static 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 | ||
207 | static void op_rand (word opcode) | 262 | static 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 | ||
212 | static void math_or (byte *reg1,byte reg2) | 267 | static 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 | ||
228 | static void math_and (byte *reg1,byte reg2) | 284 | static 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) */ | ||
334 | static 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! */ | ||
347 | static 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 | } | ||
365 | static 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 | |||
276 | static void op_system (word opcode) | 384 | static 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 | ||
292 | static void op_misc (word opcode) | 433 | static 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 | ||
636 | STATIC byte chip8_trace; | ||
637 | STATIC 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 | /****************************************************************************/ |
411 | static void chip8_update_display(void) | 643 | STATIC 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 | |||
437 | static 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 | /****************************************************************************/ |
484 | static void chip8_execute(void) | 817 | STATIC 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 | /****************************************************************************/ |
520 | static void chip8_reset(void) | 859 | STATIC 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 | /****************************************************************************/ | ||
919 | STATIC 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 | |||
976 | static byte chip8_virtual_keys[16]; | ||
977 | static byte chip8_keymap[16]; | ||
978 | |||
979 | static unsigned long starttimer; /* Timer value at the beginning */ | ||
980 | static unsigned long cycles; /* Number of update cycles (50Hz) */ | ||
981 | |||
982 | #ifndef SIMULATOR | ||
983 | static bool is_playing; | ||
984 | #endif | ||
985 | |||
986 | /* one frame of bitswapped mp3 data */ | ||
987 | static unsigned char beep[]={255, | ||
988 | 223, 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, | ||
993 | 252,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, | ||
998 | 111,181,184,144, 17,148, 21,101,166,227,100, 86, 85, 85, 85}; | ||
999 | |||
1000 | /* callback to request more mp3 data */ | ||
1001 | void 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 | /****************************************************************************/ | ||
1010 | static 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 | /****************************************************************************/ | ||
1021 | static 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 | /****************************************************************************/ | ||
1032 | static 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 | |||
1073 | static 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 | /****************************************************************************/ | ||
1123 | static 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 | ||
550 | static bool chip8_init(char* file) | 1145 | static 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 */ |
diff --git a/docs/CREDITS b/docs/CREDITS index 6903b458b1..0d1174ae86 100644 --- a/docs/CREDITS +++ b/docs/CREDITS | |||
@@ -127,3 +127,4 @@ Sander Sweers | |||
127 | Antonius Hellman | 127 | Antonius Hellman |
128 | Ryan Jackson | 128 | Ryan Jackson |
129 | Per Holmäng | 129 | Per Holmäng |
130 | Frederic Devernay | ||