auto PPU::Background::clip(int n) -> int { //13-bit sign extend: --s---nnnnnnnnnn -> ssssssnnnnnnnnnn return n & 0x2000 ? (n | ~1023) : (n & 1023); } //H = 28 auto PPU::Background::beginMode7() -> void { latch.hoffset = ppu.r.hoffsetMode7; latch.voffset = ppu.r.voffsetMode7; } auto PPU::Background::runMode7() -> void { int a = (int16)ppu.r.m7a; int b = (int16)ppu.r.m7b; int c = (int16)ppu.r.m7c; int d = (int16)ppu.r.m7d; int cx = (int13)ppu.r.m7x; int cy = (int13)ppu.r.m7y; int hoffset = (int13)latch.hoffset; int voffset = (int13)latch.voffset; if(Background::x++ & ~255) return; uint x = mosaic.hoffset; uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size if(--mosaic.hcounter == 0) { mosaic.hcounter = r.mosaic + 1; mosaic.hoffset += r.mosaic + 1; } if(ppu.r.hflipMode7) x = 255 - x; if(ppu.r.vflipMode7) y = 255 - y; int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8); int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8); int px = psx + (a * x); int py = psy + (c * x); //mask pseudo-FP bits px >>= 8; py >>= 8; uint tile; uint palette; switch(ppu.r.repeatMode7) { //screen repetition outside of screen area case 0: case 1: px &= 1023; py &= 1023; tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; break; //palette color 0 outside of screen area case 2: if((px | py) & ~1023) { palette = 0; } else { px &= 1023; py &= 1023; tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; } break; //character 0 repetition outside of screen area case 3: if((px | py) & ~1023) { tile = 0; } else { px &= 1023; py &= 1023; tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; } palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; break; } uint priority; if(id == ID::BG1) { priority = r.priority[0]; } else if(id == ID::BG2) { priority = r.priority[bool(palette & 0x80)]; palette &= 0x7f; } if(palette == 0) return; if(r.aboveEnable) { output.above.palette = palette; output.above.priority = priority; output.above.tile = 0; } if(r.belowEnable) { output.below.palette = palette; output.below.priority = priority; output.below.tile = 0; } }