17static const int kLayersPerMode[10][12] = {
18 {4, 0, 1, 4, 0, 1, 4, 2, 3, 4, 2, 3}, {4, 0, 1, 4, 0, 1, 4, 2, 4, 2, 5, 5},
19 {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5}, {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
20 {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5}, {4, 0, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5},
21 {4, 0, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5}, {4, 4, 4, 0, 4, 5, 5, 5, 5, 5, 5, 5},
22 {2, 4, 0, 1, 4, 0, 1, 4, 4, 2, 5, 5}, {4, 4, 1, 4, 0, 4, 1, 5, 5, 5, 5, 5}};
24static const int kPrioritysPerMode[10][12] = {
25 {3, 1, 1, 2, 0, 0, 1, 1, 1, 0, 0, 0}, {3, 1, 1, 2, 0, 0, 1, 1, 0, 0, 5, 5},
26 {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5}, {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
27 {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5}, {3, 1, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5},
28 {3, 1, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5}, {3, 2, 1, 0, 0, 5, 5, 5, 5, 5, 5, 5},
29 {1, 3, 1, 1, 2, 0, 0, 1, 0, 0, 5, 5}, {3, 2, 1, 1, 0, 0, 0, 5, 5, 5, 5, 5}};
31static const int kLayerCountPerMode[10] = {12, 10, 8, 8, 8, 8, 6, 5, 10, 7};
33static const int kBitDepthsPerMode[10][4] = {
34 {2, 2, 2, 2}, {4, 4, 2, 5}, {4, 4, 5, 5}, {8, 4, 5, 5}, {8, 2, 5, 5},
35 {4, 2, 5, 5}, {4, 5, 5, 5}, {8, 5, 5, 5}, {4, 4, 2, 5}, {8, 7, 5, 5}};
37static const int kSpriteSizes[8][2] = {{8, 16}, {8, 32}, {8, 64}, {16, 32},
38 {16, 64}, {32, 64}, {16, 32}, {16, 32}};
51 memset(
oam, 0,
sizeof(
oam));
68 for (
int i = 0; i < 4; i++) {
82 for (
int i = 0; i < 5; i++) {
97 for (
int i = 0; i < 6; i++) {
163 int target_x = h_pos / 4;
166 if (target_x > 256) target_x = 256;
186 int mainLayer =
GetPixel(x, y,
false, &r, &g, &b);
201 secondLayer =
GetPixel(x, y,
true, &r2, &g2, &b2);
257 ((b2 << 3) | (b2 >> 2));
259 ((g2 << 3) | (g2 >> 2));
261 ((r2 << 3) | (r2 >> 2));
267 ((b << 3) | (b >> 2));
269 ((g << 3) | (g >> 2));
271 ((r << 3) | (r >> 2));
285 for (
int i = 0; i < kLayerCountPerMode[actMode]; i++) {
286 int curLayer = kLayersPerMode[actMode][i];
287 int curPriority = kPrioritysPerMode[actMode][i];
288 bool layerActive =
false;
338 if (
direct_color_ && layer < 4 && kBitDepthsPerMode[actMode][layer] == 8) {
339 *r = ((pixel & 0x7) << 2) | ((pixel & 0x100) >> 7);
340 *g = ((pixel & 0x38) >> 1) | ((pixel & 0x200) >> 8);
341 *b = ((pixel & 0xc0) >> 3) | ((pixel & 0x400) >> 8);
343 uint16_t color =
cgram[pixel & 0xff];
345 *g = (color >> 5) & 0x1f;
346 *b = (color >> 10) & 0x1f;
348 if (layer == 4 && pixel < 0xc0)
354 uint8_t rx =
m7xFlip ? 255 - x : x;
357 bool outsideMap = xPos < 0 || xPos >= 1024 || yPos < 0 || yPos >= 1024;
362 uint8_t tile = outsideMap ? 0 :
vram[(yPos >> 3) * 128 + (xPos >> 3)] & 0xff;
365 :
vram[tile * 64 + (yPos & 7) * 8 + (xPos & 7)] >> 8;
367 if (((
bool)(pixel & 0x80)) != priority)
395 return test1 || test2;
397 return test1 && test2;
399 return test1 != test2;
401 return test1 == test2;
411 column = ((x - (x & 0xf)) - ((
bg_layer_[layer].
hScroll * 2) & 0xfff0)) >> 4;
417 int valid = layer == 0 ? 0x2000 : 0x4000;
419 uint16_t vOffset = 0;
421 if (hOffset & 0x8000) {
431 *lx = (((hOffset & 0x3f8) + (column * 8)) * 2) | (x & 0xf);
434 *lx = ((hOffset & 0x3f8) + (column * 8)) | (x & 0x7);
438 *ly = (vOffset & 0x3ff) + (y -
bg_layer_[layer].vScroll);
447 uint16_t tilemapAdr =
449 (((y >> tileBits) & 0x1f) << 5 | ((x >> tileBits) & 0x1f));
453 tilemapAdr +=
bg_layer_[2].tilemapWider ? 0x800 : 0x400;
454 return vram[tilemapAdr & 0x7fff];
460 int tileBitsX = wideTiles ? 4 : 3;
461 int tileHighBitX = wideTiles ? 0x200 : 0x100;
464 uint16_t tilemapAdr =
466 (((y >> tileBitsY) & 0x1f) << 5 | ((x >> tileBitsX) & 0x1f));
470 tilemapAdr +=
bg_layer_[layer].tilemapWider ? 0x800 : 0x400;
471 uint16_t tile =
vram[tilemapAdr & 0x7fff];
473 if (((
bool)(tile & 0x2000)) != priority)
475 int paletteNum = (tile & 0x1c00) >> 10;
477 int row = (tile & 0x8000) ? 7 - (y & 0x7) : (y & 0x7);
478 int col = (tile & 0x4000) ? (x & 0x7) : 7 - (x & 0x7);
479 int tileNum = tile & 0x3ff;
482 if (((
bool)(x & 8)) ^ ((bool)(tile & 0x4000)))
487 if (((
bool)(y & 8)) ^ ((bool)(tile & 0x8000)))
491 int bitDepth = kBitDepthsPerMode[
mode][layer];
493 paletteNum += 8 * layer;
497 ((tileNum & 0x3ff) * 4 * bitDepth) + row) &
499 int pixel = (plane1 >> col) & 1;
500 pixel |= ((plane1 >> (8 + col)) & 1) << 1;
505 ((tileNum & 0x3ff) * 4 * bitDepth) + 8 + row) &
507 pixel |= ((plane2 >> col) & 1) << 2;
508 pixel |= ((plane2 >> (8 + col)) & 1) << 3;
514 ((tileNum & 0x3ff) * 4 * bitDepth) + 16 + row) &
516 pixel |= ((plane3 >> col) & 1) << 4;
517 pixel |= ((plane3 >> (8 + col)) & 1) << 5;
519 ((tileNum & 0x3ff) * 4 * bitDepth) + 24 + row) &
521 pixel |= ((plane4 >> col) & 1) << 6;
522 pixel |= ((plane4 >> (8 + col)) & 1) << 7;
526 return pixel == 0 ? 0 : paletteSize * paletteNum + pixel;
532 int spritesFound = 0;
534 uint8_t foundSprites[32] = {};
536 for (
int i = 0; i < 128; i++) {
537 uint8_t y =
oam[index] >> 8;
539 uint8_t row = line - y;
542 [(
high_oam_[index >> 3] >> ((index & 7) + 1)) & 1];
544 if (row < spriteHeight) {
546 int x =
oam[index] & 0xff;
547 x |= ((
high_oam_[index >> 3] >> (index & 7)) & 1) << 8;
551 if (x > -spriteSize) {
554 if (spritesFound > 32) {
559 foundSprites[spritesFound - 1] = index;
565 for (
int i = spritesFound; i > 0; i--) {
566 index = foundSprites[i - 1];
567 uint8_t y =
oam[index] >> 8;
568 uint8_t row = line - y;
571 [(
high_oam_[index >> 3] >> ((index & 7) + 1)) & 1];
572 int x =
oam[index] & 0xff;
573 x |= ((
high_oam_[index >> 3] >> (index & 7)) & 1) << 8;
576 if (x > -spriteSize) {
581 int tile =
oam[index + 1] & 0xff;
582 int palette = (
oam[index + 1] & 0xe00) >> 9;
583 bool hFlipped =
oam[index + 1] & 0x4000;
584 if (
oam[index + 1] & 0x8000)
585 row = spriteSize - 1 - row;
587 for (
int col = 0; col < spriteSize; col += 8) {
588 if (col + x > -8 && col + x < 256) {
591 if (tilesFound > 34) {
597 int usedCol = hFlipped ? spriteSize - 1 - col : col;
598 uint8_t usedTile = (((tile >> 4) + (row / 8)) << 4) |
599 (((tile & 0xf) + (usedCol / 8)) & 0xf);
603 vram[(objAdr + usedTile * 16 + (row & 0x7)) & 0x7fff];
605 vram[(objAdr + usedTile * 16 + 8 + (row & 0x7)) & 0x7fff];
607 for (
int px = 0; px < 8; px++) {
608 int shift = hFlipped ? px : 7 - px;
609 int pixel = (plane1 >> shift) & 1;
610 pixel |= ((plane1 >> (8 + shift)) & 1) << 1;
611 pixel |= ((plane2 >> shift) & 1) << 2;
612 pixel |= ((plane2 >> (8 + shift)) & 1) << 3;
614 int screenCol = col + x + px;
615 if (pixel > 0 && screenCol >= 0 && screenCol < 256) {
630 int hScroll = ((int16_t)(
m7matrix[6] << 3)) >> 3;
631 int vScroll = ((int16_t)(
m7matrix[7] << 3)) >> 3;
632 int xCenter = ((int16_t)(
m7matrix[4] << 3)) >> 3;
633 int yCenter = ((int16_t)(
m7matrix[5] << 3)) >> 3;
635 int clippedH = hScroll - xCenter;
636 int clippedV = vScroll - yCenter;
637 clippedH = (clippedH & 0x2000) ? (clippedH | ~1023) : (clippedH & 1023);
638 clippedV = (clippedV & 0x2000) ? (clippedV | ~1023) : (clippedV & 1023);
642 uint8_t ry =
m7yFlip ? 255 - y : y;
644 ((
m7matrix[1] * clippedV) & ~63) + (xCenter << 8));
646 ((
m7matrix[3] * clippedV) & ~63) + (yCenter << 8));
660 static int vblank_dump_counter = 0;
661 if (++vblank_dump_counter >= 120) {
662 vblank_dump_counter = 0;
920 if ((val & 3) == 0) {
922 }
else if ((val & 3) == 1) {
944 vram[vramAdr & 0x7fff] = (
vram[vramAdr & 0x7fff] & 0xff00) | val;
951 vram[vramAdr & 0x7fff] = (
vram[vramAdr & 0x7fff] & 0x00ff) | (val << 8);
994 windowLayer[(adr - 0x23) * 2].window1inversed = val & 0x1;
995 windowLayer[(adr - 0x23) * 2].window1enabled = val & 0x2;
996 windowLayer[(adr - 0x23) * 2].window2inversed = val & 0x4;
997 windowLayer[(adr - 0x23) * 2].window2enabled = val & 0x8;
998 windowLayer[(adr - 0x23) * 2 + 1].window1inversed = val & 0x10;
999 windowLayer[(adr - 0x23) * 2 + 1].window1enabled = val & 0x20;
1000 windowLayer[(adr - 0x23) * 2 + 1].window2inversed = val & 0x40;
1001 windowLayer[(adr - 0x23) * 2 + 1].window2enabled = val & 0x80;
1074 for (
int i = 0; i < 6; i++) {
1108 return (adr & 0xff00) | ((adr & 0xe0) >> 5) | ((adr & 0x1f) << 3);
1110 return (adr & 0xfe00) | ((adr & 0x1c0) >> 6) | ((adr & 0x3f) << 3);
1112 return (adr & 0xfc00) | ((adr & 0x380) >> 7) | ((adr & 0x7f) << 3);
1120 int y1 = y, y2 = y + 239;
1125 memcpy(pixels + (dest * 2048), &
pixelBuffer[y1 * 2048], 2048);
1126 memcpy(pixels + ((dest + 1) * 2048), &
pixelBuffer[y2 * 2048], 2048);
1129 memset(pixels, 0, 2048 * 2);
1131 memset(pixels + (2 * 2048), 0, 2048 * 14);
1132 memset(pixels + (464 * 2048), 0, 2048 * 16);
1137 printf(
"=== PPU State Dump ===\n");
1138 printf(
"$2100: forced_blank=%d brightness=%d\n",
forced_blank_ ? 1 : 0,
1141 printf(
"$212C (Main Screen): BG1=%d BG2=%d BG3=%d BG4=%d OBJ=%d\n",
1142 layer_[0].mainScreenEnabled ? 1 : 0,
1147 printf(
"$212D (Sub Screen): BG1=%d BG2=%d BG3=%d BG4=%d OBJ=%d\n",
1148 layer_[0].subScreenEnabled ? 1 : 0,
1153 for (
int i = 0; i < 4; i++) {
1154 printf(
"BG%d: tilemapAdr=$%04X tileAdr=$%04X hScroll=%d vScroll=%d "
1162 uint16_t first_entry =
vram[tm_addr];
1163 int actual_pal = (first_entry >> 10) & 7;
1164 printf(
"First tilemap entry: $%04X (tile=$%03X, pal=%d, pri=%d, hflip=%d, "
1166 first_entry, first_entry & 0x3FF, actual_pal,
1167 (first_entry >> 13) & 1, (first_entry >> 14) & 1,
1168 (first_entry >> 15) & 1);
1170 printf(
"CGRAM Pal0[0-15]: %04X %04X %04X %04X %04X %04X %04X %04X "
1171 "%04X %04X %04X %04X %04X %04X %04X %04X\n",
1176 int pal_start = actual_pal * 16;
1177 printf(
"CGRAM Pal%d[0-15]: %04X %04X %04X %04X %04X %04X %04X %04X "
1178 "%04X %04X %04X %04X %04X %04X %04X %04X\n",
1179 actual_pal,
cgram[pal_start],
cgram[pal_start + 1],
1184 cgram[pal_start + 14],
cgram[pal_start + 15]);
1186 printf(
"VRAM@$%04X (BG1 tilemap): %04X %04X %04X %04X %04X %04X %04X %04X\n",
1187 tm_addr,
vram[tm_addr],
vram[tm_addr + 1],
vram[tm_addr + 2],
1188 vram[tm_addr + 3],
vram[tm_addr + 4],
vram[tm_addr + 5],
1189 vram[tm_addr + 6],
vram[tm_addr + 7]);
1191 uint16_t first_tile =
vram[tm_addr] & 0x3FF;
1193 printf(
"Tile $%03X @ VRAM $%04X: %04X %04X %04X %04X %04X %04X %04X %04X\n",
1194 first_tile, actual_tile_addr,
vram[actual_tile_addr & 0x7FFF],
1195 vram[(actual_tile_addr + 1) & 0x7FFF],
1196 vram[(actual_tile_addr + 2) & 0x7FFF],
1197 vram[(actual_tile_addr + 3) & 0x7FFF],
1198 vram[(actual_tile_addr + 4) & 0x7FFF],
1199 vram[(actual_tile_addr + 5) & 0x7FFF],
1200 vram[(actual_tile_addr + 6) & 0x7FFF],
1201 vram[(actual_tile_addr + 7) & 0x7FFF]);
1202 printf(
"=== End PPU Dump ===\n");
1212 stream.write(
reinterpret_cast<const char*
>(&
mode),
sizeof(
mode));
1224 stream.write(
reinterpret_cast<const char*
>(
vram),
sizeof(
vram));
1231 stream.write(
reinterpret_cast<const char*
>(
cgram),
sizeof(
cgram));
1237 stream.write(
reinterpret_cast<const char*
>(
oam),
sizeof(
oam));
1269 for (
const auto& layer :
layer_) {
1270 uint8_t flags[4] = {
static_cast<uint8_t
>(layer.mainScreenEnabled),
1271 static_cast<uint8_t
>(layer.subScreenEnabled),
1272 static_cast<uint8_t
>(layer.mainScreenWindowed),
1273 static_cast<uint8_t
>(layer.subScreenWindowed)};
1274 stream.write(
reinterpret_cast<const char*
>(flags),
sizeof(flags));
1278 stream.write(
reinterpret_cast<const char*
>(&
m7prev),
sizeof(
m7prev));
1281 stream.write(
reinterpret_cast<const char*
>(&
m7xFlip),
sizeof(
m7xFlip));
1282 stream.write(
reinterpret_cast<const char*
>(&
m7yFlip),
sizeof(
m7yFlip));
1283 stream.write(
reinterpret_cast<const char*
>(&
m7extBg),
sizeof(
m7extBg));
1288 uint8_t encoded[5] = {
static_cast<uint8_t
>(win.window1enabled),
1289 static_cast<uint8_t
>(win.window2enabled),
1290 static_cast<uint8_t
>(win.window1inversed),
1291 static_cast<uint8_t
>(win.window2inversed), win.maskLogic};
1292 stream.write(
reinterpret_cast<const char*
>(encoded),
sizeof(encoded));
1301 stream.write(
reinterpret_cast<const char*
>(&bg.hScroll),
sizeof(bg.hScroll));
1302 stream.write(
reinterpret_cast<const char*
>(&bg.vScroll),
sizeof(bg.vScroll));
1303 uint8_t flags[4] = {
static_cast<uint8_t
>(bg.tilemapWider),
1304 static_cast<uint8_t
>(bg.tilemapHigher),
1305 static_cast<uint8_t
>(bg.bigTiles),
1306 static_cast<uint8_t
>(bg.mosaicEnabled)};
1307 stream.write(
reinterpret_cast<const char*
>(flags),
sizeof(flags));
1308 stream.write(
reinterpret_cast<const char*
>(&bg.tilemapAdr),
sizeof(bg.tilemapAdr));
1309 stream.write(
reinterpret_cast<const char*
>(&bg.tileAdr),
sizeof(bg.tileAdr));
1337 stream.write(
reinterpret_cast<const char*
>(&
mosaic_),
sizeof(
mosaic_));
1338 stream.write(
reinterpret_cast<const char*
>(&
bgsc_),
sizeof(
bgsc_));
1339 stream.write(
reinterpret_cast<const char*
>(&
bgnba_),
sizeof(
bgnba_));
1340 stream.write(
reinterpret_cast<const char*
>(&
bghofs_),
sizeof(
bghofs_));
1341 stream.write(
reinterpret_cast<const char*
>(&
bgvofs_),
sizeof(
bgvofs_));
1350 stream.read(
reinterpret_cast<char*
>(&
mode),
sizeof(
mode));
1362 stream.read(
reinterpret_cast<char*
>(
vram),
sizeof(
vram));
1369 stream.read(
reinterpret_cast<char*
>(
cgram),
sizeof(
cgram));
1375 stream.read(
reinterpret_cast<char*
>(
oam),
sizeof(
oam));
1407 for (
auto& layer :
layer_) {
1409 stream.read(
reinterpret_cast<char*
>(flags),
sizeof(flags));
1410 layer.mainScreenEnabled = flags[0];
1411 layer.subScreenEnabled = flags[1];
1412 layer.mainScreenWindowed = flags[2];
1413 layer.subScreenWindowed = flags[3];
1417 stream.read(
reinterpret_cast<char*
>(&
m7prev),
sizeof(
m7prev));
1428 stream.read(
reinterpret_cast<char*
>(encoded),
sizeof(encoded));
1429 win.window1enabled = encoded[0];
1430 win.window2enabled = encoded[1];
1431 win.window1inversed = encoded[2];
1432 win.window2inversed = encoded[3];
1433 win.maskLogic = encoded[4];
1442 stream.read(
reinterpret_cast<char*
>(&bg.hScroll),
sizeof(bg.hScroll));
1443 stream.read(
reinterpret_cast<char*
>(&bg.vScroll),
sizeof(bg.vScroll));
1445 stream.read(
reinterpret_cast<char*
>(flags),
sizeof(flags));
1446 bg.tilemapWider = flags[0];
1447 bg.tilemapHigher = flags[1];
1448 bg.bigTiles = flags[2];
1449 bg.mosaicEnabled = flags[3];
1450 stream.read(
reinterpret_cast<char*
>(&bg.tilemapAdr),
sizeof(bg.tilemapAdr));
1451 stream.read(
reinterpret_cast<char*
>(&bg.tileAdr),
sizeof(bg.tileAdr));
1480 stream.read(
reinterpret_cast<char*
>(&
bgsc_),
sizeof(
bgsc_));
1481 stream.read(
reinterpret_cast<char*
>(&
bgnba_),
sizeof(
bgnba_));
virtual auto pal_timing() const -> bool=0
virtual auto v_pos() const -> uint16_t=0
virtual uint8_t open_bus() const =0
void HandleOPT(int layer, int *lx, int *ly)
void HandlePixel(int x, int y)
void EvaluateSprites(int line)
uint8_t pixelBuffer[512 *4 *239 *2]
uint16_t screen_brightness_
int GetPixel(int x, int y, bool sub, int *r, int *g, int *b)
uint16_t tilemap_base_address_
std::array< BGVOFS, 4 > bgvofs_
uint8_t prevent_math_mode_
bool GetWindowState(int layer, int x)
void CalculateMode7Starts(int y)
bool vram_increment_on_high_
void SaveState(std::ostream &stream)
uint16_t vram_base_address_
void Write(uint8_t adr, uint8_t val)
std::array< BGHOFS, 4 > bghofs_
std::array< BGNBA, 4 > bgnba_
std::array< uint8_t, 256 > obj_pixel_buffer_
void PutPixels(uint8_t *pixel_data)
std::array< uint8_t, 256 > obj_priority_buffer_
uint8_t Read(uint8_t adr, bool latch)
uint8_t mosaic_startline_
bool oam_in_high_written_
uint8_t pixelOutputFormat
uint16_t GetOffsetValue(int col, int row)
std::array< BGSC, 4 > bgsc_
bool math_enabled_array_[6]
int GetPixelForBgLayer(int x, int y, int layer, bool priority)
int GetPixelForMode7(int x, int layer, bool priority)
WindowLayer windowLayer[6]
uint16_t vram_read_buffer_
void LoadState(std::istream &stream)