[原创] 【试用心得】外传——《手把手教你移植InfoNES(到HANKER-LM4F232)》更新至20131020

sjtitr   2013-10-20 20:26 楼主
未完待续……更新至2013.10.20 - 20:26 温馨提示,本文中每个部分涉及到的工程包括源文件,都可以在本文的最后发现下载链接哟! 由于最近身体不适,移植进度有点慢了,前面的帖子不能再更新了,所以没办法,我们新开一贴继续研究。 续前篇:https://bbs.eeworld.com.cn/thread-415692-1-1.html 有童鞋问了,神马是InfNES?这是一款NES游戏模拟器,也就是任天堂的红白机,80后的童年……InfoNES可以很容易地被移植到各个平台,可以说各大开发论坛上都可见它的身影。 如果你是有关技术的老鸟,那不好意思你可能什么都学不到了,更可能会发现本文的诸多错误,阅读本文只会让你更多地浪费生命,对此我十分抱歉。 好吧,节目继续。 第四部分是让我们的程序在板子上运行起来 不得不说,这一部分才是最难最艰难的工作,以至于我们又得被学习很多知识了。 上回说,尽管成功编译通过了,可是根本没法运行,最重要的原因就是上文中的最后一步,我们“主观”上增大了内存容量……实际上如果在你们的板子上,内存足够的情况下,可能根本不需要增加,也不会出现最后一步的问题,也就是说——你们已经可以运行这个模拟器了!那么你可以暂且告别这一部分,直接跨越到下一个部分去。 然而对于大多数持有工控级学习(开发)板而又想跑模拟器的童鞋来说,InfoNES在RAM方面的胃口实在是太大太大。特别说明一下,我们这次以HANKER-LM4F232为例来讨论InfoNES的移植,这块板子的片上RAM有32K……所以就以这个数量作为我们的第一个目标—— 目标1:RAM耗用量32K以内! 当然了,我们首先看看它现在吃掉了多少内存…… 在工程空间里这样双击目标名(Target 1), 工作空间 在编辑区打开的有关信息,我们来看最后面(Ctrl+End):
  1. Total RO Size (Code + RO Data) 150996 ( 147.46kB)
  2. Total RW Size (RW Data + ZI Data) 617336 ( 602.87kB)
  3. Total ROM Size (Code + RO Data + RW Data) 151796 ( 148.24kB)
所以我们总的RAM占用量应当是中间那行……羊了个驼!怎么这么大? 好吧,我暂时也不清楚是否真的能完成这个任务,总之硬着头皮搞吧。602.87K->32K,恩,看起来似乎问题不大,呵呵呵呵……有一种技能叫做不折手断!看来真得敲代码敲到手断啊。 步骤一,仍然是刚才的有关信息,我们找到“Global Symbols”这一章节。以下列举了有关全局符号的信息,我可以简单的把全局符号解释成函数和全局变量么? 根据我们之前的内容,我们可以知道RAM是从0x20000000开始的,所以直接找到这里…… 工程编译信息 注意到其中有个24,那里就是占用的大小啦,我们顺势往下找找看,到底谁占的多?
  1. WorkFrame 0x20008c20 Data 122880 infones.o(.bss)
……这是谁家的代码,怎么这么吃RAM? 分析了代码以后得知,这个是绘图的缓冲区,是以一屏画面为单位的。因为NES的画面大小为256*240,每个点在这里用2个字节来表示,所以占用RAM为2*256*240=???再根据程序流程,每个画面的内容组织完毕,再统一调用
  1. /* Transfer the contents of work frame on the screen */
  2. void
  3. InfoNES_LoadFrame()
  4. {
  5. }
这样把画面描绘在屏幕上。 InfoNES在工作时,实际上是以行为单位的,每个工作周期描画画面的一行,并执行这一行时间内的程序。整个画面执行的行数为262(大概这个数吧,记不太清了,如有错误请各位指出哈,不过这里应当暂不影响移植),其中240行是描绘出真实像素点的。我们大可以把工作过程改为,每画完一行,就调用InfoNES_LoadLine()来描画这一行像素到屏幕上。这样,这122880Byte的RAM就可以缩减到2*256=512Byte,岂不是很美…… 同样滴,变更要有可移植性。另外在代码中发现InfoNES是支持双缓冲绘图的(有点理解不能啊童鞋们……),既然这样,我们把这个地方统一成一个设置显示描画的方式吧(双缓、单缓、单行)。 增加我们的设置内容
  1. /*-------------------------------------------------------------------*/

  2. /* Config */
  3. /*-------------------------------------------------------------------*/
  4. #define WORKFRAME_DOUBLE 2
  5. #define WORKFRAME_SINGLE 1
  6. #define WORKFRAME_NONE 0
  7. #define WORKFRAME_DEFINE WORKFRAME_NONE
  8. #define APU_NONE

具体代码变更详见1楼回复。 变更之后再编译看看,RAM用量是不是少了不少呀?
  1. Total RW Size (RW Data + ZI Data) 494968 ( 483.37kB)
接下来比较大的RAM占用还有谁呢?
  1. Map85_Chr_Ram 0x20035ae0 Data 262144 infones_mapper.o(.bss)
像这种大小是无论如何也不行的,所以我们暂时把Mapper85从我们的程序中取缔吧…… 方法就是: 在InfoNES_Mapper.cpp中注掉如下的两行:
  1. // { 85, Map85_Init },
  1. // #include "mapper/InfoNES_Mapper_085.cpp"
以后每次想取缔某个mapper,就使用这个办法就OK,所以之后我就不再赘述,直接说取缔那个mapper啦。 值得一提的是,之后我们需要整理更具体的资源,所以相关代码的位置我会重新整理,然后上传成整理资源后的工程,大家可以参考调整。 之后再看还有谁吃掉的RAM比较大?
  1. RAM 0x200009cc Data 8192 infones.o(.bss)
  2. SRAM 0x200029cc Data 8192 infones.o(.bss)
  3. PPURAM 0x200049cc Data 16384 infones.o(.bss)
  4. PPUBANK 0x200089cc Data 64 infones.o(.bss)
  5. SPRRAM 0x20008a0c Data 256 infones.o(.bss)
  6. PPU_ScanTable 0x20008b0c Data 263 infones.o(.bss)
  7. WorkLine 0x20008c14 Data 512 infones.o(.bss)
  8. ChrBuf 0x20008e14 Data 32768 infones.o(.bss)
  9. PalTable 0x20010e14 Data 64 infones.o(.bss)
  10. NesHeader 0x20010e54 Data 16 infones.o(.bss)
  11. DRAM 0x20010e64 Data 40960 infones_mapper.o(.bss)
  12. Map5_Wram 0x2001ae64 Data 65536 infones_mapper.o(.bss)
  13. Map5_Ex_Ram 0x2002ae64 Data 1024 infones_mapper.o(.bss)
  14. Map5_Ex_Vram 0x2002b264 Data 1024 infones_mapper.o(.bss)
  15. Map5_Ex_Nam 0x2002b664 Data 1024 infones_mapper.o(.bss)
  16. Map5_Chr_Reg 0x2002ba64 Data 16 infones_mapper.o(.bss)
  17. Map6_Chr_Ram 0x2002ba74 Data 32768 infones_mapper.o(.bss)
  18. Map18_Regs 0x20033a74 Data 11 infones_mapper.o(.bss)
  19. Map19_Chr_Ram 0x20033a7f Data 8192 infones_mapper.o(.bss)
  20. Map21_Regs 0x20035a7f Data 10 infones_mapper.o(.bss)
  21. Map23_Regs 0x20035a89 Data 9 infones_mapper.o(.bss)
  22. Map25_VBank 0x20035a92 Data 16 infones_mapper.o(.bss)
  23. Map45_P 0x20035aa4 Data 16 infones_mapper.o(.bss)
  24. Map45_C 0x20035ab4 Data 32 infones_mapper.o(.bss)
  25. Map185_Dummy_Chr_Rom 0x20035ad4 Data 1024 infones_mapper.o(.bss)
  26. Map187_Chr 0x20035ed4 Data 32 infones_mapper.o(.bss)
  27. Map188_Dummy 0x20035ef4 Data 8192 infones_mapper.o(.bss)
  28. Map251_Reg 0x20037ef4 Data 11 infones_mapper.o(.bss)
  29. Map252_Reg 0x20037eff Data 9 infones_mapper.o(.bss)
看看这些啊……都这么大~情不自禁地我就想说:那几个大的mapper取缔了吧! 从上面捋,它们怎么办? 欲知后文请继续围观。 [ 本帖最后由 sjtitr 于 2013-10-21 07:17 编辑 ]

回复评论 (4)

回复 关于屏幕显示变更的变更代码

InfoNES_System.h
40-41
  1. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  2. /* Transfer the contents of work line on the screen */
  3. void InfoNES_LoadLine(void);
  4. #else
  5. /* Transfer the
  6. contents of work frame on the screen */
  7. void InfoNES_LoadFrame(void);
  8. #endif
InfoNES.h
197-203
  1. #if WORKFRAME_DEFINE == WORKFRAME_DOUBLE
  2. extern WORD DoubleFrame[ 2 ][ NES_DISP_WIDTH * NES_DISP_HEIGHT ];
  3. extern WORD *WorkFrame;
  4. extern WORD WorkFrameIdx;
  5. #elif WORKFRAME_DEFINE == WORKFRAME_SINGLE
  6. extern WORD WorkFrame[ NES_DISP_WIDTH * NES_DISP_HEIGHT ];
  7. #else
  8. extern WORD WorkLine[ NES_DISP_WIDTH ];
  9. #endif
InfoNES.cpp
160-166
  1. #if WORKFRAME_DEFINE == WORKFRAME_DOUBLE
  2.   WORD DoubleFrame[ 2 ][ NES_DISP_WIDTH * NES_DISP_HEIGHT ];
  3.   WORD *WorkFrame;
  4.   WORD WorkFrameIdx;
  5. #elif WORKFRAME_DEFINE == WORKFRAME_SINGLE
  6.   WORD WorkFrame[ NES_DISP_WIDTH * NES_DISP_HEIGHT ];
  7. #else
  8.   WORD WorkLine[ NES_DISP_WIDTH ];
  9. #endif
403-407
  1. #if WORKFRAME_DEFINE == WORKFRAME_DOUBLE
  2.   // Reset work frame
  3.   WorkFrame = DoubleFrame[ 0 ];
  4.   WorkFrameIdx = 0;
  5. #endif
685
  1.     InfoNES_DrawLine();
  2. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  3. // Render a scanline to screen
  4. InfoNES_LoadLine();
  5. #endif  
728-735
  1. #if WORKFRAME_DEFINE != WORKFRAME_NONE
  2.         // Transfer the contents of work frame on the screen
  3.         InfoNES_LoadFrame();
  4. #if WORKFRAME_DEFINE == WORKFRAME_DOUBLE
  5.         // Switching of the double buffer
  6.         WorkFrameIdx = 1 - WorkFrameIdx;//我不会告诉你如果是0和1反复变换可能使用异或会比较快,此处为原代码,暂不更改
  7.         WorkFrame = DoubleFrame[ WorkFrameIdx ];
  8. #endif
  9. #endif
815
  1. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  2.   pPoint = WorkLine;
  3. #else
  4.   pPoint = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
  5. #endif
949
  1. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  2.    pPointTop = WorkLine;
  3. #else
  4.    pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
  5. #endif
965
  1. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  2.    pPointTop = WorkLine;
  3. #else
  4.    pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
  5. #endif
1090
  1. #if WORKFRAME_DEFINE == WORKFRAME_NONE
  2.    pPointTop = WorkLine;
  3. #else
  4.    pPointTop = &WorkFrame[ PPU_Scanline * NES_DISP_WIDTH ];
  5. #endif
最后不要忘记在我们的InfoNES_system.c中增加一个函数:
  1. /* Transfer the contents of work line on the screen */
  2. void InfoNES_LoadLine()
  3. {
  4. }
所以之前写过的InfoNES_LoadFrame可能将来就用不到了。

[ 本帖最后由 sjtitr 于 2013-10-21 06:28 编辑 ]
点赞  2013-10-20 20:27
哇 很给力  赞
加油!在电子行业默默贡献自己的力量!:)
点赞  2013-10-21 10:48
InfoNES_Mapper.h
最上面
  1. /*-------------------------------------------------------------------*/
  2. /*  Constants                                                        */
  3. /*-------------------------------------------------------------------*/

  4. #ifdef RAM_LACK
  5. #define DRAM_SIZE    0x0001  
  6. #define CRAM_SIZE    0x2000  
  7. #else
  8. #define DRAM_SIZE    0xA000
  9. #endif /* RAM_LACK */

  10. /*-------------------------------------------------------------------*/
  11. /*  Mapper resources                                                 */
  12. /*-------------------------------------------------------------------*/
  13. /* Disk System RAM */
  14. extern BYTE DRAM[];
  15.   
  16. #ifdef RAM_LACK
  17. extern BYTE CRAM[];
  18. #endif

  19. /*-------------------------------------------------------------------*/
  20. /*  Macros                                                           */
  21. /*-------------------------------------------------------------------*/

  22. /* The address of 8Kbytes unit of the ROM */
  23. #define ROMPAGE(a)     &ROM[ (a) * 0x2000 ]
  24. /* From behind the ROM, the address of 8kbytes unit */
  25. #define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ]
  26. /* The address of 1Kbytes unit of the VROM */
  27. #define VROMPAGE(a)    &VROM[ (a) * 0x400 ]

  28. #ifdef RAM_LACK
  29. /* The address of 1Kbytes unit of the CRAM */
  30. #define CRAMPAGE(a)   &CRAM[ (a) * 0x400 ]
  31. /* The address of 1Kbytes unit of the VRAM */
  32. #define VRAMPAGE(a)    &VRAM[ (a) * 0x400 ]
  33. /* Translate the pointer to ChrBuf into the address of Pattern Table */
  34. #define PATTBL(a)      ( ( (a) - ChrBuf ) >> 2 )
  35. #else
  36. /* The address of 1Kbytes unit of the CRAM */
  37. #define CRAMPAGE(a)   &PPURAM[ 0x0000 + ((a)&0x1F) * 0x400 ]
  38. /* The address of 1Kbytes unit of the VRAM */
  39. #define VRAMPAGE(a)    &PPURAM[ 0x2000 + (a) * 0x400 ]
  40. /* Translate the pointer to ChrBuf into the address of Pattern Table */
  41. #define PATTBL(a)      ( ( (a) - ChrBuf ) >> 2 )
  42. #endif
InfoNES_Mapper.cpp
最上面
  1. /*-------------------------------------------------------------------*/
  2. /*  Mapper resources                                                 */
  3. /*-------------------------------------------------------------------*/
  4. //* Disk System RAM */
  5. BYTE DRAM[ DRAM_SIZE ];
  6.   
  7. #ifdef RAM_LACK
  8. BYTE CRAM[ CRAM_SIZE ];
  9. #endif
  10.   
InfoNES.h
26-28
  1. #ifdef RAM_LACK
  2. #define RAM_SIZE     0x800
  3. #define VRAM_SIZE    0x800
  4. #else
  5. #define RAM_SIZE     0x2000
  6. #define PPURAM_SIZE  0x4000
  7. #endif
  8. #define SRAM_SIZE    0x2000
59-60
  1. #ifdef RAM_LACK
  2. /* PPU VRAM */
  3. extern BYTE VRAM[];
  4. #else
  5. /* PPU RAM */
  6. extern BYTE PPURAM[];
  7. #endif
InfoNES.cpp
73-74
  1. #ifdef RAM_LACK
  2. /* PPU VRAM */
  3. BYTE VRAM[ VRAM_SIZE ];
  4. #else
  5. /* PPU RAM */
  6. BYTE PPURAM[ PPURAM_SIZE ];
  7. #endif
187-192
  1. #ifdef RAM_LACK
  2.   { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3 },
  3.   { NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3 },
  4.   { NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3 },
  5.   { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3 },
  6.   { NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE2 & 0x3, NAME_TABLE3 & 0x3 },
  7.   { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3 }
  8. #else
  9.   { NAME_TABLE0, NAME_TABLE0, NAME_TABLE1, NAME_TABLE1 },
  10.   { NAME_TABLE0, NAME_TABLE1, NAME_TABLE0, NAME_TABLE1 },
  11.   { NAME_TABLE1, NAME_TABLE1, NAME_TABLE1, NAME_TABLE1 },
  12.   { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE0 },
  13.   { NAME_TABLE0, NAME_TABLE1, NAME_TABLE2, NAME_TABLE3 },
  14.   { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE1 }
  15. #endif
474
  1. #ifdef RAM_LACK
  2.   InfoNES_MemorySet( CRAM, 0, CRAM_SIZE );
  3.   InfoNES_MemorySet( VRAM, 0, VRAM_SIZE );
  4. #else
  5.   InfoNES_MemorySet( PPURAM, 0, sizeof PPURAM );
  6. #endif
516-517
  1. #ifdef RAM_LACK
  2.   for ( nPage = 0; nPage < 8; ++nPage )
  3.     PPUBANK[ nPage ] = CRAMPAGE( nPage );
  4.   for ( nPage = 8; nPage < 12; ++nPage )
  5.     PPUBANK[ nPage ] = VRAMPAGE( nPage & 0x3 );
  6. #else
  7.   for ( nPage = 0; nPage < 16; ++nPage )
  8.     PPUBANK[ nPage ] = &PPURAM[ nPage * 0x400 ];
  9. #endif
553-557
  1. #ifdef RAM_LACK
  2.   PPUBANK[ NAME_TABLE0 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 0 ] );
  3.   PPUBANK[ NAME_TABLE1 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 1 ] );
  4.   PPUBANK[ NAME_TABLE2 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 2 ] );
  5.   PPUBANK[ NAME_TABLE3 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 3 ] );
  6. #else
  7.   PPUBANK[ NAME_TABLE0 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 0 ] * 0x400 ];
  8.   PPUBANK[ NAME_TABLE1 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 1 ] * 0x400 ];
  9.   PPUBANK[ NAME_TABLE2 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 2 ] * 0x400 ];
  10.   PPUBANK[ NAME_TABLE3 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 3 ] * 0x400 ];
  11. #endif
K6502_rw.h
352-355
  1. #ifndef RAM_LACK
  2.               PPURAM[ 0x3f10 ] = PPURAM[ 0x3f14 ] = PPURAM[ 0x3f18 ] = PPURAM[ 0x3f1c ] =
  3.               PPURAM[ 0x3f00 ] = PPURAM[ 0x3f04 ] = PPURAM[ 0x3f08 ] = PPURAM[ 0x3f0c ] = byData;
  4. #endif
  5.               PalTable[ 0x00 ] = PalTable[ 0x04 ] = PalTable[ 0x08 ] = PalTable[ 0x0c ] =
  6.               PalTable[ 0x10 ] = PalTable[ 0x14 ] = PalTable[ 0x18 ] = PalTable[ 0x1c ] = NesPalette[ byData ];
363
  1. #ifndef RAM_LACK
  2.               PPURAM[ addr ] = byData;
  3. #endif
点赞  2013-10-22 19:43
K6502_rw.h
243-244
  1. #ifdef RAM_LACK
  2.           PPU_BG_Base = ( PPU_R0 & R0_BG_ADDR ) ? PPUBANK[ 4 ] : PPUBANK[ 0 ];
  3.           PPU_SP_Base = ( PPU_R0 & R0_SP_ADDR ) ? PPUBANK[ 4 ] : PPUBANK[ 0 ];
  4. #else
  5.           PPU_BG_Base = ( PPU_R0 & R0_BG_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
  6.           PPU_SP_Base = ( PPU_R0 & R0_SP_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
  7. #endif /* RAM_LACK */
343
  1. #ifndef RAM_LACK
  2.               ChrBufUpdate |= ( 1 << ( addr >> 10 ) );
  3. #endif /* !RAM_LACK */
InfoNES_Mapper.h
60
  1. #define PATTBL(a)      ( ( (a)  ) >> 2 )
InfoNES.h
218-220
  1. #ifndef RAM_LACK
  2. extern BYTE ChrBuf[];
  3. extern BYTE ChrBufUpdate;
  4. #endif /* !RAM_LACK */
314-315
  1. #ifdef RAM_LACK
  2. #define InfoNES_SetupChr() {}
  3. #else
  4. /* Develop character data */
  5. void InfoNES_SetupChr(void);
  6. #endif /* RAM_LACK */
InfoNES.cpp
175-179
  1. #ifndef RAM_LACK
  2. /* Character Buffer */
  3. BYTE ChrBuf[ 256 * 2 * 8 * 8 ];
  4. /* Update flag for ChrBuf */
  5. BYTE ChrBufUpdate;
  6. #endif /* !RAM_LACK */
402
  1. #ifndef RAM_LACK
  2.   // Reset update flag of ChrBuf
  3.   ChrBufUpdate = 0xff;
  4. #endif /* !RAM_LACK */
514-515
  1. #ifdef RAM_LACK
  2.   PPU_BG_Base = PPUBANK[ 0 ];
  3.   PPU_SP_Base = PPUBANK[ 4 ];
  4. #else
  5.   PPU_BG_Base = ChrBuf;
  6.   PPU_SP_Base = ChrBuf + 256 * 64;
  7. #endif /* RAM_LACK */
799
InfoNES_DrawLine函数里面全部注掉

1125
InfoNES_GetSprHitY函数里面全部注掉

1185
InfoNES_SetupChr函数从外面使用RAM_LACK宏开关关闭
点赞  2013-10-22 19:46
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复