为方便讲解,代码我直接放到最后一页

对于nes_main.c我们来看u8 nes_main(void)第三行代码

u8 nes_main(void)
{
    u16 offset = 0;
    u8 res;
    NesHeader *neshreader = (NesHeader *) rom_file;
    ...................................

 没错,这行代码指向的就是你的游戏文件数组,即在第一篇讲的nes_rom.h里面的游戏数组,

即你想玩什么游戏,吧该指针指向那里就行了

往下的代码就没什么可以讲的了,主要就是验证你的数组是不是真的是NES文件,

就是这一部分

u16 offset = 0;
    u8 res;
    NesHeader *neshreader = (NesHeader *) rom_file;
    //由于NES文件头类型以0x1A结束,(0x1a是Ctrl+Z,这是模拟文件结束的符号)
    //所以使用strcncmp比较前3个字节。
    if (strncmp(neshreader->filetype, "NES", 3) != 0)
    {
        printf("\r\n文件未加载或文件类型错误, NES模拟器退出。");
        return 1;
    }
    else
    {
        printf("\r\n文件加载完成。");
        printf("\r\n  16kB  ROM 的数目: %d", neshreader->romnum);
        printf("\r\n   8kB VROM 的数目: %d", neshreader->vromnum);
        if ((neshreader->romfeature & 0x01) == 0)
        {
            printf("\r\n  水平镜像");
        }
        else
        {
            printf("\r\n  垂直镜像");
        }

        if ((neshreader->romfeature & 0x02) == 0)
        {
            printf("\r\n  无记忆SRAM");
        }
        else
        {
            printf("\r\n  有记忆SRAM");
        }

        if ((neshreader->romfeature & 0x04) == 0)
        {
            printf("\r\n  无512字节的trainer($7000-$71FF)");
        }
        else
        {
            offset = 512;
            printf("\r\n  有512字节的trainer(ROM格式暂不支持)");
        }

        if ((neshreader->romfeature & 0x08) == 0)
        {
            printf("\r\n  2屏幕VRAM布局");
        }
        else
        {
            printf("\r\n  4屏幕VRAM布局(暂不支持)");
        }

        printf("\r\n  iNES Mapper Numbers: %d", (neshreader->rommappernum & 0xF0) | (neshreader->romfeature >> 4));
    }

验证完之后,看下面这部分代码 

printf("\r\n  开始申请内存\n");
    res = nes_mem_creat(); //申请内存
    if (res == 0) //申请成功了.则运行游戏
    {
        printf("\r\n  开始申请成功\n");
        printf("\r\n  初始化按键\n");
        printf("\r\n  初始化屏幕\n");
        printf("\r\n  初始化ppu\n");
        printf("\r\n  初始化joypad\n");
        printf("\r\n  初始化6502\n");
        printf("\r\n  无限循环执行游戏\n");
        printf("\r\n  按下退出游戏键\n");
    }
    else   printf("\r\n  开始申请失败\n");
    nes_mem_delete();//释放内存
    return res;
}

验证完之后,就是开始内存申请了,即开辟为游戏运行的内存 ,然后初始化各类设备,这里面的内容第三篇开始讲解

res = nes_mem_creat(); //申请内存

接下来,我们来看与内存开辟的相关代码

//PPU使用
 u8 *NameTable;			//2K的变量
 u16	*Buffer_scanline;	//行显示缓存,上下标越界最大为7,显示区 7 ~ 263  0~7 263~270 为防止溢出区
//CPU使用
 u8 *ram6502;  			//RAM  2K字节,由malloc申请
portMUX_TYPE isr_nes_creat = portMUX_INITIALIZER_UNLOCKED;

//开辟nes运行所需的RAM.
//返回值:0,成功;
//    其他,错误代码.
u8 nes_mem_creat(void)
{
    portENTER_CRITICAL_ISR(&isr_nes_creat);
    ram6502 = (u8 *)malloc(2048); //申请2K内存
    if (ram6502 == NULL)return 1;       //申请失败
    NameTable = (u8 *)malloc(2048); //申请2K内存
    if (NameTable == NULL)return 2;
    Buffer_scanline = (u16 *)malloc((8 + 256 + 8) * 2);
    if (Buffer_scanline == NULL)return 3;
    portEXIT_CRITICAL_ISR(&isr_nes_creat);
    return 0;
}

可以看到前面几行定义的变量

//PPU使用
 u8 *NameTable;			//2K的变量
 u16	*Buffer_scanline;	//行显示缓存,上下标越界最大为7,显示区 7 ~ 263  0~7 263~270 为防止溢出区
//CPU使用
 u8 *ram6502;  			//RAM  2K字节,由malloc申请

 这几个变量是测试本篇用的,真正定义的时候并不在这个文件里面而在ppu.c和CPU(即6502.c)文件里面定义。

接下来可能有人会不懂,下面这行代码是啥意思,当你用的时候这段也可以直接删除,对程序没有影响

portMUX_TYPE isr_nes_creat = portMUX_INITIALIZER_UNLOCKED;

这个是定义一个代码临界段变量用的 ,可能你还是不懂,但是看到下面的函数你可能就懂了

//开辟nes运行所需的RAM.
//返回值:0,成功;
//    其他,错误代码.
u8 nes_mem_creat(void)
{
    portENTER_CRITICAL_ISR(&isr_nes_creat);       //内存申请不可被打断
    ram6502 = (u8 *)malloc(2048); //申请2K内存
    if (ram6502 == NULL)
        return 1;                   //申请失败
    NameTable = (u8 *)malloc(2048); //申请2K内存
    if (NameTable == NULL)
        return 2;
    Buffer_scanline = (u16 *)malloc((8 + 256 + 8) * 2);
    if (Buffer_scanline == NULL)
        return 3;
    portEXIT_CRITICAL_ISR(&isr_nes_creat);        //内存申请可以被打断
    return 0;
}

 通过引用 portENTER_CRITICAL_ISR(&isr_nes_creat);      函数

可以使在申请内存操作时,CPU不会被其他中断操作给打断,当然如果你使用的不是ESP32_Arduino平台开发的话,这下面这两句不写也是可以的。 

portENTER_CRITICAL_ISR(&isr_nes_creat);       //内存申请不可被打断
 portEXIT_CRITICAL_ISR(&isr_nes_creat);        //内存申请可以被打断

至此,内存申请测试就此完结,下面贴出nes_main.c,内存申请测试代码,继续学习,请看第三篇

ppu文件的讲解

#include "malloc.h"
#include "nes_main.h"


//返回值:0,执行OK;
//    其他,错误代码
u8 nes_main(void)
{
    u16 offset = 0;
    u8 res;
    NesHeader *neshreader = (NesHeader *) rom_file;
    //由于NES文件头类型以0x1A结束,(0x1a是Ctrl+Z,这是模拟文件结束的符号)
    //所以使用strcncmp比较前3个字节。
    if (strncmp(neshreader->filetype, "NES", 3) != 0)
    {
        printf("\r\n文件未加载或文件类型错误, NES模拟器退出。");
        return 1;
    }
    else
    {
        printf("\r\n文件加载完成。");
        printf("\r\n  16kB  ROM 的数目: %d", neshreader->romnum);
        printf("\r\n   8kB VROM 的数目: %d", neshreader->vromnum);
        if ((neshreader->romfeature & 0x01) == 0)
        {
            printf("\r\n  水平镜像");
        }
        else
        {
            printf("\r\n  垂直镜像");
        }

        if ((neshreader->romfeature & 0x02) == 0)
        {
            printf("\r\n  无记忆SRAM");
        }
        else
        {
            printf("\r\n  有记忆SRAM");
        }

        if ((neshreader->romfeature & 0x04) == 0)
        {
            printf("\r\n  无512字节的trainer($7000-$71FF)");
        }
        else
        {
            offset = 512;
            printf("\r\n  有512字节的trainer(ROM格式暂不支持)");
        }

        if ((neshreader->romfeature & 0x08) == 0)
        {
            printf("\r\n  2屏幕VRAM布局");
        }
        else
        {
            printf("\r\n  4屏幕VRAM布局(暂不支持)");
        }

        printf("\r\n  iNES Mapper Numbers: %d", (neshreader->rommappernum & 0xF0) | (neshreader->romfeature >> 4));
    }
    printf("\r\n  开始申请内存\n");
    res = nes_mem_creat(); //申请内存
    if (res == 0) //申请成功了.则运行游戏
    {
        printf("\r\n  开始申请成功\n");

    }
    else   printf("\r\n  开始申请失败\n");
    nes_mem_delete();//释放内存
    return res;
}


u8 *ram6502;        //RAM  2K字节,由malloc申请
portMUX_TYPE isr_nes_creat = portMUX_INITIALIZER_UNLOCKED;

//开辟nes运行所需的RAM.
//返回值:0,成功;
//    其他,错误代码.
u8 nes_mem_creat(void)
{
    portENTER_CRITICAL_ISR(&isr_nes_creat);
    ram6502 = (u8 *)malloc(2048); //申请2K内存
    if (ram6502 == NULL)return 1;       //申请失败
    NameTable = (u8 *)malloc(2048); //申请2K内存
    if (NameTable == NULL)return 2;
    Buffer_scanline = (u16 *)malloc((8 + 256 + 8) * 2);
    if (Buffer_scanline == NULL)return 3;
    portEXIT_CRITICAL_ISR(&isr_nes_creat);
    return 0;
}
//删除nes运行时申请的RAM
void nes_mem_delete(void)
{
    free(ram6502);
    free(NameTable);
    free(Buffer_scanline);
}