fc模拟器ppu关键代码的理解

static void Background_PreFetch( unsigned int LineBufferIndex, H_NES_Console* Console )
{    
    Huint16 t_uint16;
    Huint32* tp_uint32;
    Huint16 v;
    Huint16 Pattern;
    Huint32 Attribute;
    Huint32 LowPattern;
    Huint32 HighPattern;
    int j, value1, value2;
    if( (Console->PPU.Register.Register[vH_NES_PPU_Register_PPUCTRL]&vH_NES_PPU_PPUCTRL_B) != 0U ){
        Pattern = 0x1000U;
    }else{
        Pattern = 0x0000U;
        printf( "Pattern = %x\n", Pattern );
    }
    
    
    v = Console->PPU.Register.Internal.v;

    //printf( "v = %x\n", v );
    
    

    Attribute = Console->PPU.NameTable[(v&0x0C00U)>>10][0x03C0U+(((v>>4)&0x0038U)|((v>>2)&0x0007U))];
    //0x3c0+index  0x38 0x80个瓦片一个字节循环 行号
    //0x07 取列号

    //瓦片排列图
    //00 01 02 03 04 05 06 07 ... 1c 1d 1e 1f
    //20 21 22 23 24 25 26 27 ... 3c 3d 3e 3f
    //40 41 42 43 44 45 46 47 ... 5c 5d 5e 5f
    //60 61 62 63 64 65 66 67 ... 6c 6d 6e 7f
    //80 81 82 83 84 85 86 87 ... 9c 9d 9e 9f
    //a0 a1 a2 a3 a4 a5 a6 a7 ... bc bd be bf
    //from 0x3c0之后,是属性表区域,描述前面960个瓦片的颜色属性,总共有64字节的属性字节
    //属性字节一个字节是8bit,每2bit表示相邻的4个瓦片的颜色属性,这个值是代表调色板的索引
    //背景调色板有4个,00,01,10,11
    //由属性表可以索引到使用的背景子调色板
    //每个子调色板有4种颜色可用
    //Pattern表中 一个瓦片由16字节组成,8*8像素,一个像素占2bit
    //这个2bit代表子调色板的颜色索引.
    
    //颜色属性表2bit表示相邻的4个瓦片的颜色属性索引,举个梨子如下:
    //0x3c0:bit1, bit0    管瓦片 00 01 20 21
    //0x3c0:bit3, bit2    管瓦片 02 03    22 23
    //0x3c0:bit5, bit4    管瓦片 40 41 60 61
    //0x3c0:bit7, bit6    管瓦片 42 43 62 63
    //所以前面128个瓦片 占用的属性表区域是0x3c0-0x3c7
    //一个字节管16个瓦片[4行4列] 
    //每行有32个瓦片 需要8个字节 [4行32列]
    //0x3c8开始管 80...开始的瓦片.
    
    t_uint16  = (v&0x0002U)|((v>>4)&0x0004U);
    //per 2bit ofset in a byte
    Attribute = ((Attribute>>t_uint16)<<2)&0x0000000CU;
    //调色板地址 = 基地址 + (属性<<2)

  
    t_uint16 = ((Huint16)Console->PPU.NameTable[(v&0x0C00U)>>10][v&0x03FFU]) << 4; 
    //每个8x8像素的NES背景图块(瓦片) 在CHR-ROM中占用16字节:
    //前8字节存储低位平面(Bit 0),         后8字节存储高位平面(Bit 1)
    //通过左移4位实现索引值 *16 的地址换算, 精确定位图块起始地址
    //NES PPU采用16字节对齐的 pattern table布局  
    //比如   NameTable[0][0x0] = 0, 瓦片0的起始地址0; 比如   NameTable[0][0x0] = 1, 瓦片1的起始地址16
                                                                                                            
    t_uint16 += Pattern + ((v>>12)&0x0007U);
    //提取PPU内部寄存器v的[14:12]位 (当前扫描线在8像素图块[瓦片]内的行号0-7) 与0x0007掩码确保数值范围安全
    //‌最终地址合成‌将三者相加实现:
    //最终地址 = 图块基址(t_uint16) + 图案表基址(Pattern) + 当前扫描行偏移(0-7)
    //该计算对应硬件行为:
    //PPU每渲染1个扫描线时,会根据垂直滚动位置自动切换图块内的行数据。
    //8行偏移量循环往复的特性正是NES实现平滑滚动的底层机制之一。
                                                                 
    LowPattern  = Console->Cartridge.CHR_Read( t_uint16, Console );
    HighPattern = Console->Cartridge.CHR_Read( t_uint16+8U, Console );                 

  //printf( "LineIdx = %d, t_uint16 = %x, LowPattern = %x, HighPattern = %x\n", LineBufferIndex, t_uint16, LowPattern, HighPattern );
  //printf( "v = %x\n", v );
  //printf( "(v&0x0C00U) = %x\n", (v&0x0C00U) );
  //macdbg_dmphex( (const char *)&Console->PPU.NameTable[0][0], 1024);
  //printf( "vv = %x\n", v );
  // macdbg_dmphex( (const char *)&Console->PPU.NameTable[0][0], 1024);


  #if 0
  for(j=0x00; j<960; j++){
      Console->PPU.NameTable[0][j] = 0x28;  // '-'
  }
  // macdbg_dmphex( (const char *)&Console->PPU.NameTable[0][0], 1024);
  //Console->PPU.NameTable[0][960] = Console->PPU.NameTable[0][960];
  memset( &Console->PPU.NameTable[0][960], 0x00, 64 );
  value1 = Console->PPU.NameTable[0][960];
  value2 = 0x03;
  value2 = value2<<0x00;
  value1 = value1 & 0xfc;
  value1 = value1 | value2;
  //printf( "value1 = %x\n", value1 );
  value2 = 0x03;

  value2 = value2<<0x02;
  value1 = value1 & 0xf3;
  value1 = value1 | value2;
  value2 = 0x03;

  value2 = value2<<0x04;
  value1 = value1 & 0xcf;
  value1 = value1 | value2;
  value2 = 0x03;

  value2 = value2<<0x06;
  value1 = value1 & 0x3f;
  value1 = value1 | value2;
  Console->PPU.NameTable[0][960] = value1;
  Console->PPU.NameTable[0][961] = 0xff;
  Console->PPU.NameTable[0][962] = 0xff;
  Console->PPU.NameTable[0][967] = 0x3f;
  #endif
  

   if( t_uint16>=0x1000 && t_uint16<=0x1010 ){
      //printf("LineBufferIndex = %d\n", LineBufferIndex);
      //printf("t_uint16 = %x\n", t_uint16);
      //printf("LowPattern = %x\n", LowPattern);
      //printf("HighPattern = %x\n", HighPattern);
  }
   
  tp_uint32=Console->PPU.Table->PatternToLineBuffer;

  LowPattern=tp_uint32[LowPattern];
  HighPattern=tp_uint32[HighPattern];


  if( t_uint16>=0x1000 && t_uint16<=0x1010 ){
      //printf("LineBufferIndexxxx = %d\n", LineBufferIndex);
      //printf("t_uint16 = %x\n", t_uint16);
      //printf("LowPattern = %x\n", LowPattern);
      //printf("HighPattern = %x\n", HighPattern);
  }
  

  
  //macdbg_dmphex((const char *)tp_uint32, 1024);
  //printf( "LineIdx = %d, Attribute = %x, LowPattern = %x, HighPattern = %x\n", LineBufferIndex, Attribute, LowPattern, HighPattern );
  

  Console->PPU.Renderer.LineBuffer[LineBufferIndex]=LowPattern|(HighPattern<<1)|((LowPattern|HighPattern)*Attribute);
  

}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值