|
【试用心得】外传——《手把手教你移植InfoNES(到HANKER-LM4F232)》更新至20131030
[复制链接]
完结篇……更新至2013.10.30 - 22:17
温馨提示,本文中每个部分涉及到的工程包括源文件,都可以在本文的最后发现下载链接哟!
前三部分链接:https://bbs.eeworld.com.cn/thread-415692-1-1.html
第四部分上链接:https://bbs.eeworld.com.cn/thread-416564-1-1.html
第四部分下链接:https://bbs.eeworld.com.cn/thread-416756-1-1.html
有童鞋问了,神马是InfNES? 这是一款NES游戏模拟器,也就是任天堂的红白机,80后的童年……InfoNES可以很容易地被移植到各个平台,可以说各大开发论坛上都可见它的身影。
如果你是有关技术的老鸟,那不好意思你可能什么都学不到了,更可能会发现本文的诸多错误,阅读本文只会让你更多地浪费生命,对此我十分抱歉。
好吧,节目继续。
第五部分是在目标程序可以运行的情况下,完善相关的接口,并进一步把之前移植造成的问题修复。
别忘了,之前我们写的接口还都是空函数,现在得动真格了。
好在程序已经可以下载并且调试了,之后的一切问题都可以通过调试来说话。
一切都从把示例程序的屏幕驱动移进来开始。尤其要注意包括示例的有关工程设置。
接下来呢,我们不能动态加载游戏ROM了,那么我就送给大家一个游戏ROM数组,加到工程里。具体内容各位到末尾的工程里获取吧。
当然了,读入ROM时也就不用文件名了,所以文件名参数pszFileName在本次移植之后,就没有用了,自己知道就好。
首先NesPalette是一个64个元素的调色盘数组,具体的颜色排布"翔"见下图。
参考win32工程里面的,发现源代码在此处有一定的奥秘,是关于前后景的,想一想马里奥大叔顶出问号中的蘑菇吧,是有遮挡关系的。
所以不得不承认,有一些地方需要调整,这里大家详见代码吧,我把这些解释为:NES只有64种颜色,原win32工程使用5:5:5表示RGB,我们更多时候可能要使用5:6:5,这样就用多余的一位来表示该颜色透明(即应该显示其后面被挡住的颜色),就这样吧,解释太多都是噩梦。
我的颜色表是: - WORD NesPalette[64]={
- 0x738E,0x88C4,0xA800,0x9808,0x7011,0x1015,0x0014,0x004F,
- 0x0148,0x0200,0x0280,0x11C0,0x59C3,0x0000,0x0000,0x0000,
- 0xBDD7,0xEB80,0xE9C4,0xF010,0xB817,0x581C,0x015B,0x0A59,
- 0x0391,0x0480,0x0540,0x3C80,0x8C00,0x0000,0x0000,0x0000,
- 0xFFDF,0xFDC7,0xFC8B,0xFC48,0xFBDE,0xB39F,0x639F,0x3CDF,
- 0x3DDE,0x1690,0x4EC9,0x9FCB,0xDF40,0x0000,0x0000,0x0000,
- 0xFFDF,0xFF15,0xFE98,0xFE5A,0xFE1F,0xDE1F,0xB5DF,0xAEDF,
- 0xA71F,0xA7DC,0xBF95,0xCFD6,0xF7D3,0x0000,0x0000,0x0000,
- };
复制代码反正不是RGB,就是BGR啦,位数是5:6:5,如果觉得颜色有问题的话,自己调整一下R和B的顺序,G的6位只有高5位有效,低那一位表示是否透明,对于我们描画可以忽略这个值啦(最低位1或者0无所谓,不会影响这个颜色的整体颜色感觉)。
于是要在设置中配置透明标志: - #define TRANSPARENT_COLOR 0x0020
复制代码然后是InfoNES_ReadRom函数,用来把rom各种信息加载给模拟器核心。 - /* Read ROM image file */
- extern const BYTE nes_rom[];
- int InfoNES_ReadRom( const char *pszFileName )
- {
- /*
- * Read ROM image file
- *
- * Parameters
- * const char *pszFileName (Read)
- *
- * Return values
- * 0 : Normally
- * -1 : Error
- */
- /* Read ROM Header */
- BYTE * rom = (BYTE*)nes_rom;
- memcpy( &NesHeader, rom, sizeof(NesHeader));
- if ( memcmp( NesHeader.byID, "NES\x1a", 4 ) != 0 )
- {
- /* not .nes file */
- return -1;
- }
- rom += sizeof(NesHeader);
- /* Clear SRAM */
- memset( SRAM, 0, SRAM_SIZE );
- /* If trainer presents Read Triner at 0x7000-0x71ff */
- if ( NesHeader.byInfo1 & 4 )
- {
- //memcpy( &SRAM[ 0x1000 ], rom, 512);
- rom += 512;
- }
- /* Allocate Memory for ROM Image */
- ROM = rom;
- rom += NesHeader.byRomSize * 0x4000;
- if ( NesHeader.byVRomSize > 0 )
- {
- /* Allocate Memory for VROM Image */
- VROM = (BYTE*)rom;
- rom += NesHeader.byVRomSize * 0x2000;
- }
- /* Successful */
- return 0;
- }
复制代码InfoNES_LoadLine函数用来将一行256个像素点画在屏幕上。 - /* Transfer the contents of work line on the screen */
- void InfoNES_LoadLine()
- {
- int i;
- for(i=0;i<256;i++)
- {
- GrContextForegroundSet(&sContext, WorkLine[i]);
- GrPixelDraw(&sContext, i, PPU_Scanline);
- }
- }
复制代码还有两个内存处理函数: - /* memcpy */
- void *InfoNES_MemoryCopy( void *dest, const void *src, int count ){return memcpy(dest,src,count);}
- /* memset */
- void *InfoNES_MemorySet( void *dest, int c, int count ){return memset(dest,c,count);}
复制代码事实上我的工程还增加了提高描画效率的处理和时间的有关处理,但是你要知道,只要上面这些内容搞对了,模拟器就可以疯跑啦。
前一部分还留了个坑,有两个函数从内部屏蔽了代码:InfoNES_DrawLine和InfoNES_GetSprHitY,请改成如下的样子。 - /*===================================================================*/
- /* */
- /* InfoNES_DrawLine() : Render a scanline */
- /* */
- /*===================================================================*/
- void InfoNES_DrawLine()
- {
- /*
- * Render a scanline
- *
- */
- int nX;
- int nY;
- int nY4;
- int nYBit;
- WORD *pPalTbl;
- BYTE *pAttrBase;
- WORD *pPoint;
- int nNameTable;
- BYTE *pbyNameTable;
- BYTE *pbyChrData;
- #ifdef RAM_LACK
- BYTE tileData[2] = {0, 0};
- #else
- int nIdx;
- #endif /* RAM_LACK */
- BYTE *pSPRRAM;
- int nAttr;
- int nSprCnt;
- int nSprData;
- BYTE bySprCol;
- BYTE pSprBuf[ NES_DISP_WIDTH + 7 ];
- /*-------------------------------------------------------------------*/
- /* Render Background */
- /*-------------------------------------------------------------------*/
- /* MMC5 VROM switch */
- MapperRenderScreen( 1 );
- // Pointer to the render position
- #if WORKFRAME_DEFINE == WORKFRAME_NONE
- pPoint = WorkLine;
- #else
- pPoint = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
- #endif
- // Clear a scanline if screen is off
- if ( !( PPU_R1 & R1_SHOW_SCR ) )
- {
- InfoNES_MemorySet( pPoint, 0, NES_DISP_WIDTH << 1 );
- }
- else
- {
- nNameTable = PPU_NameTableBank;
- nY = PPU_Scr_V_Byte + ( PPU_Scanline >> 3 );
- nYBit = PPU_Scr_V_Bit + ( PPU_Scanline & 7 );
- if ( nYBit > 7 )
- {
- ++nY;
- nYBit &= 7;
- }
- #ifndef RAM_LACK
- nYBit <<= 3;
- #endif /* !RAM_LACK */
- if ( nY > 29 )
- {
- // Next NameTable (An up-down direction)
- nNameTable ^= NAME_TABLE_V_MASK;
- nY -= 30;
- }
- nX = PPU_Scr_H_Byte;
- nY4 = ( ( nY & 2 ) << 1 );
- /*-------------------------------------------------------------------*/
- /* Rendering of the block of the left end */
- /*-------------------------------------------------------------------*/
- pbyNameTable = PPUBANK[ nNameTable ] + nY * 32 + nX;
- #ifdef RAM_LACK
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 4 ) + nYBit;
- tileData[0] = ( ( pbyChrData[ 0 ] >> 1 ) & 0x55 ) | ( pbyChrData[ 8 ] & 0xAA );
- tileData[1] = ( pbyChrData[ 0 ] & 0x55 ) | ( ( pbyChrData[ 8 ] << 1 ) & 0xAA );
- #else
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
- #endif /* RAM_LACK */
- pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8;
- pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
- #ifdef RAM_LACK
- switch(PPU_Scr_H_Bit)
- {
- case 0:
- *( pPoint++ ) = pPalTbl[ ( tileData[0] >> 6 ) & 3 ];
- case 1:
- *( pPoint++ ) = pPalTbl[ ( tileData[1] >> 6 ) & 3 ];
- case 2:
- *( pPoint++ ) = pPalTbl[ ( tileData[0] >> 4 ) & 3 ];
- case 3:
- *( pPoint++ ) = pPalTbl[ ( tileData[1] >> 4 ) & 3 ];
- case 4:
- *( pPoint++ ) = pPalTbl[ ( tileData[0] >> 2 ) & 3 ];
- case 5:
- *( pPoint++ ) = pPalTbl[ ( tileData[1] >> 2 ) & 3 ];
- case 6:
- *( pPoint++ ) = pPalTbl[ ( tileData[0] ) & 3 ];
- case 7:
- *( pPoint++ ) = pPalTbl[ ( tileData[1] ) & 3 ];
- default:
- break;
- }
- #else
- for ( nIdx = PPU_Scr_H_Bit; nIdx < 8; ++nIdx )
- {
- *( pPoint++ ) = pPalTbl[ pbyChrData[ nIdx ] ];
- }
- #endif
- // Callback at PPU read/write
- MapperPPU( PATTBL( pbyChrData ) );
- ++nX;
- ++pbyNameTable;
- /*-------------------------------------------------------------------*/
- /* Rendering of the left table */
- /*-------------------------------------------------------------------*/
- for ( ; nX < 32; ++nX )
- {
- #ifdef RAM_LACK
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 4 ) + nYBit;
- tileData[0] = ( ( pbyChrData[ 0 ] >> 1 ) & 0x55 ) | ( pbyChrData[ 8 ] & 0xAA );
- tileData[1] = ( pbyChrData[ 0 ] & 0x55 ) | ( ( pbyChrData[ 8 ] << 1 ) & 0xAA );
- #else
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
- #endif /* RAM_LACK */
- pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
- #ifdef RAM_LACK
- pPoint[ 0 ] = pPalTbl[ ( tileData[0] >> 6 ) & 3 ];
- pPoint[ 1 ] = pPalTbl[ ( tileData[1] >> 6 ) & 3 ];
- pPoint[ 2 ] = pPalTbl[ ( tileData[0] >> 4 ) & 3 ];
- pPoint[ 3 ] = pPalTbl[ ( tileData[1] >> 4 ) & 3 ];
- pPoint[ 4 ] = pPalTbl[ ( tileData[0] >> 2 ) & 3 ];
- pPoint[ 5 ] = pPalTbl[ ( tileData[1] >> 2 ) & 3 ];
- pPoint[ 6 ] = pPalTbl[ ( tileData[0] ) & 3 ];
- pPoint[ 7 ] = pPalTbl[ ( tileData[1] ) & 3 ];
- #else
- pPoint[ 0 ] = pPalTbl[ pbyChrData[ 0 ] ];
- pPoint[ 1 ] = pPalTbl[ pbyChrData[ 1 ] ];
- pPoint[ 2 ] = pPalTbl[ pbyChrData[ 2 ] ];
- pPoint[ 3 ] = pPalTbl[ pbyChrData[ 3 ] ];
- pPoint[ 4 ] = pPalTbl[ pbyChrData[ 4 ] ];
- pPoint[ 5 ] = pPalTbl[ pbyChrData[ 5 ] ];
- pPoint[ 6 ] = pPalTbl[ pbyChrData[ 6 ] ];
- pPoint[ 7 ] = pPalTbl[ pbyChrData[ 7 ] ];
- #endif
- pPoint += 8;
- // Callback at PPU read/write
- MapperPPU( PATTBL( pbyChrData ) );
- ++pbyNameTable;
- }
- // Holizontal Mirror
- nNameTable ^= NAME_TABLE_H_MASK;
- pbyNameTable = PPUBANK[ nNameTable ] + nY * 32;
- pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8;
- /*-------------------------------------------------------------------*/
- /* Rendering of the right table */
- /*-------------------------------------------------------------------*/
- for ( nX = 0; nX < PPU_Scr_H_Byte; ++nX )
- {
- #ifdef RAM_LACK
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 4 ) + nYBit;
- tileData[0] = ( ( pbyChrData[ 0 ] >> 1 ) & 0x55 ) | ( pbyChrData[ 8 ] & 0xAA );
- tileData[1] = ( pbyChrData[ 0 ] & 0x55 ) | ( ( pbyChrData[ 8 ] << 1 ) & 0xAA );
- #else
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
- #endif /* RAM_LACK */
- pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
- #ifdef RAM_LACK
- pPoint[ 0 ] = pPalTbl[ ( tileData[0] >> 6 ) & 3 ];
- pPoint[ 1 ] = pPalTbl[ ( tileData[1] >> 6 ) & 3 ];
- pPoint[ 2 ] = pPalTbl[ ( tileData[0] >> 4 ) & 3 ];
- pPoint[ 3 ] = pPalTbl[ ( tileData[1] >> 4 ) & 3 ];
- pPoint[ 4 ] = pPalTbl[ ( tileData[0] >> 2 ) & 3 ];
- pPoint[ 5 ] = pPalTbl[ ( tileData[1] >> 2 ) & 3 ];
- pPoint[ 6 ] = pPalTbl[ ( tileData[0] ) & 3 ];
- pPoint[ 7 ] = pPalTbl[ ( tileData[1] ) & 3 ];
- #else
- pPoint[ 0 ] = pPalTbl[ pbyChrData[ 0 ] ];
- pPoint[ 1 ] = pPalTbl[ pbyChrData[ 1 ] ];
- pPoint[ 2 ] = pPalTbl[ pbyChrData[ 2 ] ];
- pPoint[ 3 ] = pPalTbl[ pbyChrData[ 3 ] ];
- pPoint[ 4 ] = pPalTbl[ pbyChrData[ 4 ] ];
- pPoint[ 5 ] = pPalTbl[ pbyChrData[ 5 ] ];
- pPoint[ 6 ] = pPalTbl[ pbyChrData[ 6 ] ];
- pPoint[ 7 ] = pPalTbl[ pbyChrData[ 7 ] ];
- #endif
- pPoint += 8;
- // Callback at PPU read/write
- MapperPPU( PATTBL( pbyChrData ) );
- ++pbyNameTable;
- }
- /*-------------------------------------------------------------------*/
- /* Rendering of the block of the right end */
- /*-------------------------------------------------------------------*/
- #ifdef RAM_LACK
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 4 ) + nYBit;
- tileData[0] = ( ( pbyChrData[ 0 ] >> 1 ) & 0x55 ) | ( pbyChrData[ 8 ] & 0xAA );
- tileData[1] = ( pbyChrData[ 0 ] & 0x55 ) | ( ( pbyChrData[ 8 ] << 1 ) & 0xAA );
- #else
- pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
- #endif /* RAM_LACK */
- pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
- #ifdef RAM_LACK
- switch(PPU_Scr_H_Bit)
- {
- case 8:
- pPoint[ 7 ] = pPalTbl[ ( tileData[1] ) & 3 ];
- case 7:
- pPoint[ 6 ] = pPalTbl[ ( tileData[0] ) & 3 ];
- case 6:
- pPoint[ 5 ] = pPalTbl[ ( tileData[1] >> 2 ) & 3 ];
- case 5:
- pPoint[ 4 ] = pPalTbl[ ( tileData[0] >> 2 ) & 3 ];
- case 4:
- pPoint[ 3 ] = pPalTbl[ ( tileData[1] >> 4 ) & 3 ];
- case 3:
- pPoint[ 2 ] = pPalTbl[ ( tileData[0] >> 4 ) & 3 ];
- case 2:
- pPoint[ 1 ] = pPalTbl[ ( tileData[1] >> 6 ) & 3 ];
- case 1:
- pPoint[ 0 ] = pPalTbl[ ( tileData[0] >> 6 ) & 3 ];
- case 0:
- default:
- break;
- }
- #else
- for ( nIdx = 0; nIdx < PPU_Scr_H_Bit; ++nIdx )
- {
- pPoint[ nIdx ] = pPalTbl[ pbyChrData[ nIdx ] ];
- }
- #endif
- // Callback at PPU read/write
- MapperPPU( PATTBL( pbyChrData ) );
- /*-------------------------------------------------------------------*/
- /* Backgroud Clipping */
- /*-------------------------------------------------------------------*/
- if ( !( PPU_R1 & R1_CLIP_BG ) )
- {
- WORD *pPointTop;
- #if WORKFRAME_DEFINE == WORKFRAME_NONE
- pPointTop = WorkLine;
- #else
- pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
- #endif
- InfoNES_MemorySet( pPointTop, 0, 8 << 1 );
- }
- /*-------------------------------------------------------------------*/
- /* Clear a scanline if up and down clipping flag is set */
- /*-------------------------------------------------------------------*/
- if ( PPU_UpDown_Clip &&
- ( SCAN_ON_SCREEN_START > PPU_Scanline || PPU_Scanline > SCAN_BOTTOM_OFF_SCREEN_START ) )
- {
- WORD *pPointTop;
- #if WORKFRAME_DEFINE == WORKFRAME_NONE
- pPointTop = WorkLine;
- #else
- pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
- #endif
- InfoNES_MemorySet( pPointTop, 0, NES_DISP_WIDTH << 1 );
- }
- }
- /*-------------------------------------------------------------------*/
- /* Render a sprite */
- /*-------------------------------------------------------------------*/
- /* MMC5 VROM switch */
- MapperRenderScreen( 0 );
- if ( PPU_R1 & R1_SHOW_SP )
- {
- // Reset Scanline Sprite Count
- PPU_R2 &= ~R2_MAX_SP;
- // Reset sprite buffer
- InfoNES_MemorySet( pSprBuf, 0, sizeof pSprBuf );
- // Render a sprite to the sprite buffer
- nSprCnt = 0;
- for ( pSPRRAM = SPRRAM + ( 63 << 2 ); pSPRRAM >= SPRRAM; pSPRRAM -= 4 )
- {
- nY = pSPRRAM[ SPR_Y ] + 1;
- if ( nY > PPU_Scanline || nY + PPU_SP_Height <= PPU_Scanline )
- continue; // Next sprite
- /*-------------------------------------------------------------------*/
- /* A sprite in scanning line */
- /*-------------------------------------------------------------------*/
- // Holizontal Sprite Count +1
- ++nSprCnt;
-
- nAttr = pSPRRAM[ SPR_ATTR ];
- nYBit = PPU_Scanline - nY;
- nYBit = ( nAttr & SPR_ATTR_V_FLIP ) ? ( PPU_SP_Height - nYBit - 1 ) : nYBit;
- #ifndef RAM_LACK
- nYBit <<= 3;
- #endif /* !RAM_LACK */
- if ( PPU_R0 & R0_SP_SIZE )
- {
- // Sprite size 8x16
- if ( pSPRRAM[ SPR_CHR ] & 1 )
- {
- #ifdef RAM_LACK
- pbyChrData = PPUBANK[ 4 ] + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 4 ) + ((nYBit & 0x8) << 1) + (nYBit & 0x7);
- #else
- pbyChrData = ChrBuf + 256 * 64 + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit;
- #endif /* RAM_LACK */
- }
- else
- {
- #ifdef RAM_LACK
- pbyChrData = PPUBANK[ 0 ] + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 4 ) + ((nYBit & 0x8) << 1) + (nYBit & 0x7);
- #else
- pbyChrData = ChrBuf + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit;
- #endif /* RAM_LACK */
- }
- }
- else
- {
- // Sprite size 8x8
- #ifdef RAM_LACK
- pbyChrData = PPU_SP_Base + ( pSPRRAM[ SPR_CHR ] << 4 ) + nYBit;
- #else
- pbyChrData = PPU_SP_Base + ( pSPRRAM[ SPR_CHR ] << 6 ) + nYBit;
- #endif /* RAM_LACK */
- }
- nAttr ^= SPR_ATTR_PRI;
- bySprCol = ( nAttr & ( SPR_ATTR_COLOR | SPR_ATTR_PRI ) ) << 2;
- nX = pSPRRAM[ SPR_X ];
- #ifdef RAM_LACK
- tileData[0] = ( ( pbyChrData[ 0 ] >> 1 ) & 0x55 ) | ( pbyChrData[ 8 ] & 0xAA );
- tileData[1] = ( pbyChrData[ 0 ] & 0x55 ) | ( ( pbyChrData[ 8 ] << 1 ) & 0xAA );
- #endif /* RAM_LACK */
- if ( nAttr & SPR_ATTR_H_FLIP )
- {
- // Horizontal flip
- #ifdef RAM_LACK
- if ( ( tileData[1] ) & 3 )
- pSprBuf[ nX ] = bySprCol | (( tileData[1] ) & 3);
- if ( ( tileData[0] ) & 3 )
- pSprBuf[ nX + 1 ] = bySprCol | (( tileData[0] ) & 3);
- if ( ( tileData[1] >> 2 ) & 3 )
- pSprBuf[ nX + 2 ] = bySprCol | (( tileData[1] >> 2 ) & 3);
- if ( ( tileData[0] >> 2 ) & 3 )
- pSprBuf[ nX + 3 ] = bySprCol | (( tileData[0] >> 2 ) & 3);
- if ( ( tileData[1] >> 4 ) & 3 )
- pSprBuf[ nX + 4 ] = bySprCol | (( tileData[1] >> 4 ) & 3);
- if ( ( tileData[0] >> 4 ) & 3 )
- pSprBuf[ nX + 5 ] = bySprCol | (( tileData[0] >> 4 ) & 3);
- if ( ( tileData[1] >> 6 ) & 3 )
- pSprBuf[ nX + 6 ] = bySprCol | (( tileData[1] >> 6 ) & 3);
- if ( ( tileData[0] >> 6 ) & 3 )
- pSprBuf[ nX + 7 ] = bySprCol | (( tileData[0] >> 6 ) & 3);
- #else
- if ( pbyChrData[ 7 ] )
- pSprBuf[ nX ] = bySprCol | pbyChrData[ 7 ];
- if ( pbyChrData[ 6 ] )
- pSprBuf[ nX + 1 ] = bySprCol | pbyChrData[ 6 ];
- if ( pbyChrData[ 5 ] )
- pSprBuf[ nX + 2 ] = bySprCol | pbyChrData[ 5 ];
- if ( pbyChrData[ 4 ] )
- pSprBuf[ nX + 3 ] = bySprCol | pbyChrData[ 4 ];
- if ( pbyChrData[ 3 ] )
- pSprBuf[ nX + 4 ] = bySprCol | pbyChrData[ 3 ];
- if ( pbyChrData[ 2 ] )
- pSprBuf[ nX + 5 ] = bySprCol | pbyChrData[ 2 ];
- if ( pbyChrData[ 1 ] )
- pSprBuf[ nX + 6 ] = bySprCol | pbyChrData[ 1 ];
- if ( pbyChrData[ 0 ] )
- pSprBuf[ nX + 7 ] = bySprCol | pbyChrData[ 0 ];
- #endif /* RAM_LACK */
- }
- else
- {
- // Non flip
- #ifdef RAM_LACK
- if ( ( tileData[0] >> 6 ) & 3 )
- pSprBuf[ nX ] = bySprCol | (( tileData[0] >> 6 ) & 3);
- if ( ( tileData[1] >> 6 ) & 3 )
- pSprBuf[ nX + 1 ] = bySprCol | (( tileData[1] >> 6 ) & 3);
- if ( ( tileData[0] >> 4 ) & 3 )
- pSprBuf[ nX + 2 ] = bySprCol | (( tileData[0] >> 4 ) & 3);
- if ( ( tileData[1] >> 4 ) & 3 )
- pSprBuf[ nX + 3 ] = bySprCol | (( tileData[1] >> 4 ) & 3);
- if ( ( tileData[0] >> 2 ) & 3 )
- pSprBuf[ nX + 4 ] = bySprCol | (( tileData[0] >> 2 ) & 3);
- if ( ( tileData[1] >> 2 ) & 3 )
- pSprBuf[ nX + 5 ] = bySprCol | (( tileData[1] >> 2 ) & 3);
- if ( ( tileData[0] ) & 3 )
- pSprBuf[ nX + 6 ] = bySprCol | (( tileData[0] ) & 3);
- if ( ( tileData[1] ) & 3 )
- pSprBuf[ nX + 7 ] = bySprCol | (( tileData[1] ) & 3);
- #else
- if ( pbyChrData[ 0 ] )
- pSprBuf[ nX ] = bySprCol | pbyChrData[ 0 ];
- if ( pbyChrData[ 1 ] )
- pSprBuf[ nX + 1 ] = bySprCol | pbyChrData[ 1 ];
- if ( pbyChrData[ 2 ] )
- pSprBuf[ nX + 2 ] = bySprCol | pbyChrData[ 2 ];
- if ( pbyChrData[ 3 ] )
- pSprBuf[ nX + 3 ] = bySprCol | pbyChrData[ 3 ];
- if ( pbyChrData[ 4 ] )
- pSprBuf[ nX + 4 ] = bySprCol | pbyChrData[ 4 ];
- if ( pbyChrData[ 5 ] )
- pSprBuf[ nX + 5 ] = bySprCol | pbyChrData[ 5 ];
- if ( pbyChrData[ 6 ] )
- pSprBuf[ nX + 6 ] = bySprCol | pbyChrData[ 6 ];
- if ( pbyChrData[ 7 ] )
- pSprBuf[ nX + 7 ] = bySprCol | pbyChrData[ 7 ];
- #endif /* RAM_LACK */
- }
- }
- // Rendering sprite
- pPoint -= ( NES_DISP_WIDTH - PPU_Scr_H_Bit );
- for ( nX = 0; nX < NES_DISP_WIDTH; ++nX )
- {
- nSprData = pSprBuf[ nX ];
- if ( nSprData && ( nSprData & 0x80 || pPoint[ nX ] & 0x8000 ) )
- {
- pPoint[ nX ] = PalTable[ ( nSprData & 0xf ) + 0x10 ];
- }
- }
- /*-------------------------------------------------------------------*/
- /* Sprite Clipping */
- /*-------------------------------------------------------------------*/
- if ( !( PPU_R1 & R1_CLIP_SP ) )
- {
- WORD *pPointTop;
- #if WORKFRAME_DEFINE == WORKFRAME_NONE
- pPointTop = WorkLine;
- #else
- pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
- #endif
- InfoNES_MemorySet( pPointTop, 0, 8 << 1 );
- }
- if ( nSprCnt >= 8 )
- PPU_R2 |= R2_MAX_SP; // Set a flag of maximum sprites on scanline
- }
- }
- /*===================================================================*/
- /* */
- /* InfoNES_GetSprHitY() : Get a position of scanline hits sprite #0 */
- /* */
- /*===================================================================*/
- void InfoNES_GetSprHitY()
- {
- /*
- * Get a position of scanline hits sprite #0
- *
- */
- int nYBit;
- int nLine;
- #ifdef RAM_LACK
- BYTE *pbyChrData;
- #else
- DWORD *pdwChrData;
- #endif
- int nOff;
- if ( SPRRAM[ SPR_ATTR ] & SPR_ATTR_V_FLIP )
- {
- // Vertical flip
- nYBit = ( PPU_SP_Height - 1 );
- #ifdef RAM_LACK
- nOff = -1;
- #else
- nYBit <<= 3;
- nOff = -2;
- #endif /* RAM_LACK */
- }
- else
- {
- // Non flip
- nYBit = 0;
- #ifdef RAM_LACK
- nOff = 1;
- #else
- nOff = 2;
- #endif /* RAM_LACK */
- }
- if ( PPU_R0 & R0_SP_SIZE )
- {
- // Sprite size 8x16
- if ( SPRRAM[ SPR_CHR ] & 1 )
- {
- #ifdef RAM_LACK
- pbyChrData = ( PPUBANK[ 4 ] + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 4 ) + ((nYBit & 0x8) << 1) + (nYBit & 0x7) );
- #else
- pdwChrData = (DWORD *)( ChrBuf + 256 * 64 + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit );
- #endif /* RAM_LACK */
- }
- else
- {
- #ifdef RAM_LACK
- pbyChrData = ( PPUBANK[ 0 ] + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 4 ) + ((nYBit & 0x8) << 1) + (nYBit & 0x7) );
- #else
- pdwChrData = (DWORD * )( ChrBuf + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit );
- #endif /* RAM_LACK */
- }
- }
- else
- {
- // Sprite size 8x8
- #ifdef RAM_LACK
- pbyChrData = ( PPU_SP_Base + ( SPRRAM[ SPR_CHR ] << 4 ) + nYBit );
- #else
- pdwChrData = (DWORD *)( PPU_SP_Base + ( SPRRAM[ SPR_CHR ] << 6 ) + nYBit );
- #endif /* RAM_LACK */
- }
- if ( ( SPRRAM[ SPR_Y ] + 1 <= SCAN_UNKNOWN_START ) && ( SPRRAM[SPR_Y] > 0 ) )
- {
- for ( nLine = 0; nLine < PPU_SP_Height; nLine++ )
- {
- #ifdef RAM_LACK
- if ( pbyChrData[ 0 ] | pbyChrData[ 8 ] )
- #else
- if ( pdwChrData[ 0 ] | pdwChrData[ 1 ] )
- #endif /* RAM_LACK */
- {
- // Scanline hits sprite #0
- SpriteJustHit = SPRRAM[SPR_Y] + 1 + nLine;
- nLine = SCAN_VBLANK_END;
- }
- #ifdef RAM_LACK
- if( nLine == 7)
- {
- pbyChrData += nOff * 9;
- }
- else
- {
- pbyChrData += nOff;
- }
- #else
- pdwChrData += nOff;
- #endif /* RAM_LACK */
- }
- } else {
- // Scanline didn't hit sprite #0
- SpriteJustHit = SCAN_UNKNOWN_START + 1;
- }
- }
复制代码需要解释的是,我也是参照之前原有的处理调整成这个样的,也许不免会有Bug,比如我刚刚还修改了一处不细心导致的问题。
与此同时,有一处临时修改现在需要更正,那就是InfoNES_Mapper.h的60行,修改成: - #define PATTBL(a) ( (a) - PPUBANK[ 0 ] )
复制代码基本上有了这些,模拟器就算是完工咯。
以上就是这次移植的主要工作了。
最后不要忘记调整堆栈的大小,我就是忘了调整大小了,结果马里奥大叔都穿墙跑啦……而且还不容易发现错误在哪。
什么?有童鞋说跑得很慢?第一,请开启编译优化,建议试试速度优化O3;第二,InfoNES里有个叫FrameSkip的变量,嘿嘿……
对了,似乎这样还不能控制哪,怎么处理手柄消息呢?还记得接口函数中有个: - /* Get a joypad state */
- void InfoNES_PadState( DWORD *pdwPad1, DWORD
- *pdwPad2, DWORD *pdwSystem )
- {
- }
复制代码在这里给pdwPad1和pdwPad2赋值就OK了。
具体怎么赋值?可能可以参考下图吧,我不再继续研究啦。
最后是LM4F232板上可以运行的最终工程(不能控制):
InfoNES097JRC1_SDL.7z
(1.27 MB, 下载次数: 102)
另外,这InfoNES,据我仔细观察,也不是百试百灵的,好像沙罗曼蛇玩着就非常不正常。
不过能在我的80MHz的小板上跑马里奥大叔,我也是非常欣慰了。
|
|