未完待续……更新至2013.10.22 - 20:07
温馨提示,本文中每个部分涉及到的工程包括源文件,都可以在本文的最后发现下载链接哟!
太可恶了,突然间又设置了神马审核,说不能编辑已经通过审核的帖子,你不让我编辑你倒是别让我编辑啊,还能编辑,一提交说不行请返回,一返回啥都没了……
太可恶了,我们新开一贴继续研究。
续前篇:
https://bbs.eeworld.com.cn/thread-416564-1-1.html
有童鞋问了,神马是InfNES?
这是一款NES游戏模拟器,也就是任天堂的红白机,80后的童年……InfoNES可以很容易地被移植到各个平台,可以说各大开发论坛上都可见它的身影。
如果你是有关技术的老鸟,那不好意思你可能什么都学不到了,更可能会发现本文的诸多错误,阅读本文只会让你更多地浪费生命,对此我十分抱歉。
好吧,节目继续。
第四部分是让我们的程序在板子上运行起来
看还有谁吃掉的RAM比较大?
- RAM 0x200009cc Data 8192 infones.o(.bss)
- SRAM 0x200029cc Data 8192 infones.o(.bss)
- PPURAM 0x200049cc Data 16384 infones.o(.bss)
- PPUBANK 0x200089cc Data 64 infones.o(.bss)
- SPRRAM 0x20008a0c Data 256 infones.o(.bss)
- PPU_ScanTable 0x20008b0c Data 263 infones.o(.bss)
- WorkLine 0x20008c14 Data 512 infones.o(.bss)
- ChrBuf 0x20008e14 Data 32768 infones.o(.bss)
- PalTable 0x20010e14 Data 64 infones.o(.bss)
- NesHeader 0x20010e54 Data 16 infones.o(.bss)
- DRAM 0x20010e64 Data 40960 infones_mapper.o(.bss)
- Map5_Wram 0x2001ae64 Data 65536 infones_mapper.o(.bss)
- Map5_Ex_Ram 0x2002ae64 Data 1024 infones_mapper.o(.bss)
- Map5_Ex_Vram 0x2002b264 Data 1024 infones_mapper.o(.bss)
- Map5_Ex_Nam 0x2002b664 Data 1024 infones_mapper.o(.bss)
- Map5_Chr_Reg 0x2002ba64 Data 16 infones_mapper.o(.bss)
- Map6_Chr_Ram 0x2002ba74 Data 32768 infones_mapper.o(.bss)
- Map18_Regs 0x20033a74 Data 11 infones_mapper.o(.bss)
- Map19_Chr_Ram 0x20033a7f Data 8192 infones_mapper.o(.bss)
- Map21_Regs 0x20035a7f Data 10 infones_mapper.o(.bss)
- Map23_Regs 0x20035a89 Data 9 infones_mapper.o(.bss)
- Map25_VBank 0x20035a92 Data 16 infones_mapper.o(.bss)
- Map45_P 0x20035aa4 Data 16 infones_mapper.o(.bss)
- Map45_C 0x20035ab4 Data 32 infones_mapper.o(.bss)
- Map185_Dummy_Chr_Rom 0x20035ad4 Data 1024 infones_mapper.o(.bss)
- Map187_Chr 0x20035ed4 Data 32 infones_mapper.o(.bss)
- Map188_Dummy 0x20035ef4 Data 8192 infones_mapper.o(.bss)
- Map251_Reg 0x20037ef4 Data 11 infones_mapper.o(.bss)
- Map252_Reg 0x20037eff Data 9 infones_mapper.o(.bss)
那个叫DRAM的家伙那么大,查查它是哪来的?全局搜索的结果表明,这个东西只在mapper235中使用了,用以模拟软磁盘,那还用说,取缔!并且把定义DRAM大小的DRAM_SIZE临时变更为1。由于是我们的RAM太少了,所以这里仍然用编译开关吧,又增加设置项啦:
- /*-------------------------------------------------------------------*/
- /* Config */
- /*-------------------------------------------------------------------*/
- #define WORKFRAME_DOUBLE 2
- #define WORKFRAME_SINGLE 1
- #define WORKFRAME_NONE 0
- #define WORKFRAME_DEFINE WORKFRAME_NONE
- #define RAM_LACK
- #define APU_NONE
- #ifdef RAM_LACK
- #define DRAM_SIZE 0x0001
- #else
- #define DRAM_SIZE 0xA000
- #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中:
- /* The address of 8Kbytes unit of the ROM */
- #define ROMPAGE(a) &ROM[ (a) * 0x2000 ]
- /* From behind the ROM, the address of 8kbytes unit */
- #define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ]
- /* The address of 1Kbytes unit of the VROM */
- #define VROMPAGE(a) &VROM[ (a) * 0x400 ]
- /* The address of 1Kbytes unit of the CRAM */
- #define CRAMPAGE(a) &PPURAM[ 0x0000 + ((a)&0x1F) * 0x400 ]
- /* The address of 1Kbytes unit of the VRAM */
- #define VRAMPAGE(a) &PPURAM[ 0x2000 + (a) * 0x400 ]
- /* Translate the pointer to ChrBuf into the address of Pattern Table */
- #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
最上面
- /*-------------------------------------------------------------------*/
- /* Constants */
- /*-------------------------------------------------------------------*/
- #ifdef RAM_LACK
- #define DRAM_SIZE 0x0001
- #define CRAM_SIZE 0x2000
- #else
- #define DRAM_SIZE 0xA000
- #endif /* RAM_LACK */
- /*-------------------------------------------------------------------*/
- /* Mapper resources */
- /*-------------------------------------------------------------------*/
- /* Disk System RAM */
- extern BYTE DRAM[];
-
- #ifdef RAM_LACK
- extern BYTE CRAM[];
- #endif
- /*-------------------------------------------------------------------*/
- /* Macros */
- /*-------------------------------------------------------------------*/
- /* The address of 8Kbytes unit of the ROM */
- #define ROMPAGE(a) &ROM[ (a) * 0x2000 ]
- /* From behind the ROM, the address of 8kbytes unit */
- #define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ]
- /* The address of 1Kbytes unit of the VROM */
- #define VROMPAGE(a) &VROM[ (a) * 0x400 ]
- #ifdef RAM_LACK
- /* The address of 1Kbytes unit of the CRAM */
- #define CRAMPAGE(a) &CRAM[ (a) * 0x400 ]
- /* The address of 1Kbytes unit of the VRAM */
- #define VRAMPAGE(a) &VRAM[ (a) * 0x400 ]
- /* Translate the pointer to ChrBuf into the address of Pattern Table */
- #define PATTBL(a) ( ( (a) - ChrBuf ) >> 2 )
- #else
- /* The address of 1Kbytes unit of the CRAM */
- #define CRAMPAGE(a) &PPURAM[ 0x0000 + ((a)&0x1F) * 0x400 ]
- /* The address of 1Kbytes unit of the VRAM */
- #define VRAMPAGE(a) &PPURAM[ 0x2000 + (a) * 0x400 ]
- /* Translate the pointer to ChrBuf into the address of Pattern Table */
- #define PATTBL(a) ( ( (a) - ChrBuf ) >> 2 )
- #endif
InfoNES_Mapper.cpp
最上面
- /*-------------------------------------------------------------------*/
- /* Mapper resources */
- /*-------------------------------------------------------------------*/
- //* Disk System RAM */
- BYTE DRAM[ DRAM_SIZE ];
-
- #ifdef RAM_LACK
- BYTE CRAM[ CRAM_SIZE ];
- #endif
-
InfoNES.h
26-28
- #ifdef RAM_LACK
- #define RAM_SIZE 0x800
- #define VRAM_SIZE 0x800
- #else
- #define RAM_SIZE 0x2000
- #define PPURAM_SIZE 0x4000
- #endif
- #define SRAM_SIZE 0x2000
59-60
- #ifdef RAM_LACK
- /* PPU VRAM */
- extern BYTE VRAM[];
- #else
- /* PPU RAM */
- extern BYTE PPURAM[];
- #endif
InfoNES.cpp
73-74
- #ifdef RAM_LACK
- /* PPU VRAM */
- BYTE VRAM[ VRAM_SIZE ];
- #else
- /* PPU RAM */
- BYTE PPURAM[ PPURAM_SIZE ];
- #endif
187-192
- #ifdef RAM_LACK
- { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3 },
- { NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3 },
- { NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE1 & 0x3 },
- { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3 },
- { NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3, NAME_TABLE2 & 0x3, NAME_TABLE3 & 0x3 },
- { NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE0 & 0x3, NAME_TABLE1 & 0x3 }
- #else
- { NAME_TABLE0, NAME_TABLE0, NAME_TABLE1, NAME_TABLE1 },
- { NAME_TABLE0, NAME_TABLE1, NAME_TABLE0, NAME_TABLE1 },
- { NAME_TABLE1, NAME_TABLE1, NAME_TABLE1, NAME_TABLE1 },
- { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE0 },
- { NAME_TABLE0, NAME_TABLE1, NAME_TABLE2, NAME_TABLE3 },
- { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE1 }
- #endif
474
- #ifdef RAM_LACK
- InfoNES_MemorySet( CRAM, 0, CRAM_SIZE );
- InfoNES_MemorySet( VRAM, 0, VRAM_SIZE );
- #else
- InfoNES_MemorySet( PPURAM, 0, sizeof PPURAM );
- #endif
516-517
- #ifdef RAM_LACK
- for ( nPage = 0; nPage < 8; ++nPage )
- PPUBANK[ nPage ] = CRAMPAGE( nPage );
- for ( nPage = 8; nPage < 12; ++nPage )
- PPUBANK[ nPage ] = VRAMPAGE( nPage & 0x3 );
- #else
- for ( nPage = 0; nPage < 16; ++nPage )
- PPUBANK[ nPage ] = &PPURAM[ nPage * 0x400 ];
- #endif
553-557
- #ifdef RAM_LACK
- PPUBANK[ NAME_TABLE0 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 0 ] );
- PPUBANK[ NAME_TABLE1 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 1 ] );
- PPUBANK[ NAME_TABLE2 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 2 ] );
- PPUBANK[ NAME_TABLE3 ] = VRAMPAGE( PPU_MirrorTable[ nType ][ 3 ] );
- #else
- PPUBANK[ NAME_TABLE0 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 0 ] * 0x400 ];
- PPUBANK[ NAME_TABLE1 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 1 ] * 0x400 ];
- PPUBANK[ NAME_TABLE2 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 2 ] * 0x400 ];
- PPUBANK[ NAME_TABLE3 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 3 ] * 0x400 ];
- #endif
K6502_rw.h
352-355
- #ifndef RAM_LACK
- PPURAM[ 0x3f10 ] = PPURAM[ 0x3f14 ] = PPURAM[ 0x3f18 ] = PPURAM[ 0x3f1c ] =
- PPURAM[ 0x3f00 ] = PPURAM[ 0x3f04 ] = PPURAM[ 0x3f08 ] = PPURAM[ 0x3f0c ] = byData;
- #endif
- PalTable[ 0x00 ] = PalTable[ 0x04 ] = PalTable[ 0x08 ] = PalTable[ 0x0c ] =
- PalTable[ 0x10 ] = PalTable[ 0x14 ] = PalTable[ 0x18 ] = PalTable[ 0x1c ] = NesPalette[ byData ];
363
- #ifndef RAM_LACK
- PPURAM[ addr ] = byData;
- #endif
改完代码,编译!
- Total RW Size (RW Data + ZI Data) 61696 ( 60.25kB)
还差不到30K,事实上,如果你的板子RAM有64K,那么可以在进行些许调整就可以运行了,这一部分的剩下内容可以略过。
对于我来说,目标既然是32K,那就要继续到底。
注意到有一个32K的家伙还在RAM中:ChrBuf。这个东西是最麻烦的,我们把它放在下一个部分里再解决。目前,把和它相关的所有内容屏蔽就好。
当然,在我提供的有关代码中,可不只屏蔽这样简单,有些修改是有根据的,不明之处请垂询。
K6502_rw.h
243-244
- #ifdef RAM_LACK
- PPU_BG_Base = ( PPU_R0 & R0_BG_ADDR ) ? PPUBANK[ 4 ] : PPUBANK[ 0 ];
- PPU_SP_Base = ( PPU_R0 & R0_SP_ADDR ) ? PPUBANK[ 4 ] : PPUBANK[ 0 ];
- #else
- PPU_BG_Base = ( PPU_R0 & R0_BG_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
- PPU_SP_Base = ( PPU_R0 & R0_SP_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
- #endif /* RAM_LACK */
343
- #ifndef RAM_LACK
- ChrBufUpdate |= ( 1 << ( addr >> 10 ) );
- #endif /* !RAM_LACK */
InfoNES_Mapper.h
60
- #define PATTBL(a) ( ( (a) ) >> 2 )
InfoNES.h
218-220
- #ifndef RAM_LACK
- extern BYTE ChrBuf[];
- extern BYTE ChrBufUpdate;
- #endif /* !RAM_LACK */
314-315
- #ifdef RAM_LACK
- #define InfoNES_SetupChr() {}
- #else
- /* Develop character data */
- void InfoNES_SetupChr(void);
- #endif /* RAM_LACK */
InfoNES.cpp
175-179
- #ifndef RAM_LACK
- /* Character Buffer */
- BYTE ChrBuf[ 256 * 2 * 8 * 8 ];
- /* Update flag for ChrBuf */
- BYTE ChrBufUpdate;
- #endif /* !RAM_LACK */
402
- #ifndef RAM_LACK
- // Reset update flag of ChrBuf
- ChrBufUpdate = 0xff;
- #endif /* !RAM_LACK */
514-515
- #ifdef RAM_LACK
- PPU_BG_Base = PPUBANK[ 0 ];
- PPU_SP_Base = PPUBANK[ 4 ];
- #else
- PPU_BG_Base = ChrBuf;
- PPU_SP_Base = ChrBuf + 256 * 64;
- #endif /* RAM_LACK */
799
InfoNES_DrawLine函数里面全部注掉
1125
InfoNES_GetSprHitY函数里面全部注掉
1185
InfoNES_SetupChr函数从外面使用RAM_LACK宏开关关闭
最后结果:
- Total RW Size (RW Data + ZI Data) 28896 ( 28.22kB)
28.22K!
并且看到Map185_Dummy_Chr_Rom占用了1K,随时可以通过取缔它来释放这1K,暂时就算任务达成吧。
把之前增大的RAM设置修改回原有的32K,本部分完工!
之后再写代码,就要小心RAM了。
欲知后文请继续围观。
第四部分资源
1 RAM用量控制在60K:
2 RAM用量控制在30K: