cleanup ppu class

This commit is contained in:
scawful
2024-04-26 12:05:49 -04:00
parent 89edcaa2a3
commit eca262bcc8
2 changed files with 301 additions and 298 deletions

View File

@@ -17,73 +17,73 @@ using namespace PpuRegisters;
// 0-7: mode 0-7; 8: mode 1 + l3prio; 9: mode 7 + extbg
// 0-3; layers 1-4; 4: sprites; 5: nonexistent
static const int layersPerMode[10][12] = {
static const int kLayersPerMode[10][12] = {
{4, 0, 1, 4, 0, 1, 4, 2, 3, 4, 2, 3}, {4, 0, 1, 4, 0, 1, 4, 2, 4, 2, 5, 5},
{4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5}, {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
{4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5}, {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
{4, 0, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5}, {4, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5, 5},
{2, 4, 0, 1, 4, 0, 1, 4, 4, 2, 5, 5}, {4, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5, 5}};
static const int prioritysPerMode[10][12] = {
static const int kPrioritysPerMode[10][12] = {
{3, 1, 1, 2, 0, 0, 1, 1, 1, 0, 0, 0}, {3, 1, 1, 2, 0, 0, 1, 1, 0, 0, 5, 5},
{3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5}, {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
{3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5}, {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
{3, 1, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5}, {3, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5, 5},
{1, 3, 1, 1, 2, 0, 0, 1, 0, 0, 5, 5}, {3, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5, 5}};
static const int layerCountPerMode[10] = {12, 10, 8, 8, 8, 8, 6, 5, 10, 7};
static const int kLayerCountPerMode[10] = {12, 10, 8, 8, 8, 8, 6, 5, 10, 7};
static const int bitDepthsPerMode[10][4] = {
static const int kBitDepthsPerMode[10][4] = {
{2, 2, 2, 2}, {4, 4, 2, 5}, {4, 4, 5, 5}, {8, 4, 5, 5}, {8, 2, 5, 5},
{4, 2, 5, 5}, {4, 5, 5, 5}, {8, 5, 5, 5}, {4, 4, 2, 5}, {8, 7, 5, 5}};
static const int spriteSizes[8][2] = {{8, 16}, {8, 32}, {8, 64}, {16, 32},
{16, 64}, {32, 64}, {16, 32}, {16, 32}};
static const int kSpriteSizes[8][2] = {{8, 16}, {8, 32}, {8, 64}, {16, 32},
{16, 64}, {32, 64}, {16, 32}, {16, 32}};
void Ppu::Update() {}
void Ppu::Reset() {
memset(vram, 0, sizeof(vram));
vramPointer = 0;
vramIncrementOnHigh = false;
vramIncrement = 1;
vramRemapMode = 0;
vramReadBuffer = 0;
vram_pointer = 0;
vram_increment_on_high_ = false;
vram_increment_ = 1;
vram_remap_mode_ = 0;
vram_read_buffer_ = 0;
memset(cgram, 0, sizeof(cgram));
cgramPointer = 0;
cgramSecondWrite = false;
cgramBuffer = 0;
cgram_pointer_ = 0;
cgram_second_write_ = false;
cgram_buffer_ = 0;
memset(oam, 0, sizeof(oam));
memset(highOam, 0, sizeof(highOam));
oamAdr = 0;
oamAdrWritten = 0;
oamInHigh = false;
oamInHighWritten = false;
oamSecondWrite = false;
oamBuffer = 0;
objPriority = false;
objTileAdr1 = 0;
objTileAdr2 = 0;
objSize = 0;
memset(high_oam_, 0, sizeof(high_oam_));
oam_adr_ = 0;
oam_adr_written_ = 0;
oam_in_high_ = false;
oam_in_high_written_ = false;
oam_second_write_ = false;
oam_buffer_ = 0;
obj_priority_ = false;
obj_tile_adr1_ = 0;
obj_tile_adr2_ = 0;
obj_size_ = 0;
obj_pixel_buffer_.fill(0);
memset(objPriorityBuffer, 0, sizeof(objPriorityBuffer));
obj_priority_buffer_.fill(0);
time_over_ = false;
range_over_ = false;
objInterlace = false;
obj_interlace_ = false;
for (int i = 0; i < 4; i++) {
bgLayer[i].hScroll = 0;
bgLayer[i].vScroll = 0;
bgLayer[i].tilemapWider = false;
bgLayer[i].tilemapHigher = false;
bgLayer[i].tilemapAdr = 0;
bgLayer[i].tileAdr = 0;
bgLayer[i].bigTiles = false;
bgLayer[i].mosaicEnabled = false;
bg_layer_[i].hScroll = 0;
bg_layer_[i].vScroll = 0;
bg_layer_[i].tilemapWider = false;
bg_layer_[i].tilemapHigher = false;
bg_layer_[i].tilemapAdr = 0;
bg_layer_[i].tileAdr = 0;
bg_layer_[i].bigTiles = false;
bg_layer_[i].mosaicEnabled = false;
}
scrollPrev = 0;
scrollPrev2 = 0;
mosaicSize = 1;
mosaicStartLine = 1;
scroll_prev_ = 0;
scroll_prev2_ = 0;
mosaic_size_ = 1;
mosaic_startline_ = 1;
for (int i = 0; i < 5; i++) {
layer_[i].mainScreenEnabled = false;
layer_[i].subScreenEnabled = false;
@@ -113,30 +113,30 @@ void Ppu::Reset() {
clip_mode_ = 0;
prevent_math_mode_ = 0;
add_subscreen_ = false;
subtractColor = false;
halfColor = false;
subtract_color_ = false;
half_color_ = false;
memset(math_enabled_array_, 0, sizeof(math_enabled_array_));
fixedColorR = 0;
fixedColorG = 0;
fixedColorB = 0;
forcedBlank = true;
fixed_color_r_ = 0;
fixed_color_g_ = 0;
fixed_color_b_ = 0;
forced_blank_ = true;
brightness = 0;
mode = 0;
bg3priority = false;
even_frame = false;
pseudoHires = false;
overscan = false;
frameOverscan = false;
pseudo_hires_ = false;
overscan_ = false;
frame_overscan_ = false;
interlace = false;
frame_interlace = false;
directColor = false;
hCount = 0;
vCount = 0;
hCountSecond = false;
vCountSecond = false;
countersLatched = false;
ppu1openBus = 0;
ppu2openBus = 0;
direct_color_ = false;
h_count_ = 0;
v_count_ = 0;
h_count_second_ = false;
v_count_second_ = false;
counters_latched_ = false;
ppu1_open_bus_ = 0;
ppu2_open_bus_ = 0;
memset(pixelBuffer, 0, sizeof(pixelBuffer));
}
@@ -152,7 +152,7 @@ void Ppu::RunLine(int line) {
// called for lines 1-224/239
// evaluate sprites
obj_pixel_buffer_.fill(0);
if (!forcedBlank) EvaluateSprites(line - 1);
if (!forced_blank_) EvaluateSprites(line - 1);
// actual line
if (mode == 7) CalculateMode7Starts(line);
for (int x = 0; x < 256; x++) {
@@ -164,7 +164,7 @@ void Ppu::HandlePixel(int x, int y) {
int r = 0, r2 = 0;
int g = 0, g2 = 0;
int b = 0, b2 = 0;
if (!forcedBlank) {
if (!forced_blank_) {
int mainLayer = GetPixel(x, y, false, &r, &g, &b);
bool colorWindowState = GetWindowState(5, x);
if (clip_mode_ == 3 || (clip_mode_ == 2 && colorWindowState) ||
@@ -178,23 +178,23 @@ void Ppu::HandlePixel(int x, int y) {
!(prevent_math_mode_ == 3 ||
(prevent_math_mode_ == 2 && colorWindowState) ||
(prevent_math_mode_ == 1 && !colorWindowState));
if ((mathEnabled && add_subscreen_) || pseudoHires || mode == 5 ||
if ((mathEnabled && add_subscreen_) || pseudo_hires_ || mode == 5 ||
mode == 6) {
secondLayer = GetPixel(x, y, true, &r2, &g2, &b2);
}
// TODO: subscreen pixels can be clipped to black as well
// TODO: math for subscreen pixels (add/sub sub to main)
if (mathEnabled) {
if (subtractColor) {
r -= (add_subscreen_ && secondLayer != 5) ? r2 : fixedColorR;
g -= (add_subscreen_ && secondLayer != 5) ? g2 : fixedColorG;
b -= (add_subscreen_ && secondLayer != 5) ? b2 : fixedColorB;
if (subtract_color_) {
r -= (add_subscreen_ && secondLayer != 5) ? r2 : fixed_color_r_;
g -= (add_subscreen_ && secondLayer != 5) ? g2 : fixed_color_g_;
b -= (add_subscreen_ && secondLayer != 5) ? b2 : fixed_color_b_;
} else {
r += (add_subscreen_ && secondLayer != 5) ? r2 : fixedColorR;
g += (add_subscreen_ && secondLayer != 5) ? g2 : fixedColorG;
b += (add_subscreen_ && secondLayer != 5) ? b2 : fixedColorB;
r += (add_subscreen_ && secondLayer != 5) ? r2 : fixed_color_r_;
g += (add_subscreen_ && secondLayer != 5) ? g2 : fixed_color_g_;
b += (add_subscreen_ && secondLayer != 5) ? b2 : fixed_color_b_;
}
if (halfColor && (secondLayer != 5 || !add_subscreen_)) {
if (half_color_ && (secondLayer != 5 || !add_subscreen_)) {
r >>= 1;
g >>= 1;
b >>= 1;
@@ -206,7 +206,7 @@ void Ppu::HandlePixel(int x, int y) {
if (g < 0) g = 0;
if (b < 0) b = 0;
}
if (!(pseudoHires || mode == 5 || mode == 6)) {
if (!(pseudo_hires_ || mode == 5 || mode == 6)) {
r2 = r;
g2 = g;
b2 = b;
@@ -236,9 +236,9 @@ int Ppu::GetPixel(int x, int y, bool subscreen, int* r, int* g, int* b) {
actMode = mode == 7 && m7extBg ? 9 : actMode;
int layer = 5;
int pixel = 0;
for (int i = 0; i < layerCountPerMode[actMode]; i++) {
int curLayer = layersPerMode[actMode][i];
int curPriority = prioritysPerMode[actMode][i];
for (int i = 0; i < kLayerCountPerMode[actMode]; i++) {
int curLayer = kLayersPerMode[actMode][i];
int curPriority = kPrioritysPerMode[actMode][i];
bool layerActive = false;
if (!subscreen) {
layerActive = layer_[curLayer].mainScreenEnabled &&
@@ -254,23 +254,23 @@ int Ppu::GetPixel(int x, int y, bool subscreen, int* r, int* g, int* b) {
// bg layer
int lx = x;
int ly = y;
if (bgLayer[curLayer].mosaicEnabled && mosaicSize > 1) {
lx -= lx % mosaicSize;
ly -= (ly - mosaicStartLine) % mosaicSize;
if (bg_layer_[curLayer].mosaicEnabled && mosaic_size_ > 1) {
lx -= lx % mosaic_size_;
ly -= (ly - mosaic_startline_) % mosaic_size_;
}
if (mode == 7) {
pixel = GetPixelForMode7(lx, curLayer, curPriority);
} else {
lx += bgLayer[curLayer].hScroll;
lx += bg_layer_[curLayer].hScroll;
if (mode == 5 || mode == 6) {
lx *= 2;
lx += (subscreen || bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
lx += (subscreen || bg_layer_[curLayer].mosaicEnabled) ? 0 : 1;
if (interlace) {
ly *= 2;
ly += (even_frame || bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
ly += (even_frame || bg_layer_[curLayer].mosaicEnabled) ? 0 : 1;
}
}
ly += bgLayer[curLayer].vScroll;
ly += bg_layer_[curLayer].vScroll;
if (mode == 2 || mode == 4 || mode == 6) {
HandleOPT(curLayer, &lx, &ly);
}
@@ -280,7 +280,8 @@ int Ppu::GetPixel(int x, int y, bool subscreen, int* r, int* g, int* b) {
} else {
// get a pixel from the sprite buffer
pixel = 0;
if (objPriorityBuffer[x] == curPriority) pixel = obj_pixel_buffer_[x];
if (obj_priority_buffer_[x] == curPriority)
pixel = obj_pixel_buffer_[x];
}
}
if (pixel > 0) {
@@ -288,7 +289,7 @@ int Ppu::GetPixel(int x, int y, bool subscreen, int* r, int* g, int* b) {
break;
}
}
if (directColor && layer < 4 && bitDepthsPerMode[actMode][layer] == 8) {
if (direct_color_ && layer < 4 && kBitDepthsPerMode[actMode][layer] == 8) {
*r = ((pixel & 0x7) << 2) | ((pixel & 0x100) >> 7);
*g = ((pixel & 0x38) >> 1) | ((pixel & 0x200) >> 8);
*b = ((pixel & 0xc0) >> 3) | ((pixel & 0x400) >> 8);
@@ -357,9 +358,9 @@ void Ppu::HandleOPT(int layer, int* lx, int* ly) {
int y = *ly;
int column = 0;
if (mode == 6) {
column = ((x - (x & 0xf)) - ((bgLayer[layer].hScroll * 2) & 0xfff0)) >> 4;
column = ((x - (x & 0xf)) - ((bg_layer_[layer].hScroll * 2) & 0xfff0)) >> 4;
} else {
column = ((x - (x & 0x7)) - (bgLayer[layer].hScroll & 0xfff8)) >> 3;
column = ((x - (x & 0x7)) - (bg_layer_[layer].hScroll & 0xfff8)) >> 3;
}
if (column > 0) {
// fetch offset values from layer 3 tilemap
@@ -382,36 +383,38 @@ void Ppu::HandleOPT(int layer, int* lx, int* ly) {
if (hOffset & valid) *lx = ((hOffset & 0x3f8) + (column * 8)) | (x & 0x7);
}
// TODO: not sure if correct for interlace
if (vOffset & valid) *ly = (vOffset & 0x3ff) + (y - bgLayer[layer].vScroll);
if (vOffset & valid)
*ly = (vOffset & 0x3ff) + (y - bg_layer_[layer].vScroll);
}
}
uint16_t Ppu::GetOffsetValue(int col, int row) {
int x = col * 8 + bgLayer[2].hScroll;
int y = row * 8 + bgLayer[2].vScroll;
int tileBits = bgLayer[2].bigTiles ? 4 : 3;
int tileHighBit = bgLayer[2].bigTiles ? 0x200 : 0x100;
uint16_t tilemapAdr = bgLayer[2].tilemapAdr + (((y >> tileBits) & 0x1f) << 5 |
((x >> tileBits) & 0x1f));
if ((x & tileHighBit) && bgLayer[2].tilemapWider) tilemapAdr += 0x400;
if ((y & tileHighBit) && bgLayer[2].tilemapHigher)
tilemapAdr += bgLayer[2].tilemapWider ? 0x800 : 0x400;
int x = col * 8 + bg_layer_[2].hScroll;
int y = row * 8 + bg_layer_[2].vScroll;
int tileBits = bg_layer_[2].bigTiles ? 4 : 3;
int tileHighBit = bg_layer_[2].bigTiles ? 0x200 : 0x100;
uint16_t tilemapAdr =
bg_layer_[2].tilemapAdr +
(((y >> tileBits) & 0x1f) << 5 | ((x >> tileBits) & 0x1f));
if ((x & tileHighBit) && bg_layer_[2].tilemapWider) tilemapAdr += 0x400;
if ((y & tileHighBit) && bg_layer_[2].tilemapHigher)
tilemapAdr += bg_layer_[2].tilemapWider ? 0x800 : 0x400;
return vram[tilemapAdr & 0x7fff];
}
int Ppu::GetPixelForBgLayer(int x, int y, int layer, bool priority) {
// figure out address of tilemap word and read it
bool wideTiles = bgLayer[layer].bigTiles || mode == 5 || mode == 6;
bool wideTiles = bg_layer_[layer].bigTiles || mode == 5 || mode == 6;
int tileBitsX = wideTiles ? 4 : 3;
int tileHighBitX = wideTiles ? 0x200 : 0x100;
int tileBitsY = bgLayer[layer].bigTiles ? 4 : 3;
int tileHighBitY = bgLayer[layer].bigTiles ? 0x200 : 0x100;
int tileBitsY = bg_layer_[layer].bigTiles ? 4 : 3;
int tileHighBitY = bg_layer_[layer].bigTiles ? 0x200 : 0x100;
uint16_t tilemapAdr =
bgLayer[layer].tilemapAdr +
bg_layer_[layer].tilemapAdr +
(((y >> tileBitsY) & 0x1f) << 5 | ((x >> tileBitsX) & 0x1f));
if ((x & tileHighBitX) && bgLayer[layer].tilemapWider) tilemapAdr += 0x400;
if ((y & tileHighBitY) && bgLayer[layer].tilemapHigher)
tilemapAdr += bgLayer[layer].tilemapWider ? 0x800 : 0x400;
if ((x & tileHighBitX) && bg_layer_[layer].tilemapWider) tilemapAdr += 0x400;
if ((y & tileHighBitY) && bg_layer_[layer].tilemapHigher)
tilemapAdr += bg_layer_[layer].tilemapWider ? 0x800 : 0x400;
uint16_t tile = vram[tilemapAdr & 0x7fff];
// check priority, get palette
if (((bool)(tile & 0x2000)) != priority) return 0; // wrong priority
@@ -424,24 +427,24 @@ int Ppu::GetPixelForBgLayer(int x, int y, int layer, bool priority) {
// if unflipped right half of tile, or flipped left half of tile
if (((bool)(x & 8)) ^ ((bool)(tile & 0x4000))) tileNum += 1;
}
if (bgLayer[layer].bigTiles) {
if (bg_layer_[layer].bigTiles) {
// if unflipped bottom half of tile, or flipped upper half of tile
if (((bool)(y & 8)) ^ ((bool)(tile & 0x8000))) tileNum += 0x10;
}
// read tiledata, ajust palette for mode 0
int bitDepth = bitDepthsPerMode[mode][layer];
int bitDepth = kBitDepthsPerMode[mode][layer];
if (mode == 0) paletteNum += 8 * layer;
// plane 1 (always)
int paletteSize = 4;
uint16_t plane1 =
vram[(bgLayer[layer].tileAdr + ((tileNum & 0x3ff) * 4 * bitDepth) + row) &
0x7fff];
uint16_t plane1 = vram[(bg_layer_[layer].tileAdr +
((tileNum & 0x3ff) * 4 * bitDepth) + row) &
0x7fff];
int pixel = (plane1 >> col) & 1;
pixel |= ((plane1 >> (8 + col)) & 1) << 1;
// plane 2 (for 4bpp, 8bpp)
if (bitDepth > 2) {
paletteSize = 16;
uint16_t plane2 = vram[(bgLayer[layer].tileAdr +
uint16_t plane2 = vram[(bg_layer_[layer].tileAdr +
((tileNum & 0x3ff) * 4 * bitDepth) + 8 + row) &
0x7fff];
pixel |= ((plane2 >> col) & 1) << 2;
@@ -450,12 +453,12 @@ int Ppu::GetPixelForBgLayer(int x, int y, int layer, bool priority) {
// plane 3 & 4 (for 8bpp)
if (bitDepth > 4) {
paletteSize = 256;
uint16_t plane3 = vram[(bgLayer[layer].tileAdr +
uint16_t plane3 = vram[(bg_layer_[layer].tileAdr +
((tileNum & 0x3ff) * 4 * bitDepth) + 16 + row) &
0x7fff];
pixel |= ((plane3 >> col) & 1) << 4;
pixel |= ((plane3 >> (8 + col)) & 1) << 5;
uint16_t plane4 = vram[(bgLayer[layer].tileAdr +
uint16_t plane4 = vram[(bg_layer_[layer].tileAdr +
((tileNum & 0x3ff) * 4 * bitDepth) + 24 + row) &
0x7fff];
pixel |= ((plane4 >> col) & 1) << 6;
@@ -468,7 +471,7 @@ int Ppu::GetPixelForBgLayer(int x, int y, int layer, bool priority) {
void Ppu::EvaluateSprites(int line) {
// TODO: rectangular sprites, wierdness with sprites at -256
uint8_t index = objPriority ? (oamAdr & 0xfe) : 0;
uint8_t index = obj_priority_ ? (oam_adr_ & 0xfe) : 0;
int spritesFound = 0;
int tilesFound = 0;
uint8_t foundSprites[32] = {};
@@ -478,12 +481,13 @@ void Ppu::EvaluateSprites(int line) {
// check if the sprite is on this line and get the sprite size
uint8_t row = line - y;
int spriteSize =
spriteSizes[objSize][(highOam[index >> 3] >> ((index & 7) + 1)) & 1];
int spriteHeight = objInterlace ? spriteSize / 2 : spriteSize;
kSpriteSizes[obj_size_]
[(high_oam_[index >> 3] >> ((index & 7) + 1)) & 1];
int spriteHeight = obj_interlace_ ? spriteSize / 2 : spriteSize;
if (row < spriteHeight) {
// in y-range, get the x location, using the high bit as well
int x = oam[index] & 0xff;
x |= ((highOam[index >> 3] >> (index & 7)) & 1) << 8;
x |= ((high_oam_[index >> 3] >> (index & 7)) & 1) << 8;
if (x > 255) x -= 512;
// if in x-range, record
if (x > -spriteSize) {
@@ -505,13 +509,14 @@ void Ppu::EvaluateSprites(int line) {
uint8_t y = oam[index] >> 8;
uint8_t row = line - y;
int spriteSize =
spriteSizes[objSize][(highOam[index >> 3] >> ((index & 7) + 1)) & 1];
kSpriteSizes[obj_size_]
[(high_oam_[index >> 3] >> ((index & 7) + 1)) & 1];
int x = oam[index] & 0xff;
x |= ((highOam[index >> 3] >> (index & 7)) & 1) << 8;
x |= ((high_oam_[index >> 3] >> (index & 7)) & 1) << 8;
if (x > 255) x -= 512;
if (x > -spriteSize) {
// update row according to obj-interlace
if (objInterlace) row = row * 2 + (even_frame ? 0 : 1);
if (obj_interlace_) row = row * 2 + (even_frame ? 0 : 1);
// get some data for the sprite and y-flip row if needed
int tile = oam[index + 1] & 0xff;
int palette = (oam[index + 1] & 0xe00) >> 9;
@@ -532,7 +537,7 @@ void Ppu::EvaluateSprites(int line) {
uint8_t usedTile = (((tile >> 4) + (row / 8)) << 4) |
(((tile & 0xf) + (usedCol / 8)) & 0xf);
uint16_t objAdr =
(oam[index + 1] & 0x100) ? objTileAdr2 : objTileAdr1;
(oam[index + 1] & 0x100) ? obj_tile_adr2_ : obj_tile_adr1_;
uint16_t plane1 =
vram[(objAdr + usedTile * 16 + (row & 0x7)) & 0x7fff];
uint16_t plane2 =
@@ -548,7 +553,7 @@ void Ppu::EvaluateSprites(int line) {
int screenCol = col + x + px;
if (pixel > 0 && screenCol >= 0 && screenCol < 256) {
obj_pixel_buffer_[screenCol] = 0x80 + 16 * palette + pixel;
objPriorityBuffer[screenCol] = (oam[index + 1] & 0x3000) >> 12;
obj_priority_buffer_[screenCol] = (oam[index + 1] & 0x3000) >> 12;
}
}
}
@@ -570,8 +575,8 @@ void Ppu::CalculateMode7Starts(int y) {
int clippedV = vScroll - yCenter;
clippedH = (clippedH & 0x2000) ? (clippedH | ~1023) : (clippedH & 1023);
clippedV = (clippedV & 0x2000) ? (clippedV | ~1023) : (clippedV & 1023);
if (bgLayer[0].mosaicEnabled && mosaicSize > 1) {
y -= (y - mosaicStartLine) % mosaicSize;
if (bg_layer_[0].mosaicEnabled && mosaic_size_ > 1) {
y -= (y - mosaic_startline_) % mosaic_size_;
}
uint8_t ry = m7yFlip ? 255 - y : y;
m7startX = (((m7matrix[0] * clippedH) & ~63) + ((m7matrix[1] * ry) & ~63) +
@@ -582,10 +587,10 @@ void Ppu::CalculateMode7Starts(int y) {
void Ppu::HandleVblank() {
// called either right after CheckOverscan at (0,225), or at (0,240)
if (!forcedBlank) {
oamAdr = oamAdrWritten;
oamInHigh = oamInHighWritten;
oamSecondWrite = false;
if (!forced_blank_) {
oam_adr_ = oam_adr_written_;
oam_in_high_ = oam_in_high_written_;
oam_second_write_ = false;
}
frame_interlace = interlace; // set if we have a interlaced frame
}
@@ -610,14 +615,14 @@ uint8_t Ppu::Read(uint8_t adr, bool latch) {
case 0x0a:
case 0x1a:
case 0x2a: {
return ppu1openBus;
return ppu1_open_bus_;
}
case 0x34:
case 0x35:
case 0x36: {
int result = m7matrix[0] * (m7matrix[1] >> 8);
ppu1openBus = (result >> (8 * (adr - 0x34))) & 0xff;
return ppu1openBus;
ppu1_open_bus_ = (result >> (8 * (adr - 0x34))) & 0xff;
return ppu1_open_bus_;
}
case 0x37: {
// TODO: only when ppulatch is set
@@ -628,95 +633,95 @@ uint8_t Ppu::Read(uint8_t adr, bool latch) {
}
case 0x38: {
uint8_t ret = 0;
if (oamInHigh) {
ret = highOam[((oamAdr & 0xf) << 1) | oamSecondWrite];
if (oamSecondWrite) {
oamAdr++;
if (oamAdr == 0) oamInHigh = false;
if (oam_in_high_) {
ret = high_oam_[((oam_adr_ & 0xf) << 1) | oam_second_write_];
if (oam_second_write_) {
oam_adr_++;
if (oam_adr_ == 0) oam_in_high_ = false;
}
} else {
if (!oamSecondWrite) {
ret = oam[oamAdr] & 0xff;
if (!oam_second_write_) {
ret = oam[oam_adr_] & 0xff;
} else {
ret = oam[oamAdr++] >> 8;
if (oamAdr == 0) oamInHigh = true;
ret = oam[oam_adr_++] >> 8;
if (oam_adr_ == 0) oam_in_high_ = true;
}
}
oamSecondWrite = !oamSecondWrite;
ppu1openBus = ret;
oam_second_write_ = !oam_second_write_;
ppu1_open_bus_ = ret;
return ret;
}
case 0x39: {
uint16_t val = vramReadBuffer;
if (!vramIncrementOnHigh) {
vramReadBuffer = vram[GetVramRemap() & 0x7fff];
vramPointer += vramIncrement;
uint16_t val = vram_read_buffer_;
if (!vram_increment_on_high_) {
vram_read_buffer_ = vram[GetVramRemap() & 0x7fff];
vram_pointer += vram_increment_;
}
ppu1openBus = val & 0xff;
ppu1_open_bus_ = val & 0xff;
return val & 0xff;
}
case 0x3a: {
uint16_t val = vramReadBuffer;
if (vramIncrementOnHigh) {
vramReadBuffer = vram[GetVramRemap() & 0x7fff];
vramPointer += vramIncrement;
uint16_t val = vram_read_buffer_;
if (vram_increment_on_high_) {
vram_read_buffer_ = vram[GetVramRemap() & 0x7fff];
vram_pointer += vram_increment_;
}
ppu1openBus = val >> 8;
ppu1_open_bus_ = val >> 8;
return val >> 8;
}
case 0x3b: {
uint8_t ret = 0;
if (!cgramSecondWrite) {
ret = cgram[cgramPointer] & 0xff;
if (!cgram_second_write_) {
ret = cgram[cgram_pointer_] & 0xff;
} else {
ret = ((cgram[cgramPointer++] >> 8) & 0x7f) | (ppu2openBus & 0x80);
ret = ((cgram[cgram_pointer_++] >> 8) & 0x7f) | (ppu2_open_bus_ & 0x80);
}
cgramSecondWrite = !cgramSecondWrite;
ppu2openBus = ret;
cgram_second_write_ = !cgram_second_write_;
ppu2_open_bus_ = ret;
return ret;
}
case 0x3c: {
uint8_t val = 0;
if (hCountSecond) {
val = ((hCount >> 8) & 1) | (ppu2openBus & 0xfe);
if (h_count_second_) {
val = ((h_count_ >> 8) & 1) | (ppu2_open_bus_ & 0xfe);
} else {
val = hCount & 0xff;
val = h_count_ & 0xff;
}
hCountSecond = !hCountSecond;
ppu2openBus = val;
h_count_second_ = !h_count_second_;
ppu2_open_bus_ = val;
return val;
}
case 0x3d: {
uint8_t val = 0;
if (vCountSecond) {
val = ((vCount >> 8) & 1) | (ppu2openBus & 0xfe);
if (v_count_second_) {
val = ((v_count_ >> 8) & 1) | (ppu2_open_bus_ & 0xfe);
} else {
val = vCount & 0xff;
val = v_count_ & 0xff;
}
vCountSecond = !vCountSecond;
ppu2openBus = val;
v_count_second_ = !v_count_second_;
ppu2_open_bus_ = val;
return val;
}
case 0x3e: {
uint8_t val = 0x1; // ppu1 version (4 bit)
val |= ppu1openBus & 0x10;
val |= ppu1_open_bus_ & 0x10;
val |= range_over_ << 6;
val |= time_over_ << 7;
ppu1openBus = val;
ppu1_open_bus_ = val;
return val;
}
case 0x3f: {
uint8_t val = 0x3; // ppu2 version (4 bit)
val |= memory_.pal_timing() << 4; // ntsc/pal
val |= ppu2openBus & 0x20;
val |= countersLatched << 6;
val |= ppu2_open_bus_ & 0x20;
val |= counters_latched_ << 6;
val |= even_frame << 7;
if (latch) {
countersLatched = false;
hCountSecond = false;
vCountSecond = false;
counters_latched_ = false;
h_count_second_ = false;
v_count_second_ = false;
}
ppu2openBus = val;
ppu2_open_bus_ = val;
return val;
}
default: {
@@ -731,84 +736,84 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
// TODO: oam address reset when written on first line of vblank, (and when
// forced blank is disabled?)
brightness = val & 0xf;
forcedBlank = val & 0x80;
forced_blank_ = val & 0x80;
break;
}
case 0x01: {
objSize = val >> 5;
objTileAdr1 = (val & 7) << 13;
objTileAdr2 = objTileAdr1 + (((val & 0x18) + 8) << 9);
obj_size_ = val >> 5;
obj_tile_adr1_ = (val & 7) << 13;
obj_tile_adr2_ = obj_tile_adr1_ + (((val & 0x18) + 8) << 9);
break;
}
case 0x02: {
oamAdr = val;
oamAdrWritten = oamAdr;
oamInHigh = oamInHighWritten;
oamSecondWrite = false;
oam_adr_ = val;
oam_adr_written_ = oam_adr_;
oam_in_high_ = oam_in_high_written_;
oam_second_write_ = false;
break;
}
case 0x03: {
objPriority = val & 0x80;
oamInHigh = val & 1;
oamInHighWritten = oamInHigh;
oamAdr = oamAdrWritten;
oamSecondWrite = false;
obj_priority_ = val & 0x80;
oam_in_high_ = val & 1;
oam_in_high_written_ = oam_in_high_;
oam_adr_ = oam_adr_written_;
oam_second_write_ = false;
break;
}
case 0x04: {
if (oamInHigh) {
highOam[((oamAdr & 0xf) << 1) | oamSecondWrite] = val;
if (oamSecondWrite) {
oamAdr++;
if (oamAdr == 0) oamInHigh = false;
if (oam_in_high_) {
high_oam_[((oam_adr_ & 0xf) << 1) | oam_second_write_] = val;
if (oam_second_write_) {
oam_adr_++;
if (oam_adr_ == 0) oam_in_high_ = false;
}
} else {
if (!oamSecondWrite) {
oamBuffer = val;
if (!oam_second_write_) {
oam_buffer_ = val;
} else {
oam[oamAdr++] = (val << 8) | oamBuffer;
if (oamAdr == 0) oamInHigh = true;
oam[oam_adr_++] = (val << 8) | oam_buffer_;
if (oam_adr_ == 0) oam_in_high_ = true;
}
}
oamSecondWrite = !oamSecondWrite;
oam_second_write_ = !oam_second_write_;
break;
}
case 0x05: {
mode = val & 0x7;
bg3priority = val & 0x8;
bgLayer[0].bigTiles = val & 0x10;
bgLayer[1].bigTiles = val & 0x20;
bgLayer[2].bigTiles = val & 0x40;
bgLayer[3].bigTiles = val & 0x80;
bg_layer_[0].bigTiles = val & 0x10;
bg_layer_[1].bigTiles = val & 0x20;
bg_layer_[2].bigTiles = val & 0x40;
bg_layer_[3].bigTiles = val & 0x80;
break;
}
case 0x06: {
// TODO: mosaic line reset specifics
bgLayer[0].mosaicEnabled = val & 0x1;
bgLayer[1].mosaicEnabled = val & 0x2;
bgLayer[2].mosaicEnabled = val & 0x4;
bgLayer[3].mosaicEnabled = val & 0x8;
mosaicSize = (val >> 4) + 1;
mosaicStartLine = memory_.v_pos();
bg_layer_[0].mosaicEnabled = val & 0x1;
bg_layer_[1].mosaicEnabled = val & 0x2;
bg_layer_[2].mosaicEnabled = val & 0x4;
bg_layer_[3].mosaicEnabled = val & 0x8;
mosaic_size_ = (val >> 4) + 1;
mosaic_startline_ = memory_.v_pos();
break;
}
case 0x07:
case 0x08:
case 0x09:
case 0x0a: {
bgLayer[adr - 7].tilemapWider = val & 0x1;
bgLayer[adr - 7].tilemapHigher = val & 0x2;
bgLayer[adr - 7].tilemapAdr = (val & 0xfc) << 8;
bg_layer_[adr - 7].tilemapWider = val & 0x1;
bg_layer_[adr - 7].tilemapHigher = val & 0x2;
bg_layer_[adr - 7].tilemapAdr = (val & 0xfc) << 8;
break;
}
case 0x0b: {
bgLayer[0].tileAdr = (val & 0xf) << 12;
bgLayer[1].tileAdr = (val & 0xf0) << 8;
bg_layer_[0].tileAdr = (val & 0xf) << 12;
bg_layer_[1].tileAdr = (val & 0xf0) << 8;
break;
}
case 0x0c: {
bgLayer[2].tileAdr = (val & 0xf) << 12;
bgLayer[3].tileAdr = (val & 0xf0) << 8;
bg_layer_[2].tileAdr = (val & 0xf) << 12;
bg_layer_[3].tileAdr = (val & 0xf0) << 8;
break;
}
case 0x0d: {
@@ -819,10 +824,10 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
case 0x0f:
case 0x11:
case 0x13: {
bgLayer[(adr - 0xd) / 2].hScroll =
((val << 8) | (scrollPrev & 0xf8) | (scrollPrev2 & 0x7)) & 0x3ff;
scrollPrev = val;
scrollPrev2 = val;
bg_layer_[(adr - 0xd) / 2].hScroll =
((val << 8) | (scroll_prev_ & 0xf8) | (scroll_prev2_ & 0x7)) & 0x3ff;
scroll_prev_ = val;
scroll_prev2_ = val;
break;
}
case 0x0e: {
@@ -833,43 +838,43 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
case 0x10:
case 0x12:
case 0x14: {
bgLayer[(adr - 0xe) / 2].vScroll = ((val << 8) | scrollPrev) & 0x3ff;
scrollPrev = val;
bg_layer_[(adr - 0xe) / 2].vScroll = ((val << 8) | scroll_prev_) & 0x3ff;
scroll_prev_ = val;
break;
}
case 0x15: {
if ((val & 3) == 0) {
vramIncrement = 1;
vram_increment_ = 1;
} else if ((val & 3) == 1) {
vramIncrement = 32;
vram_increment_ = 32;
} else {
vramIncrement = 128;
vram_increment_ = 128;
}
vramRemapMode = (val & 0xc) >> 2;
vramIncrementOnHigh = val & 0x80;
vram_remap_mode_ = (val & 0xc) >> 2;
vram_increment_on_high_ = val & 0x80;
break;
}
case 0x16: {
vramPointer = (vramPointer & 0xff00) | val;
vramReadBuffer = vram[GetVramRemap() & 0x7fff];
vram_pointer = (vram_pointer & 0xff00) | val;
vram_read_buffer_ = vram[GetVramRemap() & 0x7fff];
break;
}
case 0x17: {
vramPointer = (vramPointer & 0x00ff) | (val << 8);
vramReadBuffer = vram[GetVramRemap() & 0x7fff];
vram_pointer = (vram_pointer & 0x00ff) | (val << 8);
vram_read_buffer_ = vram[GetVramRemap() & 0x7fff];
break;
}
case 0x18: {
// TODO: vram access during rendering (also cgram and oam)
uint16_t vramAdr = GetVramRemap();
vram[vramAdr & 0x7fff] = (vram[vramAdr & 0x7fff] & 0xff00) | val;
if (!vramIncrementOnHigh) vramPointer += vramIncrement;
if (!vram_increment_on_high_) vram_pointer += vram_increment_;
break;
}
case 0x19: {
uint16_t vramAdr = GetVramRemap();
vram[vramAdr & 0x7fff] = (vram[vramAdr & 0x7fff] & 0x00ff) | (val << 8);
if (vramIncrementOnHigh) vramPointer += vramIncrement;
if (vram_increment_on_high_) vram_pointer += vram_increment_;
break;
}
case 0x1a: {
@@ -894,17 +899,17 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
break;
}
case 0x21: {
cgramPointer = val;
cgramSecondWrite = false;
cgram_pointer_ = val;
cgram_second_write_ = false;
break;
}
case 0x22: {
if (!cgramSecondWrite) {
cgramBuffer = val;
if (!cgram_second_write_) {
cgram_buffer_ = val;
} else {
cgram[cgramPointer++] = (val << 8) | cgramBuffer;
cgram[cgram_pointer_++] = (val << 8) | cgram_buffer_;
}
cgramSecondWrite = !cgramSecondWrite;
cgram_second_write_ = !cgram_second_write_;
break;
}
case 0x23:
@@ -981,31 +986,31 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
break;
}
case 0x30: {
directColor = val & 0x1;
direct_color_ = val & 0x1;
add_subscreen_ = val & 0x2;
prevent_math_mode_ = (val & 0x30) >> 4;
clip_mode_ = (val & 0xc0) >> 6;
break;
}
case 0x31: {
subtractColor = val & 0x80;
halfColor = val & 0x40;
subtract_color_ = val & 0x80;
half_color_ = val & 0x40;
for (int i = 0; i < 6; i++) {
math_enabled_array_[i] = val & (1 << i);
}
break;
}
case 0x32: {
if (val & 0x80) fixedColorB = val & 0x1f;
if (val & 0x40) fixedColorG = val & 0x1f;
if (val & 0x20) fixedColorR = val & 0x1f;
if (val & 0x80) fixed_color_b_ = val & 0x1f;
if (val & 0x40) fixed_color_g_ = val & 0x1f;
if (val & 0x20) fixed_color_r_ = val & 0x1f;
break;
}
case 0x33: {
interlace = val & 0x1;
objInterlace = val & 0x2;
overscan = val & 0x4;
pseudoHires = val & 0x8;
obj_interlace_ = val & 0x2;
overscan_ = val & 0x4;
pseudo_hires_ = val & 0x8;
m7extBg = val & 0x40;
break;
}
@@ -1016,8 +1021,8 @@ void Ppu::Write(uint8_t adr, uint8_t val) {
}
uint16_t Ppu::GetVramRemap() {
uint16_t adr = vramPointer;
switch (vramRemapMode) {
uint16_t adr = vram_pointer;
switch (vram_remap_mode_) {
case 0:
return adr;
case 1:
@@ -1031,8 +1036,8 @@ uint16_t Ppu::GetVramRemap() {
}
void Ppu::PutPixels(uint8_t* pixels) {
for (int y = 0; y < (frameOverscan ? 239 : 224); y++) {
int dest = y * 2 + (frameOverscan ? 2 : 16);
for (int y = 0; y < (frame_overscan_ ? 239 : 224); y++) {
int dest = y * 2 + (frame_overscan_ ? 2 : 16);
int y1 = y, y2 = y + 239;
if (!frame_interlace) {
y1 = y + (even_frame ? 0 : 239);
@@ -1043,7 +1048,7 @@ void Ppu::PutPixels(uint8_t* pixels) {
}
// clear top 2 lines, and following 14 and last 16 lines if not overscanning
memset(pixels, 0, 2048 * 2);
if (!frameOverscan) {
if (!frame_overscan_) {
memset(pixels + (2 * 2048), 0, 2048 * 14);
memset(pixels + (464 * 2048), 0, 2048 * 16);
}

View File

@@ -279,9 +279,9 @@ class Ppu : public SharedRom {
void HandlePixel(int x, int y);
void LatchHV() {
hCount = memory_.h_pos() / 4;
vCount = memory_.v_pos();
countersLatched = true;
h_count_ = memory_.h_pos() / 4;
v_count_ = memory_.v_pos();
counters_latched_ = true;
}
int GetPixel(int x, int y, bool sub, int* r, int* g, int* b);
@@ -292,23 +292,21 @@ class Ppu : public SharedRom {
bool GetWindowState(int layer, int x);
// if we are overscanning this frame (determined at 0,225)
bool frame_overscan_ = false;
bool overscan_ = false;
// settings
bool forcedBlank;
bool forced_blank_;
uint8_t brightness;
uint8_t mode;
bool bg3priority;
bool even_frame;
bool pseudoHires;
bool overscan;
bool
frameOverscan; // if we are overscanning this frame (determined at 0,225)
bool pseudo_hires_;
bool interlace;
bool frame_interlace; // if we are interlacing this frame (determined at
// start vblank)
bool directColor;
bool direct_color_;
bool CheckOverscan() {
frame_overscan_ = overscan_;
@@ -331,61 +329,62 @@ class Ppu : public SharedRom {
const std::vector<uint8_t>& GetFrameBuffer() const { return frame_buffer_; }
private:
bool enable_forced_blanking_ = false;
int GetPixelForMode7(int x, int layer, bool priority);
int cycle_count_ = 0;
int current_scanline_ = 0;
const int cyclesPerScanline = 341; // SNES PPU has 341 cycles per scanline
const int totalScanlines = 262; // SNES PPU has 262 scanlines per frame
const int visibleScanlines = 224; // SNES PPU renders 224 visible scanlines
int GetPixelForMode7(int x, int layer, bool priority);
bool enable_forced_blanking_ = false;
int cycle_count_ = 0;
int current_scanline_ = 0;
// vram access
uint16_t vram[0x8000];
uint16_t vramPointer;
bool vramIncrementOnHigh;
uint16_t vramIncrement;
uint8_t vramRemapMode;
uint16_t vramReadBuffer;
uint16_t vram_pointer;
bool vram_increment_on_high_;
uint16_t vram_increment_;
uint8_t vram_remap_mode_;
uint16_t vram_read_buffer_;
// cgram access
uint16_t cgram[0x100];
uint8_t cgramPointer;
bool cgramSecondWrite;
uint8_t cgramBuffer;
uint8_t cgram_pointer_;
bool cgram_second_write_;
uint8_t cgram_buffer_;
// oam access
uint16_t oam[0x100];
uint8_t highOam[0x20];
uint8_t oamAdr;
uint8_t oamAdrWritten;
bool oamInHigh;
bool oamInHighWritten;
bool oamSecondWrite;
uint8_t oamBuffer;
uint8_t high_oam_[0x20];
uint8_t oam_adr_;
uint8_t oam_adr_written_;
bool oam_in_high_;
bool oam_in_high_written_;
bool oam_second_write_;
uint8_t oam_buffer_;
// Objects / Sprites
bool objPriority;
uint16_t objTileAdr1;
uint16_t objTileAdr2;
uint8_t objSize;
std::array<uint8_t, 256> obj_pixel_buffer_;
uint8_t objPriorityBuffer[256];
bool time_over_ = false;
bool range_over_ = false;
bool objInterlace;
bool obj_interlace_;
bool obj_priority_;
uint16_t obj_tile_adr1_;
uint16_t obj_tile_adr2_;
uint8_t obj_size_;
std::array<uint8_t, 256> obj_pixel_buffer_;
std::array<uint8_t, 256> obj_priority_buffer_;
// Color Math
uint8_t clip_mode_ = 0;
uint8_t prevent_math_mode_ = 0;
bool math_enabled_array_[6] = {false, false, false, false, false, false};
bool add_subscreen_ = false;
bool subtractColor;
bool halfColor;
uint8_t fixedColorR;
uint8_t fixedColorG;
uint8_t fixedColorB;
bool subtract_color_;
bool half_color_;
uint8_t fixed_color_r_;
uint8_t fixed_color_g_;
uint8_t fixed_color_b_;
// layers
Layer layer_[5];
@@ -414,11 +413,10 @@ class Ppu : public SharedRom {
std::array<BackgroundLayer, 4> bg_layers_;
uint8_t mosaic_startline_ = 1;
BgLayer bgLayer[4];
uint8_t scrollPrev;
uint8_t scrollPrev2;
uint8_t mosaicSize;
uint8_t mosaicStartLine;
BgLayer bg_layer_[4];
uint8_t scroll_prev_;
uint8_t scroll_prev2_;
uint8_t mosaic_size_;
// pixel buffer (xbgr)
// times 2 for even and odd frame
@@ -426,13 +424,13 @@ class Ppu : public SharedRom {
uint8_t pixelOutputFormat = 0;
// latching
uint16_t hCount;
uint16_t vCount;
bool hCountSecond;
bool vCountSecond;
bool countersLatched;
uint8_t ppu1openBus;
uint8_t ppu2openBus;
uint16_t h_count_;
uint16_t v_count_;
bool h_count_second_;
bool v_count_second_;
bool counters_latched_;
uint8_t ppu1_open_bus_;
uint8_t ppu2_open_bus_;
uint16_t tile_data_size_;
uint16_t vram_base_address_;