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

sjtitr   2013-10-22 20:07 楼主
未完待续……更新至2013.10.22 - 20:07
温馨提示,本文中每个部分涉及到的工程包括源文件,都可以在本文的最后发现下载链接哟!
太可恶了,突然间又设置了神马审核,说不能编辑已经通过审核的帖子,你不让我编辑你倒是别让我编辑啊,还能编辑,一提交说不行请返回,一返回啥都没了……
太可恶了,我们新开一贴继续研究。

续前篇:https://bbs.eeworld.com.cn/thread-416564-1-1.html

有童鞋问了,神马是InfNES?这是一款NES游戏模拟器,也就是任天堂的红白机,80后的童年……InfoNES可以很容易地被移植到各个平台,可以说各大开发论坛上都可见它的身影。
如果你是有关技术的老鸟,那不好意思你可能什么都学不到了,更可能会发现本文的诸多错误,阅读本文只会让你更多地浪费生命,对此我十分抱歉。

好吧,节目继续。

第四部分是让我们的程序在板子上运行起来

看还有谁吃掉的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)
那个叫DRAM的家伙那么大,查查它是哪来的?全局搜索的结果表明,这个东西只在mapper235中使用了,用以模拟软磁盘,那还用说,取缔!并且把定义DRAM大小的DRAM_SIZE临时变更为1。由于是我们的RAM太少了,所以这里仍然用编译开关吧,又增加设置项啦:

  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 RAM_LACK  
  9. #define APU_NONE

  1. #ifdef RAM_LACK
  2. #define DRAM_SIZE    0x0001  
  3. #else
  4. #define DRAM_SIZE    0xA000
  5. #endif /* RAM_LACK */
然后从最上面开始看:

RAM是用来模拟NES中的主内存的,实际上,这个主内存实际大小只有0x0-0x7ff,而它的地址范围是0x0-0x1fff,0x800-0x1fff都是反复映射到0x0-0x7ff,所以这里我们可以进行调整:把RAM定义为RAM[0x800],然后工程内全局搜索,把对它的访问都写成RAM[ Address & 0x7FF ]。

SRAM暂时来看没法省,它代表卡带当中带有的内存。

PPURAM应该可以省下一些。PPURAM是PPU(相当于我们今天的GPU,显卡芯片)中的存储空间,其中不光是RAM,可能还有卡带当中的RAM,具体的讲,最前面的8K,我称它为马赛克区(童鞋们需要清除,NES游戏中,画面全是由一块块的马赛克拼接而成的),其中一共有512个马赛克,之后的8K空间,就是画板空间,和RAM同样滴,实际上只有2K,被映射为8K。在这里调整的时候,我比较主张将这两部分分开定义,CRAM和VRAM,原因我不多解释,大家慢慢体会(其实没什么关系吧?)。这样的话,仍然全局搜索,把所有对PPURAM的访问都改为CRAM或者VRAM。

由于运行的需要,我们可以发现在InfoNES_Mapper.h中:

  1. /* The address of 8Kbytes unit of the ROM */
  2. #define ROMPAGE(a)     &ROM[ (a) * 0x2000 ]
  3. /* From behind the ROM, the address of 8kbytes unit */
  4. #define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ]
  5. /* The address of 1Kbytes unit of the VROM */
  6. #define VROMPAGE(a)    &VROM[ (a) * 0x400 ]
  7. /* The address of 1Kbytes unit of the CRAM */
  8. #define CRAMPAGE(a)   &PPURAM[ 0x0000 + ((a)&0x1F) * 0x400 ]
  9. /* The address of 1Kbytes unit of the VRAM */
  10. #define VRAMPAGE(a)    &PPURAM[ 0x2000 + (a) * 0x400 ]
  11. /* Translate the pointer to ChrBuf into the address of Pattern Table */
  12. #define PATTBL(a)      ( ( (a) - ChrBuf ) >> 2 )
关于ROM和RAM的访问都经过了单元映射。

等等,里面怎么有个VROM?哦……卡带当中的ROM可能会被映射为马赛克区,这种情况下CRAM可能就没有用了,可以理解为CRAM是比较高级一些的卡带才有的东西,它们的马赛克是动态生成的,这样比用ROM的好处就是,马赛克数量可以大于512个,想用哪个就放在马赛克表里。

另外关于ROM,因为我们内存比较小,所以ROM不能用加载到内存的方式了,而只能在Flash中使用,也就是const数组。好吧,我们连InfoNES_ReadRom都不需要了吧……NO,应该还是要的,因为要把ROM定义在各种单元映射上,这个过程还是要得的。

PPUBANK定义着和VROM、CRAM、VRAM的映射关系。

详细的内容比较多了,所有这些,我统统定义为RAM_LACK引起的调整,于是都用到这个编译开关,详细内容统统参见我下面的代码吧,大部分童鞋直接用我的代码应该就可以了。

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
改完代码,编译!
  1.     Total RW  Size (RW Data + ZI Data)             61696 (  60.25kB)
还差不到30K,事实上,如果你的板子RAM有64K,那么可以在进行些许调整就可以运行了,这一部分的剩下内容可以略过。
对于我来说,目标既然是32K,那就要继续到底。

注意到有一个32K的家伙还在RAM中:ChrBuf。这个东西是最麻烦的,我们把它放在下一个部分里再解决。目前,把和它相关的所有内容屏蔽就好。
当然,在我提供的有关代码中,可不只屏蔽这样简单,有些修改是有根据的,不明之处请垂询。

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宏开关关闭

最后结果:
  1.     Total RW  Size (RW Data + ZI Data)             28896 (  28.22kB)
28.22K!

并且看到Map185_Dummy_Chr_Rom占用了1K,随时可以通过取缔它来释放这1K,暂时就算任务达成吧。

把之前增大的RAM设置修改回原有的32K,本部分完工!
之后再写代码,就要小心RAM了。

欲知后文请继续围观。

第四部分资源
1 RAM用量控制在60K:
prj20131022-60K.7z (117.1 KB)
(下载次数: 45, 2013-10-22 20:07 上传)

2 RAM用量控制在30K:
prj20131022-30K.7z (117.16 KB)
(下载次数: 33, 2013-10-22 20:07 上传)

回复评论 (1)

楼主,好厉害,学习了
点赞  2016-9-19 20:45
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复