OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7071|回复: 8

正点原子F4的nes例程移植求助!!!

[复制链接]

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
发表于 2022-5-18 16:57:47 | 显示全部楼层 |阅读模式
30金钱
用正点原子F4的nes例程做移植到F1的时候,bg_enabled()和spr_enabled()一直为0导致刷新屏幕的都是背景色,进不去这个if:
uint32 spr_enabled(void)    { return ppu->LowRegs[1] & 0x10; }
uint32 bg_enabled(void)     { return ppu->LowRegs[1] & 0x08; }


if(spr_enabled() || bg_enabled())
  {
    LOOPY_SCANLINE_START(ppu->loopy_v, ppu->loopy_t);
    if(bg_enabled())
    {
      // draw background画背景
      render_bg(buf);
    }
    else
    {
      // clear out solid buffer清除固体缓冲区
     memset(ppu->solid_buf, 0x00, sizeof(ppu->solid_buf));
    }

    if(spr_enabled())
    {
      // draw sprites绘制精灵
      render_spr(buf);
    }

    LOOPY_NEXT_LINE(ppu->loopy_v);
  }
那么在原子nes的例程中,spr_enabled() 和bg_enabled()什么时候会被更改呢?
希望有移植过的高人来指点一下。
求解!!!!!!!

最佳答案

查看完整内容[请看2#楼]

问题已解决,因为原子例程是从外部SRAM加载游戏源码,我是从flash加载。两者有区别。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-18 16:57:48 | 显示全部楼层
问题已解决,因为原子例程是从外部SRAM加载游戏源码,我是从flash加载。两者有区别。
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-18 20:01:44 | 显示全部楼层
自顶顶顶!!!!
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-18 21:22:32 | 显示全部楼层
在查错的时候又有一个疑惑,以下代码如果不注释的话运行会卡住,不刷新屏幕(虽然是黑屏),那么这段代码是什么意思?
/**
NES_Mapper->VSync();  // 空扫描一次
// LINES 242-261
for(NES_scanline=241;NES_scanline<262;NES_scanline++)
{
        run6502(113*256);
        NES_Mapper->HSync(NES_scanline);
}
**/
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
发表于 2022-5-18 21:57:00 | 显示全部楼层
用我们战舰板的
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-18 22:06:28 | 显示全部楼层
好的,我试试
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-18 23:04:08 | 显示全部楼层
本帖最后由 冒冒mao 于 2022-5-19 15:02 编辑

用了战舰版的例程还是不行。bg_enabled()和spr_enabled()还是为0,刷新的都是背景色。没有游戏画面。由于无手柄,无声音,无部SRAM在原来的例程上注释了一些没有的外设。主要函数是最后的LoadNes(),内存分配,加载rom,map的返回值正确。
另外我发现一个现象,下段代码运行会导致不能刷新屏幕(虽然刷新的还是背景色),

NES_Mapper->VSync();
// LINES 242-261
for(NES_scanline=241;NES_scanline<262;NES_scanline++)
{
      run6502(113*256);
      NES_Mapper->HSync(NES_scanline);
}

这里我放上nes_main的主要代码:
u8 nes_load_rom(void)
{  
  u8* p;  
        u8 i;
        u8 res=0;
        p=(u8*)romfile;       
        if(strncmp((char*)p,"NES",3)==0)  //判断是不是NES文件
        {  
                RomHeader->ctrl_z=p[3];
                RomHeader->num_16k_rom_banks=p[4];  //程序存储区16KB
                RomHeader->num_8k_vrom_banks=p[5];  //图像存储区8KB
                RomHeader->flags_1=p[6];
                RomHeader->flags_2=p[7];
                if(RomHeader->flags_1&0x04)p+=512;                //有512字节的trainer:
                if(RomHeader->num_8k_vrom_banks>0)                //存在VROM,进行预解码
                {       
                        VROM_banks=p+16+(RomHeader->num_16k_rom_banks*0x4000); //PRG_ROM  nes的程序ROM        ->16KB
#if        NES_RAM_SPEED==1        //1:内存占用小 0:速度快         
                        VROM_tiles=VROM_banks;         
#else  
                        VROM_tiles=mymalloc(SRAMIN,RomHeader->num_8k_vrom_banks*8*1024);//这里可能申请多达1MB内存!!!
                        if(VROM_tiles==0)VROM_tiles=VROM_banks;//内存不够用的情况下,尝试VROM_titles与VROM_banks共用内存                       
                        compile(RomHeader->num_8k_vrom_banks*8*1024/16,VROM_banks,VROM_tiles);  
#endif       
                }else
                {
                        VROM_banks=mymalloc(SRAMIN,8*1024);
                        VROM_tiles=mymalloc(SRAMIN,8*1024);
                        if(!VROM_banks||!VROM_tiles)res=1;
                }        
                VROM_1K_SIZE = RomHeader->num_8k_vrom_banks * 8;
                VROM_8K_SIZE = RomHeader->num_8k_vrom_banks;  
                MapperNo=(RomHeader->flags_1>>4)|(RomHeader->flags_2&0xf0);
                if(RomHeader->flags_2 & 0x0E)MapperNo=RomHeader->flags_1>>4;//忽略高四位,如果头看起来很糟糕
                printf("use map:%d\r\n",MapperNo);
                for(i=0;i<255;i++)  // 查找支持的Mapper号
                {               
                        if (MapTab==MapperNo)break;               
                        if (MapTab==-1)res=3;
                }
                if(res==0)
                {
                        switch(MapperNo)
                        {
                                case 1:  
                                        MAP1=mymalloc(SRAMIN,sizeof(Mapper1Res));
                                        if(!MAP1)res=1;
                                        break;
                                case 4:  
                                case 6:
                                case 16:
                                case 17:
                                case 18:
                                case 19:
                                case 21:
                                case 23:
                                case 24:
                                case 25:
                                case 64:
                                case 65:
                                case 67:
                                case 69:
                                case 85:
                                case 189:
                                        MAPx=mymalloc(SRAMIN,sizeof(MapperCommRes));
                                        if(!MAPx)res=1;
                                        break;  
                                default:
                                        break;
                        }
                }
        }
        return res;        //返回执行结果
}
//释放内存
void nes_sram_free(void)
{
        //u8 i;
        myfree(SRAMIN,NES_RAM);               
        myfree(SRAMIN,NES_SRAM);       
        myfree(SRAMIN,RomHeader);       
        myfree(SRAMIN,NES_Mapper);
        myfree(SRAMIN,spr_ram);               
        myfree(SRAMIN,ppu);       
        //myfree(SRAMIN,apu);       
        //myfree(SRAMIN,wave_buffers);
        //for(i=0;i<NES_APU_BUF_NUM;i++)myfree(SRAMIN,nesapusbuf);//释放APU BUFs
        //myfree(SRAMIN,romfile);          
        if((VROM_tiles!=VROM_banks)&&VROM_banks&&VROM_tiles)//如果分别为VROM_banks和VROM_tiles申请了内存,则释放
        {
                myfree(SRAMIN,VROM_banks);
                myfree(SRAMIN,VROM_tiles);                 
        }
        switch (MapperNo)//释放map内存
        {
                case 1:                         //释放内存
                        myfree(SRAMIN,MAP1);
                        break;                
                case 4:
                case 6:
                case 16:
                case 17:
                case 18:
                case 19:
                case 21:
                case 23:
                case 24:
                case 25:
                case 64:
                case 65:
                case 67:
                case 69:
                case 85:
                case 189:
                        myfree(SRAMIN,MAPx);break;                         //释放内存
                default:break;
        }
        NES_RAM=0;       
        NES_SRAM=0;
        RomHeader=0;
        NES_Mapper=0;
        spr_ram=0;
        ppu=0;
        //apu=0;
        //wave_buffers=0;
        //for(i=0;i<NES_APU_BUF_NUM;i++)nesapusbuf=0;
        VROM_banks=0;
        VROM_tiles=0;
        MAP1=0;
        MAPx=0;
}
//为NES运行申请内存
//romsize:nes文件大小
//返回值:0,申请成功
//       1,申请失败
u8 nes_sram_malloc()
{
        u16 i=0;
        for(i=0;i<64;i++)//为NES_RAM,查找1024对齐的内存
        {
                NES_SRAM=mymalloc(SRAMIN,i*32);
                NES_RAM=mymalloc(SRAMIN,0X800);        //申请2K字节,必须1024字节对齐
                if((u32)NES_RAM%1024)                        //不是1024字节对齐
                {
                        myfree(SRAMIN,NES_RAM);                //释放内存,然后重新尝试分配
                        myfree(SRAMIN,NES_SRAM);
                }else
                {
                        myfree(SRAMIN,NES_SRAM);         //释放内存
                        break;
                }
        }
        //NES_RAM=mymalloc(SRAMIN,1024);
        //NES_SRAM=mymalloc(SRAMIN,0X2000);
               
        NES_SRAM=mymalloc(SRAMIN,8192);           //为NES申请内存空间8KB !!!!!

        RomHeader=mymalloc(SRAMIN,sizeof(NES_header));
        NES_Mapper=mymalloc(SRAMIN,sizeof(MAPPER));
        spr_ram=mymalloc(SRAMIN,0X100);               
        ppu=mymalloc(SRAMIN,sizeof(ppu_data));
        /**
        apu=mymalloc(SRAMIN,sizeof(apu_t));                //sizeof(apu_t)=  12588
        wave_buffers=mymalloc(SRAMIN,APU_PCMBUF_SIZE);
        for(i=0;i<NES_APU_BUF_NUM;i++)
        {
                nesapusbuf=mymalloc(SRAMIN,APU_PCMBUF_SIZE+10);//申请内存
        }
       
        romfile=mymalloc(SRAMIN,romsize);                        //申请游戏rom空间,等于nes文件大小
       
        if(romfile==NULL)//内存不够?释放主界面占用内存,再重新申请
        {
                //spb_delete();//释放SPB占用的内存
                romfile=mymalloc(SRAMIN,romsize);//重新申请
        }
        **/
        /**
        if(i==64||!NES_RAM||!NES_SRAM||!RomHeader||!NES_Mapper||!spr_ram||!ppu||!apu||!wave_buffers||!nesapusbuf[NES_APU_BUF_NUM-1]||!romfile)
        {
                nes_sram_free();
                return 1;
        }
        **/
        if(i==64||!NES_RAM||!NES_SRAM||!RomHeader||!NES_Mapper||!spr_ram||!ppu)
        {
                nes_sram_free();
                return 1;
        }
        memset(NES_SRAM,0,8192);                                //清零
        memset(RomHeader,0,sizeof(NES_header));        //清零
        memset(NES_Mapper,0,sizeof(MAPPER));        //清零
        memset(spr_ram,0,0X100);                                //清零
        memset(ppu,0,sizeof(ppu_data));                        //清零
        //memset(apu,0,sizeof(apu_t));                        //清零
        //memset(wave_buffers,0,APU_PCMBUF_SIZE);        //清零
        //for(i=0;i<NES_APU_BUF_NUM;i++)memset(nesapusbuf,0,APU_PCMBUF_SIZE+10);//清零
        //memset(romfile,0,romsize);                                //清零
        return 0;
}

//频率设置
//PLL,倍频数
void nes_clock_set(u8 PLL)
{
        u16 tPLL=PLL;
        u8 temp=0;         
        RCC->CFGR&=0XFFFFFFFC;        //修改时钟频率为内部8M          
        RCC->CR&=~0x01000000;          //PLLOFF  
        RCC->CFGR&=~(0XF<<18);        //清空原来的设置
        PLL-=2;//抵消2个单位
        RCC->CFGR|=PLL<<18;           //设置PLL值 2~16
        RCC->CFGR|=1<<16;                  //PLLSRC ON
        FLASH->ACR|=0x12;                  //FLASH 2个延时周期
        RCC->CR|=0x01000000;          //PLLON
        while(!(RCC->CR>>25));        //等待PLL锁定
        RCC->CFGR|=0x02;                //PLL作为系统时钟         
        while(temp!=0x02)            //等待PLL作为系统时钟设置成功
        {   
                temp=RCC->CFGR>>2;
                temp&=0x03;
        }  
        //顺便设置延时和串口                                                                                  
        //delay_init(tPLL*8);                        //延时初始化
        //uart_initx(tPLL*8,115200);         //串口1初始化   
}  

u8 nes_xoff=0;        //显示在x轴方向的偏移量(实际显示宽度=256-2*nes_xoff)
//设置游戏显示窗口
void nes_set_window(void)
{       
        u16 xoff=0,yoff=0;
        u16 lcdwidth,lcdheight;
        if(lcddev.width==240)
        {
                lcdwidth=240;
                lcdheight=240;
                nes_xoff=(256-lcddev.width)/2;        //得到x轴方向的偏移量
                xoff=0;
        }else if(lcddev.width==320)
        {
                lcdwidth=256;
                lcdheight=240;
                nes_xoff=0;
                xoff=(lcddev.width-256)/2;
        }else if(lcddev.width==480)
        {
                lcdwidth=480;
                lcdheight=480;
                nes_xoff=(256-(lcddev.width/2))/2;//得到x轴方向的偏移量
                xoff=0;  
        }       
        yoff=(lcddev.height-lcdheight)/2;//屏幕高度
        LCD_Set_Window(xoff,yoff,lcdwidth,lcdheight);//让NES始终在屏幕的正中央显示
        LCD_WriteRAM_Prepare();//写入LCD RAM的准备        
}

void NesGetGamepadval(void)
{  
        u8 key;
//        PADdata0=GetJoypadKey();        //读取手柄1的值
        //printf("%d\r\n",PADdata0);
        key=KEY_Scan();
        if(key==5)PADdata0=1;
        else if(key==6)PADdata0=2;
        else if(key==7)PADdata0=4;
        else if(key==8)PADdata0=8;
        else if(key==9)PADdata0=16;
        else if(key==10)PADdata0=32;
        else if(key==11)PADdata0=64;
        else if(key==12)PADdata0=128;
}

//nes模拟器主循环
void nes_emulate_frame(void)
{  
        u8 nes_frame = 0;
        //TIM3_Int_Init(10000-1,12800-1);//启动TIM3 ,1s中断一次       
        nes_set_window();//设置窗口
        //system_task_return=0;
        while(1)
        {       
                // LINES 0-239
                PPU_start_frame();
                for(NES_scanline = 0; NES_scanline< 240; NES_scanline++)
                {
                        run6502(113*256);
                        NES_Mapper->HSync(NES_scanline);
                        //扫描一行                  
                        if(nes_frame==0)scanline_draw(NES_scanline);
                        else do_scanline_and_dont_draw(NES_scanline);
                }  
                NES_scanline=240;
                run6502(113*256);//运行1线
                NES_Mapper->HSync(NES_scanline);
                start_vblank();
                if(NMI_enabled())
                {
                        cpunmi=1;
                        printf("555");
                        run6502(7*256);//运行中断
                }

                NES_Mapper->VSync();
                // LINES 242-261   
                for(NES_scanline=241;NES_scanline<262;NES_scanline++)
                {
                        run6502(113*256);          
                        NES_Mapper->HSync(NES_scanline);                  
                }

                end_vblank();
                NesGetGamepadval();
                //nes_get_gamepadval();        //每3帧查询一次USB
                //apu_soundoutput();                //输出游戏声音       
               
                //frame_cnt++;
                LCD_ShowxNum(24,0,nes_frame,1,16,0);//屏幕左上角显示帧数               
                nes_frame++;
                if(nes_frame>NES_SKIP_FRAME)
                {
                        nes_frame=0;//跳帧
                        //if(lcddev.id==0X1963)nes_set_window();//重设窗口
                }
                /**
                if(system_task_return)
                {
                        if(TPAD_Scan(1))//再次确认TPAD返回  
                        {
                                break;
                        }
                        system_task_return=0;
                }
                **/
        }
        LCD_Set_Window(0,0,lcddev.width,lcddev.height);//恢复屏幕窗口
        //TIM3->CR1&=~(1<<0);//关闭定时器3
}
//在6502.s里面被调用
void debug_6502(u16 reg0,u8 reg1)
{
        printf("6502 error:%x,%d\r\n",reg0,reg1);
}


u8 LoadNes(unsigned char* pname,u32 size){
        u8 res=0;
        romfile=(u8*)pname;       //游戏源码地址
  res=nes_sram_malloc();                        //申请内存
        printf("malloc=%d\r\n",res);
  NESrom_crc32=get_crc32(romfile+16,size-16);//获取CRC32的值       
  res=nes_load_rom();                                        //加载游戏ROM
  printf("res=%d\r\n",res);
  //nes_clock_set(16);          //设置系统时钟为128MHZ 16*8
  //JoypadInit();             //游戏手柄初始化
        if(res==0){
                cpu6502_init();                                                //初始化6502,并复位
                Mapper_Init();                                                //map初始化
                PPU_reset();                                                        //ppu复位
                //apu_init();                                                         //apu初始化
                nes_emulate_frame();                    //进入NES模拟器主循环
        }
        myfree(SRAMIN,romfile);//释放内存
        nes_sram_free();
  return res;
}
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2022-3-30
在线时间
36 小时
 楼主| 发表于 2022-5-19 10:11:01 | 显示全部楼层
自顶加热度!!!
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2023-3-9
在线时间
0 小时
发表于 2023-3-9 19:23:40 来自手机 | 显示全部楼层
楼主好,我想问一下nes模拟器这个相关的资料和教程在哪里呀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 14:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表