nes 红白机模拟器 第2篇 InfoNES
InfoNES 支持 map ,声音,代码比较少,方便 移值。
在上个 LiteNES 的基础上,其实不到半小时就移值好了这个,但问题是,一直是黑屏。InfoNES_LoadFrame () WorkFrame 中一直是 0 。
解决的过程很漫长,最终看到 说是 ADS 中 有符号 无符号的问题,但是 这里用的是 makefile 不是 ADS ,试着改了 makefile 加上 CCFLAGS = -O2 -fsigned-char 。
终于有输出了,性能还算不错。
InfoNES 源码 http://www.zophar.net/pocket-pc/nes/infonesft.html
主要修改的是 InfoNES_System_Linux.cpp 和 Makefile
同样的,现在仅实现显示未加输入,声音,全屏等。后期在加。
InfoNES_System_Linux.cpp
1 /*===================================================================*/ 2 /* */ 3 /* InfoNES_System_Linux.cpp : Linux specific File */ 4 /* */ 5 /* 2001/05/18 InfoNES Project ( Sound is based on DarcNES ) */ 6 /* */ 7 /*===================================================================*/ 8 9 /*-------------------------------------------------------------------*/ 10 /* Include files */ 11 /*-------------------------------------------------------------------*/ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <pthread.h> 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <sys/ioctl.h> 22 #include <unistd.h> 23 #include <sys/soundcard.h> 24 25 #include "../InfoNES.h" 26 #include "../InfoNES_System.h" 27 #include "../InfoNES_pAPU.h" 28 29 //bool define 30 #define TRUE 1 31 #define FALSE 0 32 33 /* lcd 操作相关 头文件 */ 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <linux/fb.h> 38 #include <sys/ioctl.h> 39 #include <unistd.h> 40 #include <string.h> 41 #include <sys/mman.h> 42 43 static int fb_fd; 44 static unsigned char *fb_mem; 45 static int px_width; 46 static int line_width; 47 static int screen_width; 48 static struct fb_var_screeninfo var; 49 50 static int lcd_fb_display_px(WORD color, int x, int y) 51 { 52 unsigned char *pen8; 53 unsigned short *pen16; 54 55 pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width); 56 pen16 = (unsigned short *)pen8; 57 *pen16 = color; 58 59 return 0; 60 } 61 62 static int lcd_fb_init() 63 { 64 //如果使用 mmap 打开方式 必须是 读定方式 65 fb_fd = open("/dev/fb0", O_RDWR); 66 if(-1 == fb_fd) 67 { 68 printf("cat't open /dev/fb0 \n"); 69 return -1; 70 } 71 //获取屏幕参数 72 if(-1 == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var)) 73 { 74 close(fb_fd); 75 printf("cat't ioctl /dev/fb0 \n"); 76 return -1; 77 } 78 79 //计算参数 80 px_width = var.bits_per_pixel / 8; 81 line_width = var.xres * px_width; 82 screen_width = var.yres * line_width; 83 84 fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0); 85 if(fb_mem == (void *)-1) 86 { 87 close(fb_fd); 88 printf("cat't mmap /dev/fb0 \n"); 89 return -1; 90 } 91 //清屏 92 memset(fb_mem, 0 , screen_width); 93 return 0; 94 } 95 96 /*-------------------------------------------------------------------*/ 97 /* ROM image file information */ 98 /*-------------------------------------------------------------------*/ 99 100 char szRomName[256]; 101 char szSaveName[256]; 102 int nSRAM_SaveFlag; 103 104 /*-------------------------------------------------------------------*/ 105 /* Constants ( Linux specific ) */ 106 /*-------------------------------------------------------------------*/ 107 108 #define VBOX_SIZE 7 109 #define SOUND_DEVICE "/dev/dsp" 110 #define VERSION "InfoNES v0.91J" 111 112 /*-------------------------------------------------------------------*/ 113 /* Global Variables ( Linux specific ) */ 114 /*-------------------------------------------------------------------*/ 115 116 /* Emulation thread */ 117 pthread_t emulation_tid; 118 int bThread; 119 120 /* Pad state */ 121 DWORD dwKeyPad1; 122 DWORD dwKeyPad2; 123 DWORD dwKeySystem; 124 125 /* For Sound Emulation */ 126 BYTE final_wave[2048]; 127 int waveptr; 128 int wavflag; 129 int sound_fd; 130 131 /*-------------------------------------------------------------------*/ 132 /* Function prototypes ( Linux specific ) */ 133 /*-------------------------------------------------------------------*/ 134 135 void *emulation_thread( void *args ); 136 137 138 void start_application( char *filename ); 139 140 141 int LoadSRAM(); 142 143 144 int SaveSRAM(); 145 146 147 /* Palette data */ 148 WORD NesPalette[64] = 149 { 150 0x39ce, 0x1071, 0x0015, 0x2013, 0x440e, 0x5402, 0x5000, 0x3c20, 151 0x20a0, 0x0100, 0x0140, 0x00e2, 0x0ceb, 0x0000, 0x0000, 0x0000, 152 0x5ef7, 0x01dd, 0x10fd, 0x401e, 0x5c17, 0x700b, 0x6ca0, 0x6521, 153 0x45c0, 0x0240, 0x02a0, 0x0247, 0x0211, 0x0000, 0x0000, 0x0000, 154 0x7fff, 0x1eff, 0x2e5f, 0x223f, 0x79ff, 0x7dd6, 0x7dcc, 0x7e67, 155 0x7ae7, 0x4342, 0x2769, 0x2ff3, 0x03bb, 0x0000, 0x0000, 0x0000, 156 0x7fff, 0x579f, 0x635f, 0x6b3f, 0x7f1f, 0x7f1b, 0x7ef6, 0x7f75, 157 0x7f94, 0x73f4, 0x57d7, 0x5bf9, 0x4ffe, 0x0000, 0x0000, 0x0000 158 }; 159 160 /*===================================================================*/ 161 /* */ 162 /* main() : Application main */ 163 /* */ 164 /*===================================================================*/ 165 166 /* Application main */ 167 int main( int argc, char **argv ) 168 { 169 int i; 170 171 /*-------------------------------------------------------------------*/ 172 /* Pad Control */ 173 /*-------------------------------------------------------------------*/ 174 175 /* Initialize a pad state */ 176 dwKeyPad1 = 0; 177 dwKeyPad2 = 0; 178 dwKeySystem = 0; 179 180 /*-------------------------------------------------------------------*/ 181 /* Load Cassette & Create Thread */ 182 /*-------------------------------------------------------------------*/ 183 184 /* Initialize thread state */ 185 bThread = FALSE; 186 187 /* If a rom name specified, start it */ 188 if ( argc == 2 ) 189 { 190 start_application( argv[1] ); 191 } 192 193 lcd_fb_init(); 194 195 //主循环不要让程序退出 196 while(1) 197 { 198 199 } 200 return(0); 201 } 202 203 204 /*===================================================================*/ 205 /* */ 206 /* emulation_thread() : Thread Hooking Routine */ 207 /* */ 208 /*===================================================================*/ 209 210 void *emulation_thread( void *args ) 211 { 212 InfoNES_Main(); 213 } 214 215 216 /*===================================================================*/ 217 /* */ 218 /* start_application() : Start NES Hardware */ 219 /* */ 220 /*===================================================================*/ 221 void start_application( char *filename ) 222 { 223 /* Set a ROM image name */ 224 strcpy( szRomName, filename ); 225 226 /* Load cassette */ 227 if ( InfoNES_Load( szRomName ) == 0 ) 228 { 229 /* Load SRAM */ 230 LoadSRAM(); 231 232 /* Create Emulation Thread */ 233 bThread = TRUE; 234 pthread_create( &emulation_tid, NULL, emulation_thread, NULL ); 235 } 236 } 237 238 239 /*===================================================================*/ 240 /* */ 241 /* LoadSRAM() : Load a SRAM */ 242 /* */ 243 /*===================================================================*/ 244 int LoadSRAM() 245 { 246 /* 247 * Load a SRAM 248 * 249 * Return values 250 * 0 : Normally 251 * -1 : SRAM data couldn't be read 252 */ 253 254 FILE *fp; 255 unsigned char pSrcBuf[SRAM_SIZE]; 256 unsigned char chData; 257 unsigned char chTag; 258 int nRunLen; 259 int nDecoded; 260 int nDecLen; 261 int nIdx; 262 263 /* It doesn't need to save it */ 264 nSRAM_SaveFlag = 0; 265 266 /* It is finished if the ROM doesn't have SRAM */ 267 if ( !ROM_SRAM ) 268 return(0); 269 270 /* There is necessity to save it */ 271 nSRAM_SaveFlag = 1; 272 273 /* The preparation of the SRAM file name */ 274 strcpy( szSaveName, szRomName ); 275 strcpy( strrchr( szSaveName, '.' ) + 1, "srm" ); 276 277 /*-------------------------------------------------------------------*/ 278 /* Read a SRAM data */ 279 /*-------------------------------------------------------------------*/ 280 281 /* Open SRAM file */ 282 fp = fopen( szSaveName, "rb" ); 283 if ( fp == NULL ) 284 return(-1); 285 286 /* Read SRAM data */ 287 fread( pSrcBuf, SRAM_SIZE, 1, fp ); 288 289 /* Close SRAM file */ 290 fclose( fp ); 291 292 /*-------------------------------------------------------------------*/ 293 /* Extract a SRAM data */ 294 /*-------------------------------------------------------------------*/ 295 296 nDecoded = 0; 297 nDecLen = 0; 298 299 chTag = pSrcBuf[nDecoded++]; 300 301 while ( nDecLen < 8192 ) 302 { 303 chData = pSrcBuf[nDecoded++]; 304 305 if ( chData == chTag ) 306 { 307 chData = pSrcBuf[nDecoded++]; 308 nRunLen = pSrcBuf[nDecoded++]; 309 for ( nIdx = 0; nIdx < nRunLen + 1; ++nIdx ) 310 { 311 SRAM[nDecLen++] = chData; 312 } 313 }else { 314 SRAM[nDecLen++] = chData; 315 } 316 } 317 318 /* Successful */ 319 return(0); 320 } 321 322 323 /*===================================================================*/ 324 /* */ 325 /* SaveSRAM() : Save a SRAM */ 326 /* */ 327 /*===================================================================*/ 328 int SaveSRAM() 329 { 330 /* 331 * Save a SRAM 332 * 333 * Return values 334 * 0 : Normally 335 * -1 : SRAM data couldn't be written 336 */ 337 338 FILE *fp; 339 int nUsedTable[256]; 340 unsigned char chData; 341 unsigned char chPrevData; 342 unsigned char chTag; 343 int nIdx; 344 int nEncoded; 345 int nEncLen; 346 int nRunLen; 347 unsigned char pDstBuf[SRAM_SIZE]; 348 349 if ( !nSRAM_SaveFlag ) 350 return(0); /* It doesn't need to save it */ 351 352 /*-------------------------------------------------------------------*/ 353 /* Compress a SRAM data */ 354 /*-------------------------------------------------------------------*/ 355 356 memset( nUsedTable, 0, sizeof nUsedTable ); 357 358 for ( nIdx = 0; nIdx < SRAM_SIZE; ++nIdx ) 359 { 360 ++nUsedTable[SRAM[nIdx++]]; 361 } 362 for ( nIdx = 1, chTag = 0; nIdx < 256; ++nIdx ) 363 { 364 if ( nUsedTable[nIdx] < nUsedTable[chTag] ) 365 chTag = nIdx; 366 } 367 368 nEncoded = 0; 369 nEncLen = 0; 370 nRunLen = 1; 371 372 pDstBuf[nEncLen++] = chTag; 373 374 chPrevData = SRAM[nEncoded++]; 375 376 while ( nEncoded < SRAM_SIZE && nEncLen < SRAM_SIZE - 133 ) 377 { 378 chData = SRAM[nEncoded++]; 379 380 if ( chPrevData == chData && nRunLen < 256 ) 381 ++nRunLen; 382 else{ 383 if ( nRunLen >= 4 || chPrevData == chTag ) 384 { 385 pDstBuf[nEncLen++] = chTag; 386 pDstBuf[nEncLen++] = chPrevData; 387 pDstBuf[nEncLen++] = nRunLen - 1; 388 }else { 389 for ( nIdx = 0; nIdx < nRunLen; ++nIdx ) 390 pDstBuf[nEncLen++] = chPrevData; 391 } 392 393 chPrevData = chData; 394 nRunLen = 1; 395 } 396 } 397 if ( nRunLen >= 4 || chPrevData == chTag ) 398 { 399 pDstBuf[nEncLen++] = chTag; 400 pDstBuf[nEncLen++] = chPrevData; 401 pDstBuf[nEncLen++] = nRunLen - 1; 402 }else { 403 for ( nIdx = 0; nIdx < nRunLen; ++nIdx ) 404 pDstBuf[nEncLen++] = chPrevData; 405 } 406 407 /*-------------------------------------------------------------------*/ 408 /* Write a SRAM data */ 409 /*-------------------------------------------------------------------*/ 410 411 /* Open SRAM file */ 412 fp = fopen( szSaveName, "wb" ); 413 if ( fp == NULL ) 414 return(-1); 415 416 /* Write SRAM data */ 417 fwrite( pDstBuf, nEncLen, 1, fp ); 418 419 /* Close SRAM file */ 420 fclose( fp ); 421 422 /* Successful */ 423 return(0); 424 } 425 426 427 /*===================================================================*/ 428 /* */ 429 /* InfoNES_Menu() : Menu screen */ 430 /* */ 431 /*===================================================================*/ 432 int InfoNES_Menu() 433 { 434 /* 435 * Menu screen 436 * 437 * Return values 438 * 0 : Normally 439 * -1 : Exit InfoNES 440 */ 441 442 /* If terminated */ 443 if ( bThread == FALSE ) 444 { 445 return(-1); 446 } 447 448 /* Nothing to do here */ 449 return(0); 450 } 451 452 453 /*===================================================================*/ 454 /* */ 455 /* InfoNES_ReadRom() : Read ROM image file */ 456 /* */ 457 /*===================================================================*/ 458 int InfoNES_ReadRom( const char *pszFileName ) 459 { 460 /* 461 * Read ROM image file 462 * 463 * Parameters 464 * const char *pszFileName (Read) 465 * 466 * Return values 467 * 0 : Normally 468 * -1 : Error 469 */ 470 471 FILE *fp; 472 473 /* Open ROM file */ 474 fp = fopen( pszFileName, "rb" ); 475 if ( fp == NULL ) 476 return(-1); 477 478 /* Read ROM Header */ 479 fread( &NesHeader, sizeof NesHeader, 1, fp ); 480 if ( memcmp( NesHeader.byID, "NES\x1a", 4 ) != 0 ) 481 { 482 /* not .nes file */ 483 fclose( fp ); 484 return(-1); 485 } 486 487 /* Clear SRAM */ 488 memset( SRAM, 0, SRAM_SIZE ); 489 490 /* If trainer presents Read Triner at 0x7000-0x71ff */ 491 if ( NesHeader.byInfo1 & 4 ) 492 { 493 fread( &SRAM[0x1000], 512, 1, fp ); 494 } 495 496 /* Allocate Memory for ROM Image */ 497 ROM = (BYTE *) malloc( NesHeader.byRomSize * 0x4000 ); 498 499 /* Read ROM Image */ 500 fread( ROM, 0x4000, NesHeader.byRomSize, fp ); 501 502 if ( NesHeader.byVRomSize > 0 ) 503 { 504 /* Allocate Memory for VROM Image */ 505 VROM = (BYTE *) malloc( NesHeader.byVRomSize * 0x2000 ); 506 507 /* Read VROM Image */ 508 fread( VROM, 0x2000, NesHeader.byVRomSize, fp ); 509 } 510 511 /* File close */ 512 fclose( fp ); 513 514 /* Successful */ 515 return(0); 516 } 517 518 519 /*===================================================================*/ 520 /* */ 521 /* InfoNES_ReleaseRom() : Release a memory for ROM */ 522 /* */ 523 /*===================================================================*/ 524 void InfoNES_ReleaseRom() 525 { 526 /* 527 * Release a memory for ROM 528 * 529 */ 530 531 if ( ROM ) 532 { 533 free( ROM ); 534 ROM = NULL; 535 } 536 537 if ( VROM ) 538 { 539 free( VROM ); 540 VROM = NULL; 541 } 542 } 543 544 545 /*===================================================================*/ 546 /* */ 547 /* InfoNES_MemoryCopy() : memcpy */ 548 /* */ 549 /*===================================================================*/ 550 void *InfoNES_MemoryCopy( void *dest, const void *src, int count ) 551 { 552 /* 553 * memcpy 554 * 555 * Parameters 556 * void *dest (Write) 557 * Points to the starting address of the copied block's destination 558 * 559 * const void *src (Read) 560 * Points to the starting address of the block of memory to copy 561 * 562 * int count (Read) 563 * Specifies the size, in bytes, of the block of memory to copy 564 * 565 * Return values 566 * Pointer of destination 567 */ 568 569 memcpy( dest, src, count ); 570 return(dest); 571 } 572 573 574 /*===================================================================*/ 575 /* */ 576 /* InfoNES_MemorySet() : memset */ 577 /* */ 578 /*===================================================================*/ 579 void *InfoNES_MemorySet( void *dest, int c, int count ) 580 { 581 /* 582 * memset 583 * 584 * Parameters 585 * void *dest (Write) 586 * Points to the starting address of the block of memory to fill 587 * 588 * int c (Read) 589 * Specifies the byte value with which to fill the memory block 590 * 591 * int count (Read) 592 * Specifies the size, in bytes, of the block of memory to fill 593 * 594 * Return values 595 * Pointer of destination 596 */ 597 598 memset( dest, c, count ); 599 return(dest); 600 } 601 602 603 /*===================================================================*/ 604 /* */ 605 /* InfoNES_LoadFrame() : */ 606 /* Transfer the contents of work frame on the screen */ 607 /* */ 608 /*===================================================================*/ 609 void InfoNES_LoadFrame() 610 { 611 int x,y; 612 WORD wColor; 613 for (y = 0; y < NES_DISP_HEIGHT; y++ ) 614 { 615 for (x = 0; x < NES_DISP_WIDTH; x++ ) 616 { 617 wColor = WorkFrame[y * NES_DISP_WIDTH + x ]; 618 lcd_fb_display_px(wColor, x, y); 619 } 620 } 621 } 622 623 624 /*===================================================================*/ 625 /* */ 626 /* InfoNES_PadState() : Get a joypad state */ 627 /* */ 628 /*===================================================================*/ 629 void InfoNES_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem ) 630 { 631 /* 632 * Get a joypad state 633 * 634 * Parameters 635 * DWORD *pdwPad1 (Write) 636 * Joypad 1 State 637 * 638 * DWORD *pdwPad2 (Write) 639 * Joypad 2 State 640 * 641 * DWORD *pdwSystem (Write) 642 * Input for InfoNES 643 * 644 */ 645 646 /* Transfer joypad state */ 647 *pdwPad1 = dwKeyPad1; 648 *pdwPad2 = dwKeyPad2; 649 *pdwSystem = dwKeySystem; 650 } 651 652 653 /*===================================================================*/ 654 /* */ 655 /* InfoNES_SoundInit() : Sound Emulation Initialize */ 656 /* */ 657 /*===================================================================*/ 658 void InfoNES_SoundInit( void ) 659 { 660 sound_fd = 0; 661 } 662 663 664 /*===================================================================*/ 665 /* */ 666 /* InfoNES_SoundOpen() : Sound Open */ 667 /* */ 668 /*===================================================================*/ 669 int InfoNES_SoundOpen( int samples_per_sync, int sample_rate ) 670 { 671 return 1; 672 } 673 674 675 /*===================================================================*/ 676 /* */ 677 /* InfoNES_SoundClose() : Sound Close */ 678 /* */ 679 /*===================================================================*/ 680 void InfoNES_SoundClose( void ) 681 { 682 if ( sound_fd ) 683 { 684 close( sound_fd ); 685 } 686 } 687 688 689 /*===================================================================*/ 690 /* */ 691 /* InfoNES_SoundOutput() : Sound Output 5 Waves */ 692 /* */ 693 /*===================================================================*/ 694 void InfoNES_SoundOutput( int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYTE *wave4, BYTE *wave5 ) 695 { 696 697 } 698 699 700 /*===================================================================*/ 701 /* */ 702 /* InfoNES_Wait() : Wait Emulation if required */ 703 /* */ 704 /*===================================================================*/ 705 void InfoNES_Wait() 706 { 707 } 708 709 710 /*===================================================================*/ 711 /* */ 712 /* InfoNES_MessageBox() : Print System Message */ 713 /* */ 714 /*===================================================================*/ 715 void InfoNES_MessageBox( char *pszMsg, ... ) 716 { 717 printf( "MessageBox: %s \n", pszMsg ); 718 } 719 720 721 /* 722 * End of InfoNES_System_Linux.cpp 723 */
Makefile
1 CC = arm-linux-gcc 2 TARBALL = InfoNES08J 3 4 # InfoNES 5 .CFILES = ./../K6502.cpp \ 6 ./../InfoNES.cpp \ 7 ./../InfoNES_Mapper.cpp \ 8 ./../InfoNES_pAPU.cpp \ 9 ./InfoNES_System_Linux.cpp 10 11 .OFILES = $(.CFILES:.cpp=.o) 12 13 CCFLAGS = -O2 -fsigned-char 14 LDFILGS = -lstdc++ # gcc3.x.x 15 16 all: InfoNES 17 18 InfoNES: $(.OFILES) 19 $(CC) $(INCLUDES) -o $@ $(.OFILES) $(LDFILGS) -lm -lz -lpthread 20 21 .cpp.o: 22 $(CC) $(INCLUDES) -c $(CCFLAGS) $*.cpp -o $@ 23 24 clean: 25 rm -f $(.OFILES) ../*~ ../*/*~ core 26 27 cleanall: 28 rm -f $(.OFILES) ../*~ ../*/*~ core InfoNES 29 30 release: clean all 31 32 tar: 33 ( cd ..; \ 34 tar cvf $(TARBALL).tar ./*; \ 35 gzip $(TARBALL).tar \ 36 ) 37 38 install: 39 install ./InfoNES /usr/local/bin