A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1619 lines 48 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Orginal from Vision-8 Emulator / Copyright (C) 1997-1999 Marcel de Kogel 11 * Modified for Archos by Blueloop (a.wenger@gmx.de) 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 2 16 * of the License, or (at your option) any later version. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ****************************************************************************/ 22#include "plugin.h" 23 24 25 26#define EXTERN static 27#define STATIC static 28#define memset rb->memset 29#define memcpy rb->memcpy 30#define printf DEBUGF 31#define rand rb->rand 32/* #define CHIP8_DEBUG */ 33 34#if (LCD_WIDTH >= 112) && (LCD_HEIGHT >= 64) 35#define CHIP8_SUPER /* SCHIP even on the archos recorder (112x64) */ 36#endif 37 38/****************************************************************************/ 39/** (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/ 40/** The core is completely generic and can be used outside of Rockbox, **/ 41/** thus the STATIC, EXTERN etc. Please do not modify. **/ 42/****************************************************************************/ 43/** Vision8: CHIP8 emulator *************************************************/ 44/** **/ 45/** CHIP8.h **/ 46/** **/ 47/** This file contains the portable CHIP8 emulation engine definitions **/ 48/** **/ 49/** Copyright (C) Marcel de Kogel 1997 **/ 50/** You are not allowed to distribute this software commercially **/ 51/** Please, notify me, if you make any changes to this file **/ 52/****************************************************************************/ 53 54#ifndef __CHIP8_H 55#define __CHIP8_H 56 57#ifndef EXTERN 58#define EXTERN extern 59#endif 60 61typedef unsigned char byte; /* sizeof(byte)==1 */ 62typedef unsigned short word; /* sizeof(word)>=2 */ 63 64struct chip8_regs_struct 65{ 66 byte alg[16]; /* 16 general registers */ 67 byte delay,sound; /* delay and sound timer */ 68 word i; /* index register */ 69 word pc; /* program counter */ 70 word sp; /* stack pointer */ 71}; 72 73EXTERN struct chip8_regs_struct chip8_regs; 74 75#ifdef CHIP8_SUPER 76#define CHIP8_WIDTH 128 77#define CHIP8_HEIGHT 64 78EXTERN byte chip8_super; /* != 0 if in SCHIP display mode */ 79#else 80#define CHIP8_WIDTH 64 81#define CHIP8_HEIGHT 32 82#endif 83 84EXTERN byte chip8_iperiod; /* number of opcodes per */ 85 /* timeslice (1/50sec.) */ 86EXTERN byte chip8_keys[16]; /* if 1, key is held down */ 87EXTERN byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT];/* 0xff if pixel is set, */ 88 /* 0x00 otherwise */ 89EXTERN byte chip8_mem[4096]; /* machine memory. program */ 90 /* is loaded at 0x200 */ 91EXTERN byte chip8_running; /* if 0, emulation stops */ 92 93EXTERN void chip8_execute (void); /* execute chip8_iperiod */ 94 /* opcodes */ 95EXTERN void chip8_reset (void); /* reset virtual machine */ 96EXTERN void chip8 (void); /* start chip8 emulation */ 97 98EXTERN void chip8_sound_on (void); /* turn sound on */ 99EXTERN void chip8_sound_off (void); /* turn sound off */ 100EXTERN void chip8_interrupt (void); /* update keyboard, */ 101 /* display, etc. */ 102 103#ifdef CHIP8_DEBUG 104EXTERN byte chip8_trace; /* if 1, call debugger */ 105 /* every opcode */ 106EXTERN word chip8_trap; /* if pc==trap, set trace */ 107 /* flag */ 108EXTERN void chip8_debug (word opcode,struct chip8_regs_struct *regs); 109#endif 110 111#endif /* __CHIP8_H */ 112 113/** Vision8: CHIP8 emulator *************************************************/ 114/** **/ 115/** CHIP8.c **/ 116/** **/ 117/** This file contains the portable CHIP8 emulation engine **/ 118/** SCHIP emulation (C) Frederic Devernay 2005 **/ 119/** **/ 120/** Copyright (C) Marcel de Kogel 1997 **/ 121/** You are not allowed to distribute this software commercially **/ 122/** Please, notify me, if you make any changes to this file **/ 123/****************************************************************************/ 124 125/* you can 126 #define STATIC static 127 #define EXTERN static 128 and include this file for single-object generation 129*/ 130 131#ifndef STATIC 132#include <stdlib.h> /* for memset, etc. */ 133#include <string.h> 134#define STATIC 135#endif 136 137#ifdef CHIP8_DEBUG 138#include <stdio.h> 139#define DBG_(_x) ((void)(_x)) 140#else 141#define DBG_(_x) ((void)0) 142#endif 143 144STATIC struct chip8_regs_struct chip8_regs; 145 146static byte chip8_key_pressed; 147STATIC byte chip8_keys[16]; /* if 1, key is held down */ 148STATIC byte chip8_display[CHIP8_WIDTH*CHIP8_HEIGHT]; /* 0xff if pixel is set, */ 149 /* 0x00 otherwise */ 150#ifdef CHIP8_SUPER 151STATIC byte chip8_super; /* != 0 if in SCHIP display mode */ 152#endif 153STATIC byte chip8_mem[4096]; /* machine memory. program */ 154 /* is loaded at 0x200 */ 155 156#define read_mem(a) (chip8_mem[(a)&4095]) 157#define write_mem(a,v) (chip8_mem[(a)&4095]=(v)) 158 159STATIC byte chip8_iperiod; 160 161STATIC byte chip8_running; /* Flag for End-of-Emulation */ 162 163#define get_reg_offset(opcode) (chip8_regs.alg+(opcode>>8)) 164#define get_reg_value(opcode) (*get_reg_offset(opcode)) 165#define get_reg_offset_2(opcode) (chip8_regs.alg+((opcode>>4)&0x0f)) 166#define get_reg_value_2(opcode) (*get_reg_offset_2(opcode)) 167 168typedef void (*opcode_fn) (word opcode); 169typedef void (*math_fn) (byte *reg1,byte reg2); 170 171 172 173static void op_call (word opcode) 174{ 175 chip8_regs.sp--; 176 write_mem (chip8_regs.sp,chip8_regs.pc&0xff); 177 chip8_regs.sp--; 178 write_mem (chip8_regs.sp,chip8_regs.pc>>8); 179 chip8_regs.pc=opcode; 180#ifdef CHIP8_DEBUG 181 if(chip8_regs.sp < 0x1c0) 182 printf("warning: more than 16 subroutine calls, sp=%x\n", chip8_regs.sp); 183#endif 184} 185 186static void op_jmp (word opcode) 187{ 188 chip8_regs.pc=opcode; 189} 190 191static void op_key (word opcode) 192{ 193#ifdef CHIP8_DEBUG 194 static byte tested[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 195#endif 196 byte key, key_value,cp_value; 197 if ((opcode&0xff)==0x9e) /* skp */ 198 cp_value=1; 199 else if ((opcode&0xff)==0xa1) /* sknp */ 200 cp_value=0; 201 else { 202 DBG_(printf("unhandled key opcode 0x%x\n", opcode)); 203 return; 204 } 205 key = get_reg_value(opcode)&0x0f; 206#ifdef CHIP8_DEBUG 207 if (!tested[key]) { 208 tested[key] = 1; 209 DBG_(printf("testing key %d\n", key)); 210 } 211#endif 212 key_value=chip8_keys[key]; 213 if (cp_value==key_value) 214 chip8_regs.pc+=2; 215} 216 217static void op_skeq_const (word opcode) 218{ 219 if (get_reg_value(opcode)==(opcode&0xff)) 220 chip8_regs.pc+=2; 221} 222 223static void op_skne_const (word opcode) 224{ 225 if (get_reg_value(opcode)!=(opcode&0xff)) 226 chip8_regs.pc+=2; 227} 228 229static void op_skeq_reg (word opcode) 230{ 231 if (get_reg_value(opcode)==get_reg_value_2(opcode)) 232 chip8_regs.pc+=2; 233} 234 235static void op_skne_reg (word opcode) 236{ 237 if (get_reg_value(opcode)!=get_reg_value_2(opcode)) 238 chip8_regs.pc+=2; 239} 240 241static void op_mov_const (word opcode) 242{ 243 *get_reg_offset(opcode)=opcode&0xff; 244} 245 246static void op_add_const (word opcode) 247{ 248 *get_reg_offset(opcode)+=opcode&0xff; 249} 250 251static void op_mvi (word opcode) 252{ 253 chip8_regs.i=opcode; 254} 255 256static void op_jmi (word opcode) 257{ 258 chip8_regs.pc=opcode+chip8_regs.alg[0]; 259} 260 261static void op_rand (word opcode) 262{ 263 *get_reg_offset(opcode)=rand()&(opcode&0xff); 264} 265 266static void math_or (byte *reg1,byte reg2) 267{ 268 *reg1|=reg2; 269} 270 271static void math_mov (byte *reg1,byte reg2) 272{ 273 *reg1=reg2; 274} 275 276static void math_nop (byte *reg1,byte reg2) 277{ 278 (void)reg1; 279 (void)reg2; 280 DBG_(printf("Warning: math nop!\n")); 281} 282 283static void math_and (byte *reg1,byte reg2) 284{ 285 *reg1&=reg2; 286} 287 288static void math_xor (byte *reg1,byte reg2) 289{ 290 *reg1^=reg2; 291} 292 293static void math_add (byte *reg1,byte reg2) 294{ 295 word tmp; 296 tmp=*reg1+reg2; 297 *reg1=(byte)tmp; 298 chip8_regs.alg[15]=tmp>>8; 299} 300 301static void math_sub (byte *reg1,byte reg2) 302{ 303 word tmp; 304 tmp=*reg1-reg2; 305 *reg1=(byte)tmp; 306 chip8_regs.alg[15]=((byte)(tmp>>8))+1; 307} 308 309static void math_shr (byte *reg1,byte reg2) 310{ 311 (void)reg2; 312 chip8_regs.alg[15]=*reg1&1; 313 *reg1>>=1; 314} 315 316static void math_shl (byte *reg1,byte reg2) 317{ 318 (void)reg2; 319 chip8_regs.alg[15]=*reg1>>7; 320 *reg1<<=1; 321} 322 323static void math_rsb (byte *reg1,byte reg2) 324{ 325 word tmp; 326 tmp=reg2-*reg1; 327 *reg1=(byte)tmp; 328 chip8_regs.alg[15]=((byte)(tmp>>8))+1; 329} 330 331#ifdef CHIP8_SUPER 332/* SUPER: scroll down n lines (or half in CHIP8 mode) */ 333static void scroll_down(word opcode) 334{ 335 int n = opcode & 0xf; 336 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1; 337 byte *src = dst - n*CHIP8_WIDTH; 338 while(src >= chip8_display) { 339 *dst-- = *src--; 340 } 341 while(dst >= chip8_display) { 342 *dst-- = 0; 343 } 344} 345/* SUPER: scroll 4 pixels left! */ 346static void scroll_left(void) 347{ 348 byte *dst = chip8_display; 349 byte *src = dst; 350 byte *eol = chip8_display + CHIP8_WIDTH; 351 byte *eoi = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT; 352 while(eol <= eoi) { 353 src+=4; 354 while(src < eol) { 355 *dst++ = *src++; 356 } 357 *dst++ = 0; 358 *dst++ = 0; 359 *dst++ = 0; 360 *dst++ = 0; 361 eol += CHIP8_WIDTH; 362 } 363} 364static void scroll_right(void) 365{ 366 byte *dst = chip8_display + CHIP8_WIDTH*CHIP8_HEIGHT -1; 367 byte *src = dst; 368 byte *bol = chip8_display + CHIP8_WIDTH*(CHIP8_HEIGHT-1); 369 while(bol >= chip8_display) { 370 src-=4; 371 while(src >= bol) { 372 *dst-- = *src--; 373 } 374 *dst-- = 0; 375 *dst-- = 0; 376 *dst-- = 0; 377 *dst-- = 0; 378 bol -= CHIP8_WIDTH; 379 } 380} 381#endif 382 383static void op_system (word opcode) 384{ 385 switch ((byte)opcode) 386 { 387#ifdef CHIP8_SUPER 388 case 0xfb: 389 scroll_right(); 390 break; 391 case 0xfc: 392 scroll_left(); 393 break; 394 case 0xfd: 395 DBG_(printf("SUPER: quit the emulator\n")); 396 chip8_reset(); 397 break; 398 case 0xfe: 399 DBG_(printf("SUPER: set CHIP-8 graphic mode\n")); 400 memset (chip8_display,0,sizeof(chip8_display)); 401 chip8_super = 0; 402 break; 403 case 0xff: 404 DBG_(printf("SUPER: set SCHIP graphic mode\n")); 405 memset (chip8_display,0,sizeof(chip8_display)); 406 chip8_super = 1; 407 break; 408#endif 409 case 0xe0: 410 memset (chip8_display,0,sizeof(chip8_display)); 411 break; 412 case 0xee: 413 chip8_regs.pc=read_mem(chip8_regs.sp)<<8; 414 chip8_regs.sp++; 415 chip8_regs.pc+=read_mem(chip8_regs.sp); 416 chip8_regs.sp++; 417 break; 418 default: 419#ifdef CHIP8_SUPER 420 if ((opcode & 0xF0) == 0xC0) 421 scroll_down(opcode); 422 else 423#endif 424 { 425 DBG_(printf("unhandled system opcode 0x%x\n", opcode)); 426 chip8_running = 3; 427 } 428 break; 429 } 430} 431 432static void op_misc (word opcode) 433{ 434 byte *reg,i,j; 435#ifdef CHIP8_DEBUG 436 static byte firstwait = 1; 437#endif 438 reg=get_reg_offset(opcode); 439 switch ((byte)opcode) 440 { 441 case 0x07: /* gdelay */ 442 *reg=chip8_regs.delay; 443 break; 444 case 0x0a: /* key */ 445#ifdef CHIP8_DEBUG 446 if(firstwait) { 447 printf("waiting for key press\n"); 448 firstwait = 0; 449 } 450#endif 451 if (chip8_key_pressed) 452 *reg=chip8_key_pressed-1; 453 else 454 chip8_regs.pc-=2; 455 break; 456 case 0x15: /* sdelay */ 457 chip8_regs.delay=*reg; 458 break; 459 case 0x18: /* ssound */ 460 chip8_regs.sound=*reg; 461 if (chip8_regs.sound) 462 chip8_sound_on(); 463 break; 464 case 0x1e: /* adi */ 465 chip8_regs.i+=(*reg); 466 break; 467 case 0x29: /* font */ 468 chip8_regs.i=((word)(*reg&0x0f))*5; 469 break; 470#ifdef CHIP8_SUPER 471 case 0x30: /* xfont */ 472 chip8_regs.i=((word)(*reg&0x0f))*10+0x50; 473 break; 474#endif 475 case 0x33: /* bcd */ 476 i=*reg; 477 for (j=0;i>=100;i-=100) 478 j++; 479 write_mem (chip8_regs.i,j); 480 for (j=0;i>=10;i-=10) 481 j++; 482 write_mem (chip8_regs.i+1,j); 483 write_mem (chip8_regs.i+2,i); 484 break; 485 case 0x55: /* str */ 486 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i) 487 write_mem(chip8_regs.i+i,chip8_regs.alg[i]); 488 break; 489 case 0x65: /* ldr */ 490 for (i=0,j=(opcode>>8)&0x0f; i<=j; ++i) 491 chip8_regs.alg[i]=read_mem(chip8_regs.i+i); 492 break; 493#ifdef CHIP8_SUPER 494 case 0x75: 495 DBG_(printf("SUPER: save V0..V%x (X<8) in the HP48 flags\n", (opcode>>8)&0x0f)); 496 break; 497 case 0x85: 498 DBG_(printf("SUPER: load V0..V%x (X<8) from the HP48 flags\n", (opcode>>8)&0x0f)); 499 break; 500#endif 501 default: 502 DBG_(printf("unhandled misc opcode 0x%x\n", opcode)); 503 break; 504 } 505} 506 507static void op_sprite (word opcode) 508{ 509 byte *q; 510 byte n,x,x2,y,collision; 511 word p; 512 x=get_reg_value(opcode); 513 y=get_reg_value_2(opcode); 514 p=chip8_regs.i; 515 n=opcode&0x0f; 516#ifdef CHIP8_SUPER 517 if (chip8_super) { 518 /*printf("SUPER: sprite(%x)\n", opcode);*/ 519 x &= 128-1; 520 y &= 64-1; 521 q=chip8_display+y*CHIP8_WIDTH; 522 if(n == 0) 523 { /* 16x16 sprite */ 524 n = 16; 525 if (n+y>64) 526 n=64-y; 527 for (collision=1;n;--n,q+=CHIP8_WIDTH) 528 { 529 /* first 8 bits */ 530 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1)) 531 if (y&0x80) 532 collision&=(q[x2]^=0xff); 533 x2=(x+8)&(CHIP8_WIDTH-1); 534 /* last 8 bits */ 535 for (y=read_mem(p++);y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1)) 536 if (y&0x80) 537 collision&=(q[x2]^=0xff); 538 } 539 } 540 else { 541 /* 8xn sprite */ 542 if (n+y>64) 543 n=64-y; 544 for (collision=1;n;--n,q+=CHIP8_WIDTH) 545 { 546 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1)) 547 if (y&0x80) 548 collision&=(q[x2]^=0xff); 549 } 550 } 551 } 552 else { 553 x &= 64-1; 554 y &= 32-1; 555 q=chip8_display+y*CHIP8_WIDTH*2; 556 if(n == 0) 557 n = 16; 558 if (n+y>32) 559 n=32-y; 560 for (collision=1;n;--n,q+=CHIP8_WIDTH*2) 561 { 562 for (y=read_mem(p++),x2=x*2;y;y<<=1,x2=(x2+2)&(CHIP8_WIDTH-1)) 563 if (y&0x80) { 564 q[x2]^=0xff; 565 q[x2+1]^=0xff; 566 q[x2+CHIP8_WIDTH]^=0xff; 567 q[x2+CHIP8_WIDTH+1]^=0xff; 568 collision &= q[x2]|q[x2+1]|q[x2+CHIP8_WIDTH]|q[x2+CHIP8_WIDTH+1]; 569 } 570 } 571 } 572#else 573 x &= 64-1; 574 y &= 32-1; 575 q=chip8_display+y*CHIP8_WIDTH; 576 if (n+y>32) 577 n=32-y; 578 for (collision=1;n;--n,q+=CHIP8_WIDTH) 579 { 580 for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&(CHIP8_WIDTH-1)) 581 if (y&0x80) 582 collision&=(q[x2]^=0xff); 583 } 584#endif 585 chip8_regs.alg[15]=collision^1; 586} 587 588static const math_fn math_opcodes[16]= 589{ 590 math_mov, 591 math_or, 592 math_and, 593 math_xor, 594 math_add, 595 math_sub, 596 math_shr, 597 math_rsb, 598 math_nop, 599 math_nop, 600 math_nop, 601 math_nop, 602 math_nop, 603 math_nop, 604 math_shl, 605 math_nop 606}; 607 608static void op_math (word opcode) 609{ 610 (*(math_opcodes[opcode&0x0f])) 611 (get_reg_offset(opcode),get_reg_value_2(opcode)); 612} 613 614static const opcode_fn main_opcodes[16]= 615{ 616 op_system, 617 op_jmp, 618 op_call, 619 op_skeq_const, 620 op_skne_const, 621 op_skeq_reg, 622 op_mov_const, 623 op_add_const, 624 op_math, 625 op_skne_reg, 626 op_mvi, 627 op_jmi, 628 op_rand, 629 op_sprite, 630 op_key, 631 op_misc 632}; 633 634#ifdef CHIP8_DEBUG 635STATIC byte chip8_trace; 636STATIC word chip8_trap; 637 638/****************************************************************************/ 639/* This routine is called every opcode when chip8_trace==1. It prints the */ 640/* current register contents and the opcode being executed */ 641/****************************************************************************/ 642STATIC void chip8_debug (word opcode,struct chip8_regs_struct *regs) 643{ 644 int i; 645 static const byte hextable[16] = "0123456789ABCDEF"; 646 byte v1[3] = "Vx\0"; 647 byte v2[3] = "Vx\0"; 648 v1[1] = hextable[(opcode>>8)&0x0f]; 649 v2[1] = hextable[(opcode>>8)&0x0f]; 650 printf ("PC=%04X: %04X - ",regs->pc,opcode); 651 switch (opcode>>12) { 652 case 0: 653 if ((opcode&0xff0) == 0xc0) { 654 printf ("SCD %01X ; Scroll down n lines",opcode&0xf); 655 } 656 else switch (opcode&0xfff) { 657 case 0xe0: 658 printf ("CLS ; Clear screen"); 659 break; 660 case 0xee: 661 printf ("RET ; Return from subroutine call"); 662 break; 663 case 0xfb: 664 printf("SCR ; Scroll right"); 665 break; 666 case 0xfc: 667 printf("SCL ; Scroll left"); 668 break; 669 case 0xfd: 670 printf("EXIT ; Terminate the interpreter"); 671 break; 672 case 0xfe: 673 printf("LOW ; Disable extended screen mode"); 674 break; 675 case 0xff: 676 printf("HIGH ; Enable extended screen mode"); 677 break; 678 default: 679 printf ("SYS %03X ; Unknown system call",opcode&0xff); 680 } 681 break; 682 case 1: 683 printf ("JP %03X ; Jump to address",opcode&0xfff); 684 break; 685 case 2: 686 printf ("CALL %03X ; Call subroutine",opcode&0xfff); 687 break; 688 case 3: 689 printf ("SE %s,%02X ; Skip if register == constant",v1,opcode&0xff); 690 break; 691 case 4: 692 printf ("SNE %s,%02X ; Skip if register <> constant",v1,opcode&0xff); 693 break; 694 case 5: 695 printf ("SE %s,%s ; Skip if register == register",v1,v2); 696 break; 697 case 6: 698 printf ("LD %s,%02X ; Set VX = Byte",v1,opcode&0xff); 699 break; 700 case 7: 701 printf ("ADD %s,%02X ; Set VX = VX + Byte",v1,opcode&0xff); 702 break; 703 case 8: 704 switch (opcode&0x0f) { 705 case 0: 706 printf ("LD %s,%s ; Set VX = VY, VF updates",v1,v2); 707 break; 708 case 1: 709 printf ("OR %s,%s ; Set VX = VX | VY, VF updates",v1,v2); 710 break; 711 case 2: 712 printf ("AND %s,%s ; Set VX = VX & VY, VF updates",v1,v2); 713 break; 714 case 3: 715 printf ("XOR %s,%s ; Set VX = VX ^ VY, VF updates",v1,v2); 716 break; 717 case 4: 718 printf ("ADD %s,%s ; Set VX = VX + VY, VF = carry",v1,v2); 719 break; 720 case 5: 721 printf ("SUB %s,%s ; Set VX = VX - VY, VF = !borrow",v1,v2); 722 break; 723 case 6: 724 printf ("SHR %s,%s ; Set VX = VX >> 1, VF = carry",v1,v2); 725 break; 726 case 7: 727 printf ("SUBN %s,%s ; Set VX = VY - VX, VF = !borrow",v1,v2); 728 break; 729 case 14: 730 printf ("SHL %s,%s ; Set VX = VX << 1, VF = carry",v1,v2); 731 break; 732 default: 733 printf ("Illegal opcode"); 734 } 735 break; 736 case 9: 737 printf ("SNE %s,%s ; Skip next instruction iv VX!=VY",v1,v2); 738 break; 739 case 10: 740 printf ("LD I,%03X ; Set I = Addr",opcode&0xfff); 741 break; 742 case 11: 743 printf ("JP V0,%03X ; Jump to Addr + V0",opcode&0xfff); 744 break; 745 case 12: 746 printf ("RND %s,%02X ; Set VX = random & Byte",v1,opcode&0xff); 747 break; 748 case 13: 749 printf ("DRW %s,%s,%X ; Draw n byte sprite stored at [i] at VX,VY. Set VF = collision",v1,v2,opcode&0x0f); 750 break; 751 case 14: 752 switch (opcode&0xff) { 753 case 0x9e: 754 printf ("SKP %s ; Skip next instruction if key VX down",v1); 755 break; 756 case 0xa1: 757 printf ("SKNP %s ; Skip next instruction if key VX up",v1); 758 break; 759 default: 760 printf ("%04X ; Illegal opcode", opcode); 761 } 762 break; 763 case 15: 764 switch (opcode&0xff) { 765 case 0x07: 766 printf ("LD %s,DT ; Set VX = delaytimer",v1); 767 break; 768 case 0x0a: 769 printf ("LD %s,K ; Set VX = key, wait for keypress",v1); 770 break; 771 case 0x15: 772 printf ("LD DT,%s ; Set delaytimer = VX",v1); 773 break; 774 case 0x18: 775 printf ("LD ST,%s ; Set soundtimer = VX",v1); 776 break; 777 case 0x1e: 778 printf ("ADD I,%s ; Set I = I + VX",v1); 779 break; 780 case 0x29: 781 printf ("LD LF,%s ; Point I to 5 byte numeric sprite for value in VX",v1); 782 break; 783 case 0x30: 784 printf ("LD HF,%s ; Point I to 10 byte numeric sprite for value in VX",v1); 785 break; 786 case 0x33: 787 printf ("LD B,%s ; Store BCD of VX in [I], [I+1], [I+2]",v1); 788 break; 789 case 0x55: 790 printf ("LD [I],%s ; Store V0..VX in [I]..[I+X]",v1); 791 break; 792 case 0x65: 793 printf ("LD %s,[I] ; Read V0..VX from [I]..[I+X]",v1); 794 break; 795 case 0x75: 796 printf ("LD R,%s ; Store V0..VX in RPL user flags (X<=7)",v1); 797 break; 798 case 0x85: 799 printf ("LD %s,R ; Read V0..VX from RPL user flags (X<=7)",v1); 800 break; 801 default: 802 printf ("%04X ; Illegal opcode", opcode); 803 } 804 break; 805 } 806 printf ("\n; Registers: "); 807 for (i=0;i<16;++i) printf ("%02x ",(regs->alg[i])&0xff); 808 printf ("\n; Index: %03x Stack:%03x Delay:%02x Sound:%02x\n", 809 regs->i&0xfff,regs->sp&0xfff,regs->delay&0xff,regs->sound&0xff); 810} 811#endif 812 813/****************************************************************************/ 814/* Execute chip8_iperiod opcodes */ 815/****************************************************************************/ 816STATIC void chip8_execute(void) 817{ 818 byte i; 819 byte key_pressed=0; 820 word opcode; 821 for (i = chip8_iperiod ; i ;--i) 822 { 823 /* Fetch the opcode */ 824 opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1); 825#ifdef CHIP8_DEBUG 826 /* Check if trap address has been reached */ 827 if ((chip8_regs.pc&4095)==chip8_trap) 828 chip8_trace=1; 829 /* Call the debugger if chip8_trace!=0 */ 830 if (chip8_trace) 831 chip8_debug (opcode,&chip8_regs); 832#endif 833 chip8_regs.pc+=2; 834 (*(main_opcodes[opcode>>12]))(opcode&0x0fff); /* Emulate this opcode */ 835 } 836 /* Update timers */ 837 if (chip8_regs.delay) 838 --chip8_regs.delay; 839 if (chip8_regs.sound) 840 if (--chip8_regs.sound == 0) 841 chip8_sound_off(); 842 843 /* Update the machine status */ 844 chip8_interrupt (); 845 846 for (i=key_pressed=0;i<16;++i) /* check if a key was first */ 847 if (chip8_keys[i]) /* pressed */ 848 key_pressed=i+1; 849 if (key_pressed && key_pressed!=chip8_key_pressed) 850 chip8_key_pressed=key_pressed; 851 else 852 chip8_key_pressed=0; 853} 854 855/****************************************************************************/ 856/* Reset the virtual chip8 machine */ 857/****************************************************************************/ 858STATIC void chip8_reset(void) 859{ 860 static const byte chip8_sprites[0x50]= 861 { 862 0xf9,0x99,0xf2,0x62,0x27, 863 0xf1,0xf8,0xff,0x1f,0x1f, 864 0x99,0xf1,0x1f,0x8f,0x1f, 865 0xf8,0xf9,0xff,0x12,0x44, 866 0xf9,0xf9,0xff,0x9f,0x1f, 867 0xf9,0xf9,0x9e,0x9e,0x9e, 868 0xf8,0x88,0xfe,0x99,0x9e, 869 0xf8,0xf8,0xff,0x8f,0x88, 870 }; /* 4x5 pixel hexadecimal character font patterns */ 871#ifdef CHIP8_SUPER 872 static const byte schip_sprites[10*10]= 873 { 874 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C, /* 0 */ 875 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, /* 1 */ 876 0x3E, 0x7F, 0xC3, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, /* 2 */ 877 0x3C, 0x7E, 0xC3, 0x03, 0x0E, 0x0E, 0x03, 0xC3, 0x7E, 0x3C, /* 3 */ 878 0x06, 0x0E, 0x1E, 0x36, 0x66, 0xC6, 0xFF, 0xFF, 0x06, 0x06, /* 4 */ 879 0xFF, 0xFF, 0xC0, 0xC0, 0xFC, 0xFE, 0x03, 0xC3, 0x7E, 0x3C, /* 5 */ 880 0x3E, 0x7C, 0xC0, 0xC0, 0xFC, 0xFE, 0xC3, 0xC3, 0x7E, 0x3C, /* 6 */ 881 0xFF, 0xFF, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, /* 7 */ 882 0x3C, 0x7E, 0xC3, 0xC3, 0x7E, 0x7E, 0xC3, 0xC3, 0x7E, 0x3C, /* 8 */ 883 0x3C, 0x7E, 0xC3, 0xC3, 0x7F, 0x3F, 0x03, 0x03, 0x3E, 0x7C, /* 9 */ 884 }; /* 8x10 pixel font patterns (only 10) */ 885#endif 886 byte i; 887 for (i=0;i<16*5;++i) 888 { 889 write_mem (i<<1,chip8_sprites[i]&0xf0); 890 write_mem ((i<<1)+1,chip8_sprites[i]<<4); 891 } 892#ifdef CHIP8_SUPER 893 /* 894 for (i=0; i<100; i++) 895 write_mem (i+0x50,schip_sprites[i]); 896 */ 897 memcpy(chip8_mem+0x50, schip_sprites, 100); 898 chip8_super = 0; 899#endif 900 memset (chip8_regs.alg,0,sizeof(chip8_regs.alg)); 901 memset (chip8_keys,0,sizeof(chip8_keys)); 902 chip8_key_pressed=0; 903 memset (chip8_display,0,sizeof(chip8_display)); 904 chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0; 905 chip8_regs.sp=0x1e0; 906 chip8_regs.pc=0x200; 907 chip8_sound_off (); 908 chip8_running=1; 909#ifdef CHIP8_DEBUG 910 chip8_trace=0; 911#endif 912} 913 914 915/****************************************************************************/ 916/* Start CHIP8 emulation */ 917/****************************************************************************/ 918STATIC void chip8 (void) 919{ 920 chip8_reset (); 921 while (chip8_running==1) chip8_execute (); 922} 923 924/****************************************************************************/ 925/** END OF (S)CHIP-8 core emulation, from Vision-8 + mods by Fdy **/ 926/****************************************************************************/ 927 928/* size of the displayed area */ 929#if (CHIP8_WIDTH == 128) && (LCD_WIDTH < 128) 930#define CHIP8_LCDWIDTH 112 931#else 932#define CHIP8_LCDWIDTH CHIP8_WIDTH 933#endif 934 935#if (LCD_WIDTH > CHIP8_LCDWIDTH) 936#define CHIP8_X ((LCD_WIDTH - CHIP8_LCDWIDTH)/2) 937#else 938#define CHIP8_X 0 939#endif 940#if (LCD_HEIGHT > CHIP8_HEIGHT) 941#define CHIP8_Y (((LCD_HEIGHT - CHIP8_HEIGHT)>>4)<<3) 942#else 943#define CHIP8_Y 0 944#endif 945 946/* variable button definitions */ 947#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ 948 (CONFIG_KEYPAD == IRIVER_H300_PAD) 949#define CHIP8_OFF BUTTON_OFF 950#define CHIP8_KEY2 BUTTON_UP 951#define CHIP8_KEY4 BUTTON_LEFT 952#define CHIP8_KEY5 BUTTON_SELECT 953#define CHIP8_KEY6 BUTTON_RIGHT 954#define CHIP8_KEY8 BUTTON_DOWN 955 956#define CHIP8_RC_OFF BUTTON_RC_STOP 957 958#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ 959 (CONFIG_KEYPAD == IPOD_3G_PAD) || \ 960 (CONFIG_KEYPAD == IPOD_1G2G_PAD) 961#define CHIP8_OFF BUTTON_MENU 962#define CHIP8_KEY2 BUTTON_SCROLL_BACK 963#define CHIP8_KEY4 BUTTON_LEFT 964#define CHIP8_KEY5 BUTTON_PLAY 965#define CHIP8_KEY6 BUTTON_RIGHT 966#define CHIP8_KEY8 BUTTON_SCROLL_FWD 967 968#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) 969#define CHIP8_OFF BUTTON_POWER 970#define CHIP8_KEY2 BUTTON_UP 971#define CHIP8_KEY4 BUTTON_LEFT 972#define CHIP8_KEY5 BUTTON_SELECT 973#define CHIP8_KEY6 BUTTON_RIGHT 974#define CHIP8_KEY8 BUTTON_DOWN 975 976#elif (CONFIG_KEYPAD == GIGABEAT_PAD) 977#define CHIP8_OFF BUTTON_POWER 978#define CHIP8_KEY1 BUTTON_MENU 979#define CHIP8_KEY2 BUTTON_UP 980#define CHIP8_KEY3 BUTTON_VOL_DOWN 981#define CHIP8_KEY4 BUTTON_LEFT 982#define CHIP8_KEY5 BUTTON_SELECT 983#define CHIP8_KEY6 BUTTON_RIGHT 984#define CHIP8_KEY7 BUTTON_VOL_UP 985#define CHIP8_KEY8 BUTTON_DOWN 986#define CHIP8_KEY9 BUTTON_A 987 988#elif CONFIG_KEYPAD == SANSA_E200_PAD || \ 989 CONFIG_KEYPAD == SANSA_FUZE_PAD 990#define CHIP8_OFF BUTTON_POWER 991#define CHIP8_KEY2 BUTTON_SCROLL_BACK 992#define CHIP8_KEY4 BUTTON_LEFT 993#define CHIP8_KEY5 BUTTON_SELECT 994#define CHIP8_KEY6 BUTTON_RIGHT 995#define CHIP8_KEY8 BUTTON_SCROLL_FWD 996 997#elif CONFIG_KEYPAD == SANSA_C200_PAD || \ 998CONFIG_KEYPAD == SANSA_CLIP_PAD || \ 999CONFIG_KEYPAD == SANSA_M200_PAD 1000#define CHIP8_OFF BUTTON_POWER 1001#define CHIP8_KEY2 BUTTON_UP 1002#define CHIP8_KEY4 BUTTON_LEFT 1003#define CHIP8_KEY5 BUTTON_SELECT 1004#define CHIP8_KEY6 BUTTON_RIGHT 1005#define CHIP8_KEY8 BUTTON_DOWN 1006 1007#elif (CONFIG_KEYPAD == IRIVER_H10_PAD) 1008#define CHIP8_OFF BUTTON_POWER 1009#define CHIP8_KEY2 BUTTON_SCROLL_UP 1010#define CHIP8_KEY4 BUTTON_LEFT 1011#define CHIP8_KEY5 BUTTON_PLAY 1012#define CHIP8_KEY6 BUTTON_RIGHT 1013#define CHIP8_KEY8 BUTTON_SCROLL_DOWN 1014 1015#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) 1016#define CHIP8_OFF BUTTON_BACK 1017#define CHIP8_KEY1 BUTTON_MENU 1018#define CHIP8_KEY2 BUTTON_UP 1019#define CHIP8_KEY3 BUTTON_VOL_DOWN 1020#define CHIP8_KEY4 BUTTON_LEFT 1021#define CHIP8_KEY5 BUTTON_SELECT 1022#define CHIP8_KEY6 BUTTON_RIGHT 1023#define CHIP8_KEY7 BUTTON_VOL_UP 1024#define CHIP8_KEY8 BUTTON_DOWN 1025#define CHIP8_KEY9 BUTTON_PLAY 1026 1027#elif (CONFIG_KEYPAD == MROBE100_PAD) 1028#define CHIP8_OFF BUTTON_POWER 1029#define CHIP8_KEY1 BUTTON_MENU 1030#define CHIP8_KEY2 BUTTON_UP 1031#define CHIP8_KEY3 BUTTON_PLAY 1032#define CHIP8_KEY4 BUTTON_LEFT 1033#define CHIP8_KEY5 BUTTON_SELECT 1034#define CHIP8_KEY6 BUTTON_RIGHT 1035#define CHIP8_KEY7 BUTTON_DISPLAY 1036#define CHIP8_KEY8 BUTTON_DOWN 1037 1038#elif CONFIG_KEYPAD == IAUDIO_M3_PAD 1039#define CHIP8_OFF BUTTON_RC_REC 1040#define CHIP8_KEY1 BUTTON_RC_MENU 1041#define CHIP8_KEY2 BUTTON_RC_VOL_UP 1042#define CHIP8_KEY3 BUTTON_RC_MODE 1043#define CHIP8_KEY4 BUTTON_RC_REW 1044#define CHIP8_KEY5 BUTTON_RC_PLAY 1045#define CHIP8_KEY6 BUTTON_RC_FF 1046#define CHIP8_KEY8 BUTTON_RC_VOL_DOWN 1047 1048#elif (CONFIG_KEYPAD == COWON_D2_PAD) 1049#define CHIP8_OFF BUTTON_POWER 1050 1051#elif CONFIG_KEYPAD == CREATIVEZVM_PAD 1052#define CHIP8_OFF BUTTON_BACK 1053#define CHIP8_KEY1 BUTTON_MENU 1054#define CHIP8_KEY2 BUTTON_UP 1055#define CHIP8_KEY3 BUTTON_CUSTOM 1056#define CHIP8_KEY4 BUTTON_LEFT 1057#define CHIP8_KEY5 BUTTON_PLAY 1058#define CHIP8_KEY6 BUTTON_RIGHT 1059#define CHIP8_KEY8 BUTTON_DOWN 1060 1061#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD 1062#define CHIP8_OFF BUTTON_POWER 1063#define CHIP8_KEY1 BUTTON_VOL_UP 1064#define CHIP8_KEY2 BUTTON_UP 1065#define CHIP8_KEY3 BUTTON_VOL_DOWN 1066#define CHIP8_KEY4 BUTTON_BACK 1067#define CHIP8_KEY5 BUTTON_PLAY 1068#define CHIP8_KEY6 BUTTON_MENU 1069#define CHIP8_KEY8 BUTTON_DOWN 1070 1071#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD 1072#define CHIP8_OFF BUTTON_POWER 1073#define CHIP8_KEY1 BUTTON_MENU 1074#define CHIP8_KEY2 BUTTON_UP 1075#define CHIP8_KEY3 BUTTON_VOL_DOWN 1076#define CHIP8_KEY4 BUTTON_LEFT 1077#define CHIP8_KEY5 BUTTON_SELECT 1078#define CHIP8_KEY6 BUTTON_RIGHT 1079#define CHIP8_KEY7 BUTTON_VOL_UP 1080#define CHIP8_KEY8 BUTTON_DOWN 1081#define CHIP8_KEY9 BUTTON_VIEW 1082 1083#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 1084#define CHIP8_OFF BUTTON_POWER 1085#define CHIP8_KEY1 BUTTON_PREV 1086#define CHIP8_KEY2 BUTTON_PLAY 1087#define CHIP8_KEY3 BUTTON_NEXT 1088#define CHIP8_KEY4 BUTTON_LEFT 1089#define CHIP8_KEY5 BUTTON_UP 1090#define CHIP8_KEY6 BUTTON_RIGHT 1091#define CHIP8_KEY7 BUTTON_MENU 1092#define CHIP8_KEY8 BUTTON_DOWN 1093#define CHIP8_KEY9 BUTTON_VIEW 1094#define CHIP8_KEY0 BUTTON_VOL_DOWN 1095 1096#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 1097#define CHIP8_OFF BUTTON_POWER 1098#define CHIP8_KEY1 BUTTON_LEFT 1099#define CHIP8_KEY2 BUTTON_UP 1100#define CHIP8_KEY3 BUTTON_RIGHT 1101#define CHIP8_KEY4 BUTTON_PREV 1102#define CHIP8_KEY5 BUTTON_PLAY 1103#define CHIP8_KEY6 BUTTON_NEXT 1104#define CHIP8_KEY7 BUTTON_MENU 1105#define CHIP8_KEY8 BUTTON_DOWN 1106#define CHIP8_KEY9 BUTTON_VOL_UP 1107#define CHIP8_KEY0 BUTTON_VOL_DOWN 1108 1109#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \ 1110CONFIG_KEYPAD == ONDAVX777_PAD || \ 1111CONFIG_KEYPAD == MROBE500_PAD 1112#define CHIP8_OFF BUTTON_POWER 1113 1114#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ 1115 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) 1116#define CHIP8_OFF BUTTON_REW 1117#define CHIP8_KEY0 BUTTON_FFWD 1118#define CHIP8_KEY2 BUTTON_UP 1119#define CHIP8_KEY4 BUTTON_LEFT 1120#define CHIP8_KEY5 BUTTON_PLAY 1121#define CHIP8_KEY6 BUTTON_RIGHT 1122#define CHIP8_KEY8 BUTTON_DOWN 1123 1124#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD 1125#define CHIP8_OFF BUTTON_REC 1126#define CHIP8_KEY2 BUTTON_UP 1127#define CHIP8_KEY4 BUTTON_PREV 1128#define CHIP8_KEY5 BUTTON_OK 1129#define CHIP8_KEY6 BUTTON_NEXT 1130#define CHIP8_KEY8 BUTTON_DOWN 1131 1132#elif CONFIG_KEYPAD == MPIO_HD200_PAD 1133 1134#define CHIP8_OFF (BUTTON_REC|BUTTON_PLAY) 1135#define CHIP8_KEY1 BUTTON_REW 1136#define CHIP8_KEY2 BUTTON_FF 1137#define CHIP8_KEY3 BUTTON_FUNC 1138#define CHIP8_KEY4 BUTTON_REC 1139#define CHIP8_KEY5 BUTTON_PLAY 1140#define CHIP8_KEY6 BUTTON_VOL_DOWN 1141#define CHIP8_KEY8 BUTTON_VOL_UP 1142 1143#elif CONFIG_KEYPAD == MPIO_HD300_PAD 1144 1145#define CHIP8_OFF (BUTTON_MENU|BUTTON_REPEAT) 1146#define CHIP8_KEY1 BUTTON_REW 1147#define CHIP8_KEY2 BUTTON_FF 1148#define CHIP8_KEY3 BUTTON_MENU 1149#define CHIP8_KEY4 BUTTON_ENTER 1150#define CHIP8_KEY5 BUTTON_REC 1151#define CHIP8_KEY6 BUTTON_PLAY 1152#define CHIP8_KEY7 BUTTON_UP 1153#define CHIP8_KEY8 BUTTON_DOWN 1154 1155#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD 1156 1157#define CHIP8_OFF BUTTON_POWER 1158#define CHIP8_KEY0 BUTTON_VOL_DOWN 1159#define CHIP8_KEY1 BUTTON_BACK 1160#define CHIP8_KEY2 BUTTON_UP 1161#define CHIP8_KEY3 BUTTON_PLAYPAUSE 1162#define CHIP8_KEY4 BUTTON_LEFT 1163#define CHIP8_KEY5 BUTTON_SELECT 1164#define CHIP8_KEY6 BUTTON_RIGHT 1165#define CHIP8_KEY7 BUTTON_BOTTOMLEFT 1166#define CHIP8_KEY8 BUTTON_DOWN 1167#define CHIP8_KEY9 BUTTON_BOTTOMRIGHT 1168#define CHIP8_KEYA BUTTON_VOL_UP 1169 1170#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD 1171 1172#define CHIP8_OFF BUTTON_POWER 1173#define CHIP8_KEY1 BUTTON_LEFT 1174#define CHIP8_KEY2 BUTTON_UP 1175#define CHIP8_KEY3 BUTTON_RIGHT 1176#define CHIP8_KEY4 BUTTON_DOWN 1177#define CHIP8_KEY5 BUTTON_NEXT 1178#define CHIP8_KEY6 BUTTON_PREV 1179#define CHIP8_KEY7 BUTTON_SELECT 1180#define CHIP8_KEY8 BUTTON_VOL_DOWN 1181#define CHIP8_KEY9 BUTTON_VOL_UP 1182 1183#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD) 1184#define CHIP8_OFF (BUTTON_BACK|BUTTON_REPEAT) 1185#define CHIP8_KEY1 BUTTON_MENU 1186#define CHIP8_KEY2 BUTTON_UP 1187#define CHIP8_KEY3 BUTTON_DOWN 1188#define CHIP8_KEY4 BUTTON_LEFT 1189#define CHIP8_KEY5 BUTTON_SELECT 1190#define CHIP8_KEY6 BUTTON_RIGHT 1191#define CHIP8_KEY7 BUTTON_BACK 1192#define CHIP8_KEY8 BUTTON_POWER 1193#define CHIP8_KEY9 BUTTON_USER 1194 1195#elif (CONFIG_KEYPAD == HM60X_PAD) 1196#define CHIP8_OFF BUTTON_POWER 1197#define CHIP8_KEY2 BUTTON_UP 1198#define CHIP8_KEY4 BUTTON_DOWN 1199#define CHIP8_KEY5 BUTTON_SELECT 1200#define CHIP8_KEY6 BUTTON_RIGHT 1201#define CHIP8_KEY8 BUTTON_LEFT 1202 1203#elif (CONFIG_KEYPAD == SONY_NWZ_PAD) 1204#define CHIP8_OFF BUTTON_BACK 1205#define CHIP8_KEY2 BUTTON_UP 1206#define CHIP8_KEY4 BUTTON_DOWN 1207#define CHIP8_KEY5 BUTTON_PLAY 1208#define CHIP8_KEY6 BUTTON_RIGHT 1209#define CHIP8_KEY8 BUTTON_LEFT 1210 1211#elif (CONFIG_KEYPAD == CREATIVE_ZEN_PAD) 1212#define CHIP8_OFF BUTTON_BACK 1213#define CHIP8_KEY2 BUTTON_UP 1214#define CHIP8_KEY4 BUTTON_DOWN 1215#define CHIP8_KEY5 BUTTON_SELECT 1216#define CHIP8_KEY6 BUTTON_RIGHT 1217#define CHIP8_KEY8 BUTTON_LEFT 1218 1219#elif (CONFIG_KEYPAD == HM801_PAD) 1220#define CHIP8_OFF (BUTTON_POWER|BUTTON_SELECT) 1221#define CHIP8_KEY1 BUTTON_PREV 1222#define CHIP8_KEY2 BUTTON_UP 1223#define CHIP8_KEY3 BUTTON_DOWN 1224#define CHIP8_KEY4 BUTTON_LEFT 1225#define CHIP8_KEY5 BUTTON_SELECT 1226#define CHIP8_KEY6 BUTTON_RIGHT 1227#define CHIP8_KEY7 BUTTON_NEXT 1228#define CHIP8_KEY8 BUTTON_PLAY 1229#define CHIP8_KEY9 BUTTON_POWER 1230 1231#elif (CONFIG_KEYPAD == DX50_PAD) 1232#define CHIP8_OFF BUTTON_POWER 1233 1234#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD 1235#define CHIP8_OFF BUTTON_POWER 1236#define CHIP8_KEY1 BUTTON_TOPLEFT 1237#define CHIP8_KEY2 BUTTON_TOPMIDDLE 1238#define CHIP8_KEY3 BUTTON_TOPRIGHT 1239#define CHIP8_KEY4 BUTTON_MIDLEFT 1240#define CHIP8_KEY5 BUTTON_CENTER 1241#define CHIP8_KEY6 BUTTON_MIDRIGHT 1242#define CHIP8_KEY7 BUTTON_BOTTOMLEFT 1243#define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE 1244#define CHIP8_KEY9 BUTTON_BOTTOMRIGHT 1245 1246#elif (CONFIG_KEYPAD == AGPTEK_ROCKER_PAD) 1247#define CHIP8_OFF BUTTON_POWER 1248#define CHIP8_KEY2 BUTTON_UP 1249#define CHIP8_KEY4 BUTTON_DOWN 1250#define CHIP8_KEY5 BUTTON_SELECT 1251#define CHIP8_KEY6 BUTTON_RIGHT 1252#define CHIP8_KEY8 BUTTON_LEFT 1253 1254#elif CONFIG_KEYPAD == XDUOO_X3_PAD || CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD 1255#define CHIP8_OFF BUTTON_POWER 1256#define CHIP8_KEY2 BUTTON_HOME 1257#define CHIP8_KEY4 BUTTON_PREV 1258#define CHIP8_KEY5 BUTTON_PLAY 1259#define CHIP8_KEY6 BUTTON_NEXT 1260#define CHIP8_KEY8 BUTTON_OPTION 1261 1262#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD 1263#define CHIP8_OFF BUTTON_POWER 1264#define CHIP8_KEY2 BUTTON_HOME 1265#define CHIP8_KEY4 BUTTON_PREV 1266#define CHIP8_KEY5 BUTTON_PLAY 1267#define CHIP8_KEY6 BUTTON_NEXT 1268#define CHIP8_KEY8 BUTTON_OPTION 1269 1270#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD 1271#define CHIP8_OFF BUTTON_POWER 1272#define CHIP8_KEY2 BUTTON_NEXT 1273#define CHIP8_KEY4 BUTTON_HOME 1274#define CHIP8_KEY5 BUTTON_VOL_UP 1275#define CHIP8_KEY6 BUTTON_VOL_DOWN 1276#define CHIP8_KEY8 BUTTON_PREV 1277 1278#elif CONFIG_KEYPAD == EROSQ_PAD 1279#define CHIP8_OFF BUTTON_POWER 1280#define CHIP8_KEY2 BUTTON_NEXT 1281#define CHIP8_KEY4 BUTTON_MENU 1282#define CHIP8_KEY5 BUTTON_PLAY 1283#define CHIP8_KEY6 BUTTON_BACK 1284#define CHIP8_KEY8 BUTTON_PREV 1285 1286#elif CONFIG_KEYPAD == FIIO_M3K_PAD 1287#define CHIP8_OFF BUTTON_POWER 1288#define CHIP8_KEY2 BUTTON_MENU 1289#define CHIP8_KEY4 BUTTON_LEFT 1290#define CHIP8_KEY5 BUTTON_SELECT 1291#define CHIP8_KEY6 BUTTON_RIGHT 1292#define CHIP8_KEY8 BUTTON_BACK 1293 1294#elif CONFIG_KEYPAD == SDL_PAD 1295/* use touchscreen */ 1296#elif (CONFIG_KEYPAD == MA_PAD) 1297#define CHIP8_OFF BUTTON_BACK 1298#define CHIP8_KEY2 BUTTON_UP 1299#define CHIP8_KEY4 BUTTON_DOWN 1300#define CHIP8_KEY5 BUTTON_PLAY 1301#define CHIP8_KEY6 BUTTON_RIGHT 1302#define CHIP8_KEY8 BUTTON_LEFT 1303 1304#elif CONFIG_KEYPAD == RG_NANO_PAD 1305#define CHIP8_OFF BUTTON_START 1306#define CHIP8_KEY1 BUTTON_Y 1307#define CHIP8_KEY2 BUTTON_A 1308#define CHIP8_KEY3 BUTTON_X 1309#define CHIP8_KEY4 BUTTON_LEFT 1310#define CHIP8_KEY5 BUTTON_UP 1311#define CHIP8_KEY6 BUTTON_RIGHT 1312#define CHIP8_KEY7 BUTTON_B 1313#define CHIP8_KEY8 BUTTON_DOWN 1314#define CHIP8_KEY9 BUTTON_R 1315#define CHIP8_KEY0 BUTTON_L 1316 1317#elif CONFIG_KEYPAD == SHANLING_Q1_PAD 1318/* use touchscreen */ 1319 1320#else 1321#error No keymap defined! 1322#endif 1323 1324#ifdef HAVE_TOUCHSCREEN 1325#ifndef CHIP8_OFF 1326#define CHIP8_OFF BUTTON_TOPLEFT 1327#endif 1328#ifndef CHIP8_KEY1 1329#define CHIP8_KEY1 BUTTON_TOPRIGHT 1330#endif 1331#ifndef CHIP8_KEY2 1332#define CHIP8_KEY2 BUTTON_TOPMIDDLE 1333#endif 1334#ifndef CHIP8_KEY3 1335#define CHIP8_KEY3 BUTTON_BOTTOMLEFT 1336#endif 1337#ifndef CHIP8_KEY4 1338#define CHIP8_KEY4 BUTTON_MIDLEFT 1339#endif 1340#ifndef CHIP8_KEY5 1341#define CHIP8_KEY5 BUTTON_CENTER 1342#endif 1343#ifndef CHIP8_KEY6 1344#define CHIP8_KEY6 BUTTON_MIDRIGHT 1345#endif 1346#ifndef CHIP8_KEY7 1347#define CHIP8_KEY7 BUTTON_BOTTOMRIGHT 1348#endif 1349#ifndef CHIP8_KEY8 1350#define CHIP8_KEY8 BUTTON_BOTTOMMIDDLE 1351#endif 1352#endif 1353 1354static byte chip8_virtual_keys[16]; 1355static byte chip8_keymap[16]; 1356 1357static unsigned long starttimer; /* Timer value at the beginning */ 1358static unsigned long cycles; /* Number of update cycles (50Hz) */ 1359 1360/****************************************************************************/ 1361/* Turn sound on */ 1362/****************************************************************************/ 1363static void chip8_sound_on (void) 1364{ 1365} 1366 1367/****************************************************************************/ 1368/* Turn sound off */ 1369/****************************************************************************/ 1370static void chip8_sound_off (void) 1371{ 1372} 1373 1374/****************************************************************************/ 1375/* Update the display */ 1376/****************************************************************************/ 1377static void chip8_update_display(void) 1378{ 1379 int x, lcd_x, y, i; 1380 byte w; 1381 byte* row; 1382 /* frame buffer in hardware fomat */ 1383 unsigned char lcd_framebuf[CHIP8_HEIGHT/8][CHIP8_LCDWIDTH]; 1384 1385 for (y=0;y<CHIP8_HEIGHT/8;++y) 1386 { 1387 row = lcd_framebuf[y]; 1388 for (x=0, lcd_x=0;x<CHIP8_WIDTH;++x,++lcd_x) 1389 { 1390 w = 0; 1391 for (i=0;i<8;i++) 1392 { 1393 w = w >> 1; 1394 if (chip8_display[x+(y*8+i)*CHIP8_WIDTH] != 0) 1395 { 1396 w += 128; 1397 } 1398 } 1399#if (CHIP8_LCDWIDTH < 128) /* LCD_WIDTH between 112 and 127 */ 1400 if (x%8 == 1) { 1401 row[-1] |= w; /* overlay on */ 1402 } 1403 else 1404#endif 1405 *row++ = w; 1406 } 1407 } 1408#if (CONFIG_PLATFORM & PLATFORM_HOSTED) || (LCD_DEPTH >= 4) 1409 rb->lcd_set_drawmode(DRMODE_SOLID); 1410 rb->lcd_mono_bitmap(lcd_framebuf[0], CHIP8_X, CHIP8_Y, CHIP8_LCDWIDTH, 1411 CHIP8_HEIGHT); 1412 rb->lcd_update(); 1413#else 1414 rb->lcd_blit_mono(lcd_framebuf[0], CHIP8_X, CHIP8_Y>>3, CHIP8_LCDWIDTH, 1415 CHIP8_HEIGHT>>3, CHIP8_LCDWIDTH); 1416#endif 1417} 1418 1419static void chip8_keyboard(void) 1420{ 1421 int i; 1422 int button = rb->button_get(false); 1423 switch (button) 1424 { 1425#ifdef CHIP8_RC_OFF 1426 case CHIP8_RC_OFF: 1427#endif 1428 case CHIP8_OFF: /* Abort Emulator */ 1429 chip8_running = 0; 1430 break; 1431 1432 case CHIP8_KEY2: chip8_virtual_keys[2] = 1; break; 1433 case CHIP8_KEY2 | BUTTON_REL: chip8_virtual_keys[2] = 0; break; 1434 case CHIP8_KEY4: chip8_virtual_keys[4] = 1; break; 1435 case CHIP8_KEY4 | BUTTON_REL: chip8_virtual_keys[4] = 0; break; 1436 case CHIP8_KEY6: chip8_virtual_keys[6] = 1; break; 1437 case CHIP8_KEY6 | BUTTON_REL: chip8_virtual_keys[6] = 0; break; 1438 case CHIP8_KEY8: chip8_virtual_keys[8] = 1; break; 1439 case CHIP8_KEY8 | BUTTON_REL: chip8_virtual_keys[8] = 0; break; 1440 case CHIP8_KEY5: chip8_virtual_keys[5] = 1; break; 1441 case CHIP8_KEY5 | BUTTON_REL: chip8_virtual_keys[5] = 0; break; 1442#ifdef CHIP8_KEY1 1443 case CHIP8_KEY1: chip8_virtual_keys[1] = 1; break; 1444 case CHIP8_KEY1 | BUTTON_REL: chip8_virtual_keys[1] = 0; break; 1445#endif 1446#ifdef CHIP8_KEY3 1447 case CHIP8_KEY3: chip8_virtual_keys[3] = 1; break; 1448 case CHIP8_KEY3 | BUTTON_REL: chip8_virtual_keys[3] = 0; break; 1449#endif 1450#ifdef CHIP8_KEY7 1451 case CHIP8_KEY7: chip8_virtual_keys[7] = 1; break; 1452 case CHIP8_KEY7 | BUTTON_REL: chip8_virtual_keys[7] = 0; break; 1453#endif 1454#ifdef CHIP8_KEY9 1455 case CHIP8_KEY9: chip8_virtual_keys[9] = 1; break; 1456 case CHIP8_KEY9 | BUTTON_REL: chip8_virtual_keys[9] = 0; break; 1457#endif 1458#ifdef CHIP8_KEYA 1459 case CHIP8_KEYA: chip8_virtual_keys[10] = 1; break; 1460 case CHIP8_KEYA | BUTTON_REL: chip8_virtual_keys[10] = 0; break; 1461#endif 1462 1463 default: 1464 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) 1465 chip8_running = 2; /* indicates stopped because of USB */ 1466 break; 1467 } 1468 for(i=0; i<16; i++) { 1469 chip8_keys[i] = chip8_virtual_keys[chip8_keymap[i]]; 1470 } 1471} 1472 1473/****************************************************************************/ 1474/* Update keyboard and display, sync emulation with VDP clock */ 1475/****************************************************************************/ 1476static void chip8_interrupt (void) 1477{ 1478 unsigned long current_tick; 1479 unsigned long timer, runtime; 1480 1481 chip8_update_display(); 1482 chip8_keyboard(); 1483 cycles ++; 1484 runtime = cycles * HZ / 50; 1485 timer = starttimer + runtime; 1486 current_tick = *rb->current_tick; 1487 if (TIME_AFTER(timer, current_tick)) 1488 { 1489 rb->sleep(timer - current_tick); 1490 } 1491 else 1492 { 1493 rb->yield(); 1494 } 1495} 1496 1497static bool chip8_init(const char* file) 1498{ 1499 int numread; 1500 int fd; 1501 int len; 1502 int i; 1503 1504 fd = rb->open(file, O_RDONLY); 1505 if (fd < 0) { 1506 rb->lcd_puts(0, 6, "File Error."); 1507 return false; 1508 } 1509 numread = rb->read(fd, chip8_mem+0x200, 4096-0x200); 1510 rb->close(fd); 1511 if (numread==-1) { 1512 rb->lcd_puts(0, 6, "I/O Error."); 1513 return false; 1514 } 1515 1516 /* is there a c8k file (chip8 keys) ? */ 1517 char c8kname[MAX_PATH]; 1518 rb->strcpy(c8kname, file); 1519 for(i=0; i<16; i++) { 1520 chip8_virtual_keys[i] = 0; 1521 chip8_keymap[i] = i; 1522 } 1523 len = rb->strlen(c8kname); 1524 c8kname[len-2] = '8'; 1525 c8kname[len-1] = 'k'; 1526 fd = rb->open(c8kname, O_RDONLY); 1527 if (fd >= 0) { 1528 rb->lcd_puts(0, 6, "File&Keymap OK."); 1529 numread = rb->read(fd, chip8_keymap, 16); 1530 rb->close(fd); 1531 } 1532 else 1533 { 1534 rb->lcd_puts(0, 6, "File OK."); 1535 } 1536 for(i=0; i<16; i++) { 1537 if (chip8_keymap[i] >= '0' 1538 && chip8_keymap[i] <= '9') 1539 chip8_keymap[i] -= '0'; 1540 else if (chip8_keymap[i] >= 'A' 1541 && chip8_keymap[i] <= 'F') 1542 chip8_keymap[i] -= 'A' - 10; 1543 else if (chip8_keymap[i] >= 'a' 1544 && chip8_keymap[i] <= 'f') 1545 chip8_keymap[i] -= 'a' - 10; 1546 else 1547 chip8_keymap[i] %= 16; 1548 } 1549 return true; 1550} 1551 1552static bool chip8_run(const char* file) 1553{ 1554 int ok; 1555 1556 rb->lcd_clear_display(); 1557 rb->lcd_puts(0, 0, "SChip8 Emulator"); 1558 rb->lcd_puts(0, 1, " (c) by "); 1559 rb->lcd_puts(0, 2, "Marcel de Kogel"); 1560 rb->lcd_puts(0, 3, " Rockbox: "); 1561 rb->lcd_puts(0, 4, " Blueloop/Fdy "); 1562 rb->lcd_puts(0, 5, "---------------"); 1563 ok = chip8_init(file); 1564 rb->lcd_update(); 1565 rb->sleep(HZ*1); 1566 if (!ok) 1567 return false; 1568 rb->lcd_clear_display(); 1569#if (CHIP8_X > 0) && (CHIP8_Y > 0) 1570 rb->lcd_drawrect(CHIP8_X-1,CHIP8_Y-1,CHIP8_LCDWIDTH+2,CHIP8_HEIGHT+2); 1571#endif 1572 rb->lcd_update(); 1573 starttimer = *rb->current_tick; 1574 1575 chip8_iperiod=15; 1576 cycles = 0; 1577 chip8(); 1578 1579 if (chip8_running == 3) { 1580 /* unsupported instruction */ 1581 rb->splash(HZ, "Error: Unsupported" 1582#ifndef CHIP8_SUPER 1583 " CHIP-8 instruction. (maybe S-CHIP)" 1584#else 1585 " (S)CHIP-8 instruction." 1586#endif 1587 ); 1588 return false; 1589 } 1590 1591 return true; 1592} 1593 1594 1595/***************** Plugin Entry Point *****************/ 1596 1597enum plugin_status plugin_start(const void* parameter) 1598{ 1599 const char* filename; 1600 1601 if (parameter == NULL) 1602 { 1603 rb->splash(HZ, "Play a .ch8 file!"); 1604 return PLUGIN_ERROR; 1605 } 1606 else 1607 { 1608 filename = (char*) parameter; 1609 } 1610 1611 /* now go ahead and have fun! */ 1612 if (chip8_run(filename)) 1613 if (chip8_running == 0) 1614 return PLUGIN_OK; 1615 else 1616 return PLUGIN_USB_CONNECTED; 1617 else 1618 return PLUGIN_ERROR; 1619}