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);
}