#include #include #include "6502.h" #include "ppu.h" byte ppuctrl = 0, ppumask = 0, ppustatus = 0x80, ppuscrollx, ppuscrolly, ppuscrolli, ppuaddrmsb, ppumem[0x4000], oamaddr, ppureadbuf ; word ppuaddr; int curx = 0, cury = 0; #define maxx 256 #define maxy 262 byte oam[256]; byte sprites[65]; void oamfill(byte b) { int i, j = 0; word p = b << 8; for(i=0;i<64;i++) { *(int*)(oam + 4 * i) = *(int*)(mem + p + 4 * i); if(oam[i] < 0xEF) sprites[j++] = i; } if(j < 64) sprites[j] = 255; } byte ppuread(word addr) { switch(addr) { case 0x2002: { byte x = ppustatus; ppustatus &= 0x7f; ppuscrolli = 0; return x; } case 0x2007: { byte x = ppureadbuf; ppureadbuf = ppumem[ppuaddr++]; return x; } default: sysfatal("read from ppu register %x either not permitted or not implemented", addr); } return 0; } void ppuwrite(word addr, byte val) { switch(addr) { case 0x2000: ppuctrl = val; break; case 0x2001: ppumask = val; break; case 0x2003: oamaddr = val; break; // case 0x2004: oammem[oamaddr++] = val; break; case 0x2005: switch(ppuscrolli) { case 0: ppuscrollx = val; ppuscrolli = 1; break; case 1: ppuscrolly = val; ppuscrolli = 0; break; }; break; case 0x2006: switch(ppuscrolli) { case 0: ppuaddrmsb = val; ppuscrolli = 1; break; case 1: ppuaddr = (ppuaddrmsb << 8) | val; ppuscrolli = 0; break; }; break; case 0x2007: ppumem[(ppuaddr) % 0x4000] = val; if(ppuctrl & 4) ppuaddr += 32; else ppuaddr++; break; default: sysfatal("write to ppu register %x either not permitted or not implemented", addr); } } const int colortable[] = { 0x788084, 0x0000FC, 0x0000C4, 0x4028C4, 0x94008C, 0xAC0028, 0xAC1000, 0x8C1800, 0x503000, 0x007800, 0x006800, 0x005800, 0x004058, 0x000000, 0x000000, 0x000008, 0xBCC0C4, 0x0078FC, 0x0088FC, 0x6848FC, 0xDC00D4, 0xE40060, 0xFC3800, 0xE46018, 0xAC8000, 0x00B800, 0x00A800, 0x00A848, 0x008894, 0x2C2C2C, 0x000000, 0x000000, 0xFCF8FC, 0x38C0FC, 0x6888FC, 0x9C78FC, 0xFC78FC, 0xFC589C, 0xFC7858, 0xFCA048, 0xFCB800, 0xBCF818, 0x58D858, 0x58F89C, 0x00E8E4, 0x606060, 0x000000, 0x000000, 0xFCF8FC, 0xA4E8FC, 0xBCB8FC, 0xDCB8FC, 0xFCB8FC, 0xF4C0E0, 0xF4D0B4, 0xFCE0B4, 0xFCD884, 0xDCF878, 0xB8F878, 0xB0F0D8, 0x00F8FC, 0xC8C0C0, 0x000000, 0x000000 }; int drawbg(void) { int x = curx, y = cury - 22; int nx = x / 8, ny = y / 8, rx = 7 - (x % 8), ry = y % 8; int nametable = 0x2000; byte nte = ppumem[nametable + nx + ny * 32]; byte ate = ppumem[nametable + 0x3C0 + nx/4 + (ny/4) * 8]; byte subtilenum = ((nx & 2) >> 1) | (ny & 2); byte paln = (ate >> (subtilenum << 1)) & 3; byte* pal = ppumem + 0x3F00 + (paln << 2); byte* pt = ppumem + 16 * nte; if(ppuctrl & (1<<4)) pt += 0x1000; byte coli = ((pt[ry] >> rx) & 1) | (((pt[ry+8] >> rx) & 1) << 1); if(coli > 0) { drawpixel(x, y, colortable[pal[coli] & 0x3F]); return 1; } else { drawpixel(x, y, colortable[ppumem[0x3F00] & 0x3F]); return 0; } } void drawspr(int opbg) { int x = curx, y = cury - 22; register int i; int h16 = (ppuctrl & 32) ? 1 : 0; for(i=0;sprites[i] != 0xFF;i++) { byte spy = oam[sprites[i]]; byte spi = oam[sprites[i]+1]; byte spa = oam[sprites[i]+2]; byte spx = oam[sprites[i]+3]; if(x < spx || x >= spx + 8 || y < spy + 1 || y >= spy + 9 + h16 * 8) continue; int cx = x - spx, cy = y - spy - 1; if(!(spa & (1<<6))) cx = 7 - cx; if(spa & (1<<7)) cy = (h16 ? 15 : 7) - cy; byte* pal = ppumem + 0x3F00 + ((4 + (spa & 3)) << 2); byte coli; if(h16) { byte* pt = ppumem + 16 * (spi & ~1); if(spi & 1) pt += 0x1000; if(cy >= 8) cy += 8; coli = ((pt[cy] >> cx) & 1) | (((pt[cy+8] >> cx) & 1) << 1); } else { byte* pt = ppumem + 16 * spi; if(ppuctrl & (1<<3)) pt += 0x1000; coli = ((pt[cy] >> cx) & 1) | (((pt[cy+8] >> cx) & 1) << 1); } if(coli > 0) { if(i == 0) { if(opbg) ppustatus |= 0x40; else ppustatus &= ~0x40; } if(!(spa & (1<<5)) || !opbg) drawpixel(x, y, colortable[pal[coli] & 0x3F]); } else if(i == 0) ppustatus &= ~0x40; } } void ppuadvance() { curx++; if(curx >= maxx) { curx = 0; cury++; if(cury >= maxy) { cury = 0; updatedisplay(); ppustatus |= 0x80; if(ppuctrl & 0x80) nmi(); } } int opbg = 0; if(cury >= 22 && (ppumask & (1<<3))) opbg = drawbg(); if(cury >= 22 && (ppumask & (1<<4))) drawspr(opbg); }