Files
player/Project/Src/NES/nes_ppu.c
2025-06-27 00:32:57 +08:00

1063 lines
24 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stm32f4xx.h"
#include "mymem.h"
#include "nes_ppu.h"
#include "string.h"
//#include "gui.h"
//#include "GUIDRV_Lin.h"
#include "lcd_rgb.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序移植自网友ye781205的NES模拟器工程
//ALIENTEK STM32F407开发板
//NES PPU 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/7/1
//版本V1.0
//////////////////////////////////////////////////////////////////////////////////
uint8* PPU_patterntables; //8192 VROM开始地址 图案表
void set_tile_banks(uint8 *bank0, uint8 *bank1, uint8 *bank2, uint8 *bank3,
uint8 *bank4, uint8 *bank5, uint8 *bank6, uint8 *bank7)
{
ppu->PPU_tile_banks[0] = bank0;
ppu->PPU_tile_banks[1] = bank1;
ppu->PPU_tile_banks[2] = bank2;
ppu->PPU_tile_banks[3] = bank3;
ppu->PPU_tile_banks[4] = bank4;
ppu->PPU_tile_banks[5] = bank5;
ppu->PPU_tile_banks[6] = bank6;
ppu->PPU_tile_banks[7] = bank7;
}
//*******************************************************************
void set_tile_bank(int i, uint8 *bank)
{
ppu->PPU_tile_banks[i] = bank;
}
void set_name_table(uint8 bank, int bank_num)
{
ppu->PPU_VRAM_banks[bank] = ppu->PPU_nametables + ((bank_num & 0x03) << 10);
}
// 0x2000
uint32 NMI_enabled(void) { return ppu->LowRegs[0] & 0x80; }
uint32 sprites_8x16() { return ppu->LowRegs[0] & 0x20; }
// 0x2001
uint32 spr_enabled(void) { return ppu->LowRegs[1] & 0x10; }
uint32 bg_enabled(void) { return ppu->LowRegs[1] & 0x08; }
uint32 spr_clip_left8() { return !(ppu->LowRegs[1] & 0x04); }
uint32 bg_clip_left8() { return !(ppu->LowRegs[1] & 0x02); }
uint32 rgb_pal() { return ppu->LowRegs[1] & 0xE0;}
// uint8 rgb_bak;
// 0x2002
uint32 sprite0_hit() { return ppu->LowRegs[2] & 0x40; }
uint32 more_than_8_sprites_on_cur_line() { return ppu->LowRegs[2] & 0x20; }
uint32 VRAM_accessible() { return ppu->LowRegs[2] & 0x10; }
// by rinao
// uint8* get_patt() { return PPU_patterntables; }
// uint8* get_namt() { return ppu->PPU_nametables; }
// uint8 get_pattype(uint8 bank) { return PPU_patterntype[bank]; }
// void set_pattype(uint8 bank, uint8 data) { PPU_patterntype[bank] = data; }
//*****************************************************************
// ROM_banks = (uint8*)malloc(header.num_16k_rom_banks * (16*1024));
// VROM_banks = (uint8*)malloc(header.num_8k_vrom_banks * (8*1024));
// VROM_tiles = (uint8 *)malloc(RomHeader->num_8k_vrom_banks * 8 * 1024 / 16 * BYTES_PER_COMPILED_TILE);
// compile(header.num_8k_vrom_banks * 8 * 1024 / 16, VROM_banks, VROM_tiles);
// uint8* get_ROM_banks() { return ROM_banks; }
// uint8* get_VROM_banks() { return VROM_banks; }
// uint8* get_VROM_tiles() { return VROM_tiles; }
// #define MASK_BANK(bank,mask) (bank) = ((bank) & (mask))
// #define VALIDATE_VROM_BANK(bank) \
// MASK_BANK(bank,VROM_mask); \
// if((bank) >= (RomHeader->num_8k_vrom_banks * 8)) return;
//****************************************************************************************************
#define EXTRACT_4_PIXELS() \
col = 0; \
if(pattern_lo & pattern_mask) col |= (0x01 << 6); \
if(pattern_hi & pattern_mask) col |= (0x02 << 6); \
pattern_mask >>= 1; \
if(pattern_lo & pattern_mask) col |= (0x01 << 4); \
if(pattern_hi & pattern_mask) col |= (0x02 << 4); \
pattern_mask >>= 1; \
if(pattern_lo & pattern_mask) col |= (0x01 << 2); \
if(pattern_hi & pattern_mask) col |= (0x02 << 2); \
pattern_mask >>= 1; \
if(pattern_lo & pattern_mask) col |= (0x01 << 0); \
if(pattern_hi & pattern_mask) col |= (0x02 << 0); \
*p++= col;
void compile1(int count, uint8 *src, uint8 *dest)
{
uint8 *p = dest;
uint8 col;
uint8 pattern_lo;
uint8 pattern_hi;
int i,line,pattern_mask;
for (i = 0; i < count; i++) {
for (line = 0; line < 8; line++) {
pattern_lo = *src;
pattern_hi = *(src + 8);
pattern_mask = 0x80;
EXTRACT_4_PIXELS();
pattern_mask >>= 1;
EXTRACT_4_PIXELS();
src++;
}
src += 8;
}
}
void compile(int count, uint8 *src, uint8 *dest)
{
u8 destemp[16];
u8 *p = destemp;
u8 col;
u8 pattern_lo;
u8 pattern_hi;
int i,line,pattern_mask;
u8 j;
for (i = 0; i < count; i++)
{
for (line = 0; line < 8; line++)
{
pattern_lo = *src;
pattern_hi = *(src + 8);
pattern_mask = 0x80;
EXTRACT_4_PIXELS();
pattern_mask >>= 1;
EXTRACT_4_PIXELS();
src++;
}
p=destemp;//重新指向数组首地址
for(j=0;j<16;j++)*dest++=destemp[j];
src += 8;
}
}
#define UPDATE_PIXEL() \
if(data & pattern_mask) *p |= bit; \
p++;
#define VRAM(addr) \
ppu->PPU_VRAM_banks[(addr) >> 10][(addr) & 0x3FF]
#define TILE(addr) \
(ppu->PPU_tile_banks[(addr) >> 10] + ((addr) & 0x3FF) / 16 * 16)
#define TILE_OFFSET(line) \
((line) * 2)
/*
scanline start (if background or sprites are enabled):
v:0000010000011111=t:0000010000011111
*/
#define LOOPY_SCANLINE_START(v,t) \
{ \
v = (v & 0xFBE0) | (t & 0x041F); \
}
#define LOOPY_NEXT_LINE(v) \
{ \
if((v & 0x7000) == 0x7000) /* is subtile y offset == 7? */ \
{ \
v &= 0x8FFF; /* subtile y offset = 0 */ \
if((v & 0x03E0) == 0x03A0) /* name_tab line == 29? */ \
{ \
v ^= 0x0800; /* switch nametables (bit 11) */ \
v &= 0xFC1F; /* name_tab line = 0 */ \
} \
else \
{ \
if((v & 0x03E0) == 0x03E0) /* line == 31? */ \
{ \
v &= 0xFC1F; /* name_tab line = 0 */ \
} \
else \
{ \
v += 0x0020; \
} \
} \
} \
else \
{ \
v += 0x1000; /* next subtile y offset */ \
} \
}
#define LOOPY_NEXT_TILE(v) \
{ \
if((v & 0x001F) == 0x001F) \
{ \
v ^= 0x0400; /* switch nametables (bit 10) */ \
v &= 0xFFE0; /* tile x = 0 */ \
} \
else \
{ \
v++; /* next tile */ \
} \
}
#define LOOPY_NEXT_PIXEL(v,x) \
{ \
if(x == 0x07) \
{ \
LOOPY_NEXT_TILE(v); \
x = 0x00; \
} \
else \
{ \
x++; \
} \
}
void PPU_Latch_FDFE(uint32 addr) {}
#define CHECK_MMC2(addr) \
if(((addr) & 0x0FC0) == 0x0FC0) \
{ \
if((((addr) & 0x0FF0) == 0x0FD0) || (((addr) & 0x0FF0) == 0x0FE0)) \
{ \
PPU_Latch_FDFE(addr); \
} \
}
//、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、初始化
static u16 *LCD_ADDR=0;
void PPU_reset(void *lcd_addr)
{
LCD_ADDR=lcd_addr;
if (LCD_ADDR==0) return;
// static u8 first=0;
// if (first==0)
// {
// first=1;
// for (int i=0;i<64;i++)
// {
// NES_Palette[i]=COLOR565TO888(NES_Palette[i]);
// }
// }
//清屏
// for (int i=0;i<480*272;i++)
// {
// LCD_ADDR[i]=0;
// }
// set up PPU memory space table
PPU_patterntables=VROM_banks;//不确定正确
ppu->PPU_VRAM_banks[0x00] = PPU_patterntables + (0*0x400);
ppu->PPU_VRAM_banks[0x01] = PPU_patterntables + (1*0x400);
ppu->PPU_VRAM_banks[0x02] = PPU_patterntables + (2*0x400);
ppu->PPU_VRAM_banks[0x03] = PPU_patterntables + (3*0x400);
ppu->PPU_VRAM_banks[0x04] = PPU_patterntables + (4*0x400);
ppu->PPU_VRAM_banks[0x05] = PPU_patterntables + (5*0x400);
ppu->PPU_VRAM_banks[0x06] = PPU_patterntables + (6*0x400);
ppu->PPU_VRAM_banks[0x07] = PPU_patterntables + (7*0x400);
// point nametables at internal name table 0
ppu->PPU_VRAM_banks[0x08] = ppu->PPU_nametables;
ppu->PPU_VRAM_banks[0x09] = ppu->PPU_nametables;
ppu->PPU_VRAM_banks[0x0A] = ppu->PPU_nametables;
ppu->PPU_VRAM_banks[0x0B] = ppu->PPU_nametables;
ppu->PPU_tile_tables=VROM_tiles;//不确定正确
//BYTES_PER_COMPILED_TILE=16
ppu->PPU_tile_banks[0x00] = ppu->PPU_tile_tables + (0*0x400);
ppu->PPU_tile_banks[0x01] = ppu->PPU_tile_tables + (1*0x400);
ppu->PPU_tile_banks[0x02] = ppu->PPU_tile_tables + (2*0x400);
ppu->PPU_tile_banks[0x03] = ppu->PPU_tile_tables + (3*0x400);
ppu->PPU_tile_banks[0x04] = ppu->PPU_tile_tables + (4*0x400);
ppu->PPU_tile_banks[0x05] = ppu->PPU_tile_tables + (5*0x400);
ppu->PPU_tile_banks[0x06] = ppu->PPU_tile_tables + (6*0x400);
ppu->PPU_tile_banks[0x07] = ppu->PPU_tile_tables + (7*0x400);
ppu->read_2007_buffer = 0x00;
ppu->in_vblank = 0;
ppu->bg_pattern_table_addr = 0;
ppu->spr_pattern_table_addr = 0;
ppu->ppu_addr_inc = 0;
ppu->loopy_v = 0;
ppu->loopy_t = 0;
ppu->loopy_x = 0;
ppu->toggle_2005_2006 = 0;
ppu->spr_ram_rw_ptr = 0;
ppu->read_2007_buffer = 0;
ppu->current_frame_line = 0;
if(RomHeader->flags_1 &0x01)set_mirroring(0,1,0,1);//垂直镜像 // PPU_set_mirroring(); 设置镜像
else set_mirroring(0,0,1,1);//水平镜像
}
//***********************************************************************************************
void set_mirroring(uint32 nt0, uint32 nt1, uint32 nt2, uint32 nt3)//设置垂直水平镜像
{
ppu->PPU_VRAM_banks[0x08] = ppu->PPU_nametables + (nt0 << 10); // * 0x0400
ppu->PPU_VRAM_banks[0x09] = ppu->PPU_nametables + (nt1 << 10);
ppu->PPU_VRAM_banks[0x0A] = ppu->PPU_nametables + (nt2 << 10);
ppu->PPU_VRAM_banks[0x0B] = ppu->PPU_nametables + (nt3 << 10);
// name_table_switched = TRUE;
}
void PPU_start_frame(void)
{
ppu->current_frame_line = 0;
if(spr_enabled() || bg_enabled())
{
ppu->loopy_v = ppu->loopy_t;
}
}
uint8 getBGColor() { return ppu->bg_pal[0]; }
void do_scanline_and_draw(uint8* buf)
{
uint16 i;
if(!bg_enabled())
{
// set to background color设置背景颜色
// memset(buf, bg_pal[0], NES_BACKBUF_WIDTH);//NES_BACKBUF_WIDTH=256+(2*8)
for(i=0;i<(256+16);i++)
{
buf[i]=ppu->bg_pal[0];
}
}
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);
}
ppu->current_frame_line++;
}
extern u8 nes_xoff; //显示在x轴方向的偏移量(实际显示宽度=256-2*nes_xoff)
extern u8 nes_yoff;
void scanline_draw(int LineNo)
{
uint16 i;
u16 sx,ex;
do_scanline_and_draw(ppu->dummy_buffer);
sx=0+8;
ex=256+8-0;
{
for(i=sx;i<ex;i++)
{
// LCD_ADDR[(480*272-1)-((NES_scanline+nes_yoff)*480+(i-8+nes_xoff))]=NES_Palette[ppu->dummy_buffer[i]];
LCD_ADDR[((NES_scanline+nes_yoff)*480+(i-8+nes_xoff))]=NES_Palette[ppu->dummy_buffer[i]];
}
}
}
void do_scanline_and_dont_draw(int LineNo)
{
// uint16 i;
// mmc2 / punchout -- we must simulate the ppu for every line
// if(parent_NES->ROM->get_mapper_num() == 9)
// {
// do_scanline_and_draw(ppu->dummy_buffer);
// }
// else
{
// if sprite 0 flag not set and sprite 0 on current line
if((!sprite0_hit()) &&
(ppu->current_frame_line >= ((uint32)(spr_ram[0]+1))) &&
(ppu->current_frame_line < ((uint32)(spr_ram[0]+1+(sprites_8x16()?16:8))))
)
{
// render line to dummy buffer
do_scanline_and_draw(ppu->dummy_buffer);
}
else
{
if(spr_enabled() || bg_enabled())
{
LOOPY_SCANLINE_START(ppu->loopy_v, ppu->loopy_t);
LOOPY_NEXT_LINE(ppu->loopy_v);
}
ppu->current_frame_line++;
}
}
}
void start_vblank()
{
ppu->in_vblank = 1;
// set vblank register flag
ppu->LowRegs[2] |= 0x80;
}
void end_vblank()
{
ppu->in_vblank = 0;
// reset vblank register flag and sprite0 hit flag1
ppu->LowRegs[2] &= 0x3F;
}
// these functions read from/write to VRAM using loopy_v
uint8 read_2007()
{
uint16 addr;
uint8 temp;
addr = ppu->loopy_v;
ppu->loopy_v += ppu->ppu_addr_inc;
addr &= 0x3FFF;
if(addr >= 0x3000)
{
// is it a palette entry?
if(addr >= 0x3F00)
{
// palette
// handle palette mirroring
if(0x0000 == (addr & 0x0010))
{
// background palette
return ppu->bg_pal[addr & 0x000F];
}
else
{
// sprite palette
return ppu->spr_pal[addr & 0x000F];
}
}
// handle mirroring
addr &= 0xEFFF;
}
temp = ppu->read_2007_buffer;
ppu->read_2007_buffer = VRAM(addr);
return temp;
}
void write_2007(uint8 data)
{
uint16 addr;
addr = ppu->loopy_v;
ppu->loopy_v += ppu->ppu_addr_inc;
addr &= 0x3FFF;
if(addr >= 0x3000)
{
// is it a palette entry?
if(addr >= 0x3F00)
{
// palette
data &= 0x3F;
if(0x0000 == (addr & 0x000F)) // is it THE 0 entry?0的条目吗
{
ppu->bg_pal[0] = ppu->spr_pal[0] = data;
}
else if(0x0000 == (addr & 0x0010))
{
// background palette
ppu->bg_pal[addr & 0x000F] = data;
}
else
{
// sprite palette
ppu->spr_pal[addr & 0x000F] = data;
}
return;
}
// handle mirroring处理镜像
addr &= 0xEFFF;
}
VRAM(addr) = data;
if (addr < 0x2000) {
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
*(TILE(addr) + (addr & 0xf )) = data;//************************
#else
update_tile(addr, data);
#endif
}
}
#define UPDATE_4_PIXELS() \
col = 0; \
if(data & pattern_mask) col |= (bit << 6); \
pattern_mask >>= 1; \
if(data & pattern_mask) col |= (bit << 4); \
pattern_mask >>= 1; \
if(data & pattern_mask) col |= (bit << 2); \
pattern_mask >>= 1; \
if(data & pattern_mask) col |= (bit << 0); \
*p++ |= col;
void update_tile(int byte_offset, uint8 data)
{
//int tileNum = byte_offset >> 4;
int line = byte_offset & 0xf;
uint8 *p = TILE(byte_offset) + TILE_OFFSET(line & 0x7);
uint8 bit;
uint8 pattern_mask;
int col;
if (line < 8) {
// low pattern
bit = 0x01;
*(uint16 *)p &= 0xaaaa;
} else {
// high pattern
bit = 0x02;
*(uint16 *)p &= 0x5555;
}
pattern_mask = 0x80;
UPDATE_4_PIXELS();
pattern_mask >>= 1;
UPDATE_4_PIXELS();
}
uint8 PPU_ReadFromPort(uint16 addr)
{
uint8 temp;
//switch(addr)
switch(addr & 0x7)
{
//case 0x2002:
case 0x2:
// clear toggle
ppu->toggle_2005_2006 = 0;
temp = ppu->LowRegs[2];
// clear v-blank flag
ppu->LowRegs[2] &= 0x7F;
return temp;
// break;
//case 0x2007:
case 0x7:
return read_2007();
// break;
}
return ppu->LowRegs[addr & 0x0007];
}
void PPU_WriteToPort(uint8 data,uint16 addr )
{
// uint32 t;
ppu->LowRegs[addr & 0x0007] = data;
//switch(addr)
switch(addr & 0x7)
{
//case 0x2000:
case 0:
{
ppu->bg_pattern_table_addr = (data & 0x10) ? 0x1000 : 0x0000;
ppu->spr_pattern_table_addr = (data & 0x08) ? 0x1000 : 0x0000;
ppu->ppu_addr_inc = (data & 0x04) ? 32 : 1;
// t:0000110000000000=d:00000011
ppu->loopy_t = (ppu->loopy_t & 0xF3FF) | (((uint16)(data & 0x03)) << 10);
break;
}
// Rick, lazy updating stuff
//case 0x2001:
// case 1:
// bg_enabled();
//
// spr_enabled();
// break;
//case 0x2003:
case 3:
ppu->spr_ram_rw_ptr = data;
break;
//case 0x2004:
case 4:
spr_ram[ppu->spr_ram_rw_ptr++] = data;
break;
//case 0x2005:
case 5:
ppu->toggle_2005_2006 = !ppu->toggle_2005_2006;
if(ppu->toggle_2005_2006)
{
// first write
// t:0000000000011111=d:11111000
ppu->loopy_t = (ppu->loopy_t & 0xFFE0) | (((uint16)(data & 0xF8)) >> 3);
// x=d:00000111
ppu->loopy_x = data & 0x07;
}
else
{
// second write
// t:0000001111100000=d:11111000
ppu->loopy_t = (ppu->loopy_t & 0xFC1F) | (((uint16)(data & 0xF8)) << 2);
// t:0111000000000000=d:00000111
ppu->loopy_t = (ppu->loopy_t & 0x8FFF) | (((uint16)(data & 0x07)) << 12);
}
break;
//case 0x2006:
case 6:
ppu->toggle_2005_2006 = !ppu->toggle_2005_2006;
if(ppu->toggle_2005_2006)
{
// first write
// t:0011111100000000=d:00111111
// t:1100000000000000=0
ppu->loopy_t = (ppu->loopy_t & 0x00FF) | (((uint16)(data & 0x3F)) << 8);
}
else
{
// second write
// t:0000000011111111=d:11111111
ppu->loopy_t = (ppu->loopy_t & 0xFF00) | ((uint16)data);
// v=t
ppu->loopy_v = ppu->loopy_t;
}
break;
//case 0x2007:
case 7:
write_2007(data);
break;
}
}
//*****************************************************************************
#define DRAW_BG_PIXEL() \
col = attrib_bits; \
\
if(pattern_lo & pattern_mask) col |= 0x01; \
if(pattern_hi & pattern_mask) col |= 0x02; \
\
if(col & 0x03) \
{ \
*p = ppu->bg_pal[col]; \
/* set solid flag */ \
*solid = BG_WRITTEN_FLAG; \
} \
else \
{ \
*p = ppu->bg_pal[0]; \
/* set solid flag */ \
*solid = 0; \
} \
solid++; \
p++; \
//***************************************************************************************
#define NEW_BG_PIXEL() \
if (col) {\
col |= attrib_bits; \
*solid = BG_WRITTEN_FLAG; \
} else { \
col = 0; \
*solid = 0; \
} \
*p = ppu->bg_pal[col]; \
solid++; \
p++; \
void render_bg(uint8* buf)
{
uint8 *p;
uint32 i;
uint8 *solid;
uint8 *data;
uint32 col;
uint32 tile_x; // pixel coords within nametable像素坐标内nametable
uint32 tile_y;
uint32 name_addr;
uint32 line;
uint32 pattern_addr;
uint32 attrib_addr;
uint32 attrib_bits;
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
uint8 pattern_lo;
uint8 pattern_hi;
uint8 pattern_mask;
#else
int col2;
#endif
tile_x = (ppu->loopy_v & 0x001F);
tile_y = (ppu->loopy_v & 0x03E0) >> 5;
name_addr = 0x2000 + (ppu->loopy_v & 0x0FFF);
attrib_addr = 0x2000 + (ppu->loopy_v & 0x0C00) + 0x03C0 + ((tile_y & 0xFFFC)<<1) + (tile_x>>2);
if(0x0000 == (tile_y & 0x0002))
if(0x0000 == (tile_x & 0x0002))
attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
else
attrib_bits = (VRAM(attrib_addr) & 0x0C);
else
if(0x0000 == (tile_x & 0x0002))
attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
else
attrib_bits = (VRAM(attrib_addr) & 0xC0) >> 4;
p = buf + (SIDE_MARGIN - ppu->loopy_x);
solid = ppu->solid_buf + (SIDE_MARGIN - ppu->loopy_x); // set "solid" buffer ptr
line = (ppu->loopy_v & 0x7000) >> 12;
// draw 33 tiles
for(i = 33; i; i--)
{
pattern_addr = ppu->bg_pattern_table_addr + ((int32)VRAM(name_addr) << 4) + line;
// CHECK_MMC2(pattern_addr);//*******************************************************
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
data = TILE(pattern_addr) + line;
pattern_lo = *data;
pattern_hi = *(data + 8);
pattern_mask = 0x80;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
pattern_mask >>= 1;
DRAW_BG_PIXEL();
#else
data = TILE(pattern_addr) + TILE_OFFSET(line);
col2 = *data++;
col = col2 >> 6;
NEW_BG_PIXEL();
col = (col2 >> 4) & 0x03;
NEW_BG_PIXEL();
col = (col2 >> 2) & 0x03;
NEW_BG_PIXEL();
col = col2 & 0x03;
NEW_BG_PIXEL();
col2 = *data++;
col = col2 >> 6;
NEW_BG_PIXEL();
col = (col2 >> 4) & 0x03;
NEW_BG_PIXEL();
col = (col2 >> 2) & 0x03;
NEW_BG_PIXEL();
col = col2 & 0x03;
NEW_BG_PIXEL();
#endif
tile_x++;
name_addr++;
// are we crossing a dual-tile boundary?我们穿越dual-tile边界吗?
if(0x0000 == (tile_x & 0x0001))
{
// are we crossing a quad-tile boundary?
if(0x0000 == (tile_x & 0x0003))
{
// are we crossing a name table boundary?
if(0x0000 == (tile_x & 0x001F))
{
name_addr ^= 0x0400; // switch name tables
attrib_addr ^= 0x0400;
name_addr -= 0x0020;
attrib_addr -= 0x0008;
tile_x -= 0x0020;
}
attrib_addr++;
}
if(0x0000 == (tile_y & 0x0002))
if(0x0000 == (tile_x & 0x0002))
attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;
else
attrib_bits = (VRAM(attrib_addr) & 0x0C);
else
if(0x0000 == (tile_x & 0x0002))
attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;
else
attrib_bits = (VRAM(attrib_addr) & 0xC0) >> 4;
}
}
// if(bg_clip_left8())
// {
// // clip left 8 pixels夹了8个像素SIDE_MARGIN = 8,
// memset(buf + SIDE_MARGIN, bg_pal[0], 8);
// memset(solid + SIDE_MARGIN, 0, sizeof(solid[0])*8);
// }
}
void render_spr(uint8* buf)
{
int32 s; // sprite #
int32 spr_x; // sprite coordinates
uint32 spr_y;
uint8* spr; // pointer to sprite RAM entry
uint8* p; // draw pointer
int line;
//uint32 *solid;
uint8 *solid;
uint32 priority;
uint32 tile_addr;
int32 inc_x; // drawing vars
int32 start_x, end_x;
int32 x,y; // in-sprite coords
uint32 col;
uint32 num_sprites = 0;
uint8 *t;
uint32 spr_height;
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
uint8 pattern_lo;
uint8 pattern_hi;
#else
uint32 pattern;
#endif
spr_height = sprites_8x16() ? 16 : 8;
//for(s = 0; s < 64; s++)
for(s = 0, spr = spr_ram; s < 64; s++, spr+=4)
{
spr_y = spr[0]+1;
// on current scanline对当前扫描线?
if((spr_y > ppu->current_frame_line) || ((spr_y+(spr_height)) <= ppu->current_frame_line))
continue;
num_sprites++;
if(num_sprites > 8)
{
/*if(!show_more_than_8_sprites)*/ break;//**************************************
}
// get x coord
spr_x = spr[3];
start_x = 0;
end_x = 8;
// clip right
if((spr_x + 7) > 255)
{
end_x -= ((spr_x + 7) - 255);
}
// clip left
if((spr_x < 8) && (spr_clip_left8()))
{
if(0 == spr_x) continue;
start_x += (8 - spr_x);
}
y = ppu->current_frame_line - spr_y;
// CHECK_MMC2(spr[1] << 4);//**************************************************************************
// calc offsets into buffers
p = &buf[SIDE_MARGIN + spr_x + start_x];
solid = &ppu->solid_buf[SIDE_MARGIN + spr_x + start_x];
// flip horizontally?
if(spr[2] & 0x40) // yes
{
inc_x = -1;
start_x = (8-1) - start_x;
end_x = (8-1) - end_x;
}
else
{
inc_x = 1;
}
// flip vertically?
if(spr[2] & 0x80) // yes
{
y = (spr_height-1) - y;
}
line = y & 7;
// get priority bit
priority = spr[2] & 0x20;
tile_addr = spr[1] << 4;
if(sprites_8x16()) {
if(spr[1] & 0x01) {
tile_addr += 0x1000;
if(y < 8) tile_addr -= 16;
} else {
if(y >= 8) tile_addr += 16;
}
} else {
tile_addr += ppu->spr_pattern_table_addr;
}
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
t = TILE(tile_addr) + line;
pattern_lo = *t;
pattern_hi = *(t + 8);
#else
// read 16bits = 2bits x 8pixels
t = TILE(tile_addr) + TILE_OFFSET(line);
pattern = ((uint32)*t << 8) | *(t + 1);
#endif
for(x = start_x; x != end_x; x += inc_x)
{
//uint8 col = 0x00;
// if a sprite has drawn on this pixel, don't draw anything如果一个雪碧吸引了这个像素,不画任何东西
if(!((*solid) & SPR_WRITTEN_FLAG))
{
#if NES_RAM_SPEED==1 //1:内存占用小 0:速度快
col = ((pattern_hi>>(7-x)<<1)&2)|((pattern_lo>>(7-x))&1);
#else
col = pattern >> ((7 - (x & 7)) * 2);
#endif
col &= 0x03;
if (col) {
col |= (spr[2] & 0x03) << 2;
// set sprite 0 hit flag
if(!s)
{
if((*solid) & BG_WRITTEN_FLAG)
{
ppu->LowRegs[2] |= 0x40;
}
}
(*solid) |= SPR_WRITTEN_FLAG;
if(priority)
{
//(*solid) |= SPR_WRITTEN_FLAG;
if(!((*solid) & BG_WRITTEN_FLAG))
{
*p = ppu->spr_pal[col];
}
}
else
{
*p = ppu->spr_pal[col];
}
}
}
p++;
solid++;
}
}
if(num_sprites >= 8)
{
ppu->LowRegs[2] |= 0x20;
}
else
{
ppu->LowRegs[2] &= 0xDF;
}
}