初级会员
- 积分
- 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;
}
|
|