1063 lines
24 KiB
C
1063 lines
24 KiB
C
#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;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|