ref: d3138f9e13a3535c1c42aab37b592919a48df4d8
parent: bd9ecf21506e8bd9bedb37a1c86775c01186b9ed
author: Snesrev <snesrev@protonmail.com>
date: Sat Oct 1 13:32:06 EDT 2022
Simplify PPU code / interactions
--- a/attract.c
+++ b/attract.c
@@ -452,8 +452,6 @@
COLDATA_copy2 = 0x85;
CGWSEL_copy = 0x10;
CGADSUB_copy = 0xa3;
- zelda_ppu_write(WBGLOG, 0);
- zelda_ppu_write(WOBJLOG, 0);
music_control = 6;
attract_legend_flag++;
@@ -516,9 +514,7 @@
zelda_ppu_write(BG2SC, 0x3);
CGWSEL_copy = 0x80;
CGADSUB_copy = 0x21;
- zelda_ppu_write(BGMODE, 7);
BGMODE_copy = 7;
- zelda_ppu_write(M7SEL, 0x80);
WorldMap_LoadLightWorldMap();
M7Y_copy = 0xed;
M7X_copy = 0x100;
@@ -532,7 +528,6 @@
}
void AttractScene_ThroneRoom() { // 8cef4e
- zelda_snes_dummy_write(HDMAEN, 0);
HDMAEN_copy = 0;
CGWSEL_copy = 2;
CGADSUB_copy = 0x20;
@@ -712,7 +707,6 @@
}
} else {
EnableForceBlank();
- zelda_ppu_write(BGMODE, 9);
BGMODE_copy = 9;
EraseTileMaps_normal();
attract_sequence++;
--- a/dungeon.c
+++ b/dungeon.c
@@ -5915,7 +5915,6 @@
void Dungeon_SetAttrForActivatedWaterOff() { // 81ef93
CGWSEL_copy = 2;
CGADSUB_copy = 0x32;
- zelda_ppu_write(TS, 0);
TS_copy = 0;
W12SEL_copy = 0;
dung_hdr_collision = 0;
@@ -6491,11 +6490,8 @@
void LoadOWMusicIfNeeded() { // 82854c
if (!flag_which_music_type)
return;
- zelda_snes_dummy_write(NMITIMEN, 0);
- zelda_snes_dummy_write(HDMAEN, 0);
flag_which_music_type = 0;
LoadOverworldSongs();
- zelda_snes_dummy_write(NMITIMEN, 0x81);
}
void Module07_Dungeon() { // 8287a2
@@ -7853,7 +7849,6 @@
Dungeon_LoadAttributeTable();
subsubmodule_index = bak + 1;
misc_sprites_graphics_index = 10;
- zelda_ppu_write(OBSEL, 2);
InitializeTilesets();
palette_sp6 = 10;
Dungeon_LoadPalettes();
@@ -7879,11 +7874,8 @@
} else {
if (flag_which_music_type)
return;
- zelda_snes_dummy_write(NMITIMEN, 0);
- zelda_snes_dummy_write(HDMAEN, 0);
flag_which_music_type = 1;
LoadDungeonSongs();
- zelda_snes_dummy_write(NMITIMEN, 0x81);
}
}
@@ -8273,7 +8265,6 @@
// This gets called when entering a dungeon from ow.
void Dungeon_LoadAndDrawRoom() { // 82c57b
int bak = HDMAEN_copy;
- zelda_snes_dummy_write(HDMAEN, 0);
HDMAEN_copy = 0;
Dungeon_LoadRoom();
overworld_screen_transition = 0;
--- a/ending.c
+++ b/ending.c
@@ -138,7 +138,6 @@
TS_copy = 0;
Intro_InitializeBackgroundSettings();
CGWSEL_copy = 0x20;
- zelda_ppu_write(OBSEL, 2);
load_chr_halfslot_even_odd = 20;
Graphics_LoadChrHalfSlot();
load_chr_halfslot_even_odd = 0;
@@ -355,9 +354,7 @@
break;
case 2: //
EnableForceBlank();
- zelda_snes_dummy_write(NMITIMEN, 0);
LoadCreditsSongs();
- zelda_snes_dummy_write(NMITIMEN, 0x81);
dungeon_room_index = 0x189;
EraseTileMaps_normal();
Palette_RevertTranslucencySwap();
@@ -488,14 +485,11 @@
}
void Intro_InitializeBackgroundSettings() { // 82c500
- zelda_ppu_write(SETINI, 0);
BGMODE_copy = 9;
MOSAIC_copy = 0;
zelda_ppu_write(BG1SC, 0x13);
zelda_ppu_write(BG2SC, 3);
zelda_ppu_write(BG3SC, 0x63);
- zelda_ppu_write(BG12NBA, 0x22);
- zelda_ppu_write(BG34NBA, 7);
CGADSUB_copy = 32;
COLDATA_copy0 = 32;
COLDATA_copy1 = 64;
@@ -575,7 +569,6 @@
void Intro_InitializeMemory_darken() { // 8cc1f5
EnableForceBlank();
EraseTileMaps_normal();
- zelda_ppu_write(OBSEL, 2);
main_tile_theme_index = 35;
sprite_graphics_index = 125;
aux_tile_theme_index = 81;
--- a/load_gfx.c
+++ b/load_gfx.c
@@ -877,15 +877,13 @@
void Attract_LoadBG3GFX() { // 80e36d
// load 2bpp gfx for attract images
zelda_ppu_write(VMAIN, 0x80);
- zelda_ppu_write(VMADDL, 0);
- zelda_ppu_write(VMADDH, 0x78);
+ zelda_ppu_write_word(VMADDL, 0x7800);
DecompAndUpload2bpp(0x67);
}
void LoadCommonSprites_2() { // 80e384
zelda_ppu_write(VMAIN, 0x80);
- zelda_ppu_write(VMADDL, 0);
- zelda_ppu_write(VMADDH, 0x44);
+ zelda_ppu_write_word(VMADDL, 0x4400);
LoadCommonSprites();
}
@@ -951,7 +949,6 @@
}
void TransferFontToVRAM() { // 80e556
- zelda_ppu_write(OBSEL, 2);
zelda_ppu_write(VMAIN, 0x80);
zelda_ppu_write_word(VMADDL, 0x7000);
const uint16 *src = GetFontPtr();
--- a/messaging.c
+++ b/messaging.c
@@ -949,8 +949,6 @@
death_var4 = 0;
death_var5 = 0;
buffer_for_playing_songs = 0;
- zelda_snes_dummy_write(NMITIMEN, 0);
- zelda_snes_dummy_write(HDMAEN, 0);
BG1HOFS_copy2 = 0;
BG2HOFS_copy2 = 0;
BG3HOFS_copy2 = 0;
@@ -964,7 +962,6 @@
memset(save_dung_info, 0, 256 * 5);
flag_which_music_type = 0;
LoadOverworldSongs();
- zelda_snes_dummy_write(NMITIMEN, 0x81);
}
}
@@ -1229,9 +1226,7 @@
sound_effect_2 = 16;
sound_effect_ambient = 5;
music_control = 0xf2;
- zelda_ppu_write(BGMODE, 7);
BGMODE_copy = 7;
- zelda_ppu_write(M7SEL, 0x80);
}
void WorldMap_LoadLightWorldMap() { // 8aba30
@@ -1343,7 +1338,6 @@
void Attract_SetUpConclusionHDMA() { // 8abc33
HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
HDMAEN_copy = 0x80;
- zelda_ppu_write(BGMODE, 9);
BGMODE_copy = 9;
nmi_disable_core_updates = 0;
}
@@ -1375,14 +1369,6 @@
WOBJSEL_copy = 0;
TMW_copy = 0;
TSW_copy = 0;
- zelda_ppu_write(M7B, 0);
- zelda_ppu_write(M7B, 0);
- zelda_ppu_write(M7C, 0);
- zelda_ppu_write(M7C, 0);
- zelda_ppu_write(M7X, 0);
- zelda_ppu_write(M7X, 1);
- zelda_ppu_write(M7Y, 0);
- zelda_ppu_write(M7Y, 1);
if (main_module_index == 20) {
HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
@@ -1665,7 +1651,6 @@
void Module0E_03_01_00_PrepMapGraphics() { // 8ae0e4
uint8 hdmaen_bak = HDMAEN_copy;
- zelda_snes_dummy_write(HDMAEN, 0);
HDMAEN_copy = 0;
mapbak_main_tile_theme_index = main_tile_theme_index;
mapbak_sprite_graphics_index = sprite_graphics_index;
@@ -2205,7 +2190,6 @@
void DungeonMap_RecoverGFX() { // 8aef19
uint8 hdmaen_bak = HDMAEN_copy;
- zelda_snes_dummy_write(HDMAEN, 0);
HDMAEN_copy = 0;
EraseTileMaps_normal();
--- a/misc.c
+++ b/misc.c
@@ -549,7 +549,6 @@
byte_7E0379 = 0;
byte_7E03FD = 0;
EraseTileMaps_normal();
- zelda_ppu_write(OBSEL, 2);
LoadDefaultGraphics();
Sprite_LoadGraphicsProperties();
Init_LoadDefaultTileAttr();
--- a/nmi.c
+++ b/nmi.c
@@ -65,6 +65,48 @@
}
}
+void WritePpuRegisters() {
+ zelda_ppu_write(W12SEL, W12SEL_copy);
+ zelda_ppu_write(W34SEL, W34SEL_copy);
+ zelda_ppu_write(WOBJSEL, WOBJSEL_copy);
+ zelda_ppu_write(CGWSEL, CGWSEL_copy);
+ zelda_ppu_write(CGADSUB, CGADSUB_copy);
+ zelda_ppu_write(COLDATA, COLDATA_copy0);
+ zelda_ppu_write(COLDATA, COLDATA_copy1);
+ zelda_ppu_write(COLDATA, COLDATA_copy2);
+ zelda_ppu_write(TM, TM_copy);
+ zelda_ppu_write(TS, TS_copy);
+ zelda_ppu_write(TMW, TMW_copy);
+ zelda_ppu_write(TSW, TSW_copy);
+ zelda_ppu_write(BG1HOFS, BG1HOFS_copy);
+ zelda_ppu_write(BG1HOFS, BG1HOFS_copy >> 8);
+ zelda_ppu_write(BG1VOFS, BG1VOFS_copy);
+ zelda_ppu_write(BG1VOFS, BG1VOFS_copy >> 8);
+ zelda_ppu_write(BG2HOFS, BG2HOFS_copy);
+ zelda_ppu_write(BG2HOFS, BG2HOFS_copy >> 8);
+ zelda_ppu_write(BG2VOFS, BG2VOFS_copy);
+ zelda_ppu_write(BG2VOFS, BG2VOFS_copy >> 8);
+ zelda_ppu_write(BG3HOFS, BG3HOFS_copy2);
+ zelda_ppu_write(BG3HOFS, BG3HOFS_copy2 >> 8);
+ zelda_ppu_write(BG3VOFS, BG3VOFS_copy2);
+ zelda_ppu_write(BG3VOFS, BG3VOFS_copy2 >> 8);
+ zelda_ppu_write(INIDISP, INIDISP_copy);
+ zelda_ppu_write(MOSAIC, MOSAIC_copy);
+ zelda_ppu_write(BGMODE, BGMODE_copy);
+ if ((BGMODE_copy & 7) == 7) {
+ zelda_ppu_write(M7B, 0);
+ zelda_ppu_write(M7B, 0);
+ zelda_ppu_write(M7C, 0);
+ zelda_ppu_write(M7C, 0);
+ zelda_ppu_write(M7X, M7X_copy);
+ zelda_ppu_write(M7X, M7X_copy >> 8);
+ zelda_ppu_write(M7Y, M7Y_copy);
+ zelda_ppu_write(M7Y, M7Y_copy >> 8);
+ }
+ zelda_ppu_write(BG12NBA, 0x22);
+ zelda_ppu_write(BG34NBA, 7);
+}
+
void Interrupt_NMI(uint16 joypad_input) { // 8080c9
if (music_control == 0) {
if (zelda_apu_read(APUI00) == last_music_control)
@@ -92,8 +134,6 @@
sound_effect_1 = 0;
sound_effect_2 = 0;
- zelda_ppu_write(INIDISP, 0x80);
- zelda_snes_dummy_write(HDMAEN, 0);
if (!nmi_boolean) {
nmi_boolean = true;
NMI_DoUpdates();
@@ -101,91 +141,12 @@
}
if (is_nmi_thread_active) {
- NMI_SwitchThread();
- } else {
- zelda_ppu_write(W12SEL, W12SEL_copy);
- zelda_ppu_write(W34SEL, W34SEL_copy);
- zelda_ppu_write(WOBJSEL, WOBJSEL_copy);
- zelda_ppu_write(CGWSEL, CGWSEL_copy);
- zelda_ppu_write(CGADSUB, CGADSUB_copy);
- zelda_ppu_write(COLDATA, COLDATA_copy0);
- zelda_ppu_write(COLDATA, COLDATA_copy1);
- zelda_ppu_write(COLDATA, COLDATA_copy2);
- zelda_ppu_write(TM, TM_copy);
- zelda_ppu_write(TS, TS_copy);
- zelda_ppu_write(TMW, TMW_copy);
- zelda_ppu_write(TSW, TSW_copy);
- zelda_ppu_write(BG1HOFS, BG1HOFS_copy);
- zelda_ppu_write(BG1HOFS, BG1HOFS_copy >> 8);
- zelda_ppu_write(BG1VOFS, BG1VOFS_copy);
- zelda_ppu_write(BG1VOFS, BG1VOFS_copy >> 8);
- zelda_ppu_write(BG2HOFS, BG2HOFS_copy);
- zelda_ppu_write(BG2HOFS, BG2HOFS_copy >> 8);
- zelda_ppu_write(BG2VOFS, BG2VOFS_copy);
- zelda_ppu_write(BG2VOFS, BG2VOFS_copy >> 8);
- zelda_ppu_write(BG3HOFS, BG3HOFS_copy2);
- zelda_ppu_write(BG3HOFS, BG3HOFS_copy2 >> 8);
- zelda_ppu_write(BG3VOFS, BG3VOFS_copy2);
- zelda_ppu_write(BG3VOFS, BG3VOFS_copy2 >> 8);
- zelda_ppu_write(MOSAIC, MOSAIC_copy);
- zelda_ppu_write(BGMODE, BGMODE_copy);
- if ((BGMODE_copy & 7) == 7) {
- zelda_ppu_write(M7B, 0);
- zelda_ppu_write(M7B, 0);
- zelda_ppu_write(M7C, 0);
- zelda_ppu_write(M7C, 0);
- zelda_ppu_write(M7X, M7X_copy);
- zelda_ppu_write(M7X, M7X_copy >> 8);
- zelda_ppu_write(M7Y, M7Y_copy);
- zelda_ppu_write(M7Y, M7Y_copy >> 8);
- }
- //if (irq_flag) {
- // snes_dummy_read(g_snes, TIMEUP);
- // snes_dummy_write(g_snes, VTIMEL, 0x80);
- // snes_dummy_write(g_snes, VTIMEH, 0);
- // snes_dummy_write(g_snes, HTIMEL, 0);
- // snes_dummy_write(g_snes, HTIMEH, 0);
- // snes_dummy_write(g_snes, NMITIMEN, 0xa1);
- //}
- zelda_ppu_write(INIDISP, INIDISP_copy);
- zelda_snes_dummy_write(HDMAEN, HDMAEN_copy);
+ NMI_UpdateIRQGFX();
+ thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
}
+ WritePpuRegisters();
}
-void NMI_SwitchThread() { // 80822d
- NMI_UpdateIRQGFX();
- //zelda_snes_dummy_write(VTIMEL, virq_trigger);
- //zelda_snes_dummy_write(VTIMEH, 0);
- //zelda_snes_dummy_write(NMITIMEN, 0xa1);
- zelda_ppu_write(W12SEL, W12SEL_copy);
- zelda_ppu_write(W34SEL, W34SEL_copy);
- zelda_ppu_write(WOBJSEL, WOBJSEL_copy);
- zelda_ppu_write(CGWSEL, CGWSEL_copy);
- zelda_ppu_write(CGADSUB, CGADSUB_copy);
- zelda_ppu_write(COLDATA, COLDATA_copy0);
- zelda_ppu_write(COLDATA, COLDATA_copy1);
- zelda_ppu_write(COLDATA, COLDATA_copy2);
- zelda_ppu_write(TM, TM_copy);
- zelda_ppu_write(TS, TS_copy);
- zelda_ppu_write(TMW, TMW_copy);
- zelda_ppu_write(TSW, TSW_copy);
- zelda_ppu_write(BG1HOFS, BG1HOFS_copy);
- zelda_ppu_write(BG1HOFS, BG1HOFS_copy >> 8);
- zelda_ppu_write(BG1VOFS, BG1VOFS_copy);
- zelda_ppu_write(BG1VOFS, BG1VOFS_copy >> 8);
- zelda_ppu_write(BG2HOFS, BG2HOFS_copy);
- zelda_ppu_write(BG2HOFS, BG2HOFS_copy >> 8);
- zelda_ppu_write(BG2VOFS, BG2VOFS_copy);
- zelda_ppu_write(BG2VOFS, BG2VOFS_copy >> 8);
- zelda_ppu_write(BG3HOFS, BG3HOFS_copy2);
- zelda_ppu_write(BG3HOFS, BG3HOFS_copy2 >> 8);
- zelda_ppu_write(BG3VOFS, BG3VOFS_copy2);
- zelda_ppu_write(BG3VOFS, BG3VOFS_copy2 >> 8);
- zelda_ppu_write(INIDISP, INIDISP_copy);
- zelda_snes_dummy_write(HDMAEN, HDMAEN_copy);
- thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
-}
-
void NMI_ReadJoypads(uint16 joypad_input) { // 8083d1
uint16 both = joypad_input;
uint16 reversed = 0;
@@ -249,8 +210,7 @@
flag_update_hud_in_nmi = 0;
flag_update_cgram_in_nmi = 0;
- memcpy(g_zenv.ppu->oam, &g_ram[0x800], 0x200);
- memcpy(g_zenv.ppu->highOam, &g_ram[0xa00], 0x20);
+ memcpy(g_zenv.ppu->oam, &g_ram[0x800], 0x220);
if (nmi_load_bg_from_vram) {
const uint8 *p;
--- a/nmi.h
+++ b/nmi.h
@@ -7,7 +7,6 @@
void CopyToVramVertical(uint32 dstv, const uint8 *src, int len);
void CopyToVramLow(const uint8 *src, uint32 addr, int num);
void Interrupt_NMI(uint16 joypad_input);
-void NMI_SwitchThread();
void NMI_ReadJoypads(uint16 joypad_input);
void NMI_DoUpdates();
void NMI_UploadTilemap();
--- a/select_file.c
+++ b/select_file.c
@@ -184,7 +184,6 @@
}
void LoadFileSelectGraphics() { // 80e4e9
- zelda_ppu_write(OBSEL, 2);
zelda_ppu_write(VMAIN, 0x80);
zelda_ppu_write_word(VMADDL, 0x5000);
--- a/snes/ppu.c
+++ b/snes/ppu.c
@@ -20,9 +20,19 @@
static int ppu_getPixelForMode7(Ppu* ppu, int x, int layer, bool priority);
static bool ppu_getWindowState(Ppu* ppu, int layer, int x);
static bool ppu_evaluateSprites(Ppu* ppu, int line);
-static uint16_t ppu_getVramRemap(Ppu* ppu);
static void PpuDrawWholeLine(Ppu *ppu, uint y);
+#define IS_SCREEN_ENABLED(ppu, sub, layer) (ppu->screenEnabled[sub] & (1 << layer))
+#define IS_SCREEN_WINDOWED(ppu, sub, layer) (ppu->screenWindowed[sub] & (1 << layer))
+#define IS_MOSAIC_ENABLED(ppu, layer) ((ppu->mosaicEnabled & (1 << layer)))
+#define GET_WINDOW_FLAGS(ppu, layer) (ppu->windowsel >> (layer * 4))
+enum {
+ kWindow1Inversed = 1,
+ kWindow1Enabled = 2,
+ kWindow2Inversed = 4,
+ kWindow2Enabled = 8,
+};
+
Ppu* ppu_init() {
Ppu* ppu = (Ppu * )malloc(sizeof(Ppu));
ppu->extraLeftRight = kPpuExtraLeftRight;
@@ -43,28 +53,18 @@
ppu->vramPointer = 0;
ppu->vramIncrementOnHigh = false;
ppu->vramIncrement = 1;
- ppu->vramRemapMode = 0;
- ppu->vramReadBuffer = 0;
memset(ppu->cgram, 0, sizeof(ppu->cgram));
ppu->cgramPointer = 0;
ppu->cgramSecondWrite = false;
ppu->cgramBuffer = 0;
memset(ppu->oam, 0, sizeof(ppu->oam));
- memset(ppu->highOam, 0, sizeof(ppu->highOam));
ppu->oamAdr = 0;
- ppu->oamAdrWritten = 0;
- ppu->oamInHigh = false;
- ppu->oamInHighWritten = false;
ppu->oamSecondWrite = false;
ppu->oamBuffer = 0;
- ppu->objPriority = false;
- ppu->objTileAdr1 = 0;
- ppu->objTileAdr2 = 0;
+ ppu->objTileAdr1 = 0x4000;
+ ppu->objTileAdr2 = 0x5000;
ppu->objSize = 0;
memset(&ppu->objBuffer, 0, sizeof(ppu->objBuffer));
- ppu->timeOver = false;
- ppu->rangeOver = false;
- ppu->objInterlace_always_zero = false;
for(int i = 0; i < 4; i++) {
ppu->bgLayer[i].hScroll = 0;
ppu->bgLayer[i].vScroll = 0;
@@ -72,22 +72,15 @@
ppu->bgLayer[i].tilemapHigher = false;
ppu->bgLayer[i].tilemapAdr = 0;
ppu->bgLayer[i].tileAdr = 0;
- ppu->bgLayer[i].bigTiles_always_zero = false;
- ppu->bgLayer[i].mosaicEnabled = false;
}
ppu->scrollPrev = 0;
ppu->scrollPrev2 = 0;
ppu->mosaicSize = 1;
- ppu->mosaicStartLine = 1;
- for(int i = 0; i < 5; i++) {
- ppu->layer[i].screenEnabled[0] = false;
- ppu->layer[i].screenEnabled[1] = false;
- ppu->layer[i].screenWindowed[0] = false;
- ppu->layer[i].screenWindowed[1] = false;
- }
+ ppu->screenEnabled[0] = ppu->screenEnabled[1] = 0;
+ ppu->screenWindowed[0] = ppu->screenWindowed[1] = 0;
memset(ppu->m7matrix, 0, sizeof(ppu->m7matrix));
ppu->m7prev = 0;
- ppu->m7largeField = false;
+ ppu->m7largeField = true;
ppu->m7charFill = false;
ppu->m7xFlip = false;
ppu->m7yFlip = false;
@@ -94,13 +87,7 @@
ppu->m7extBg_always_zero = false;
ppu->m7startX = 0;
ppu->m7startY = 0;
- for(int i = 0; i < 6; i++) {
- ppu->windowLayer[i].window1enabled = false;
- ppu->windowLayer[i].window2enabled = false;
- ppu->windowLayer[i].window1inversed = false;
- ppu->windowLayer[i].window2inversed = false;
- ppu->windowLayer[i].maskLogic_always_zero = 0;
- }
+ ppu->windowsel = 0;
ppu->window1left = 0;
ppu->window1right = 0;
ppu->window2left = 0;
@@ -110,7 +97,7 @@
ppu->addSubscreen = false;
ppu->subtractColor = false;
ppu->halfColor = false;
- memset(ppu->mathEnabled, 0, sizeof(ppu->mathEnabled));
+ ppu->mathEnabled = 0;
ppu->fixedColorR = 0;
ppu->fixedColorG = 0;
ppu->fixedColorB = 0;
@@ -117,33 +104,24 @@
ppu->forcedBlank = true;
ppu->brightness = 0;
ppu->mode = 0;
- ppu->bg3priority = false;
- ppu->evenFrame = false;
- ppu->pseudoHires_always_zero = false;
- ppu->overscan_always_zero = false;
- ppu->frameOverscan_always_zero = false;
- ppu->interlace_always_zero = false;
- ppu->frameInterlace_always_zero = false;
- ppu->directColor_always_zero = false;
- ppu->hCount = 0;
- ppu->vCount = 0;
- ppu->hCountSecond = false;
- ppu->vCountSecond = false;
- ppu->countersLatched = false;
- ppu->ppu1openBus = 0;
- ppu->ppu2openBus = 0;
}
void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx) {
- size_t s1 = offsetof(Ppu, objSize) + 1 - offsetof(Ppu, vram);
- size_t s2 = offsetof(Ppu, mosaicModulo) - offsetof(Ppu, timeOver);
- assert(s1 == 66619 && s2 == 174);
- func(ctx, &ppu->vram, s1);
- func(ctx, &ppu->objBuffer, 512);
- func(ctx, &ppu->timeOver, s2);
+ uint8 tmp[556] = { 0 };
+
+ func(ctx, &ppu->vram, 0x8000 * 2);
+ func(ctx, tmp, 10);
+ func(ctx, &ppu->cgram, 512);
+ func(ctx, tmp, 556);
+ func(ctx, tmp, 520);
+ for (int i = 0; i < 4; i++) {
+ func(ctx, tmp, 4);
+ func(ctx, &ppu->bgLayer[i].tilemapWider, 4);
+ func(ctx, tmp, 4);
+ }
+ func(ctx, tmp, 123);
}
-
bool PpuBeginDrawing(Ppu *ppu, uint8_t *pixels, size_t pitch, uint32_t render_flags) {
ppu->renderFlags = render_flags;
bool hq = ppu->mode == 7 && !ppu->forcedBlank &&
@@ -179,11 +157,7 @@
void ppu_runLine(Ppu *ppu, int line) {
- if(line == 0) {
- ppu->rangeOver = false;
- ppu->timeOver = false;
- ppu->evenFrame = !ppu->evenFrame;
- } else {
+ if(line != 0) {
if (ppu->mosaicSize != ppu->lastMosaicModulo) {
int mod = ppu->mosaicSize;
ppu->lastMosaicModulo = mod;
@@ -238,10 +212,10 @@
}
static void PpuWindows_Calc(PpuWindows *win, Ppu *ppu, uint layer) {
- WindowLayer *wl = &ppu->windowLayer[layer];
// Evaluate which spans to render based on the window settings.
// There are at most 5 windows.
// Algorithm from Snes9x
+ uint32 winflags = GET_WINDOW_FLAGS(ppu, layer);
uint nr = 1;
int window_right = 256 + (layer != 2 ? ppu->extraRightCur : 0);
win->edges[0] = - (layer != 2 ? ppu->extraLeftCur : 0);
@@ -249,7 +223,7 @@
uint8 window_bits = 0;
uint i, j;
int t;
- bool w1_ena = wl->window1enabled && ppu->window1left <= ppu->window1right;
+ bool w1_ena = (winflags & kWindow1Enabled) && ppu->window1left <= ppu->window1right;
if (w1_ena) {
if (ppu->window1left > win->edges[0]) {
win->edges[nr] = ppu->window1left;
@@ -260,7 +234,7 @@
win->edges[++nr] = window_right;
}
}
- bool w2_ena = wl->window2enabled && ppu->window2left <= ppu->window2right;
+ bool w2_ena = (winflags & kWindow2Enabled) && ppu->window2left <= ppu->window2right;
if (w2_ena) {
for (i = 0; i <= nr && (t = ppu->window2left) != win->edges[i]; i++) {
if (t < win->edges[i]) {
@@ -287,7 +261,7 @@
for (j = i; win->edges[j] != ppu->window1right + 1; j++);
w1_bits = ((1 << (j - i)) - 1) << i;
}
- if (wl->window1enabled & wl->window1inversed)
+ if ((winflags & (kWindow1Enabled | kWindow1Inversed)) == (kWindow1Enabled | kWindow1Inversed))
w1_bits = ~w1_bits;
if (w2_ena) {
for (i = 0; win->edges[i] != ppu->window2left; i++);
@@ -294,7 +268,7 @@
for (j = i; win->edges[j] != ppu->window2right + 1; j++);
w2_bits = ((1 << (j - i)) - 1) << i;
}
- if (wl->window2enabled & wl->window2inversed)
+ if ((winflags & (kWindow2Enabled | kWindow2Inversed)) == (kWindow2Enabled | kWindow2Inversed))
w2_bits = ~w2_bits;
win->bits = w1_bits | w2_bits;
}
@@ -309,11 +283,10 @@
if ((bits & (0x80808080 >> i)) && z > dstz[i]) dstz[i] = z + pixel; } while (0)
#define READ_BITS(ta, tile) (addr = &ppu->vram[((ta) + (tile) * 16) & 0x7fff], addr[0] | addr[8] << 16)
enum { kPaletteShift = 6 };
- Layer *layerp = &ppu->layer[layer];
- if (!layerp->screenEnabled[sub])
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
BgLayer *bglayer = &ppu->bgLayer[layer];
y += bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -408,11 +381,10 @@
if (pixel && z > dstz[i]) dstz[i] = z + pixel; } while (0)
#define READ_BITS(ta, tile) (addr = &ppu->vram[(ta) + (tile) * 8 & 0x7fff], addr[0])
enum { kPaletteShift = 8 };
- Layer *layerp = &ppu->layer[layer];
- if (!layerp->screenEnabled[sub])
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
BgLayer *bglayer = &ppu->bgLayer[layer];
y += bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -506,11 +478,10 @@
#define GET_PIXEL_HFLIP(i) pixel = (bits >> 7) & 1 | (bits >> 14) & 2 | (bits >> 21) & 4 | (bits >> 28) & 8
#define READ_BITS(ta, tile) (addr = &ppu->vram[((ta) + (tile) * 16) & 0x7fff], addr[0] | addr[8] << 16)
enum { kPaletteShift = 6 };
- Layer *layerp = &ppu->layer[layer];
- if (!layerp->screenEnabled[sub])
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
BgLayer *bglayer = &ppu->bgLayer[layer];
y = ppu->mosaicModulo[y] + bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -566,11 +537,10 @@
#define GET_PIXEL_HFLIP(i) pixel = (bits >> 7) & 1 | (bits >> 14) & 2
#define READ_BITS(ta, tile) (addr = &ppu->vram[((ta) + (tile) * 8) & 0x7fff], addr[0])
enum { kPaletteShift = 8 };
- Layer *layerp = &ppu->layer[layer];
- if (!layerp->screenEnabled[sub])
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
BgLayer *bglayer = &ppu->bgLayer[layer];
y = ppu->mosaicModulo[y] + bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -626,11 +596,11 @@
#define SPRITE_PRIO_TO_PRIO_HI(prio) ((prio) * 4 + 2)
static void PpuDrawSprites(Ppu *ppu, uint y, uint sub, bool clear_backdrop) {
- Layer *layerp = &ppu->layer[4];
- if (!layerp->screenEnabled[sub])
+ int layer = 4;
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, 4) : PpuWindows_Clear(&win, ppu, 4);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
for (size_t windex = 0; windex < win.nr; windex++) {
if (win.bits & (1 << windex))
continue; // layer is disabled for this window part
@@ -652,11 +622,10 @@
// Assumes it's drawn on an empty backdrop
static void PpuDrawBackground_mode7(Ppu *ppu, uint y, bool sub, PpuZbufType z) {
int layer = 0;
- Layer *layerp = &ppu->layer[layer];
- if (!layerp->screenEnabled[sub])
+ if (!IS_SCREEN_ENABLED(ppu, sub, layer))
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
+ IS_SCREEN_WINDOWED(ppu, sub, layer) ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu, layer);
// expand 13-bit values to signed values
int hScroll = ((int16_t)(ppu->m7matrix[6] << 3)) >> 3;
@@ -667,7 +636,7 @@
int clippedV = vScroll - yCenter;
clippedH = (clippedH & 0x2000) ? (clippedH | ~1023) : (clippedH & 1023);
clippedV = (clippedV & 0x2000) ? (clippedV | ~1023) : (clippedV & 1023);
- bool mosaic_enabled = ppu->bgLayer[0].mosaicEnabled && ppu->mosaicSize > 1;
+ bool mosaic_enabled = IS_MOSAIC_ENABLED(ppu, 0);
if (mosaic_enabled)
y = ppu->mosaicModulo[y];
uint32 ry = ppu->m7yFlip ? 255 - y : y;
@@ -825,10 +794,6 @@
for (int i = 0; i < 4; i++)
memset(dst_start + pitch * i + (256 + ppu->extraLeftRight * 2 - (ppu->extraLeftRight - ppu->extraRightCur)) * 4 * sizeof(uint32), 0, n);
}
-
-
-
-
#undef DRAW_PIXEL
}
@@ -852,17 +817,17 @@
if (ppu->lineHasSprites)
PpuDrawSprites(ppu, y, sub, true);
- if (ppu->bgLayer[0].mosaicEnabled && ppu->mosaicSize > 1)
+ if (IS_MOSAIC_ENABLED(ppu, 0))
PpuDrawBackground_4bpp_mosaic(ppu, y, sub, 0, 0xc000, 0x8000);
else
PpuDrawBackground_4bpp(ppu, y, sub, 0, 0xc000, 0x8000);
- if (ppu->bgLayer[1].mosaicEnabled && ppu->mosaicSize > 1)
+ if (IS_MOSAIC_ENABLED(ppu, 1))
PpuDrawBackground_4bpp_mosaic(ppu, y, sub, 1, 0xb100, 0x7100);
else
PpuDrawBackground_4bpp(ppu, y, sub, 1, 0xb100, 0x7100);
- if (ppu->bgLayer[2].mosaicEnabled && ppu->mosaicSize > 1)
+ if (IS_MOSAIC_ENABLED(ppu, 2))
PpuDrawBackground_2bpp_mosaic(ppu, y, sub, 2, 0xf200, 0x1200);
else
PpuDrawBackground_2bpp(ppu, y, sub, 2, 0xf200, 0x1200);
@@ -895,16 +860,13 @@
PpuDrawBackgrounds(ppu, y, false);
// The 6:th bit is automatically zero, math is never applied to the first half of the sprites.
- uint32 math_enabled = ppu->mathEnabled[0] << 0 | ppu->mathEnabled[1] << 1 | ppu->mathEnabled[2] << 2 |
- ppu->mathEnabled[3] << 3 | ppu->mathEnabled[4] << 4 | ppu->mathEnabled[5] << 5;
+ uint32 math_enabled = ppu->mathEnabled;
// Render also the subscreen?
bool rendered_subscreen = false;
if (ppu->preventMathMode != 3 && ppu->addSubscreen && math_enabled) {
ClearBackdrop(&ppu->bgBuffers[1]);
-
- if (ppu->layer[0].screenEnabled[1] | ppu->layer[1].screenEnabled[1] | ppu->layer[2].screenEnabled[1] |
- ppu->layer[3].screenEnabled[1] | ppu->layer[4].screenEnabled[1]) {
+ if (ppu->screenEnabled[1] != 0) {
PpuDrawBackgrounds(ppu, y, true);
rendered_subscreen = true;
}
@@ -1005,12 +967,12 @@
r = g = b = 0;
}
int secondLayer = 5; // backdrop
- bool mathEnabled = mainLayer < 6 && ppu->mathEnabled[mainLayer] && !(
+ bool mathEnabled = mainLayer < 6 && (ppu->mathEnabled & (1 << mainLayer)) && !(
ppu->preventMathMode == 3 ||
(ppu->preventMathMode == 2 && colorWindowState) ||
(ppu->preventMathMode == 1 && !colorWindowState)
);
- if ((mathEnabled && ppu->addSubscreen) || ppu->pseudoHires_always_zero || ppu->mode == 5 || ppu->mode == 6) {
+ if ((mathEnabled && ppu->addSubscreen) || ppu->mode == 5 || ppu->mode == 6) {
secondLayer = ppu_getPixel(ppu, x, y, true, &r2, &g2, &b2);
}
// TODO: subscreen pixels can be clipped to black as well
@@ -1037,7 +999,7 @@
if (g < 0) g = 0;
if (b < 0) b = 0;
}
- if (!(ppu->pseudoHires_always_zero || ppu->mode == 5 || ppu->mode == 6)) {
+ if (!(ppu->mode == 5 || ppu->mode == 6)) {
r2 = r; g2 = g; b2 = b;
}
}
@@ -1104,7 +1066,7 @@
// figure out which color is on this location on main- or subscreen, sets it in r, g, b
// returns which layer it is: 0-3 for bg layer, 4 or 6 for sprites (depending on palette), 5 for backdrop
- int actMode = ppu->mode == 1 && ppu->bg3priority ? 8 : ppu->mode;
+ int actMode = ppu->mode == 1 ? 8 : ppu->mode;
actMode = ppu->mode == 7 && ppu->m7extBg_always_zero ? 9 : actMode;
int layer = 5;
int pixel = 0;
@@ -1113,12 +1075,12 @@
int curPriority = prioritysPerMode[actMode][i];
bool layerActive = false;
if (!sub) {
- layerActive = ppu->layer[curLayer].screenEnabled[0] && (
- !ppu->layer[curLayer].screenWindowed[0] || !ppu_getWindowState(ppu, curLayer, x)
+ layerActive = IS_SCREEN_ENABLED(ppu, 0, curLayer) && (
+ !IS_SCREEN_WINDOWED(ppu, 0, curLayer) || !ppu_getWindowState(ppu, curLayer, x)
);
} else {
- layerActive = ppu->layer[curLayer].screenEnabled[1] && (
- !ppu->layer[curLayer].screenWindowed[1] || !ppu_getWindowState(ppu, curLayer, x)
+ layerActive = IS_SCREEN_ENABLED(ppu, 1, curLayer) && (
+ !IS_SCREEN_WINDOWED(ppu, 1, curLayer) || !ppu_getWindowState(ppu, curLayer, x)
);
}
if (layerActive) {
@@ -1126,22 +1088,14 @@
// bg layer
int lx = x;
int ly = y;
- if (ppu->bgLayer[curLayer].mosaicEnabled && ppu->mosaicSize > 1) {
+ if (IS_MOSAIC_ENABLED(ppu, curLayer)) {
lx -= lx % ppu->mosaicSize;
- ly -= (ly - ppu->mosaicStartLine) % ppu->mosaicSize;
+ ly -= (ly - 1) % ppu->mosaicSize;
}
if (ppu->mode == 7) {
pixel = ppu_getPixelForMode7(ppu, lx, curLayer, curPriority);
} else {
lx += ppu->bgLayer[curLayer].hScroll;
- if (ppu->mode == 5 || ppu->mode == 6) {
- lx *= 2;
- lx += (sub || ppu->bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
- if (ppu->interlace_always_zero) {
- ly *= 2;
- ly += (ppu->evenFrame || ppu->bgLayer[curLayer].mosaicEnabled) ? 0 : 1;
- }
- }
ly += ppu->bgLayer[curLayer].vScroll;
pixel = ppu_getPixelForBgLayer(
ppu, lx & 0x3ff, ly & 0x3ff,
@@ -1160,16 +1114,10 @@
break;
}
}
- if (ppu->directColor_always_zero && layer < 4 && bitDepthsPerMode[actMode][layer] == 8) {
- *r = ((pixel & 0x7) << 2) | ((pixel & 0x100) >> 7);
- *g = ((pixel & 0x38) >> 1) | ((pixel & 0x200) >> 8);
- *b = ((pixel & 0xc0) >> 3) | ((pixel & 0x400) >> 8);
- } else {
- uint16_t color = ppu->cgram[pixel & 0xff];
- *r = color & 0x1f;
- *g = (color >> 5) & 0x1f;
- *b = (color >> 10) & 0x1f;
- }
+ uint16_t color = ppu->cgram[pixel & 0xff];
+ *r = color & 0x1f;
+ *g = (color >> 5) & 0x1f;
+ *b = (color >> 10) & 0x1f;
if (layer == 4 && pixel < 0xc0) layer = 6; // sprites with palette color < 0xc0
return layer;
@@ -1179,11 +1127,11 @@
static int ppu_getPixelForBgLayer(Ppu *ppu, int x, int y, int layer, bool priority) {
BgLayer *layerp = &ppu->bgLayer[layer];
// figure out address of tilemap word and read it
- bool wideTiles = layerp->bigTiles_always_zero || ppu->mode == 5 || ppu->mode == 6;
+ bool wideTiles = ppu->mode == 5 || ppu->mode == 6;
int tileBitsX = wideTiles ? 4 : 3;
int tileHighBitX = wideTiles ? 0x200 : 0x100;
- int tileBitsY = layerp->bigTiles_always_zero ? 4 : 3;
- int tileHighBitY = layerp->bigTiles_always_zero ? 0x200 : 0x100;
+ int tileBitsY = 3;
+ int tileHighBitY = 0x100;
uint16_t tilemapAdr = layerp->tilemapAdr + (((y >> tileBitsY) & 0x1f) << 5 | ((x >> tileBitsX) & 0x1f));
if ((x & tileHighBitX) && layerp->tilemapWider) tilemapAdr += 0x400;
if ((y & tileHighBitY) && layerp->tilemapHigher) tilemapAdr += layerp->tilemapWider ? 0x800 : 0x400;
@@ -1199,10 +1147,6 @@
// if unflipped right half of tile, or flipped left half of tile
if (((bool)(x & 8)) ^ ((bool)(tile & 0x4000))) tileNum += 1;
}
- if (layerp->bigTiles_always_zero) {
- // 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[ppu->mode][layer];
if (ppu->mode == 0) paletteNum += 8 * layer;
@@ -1243,8 +1187,8 @@
int clippedV = vScroll - yCenter;
clippedH = (clippedH & 0x2000) ? (clippedH | ~1023) : (clippedH & 1023);
clippedV = (clippedV & 0x2000) ? (clippedV | ~1023) : (clippedV & 1023);
- if(ppu->bgLayer[0].mosaicEnabled && ppu->mosaicSize > 1) {
- y -= (y - ppu->mosaicStartLine) % ppu->mosaicSize;
+ if(IS_MOSAIC_ENABLED(ppu, 0)) {
+ y -= (y - 1) % ppu->mosaicSize;
}
uint8_t ry = ppu->m7yFlip ? 255 - y : y;
ppu->m7startX = (
@@ -1262,7 +1206,7 @@
}
static int ppu_getPixelForMode7(Ppu* ppu, int x, int layer, bool priority) {
- if (ppu->bgLayer[layer].mosaicEnabled && ppu->mosaicSize > 1)
+ if (IS_MOSAIC_ENABLED(ppu, layer))
x -= x % ppu->mosaicSize;
uint8_t rx = ppu->m7xFlip ? 255 - x : x;
int xPos = (ppu->m7startX + ppu->m7matrix[0] * rx) >> 8;
@@ -1281,28 +1225,23 @@
}
static bool ppu_getWindowState(Ppu* ppu, int layer, int x) {
- if (!ppu->windowLayer[layer].window1enabled && !ppu->windowLayer[layer].window2enabled) {
+ uint32 winflags = GET_WINDOW_FLAGS(ppu, layer);
+ if (!(winflags & kWindow1Enabled) && !(winflags & kWindow2Enabled)) {
return false;
}
- if (ppu->windowLayer[layer].window1enabled && !ppu->windowLayer[layer].window2enabled) {
+ if ((winflags & kWindow1Enabled) && !(winflags & kWindow2Enabled)) {
bool test = x >= ppu->window1left && x <= ppu->window1right;
- return ppu->windowLayer[layer].window1inversed ? !test : test;
+ return (winflags & kWindow1Inversed) ? !test : test;
}
- if (!ppu->windowLayer[layer].window1enabled && ppu->windowLayer[layer].window2enabled) {
+ if (!(winflags & kWindow1Enabled) && (winflags & kWindow2Enabled)) {
bool test = x >= ppu->window2left && x <= ppu->window2right;
- return ppu->windowLayer[layer].window2inversed ? !test : test;
+ return (winflags & kWindow2Inversed) ? !test : test;
}
bool test1 = x >= ppu->window1left && x <= ppu->window1right;
bool test2 = x >= ppu->window2left && x <= ppu->window2right;
- if (ppu->windowLayer[layer].window1inversed) test1 = !test1;
- if (ppu->windowLayer[layer].window2inversed) test2 = !test2;
- switch (ppu->windowLayer[layer].maskLogic_always_zero) {
- case 0: return test1 || test2;
- case 1: return test1 && test2;
- case 2: return test1 != test2;
- case 3: return test1 == test2;
- }
- return false;
+ if (winflags & kWindow1Inversed) test1 = !test1;
+ if (winflags & kWindow2Inversed) test2 = !test2;
+ return test1 || test2;
}
static bool ppu_evaluateSprites(Ppu* ppu, int line) {
@@ -1309,7 +1248,7 @@
// TODO: iterate over oam normally to determine in-range sprites,
// then iterate those in-range sprites in reverse for tile-fetching
// TODO: rectangular sprites, wierdness with sprites at -256
- int index = ppu->objPriority ? (ppu->oamAdr & 0xfe) : 0, index_end = index;
+ int index = 0, index_end = index;
int spritesLeft = 32 + 1, tilesLeft = 34 + 1;
uint8 spriteSizes[2] = { kSpriteSizes[ppu->objSize][0], kSpriteSizes[ppu->objSize][1] };
int extra_left_right = ppu->extraLeftRight;
@@ -1323,7 +1262,7 @@
continue; // this works for zelda because sprites are always 8 or 16.
// check if the sprite is on this line and get the sprite size
int row = (line - yy) & 0xff;
- int highOam = ppu->highOam[index >> 3] >> (index & 7);
+ int highOam = ppu->oam[0x100 + (index >> 4)] >> (index & 15);
int spriteSize = spriteSizes[(highOam >> 1) & 1];
if (row >= spriteSize)
continue;
@@ -1335,7 +1274,6 @@
continue;
// break if we found 32 sprites already
if (--spritesLeft == 0) {
- ppu->rangeOver = true;
break;
}
// get some data for the sprite and y-flip row if needed
@@ -1352,7 +1290,6 @@
if (col + x > -8 - extra_left_right && col + x < 256 + extra_left_right) {
// break if we found 34 8*1 slivers already
if (--tilesLeft == 0) {
- ppu->timeOver = true;
return true;
}
// figure out which tile this uses, looping within 16x16 pages, and get it's data
@@ -1379,17 +1316,6 @@
return (tilesLeft != tilesLeftOrg);
}
-static uint16_t ppu_getVramRemap(Ppu* ppu) {
- uint16_t adr = ppu->vramPointer;
- switch(ppu->vramRemapMode) {
- case 0: return adr;
- case 1: return (adr & 0xff00) | ((adr & 0xe0) >> 5) | ((adr & 0x1f) << 3);
- case 2: return (adr & 0xfe00) | ((adr & 0x1c0) >> 6) | ((adr & 0x3f) << 3);
- case 3: return (adr & 0xfc00) | ((adr & 0x380) >> 7) | ((adr & 0x7f) << 3);
- }
- return adr;
-}
-
uint8_t ppu_read(Ppu* ppu, uint8_t adr) {
switch (adr) {
case 0x34:
@@ -1404,70 +1330,49 @@
void ppu_write(Ppu* ppu, uint8_t adr, uint8_t val) {
switch(adr) {
- case 0x00: {
- // TODO: oam address reset when written on first line of vblank, (and when forced blank is disabled?)
+ case 0x00: { // INIDISP
ppu->brightness = val & 0xf;
ppu->forcedBlank = val & 0x80;
break;
}
case 0x01: {
- ppu->objSize = val >> 5;
- ppu->objTileAdr1 = (val & 7) << 13;
- ppu->objTileAdr2 = ppu->objTileAdr1 + (((val & 0x18) + 8) << 9);
+ assert(val == 2);
break;
}
case 0x02: {
- ppu->oamAdr = val;
- ppu->oamAdrWritten = ppu->oamAdr;
- ppu->oamInHigh = ppu->oamInHighWritten;
+ ppu->oamAdr = (ppu->oamAdr & ~0xff) | val;
ppu->oamSecondWrite = false;
break;
}
case 0x03: {
- ppu->objPriority = val & 0x80;
- ppu->oamInHigh = val & 1;
- ppu->oamInHighWritten = ppu->oamInHigh;
- ppu->oamAdr = ppu->oamAdrWritten;
+ assert((val & 0x80) == 0);
+ ppu->oamAdr = (ppu->oamAdr & ~0xff00) | ((val & 1) << 8);
ppu->oamSecondWrite = false;
break;
}
case 0x04: {
- if(ppu->oamInHigh) {
- ppu->highOam[((ppu->oamAdr & 0xf) << 1) | (uint8_t)ppu->oamSecondWrite] = val;
- if(ppu->oamSecondWrite) {
- ppu->oamAdr++;
- if(ppu->oamAdr == 0) ppu->oamInHigh = false;
- }
+ if (!ppu->oamSecondWrite) {
+ ppu->oamBuffer = val;
} else {
- if(!ppu->oamSecondWrite) {
- ppu->oamBuffer = val;
- } else {
+ if (ppu->oamAdr < 0x110)
ppu->oam[ppu->oamAdr++] = (val << 8) | ppu->oamBuffer;
- if(ppu->oamAdr == 0) ppu->oamInHigh = true;
- }
}
ppu->oamSecondWrite = !ppu->oamSecondWrite;
break;
}
- case 0x05: {
+ case 0x05: { // BGMODE
ppu->mode = val & 0x7;
- ppu->bg3priority = val & 0x8;
assert(val == 7 || val == 9);
assert(ppu->mode == 1 || ppu->mode == 7);
- // bigTiles are never used
assert((val & 0xf0) == 0);
break;
}
- case 0x06: {
- // TODO: mosaic line reset specifics
- ppu->bgLayer[0].mosaicEnabled = val & 0x1;
- ppu->bgLayer[1].mosaicEnabled = val & 0x2;
- ppu->bgLayer[2].mosaicEnabled = val & 0x4;
- ppu->bgLayer[3].mosaicEnabled = val & 0x8;
+ case 0x06: { // MOSAIC
ppu->mosaicSize = (val >> 4) + 1;
+ ppu->mosaicEnabled = (ppu->mosaicSize > 1) ? val : 0;
break;
}
- case 0x07:
+ case 0x07: // BG1SC
case 0x08:
case 0x09:
case 0x0a: {
@@ -1477,17 +1382,17 @@
ppu->bgLayer[adr - 7].tilemapAdr = (val & 0xfc) << 8;
break;
}
- case 0x0b: {
+ case 0x0b: { // BG12NBA
ppu->bgLayer[0].tileAdr = (val & 0xf) << 12;
ppu->bgLayer[1].tileAdr = (val & 0xf0) << 8;
break;
}
- case 0x0c: {
+ case 0x0c: { // BG34NBA
ppu->bgLayer[2].tileAdr = (val & 0xf) << 12;
ppu->bgLayer[3].tileAdr = (val & 0xf0) << 8;
break;
}
- case 0x0d: {
+ case 0x0d: { // BG1HOFS
ppu->m7matrix[6] = ((val << 8) | ppu->m7prev) & 0x1fff;
ppu->m7prev = val;
// fallthrough to normal layer BG-HOFS
@@ -1500,7 +1405,7 @@
ppu->scrollPrev2 = val;
break;
}
- case 0x0e: {
+ case 0x0e: { // BG1VOFS
ppu->m7matrix[7] = ((val << 8) | ppu->m7prev) & 0x1fff;
ppu->m7prev = val;
// fallthrough to normal layer BG-VOFS
@@ -1520,37 +1425,32 @@
} else {
ppu->vramIncrement = 128;
}
- ppu->vramRemapMode = (val & 0xc) >> 2;
+ assert(((val & 0xc) >> 2) == 0);
ppu->vramIncrementOnHigh = val & 0x80;
break;
}
- case 0x16: {
+ case 0x16: { // VMADDL
ppu->vramPointer = (ppu->vramPointer & 0xff00) | val;
- ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
break;
}
- case 0x17: {
+ case 0x17: { // VMADDH
ppu->vramPointer = (ppu->vramPointer & 0x00ff) | (val << 8);
- ppu->vramReadBuffer = ppu->vram[ppu_getVramRemap(ppu) & 0x7fff];
break;
}
- case 0x18: {
- // TODO: vram access during rendering (also cgram and oam)
- uint16_t vramAdr = ppu_getVramRemap(ppu);
- if (val != 0xef) {
- val += 0;
- }
+ case 0x18: { // VMDATAL
+ uint16_t vramAdr = ppu->vramPointer;
ppu->vram[vramAdr & 0x7fff] = (ppu->vram[vramAdr & 0x7fff] & 0xff00) | val;
if(!ppu->vramIncrementOnHigh) ppu->vramPointer += ppu->vramIncrement;
break;
}
- case 0x19: {
- uint16_t vramAdr = ppu_getVramRemap(ppu);
+ case 0x19: { // VMDATAH
+ uint16_t vramAdr = ppu->vramPointer;
ppu->vram[vramAdr & 0x7fff] = (ppu->vram[vramAdr & 0x7fff] & 0x00ff) | (val << 8);
if(ppu->vramIncrementOnHigh) ppu->vramPointer += ppu->vramIncrement;
break;
}
- case 0x1a: {
+ case 0x1a: { // M7SEL
+ assert(val == 0x80);
ppu->m7largeField = val & 0x80;
ppu->m7charFill = val & 0x40;
ppu->m7yFlip = val & 0x2;
@@ -1557,7 +1457,7 @@
ppu->m7xFlip = val & 0x1;
break;
}
- case 0x1b:
+ case 0x1b: // M7A etc
case 0x1c:
case 0x1d:
case 0x1e: {
@@ -1585,78 +1485,46 @@
ppu->cgramSecondWrite = !ppu->cgramSecondWrite;
break;
}
- case 0x23:
- case 0x24:
- case 0x25: {
- ppu->windowLayer[(adr - 0x23) * 2].window1inversed = (val & 0x1) != 0;
- ppu->windowLayer[(adr - 0x23) * 2].window1enabled = (val & 0x2) != 0;
- ppu->windowLayer[(adr - 0x23) * 2].window2inversed = (val & 0x4) != 0;
- ppu->windowLayer[(adr - 0x23) * 2].window2enabled = (val & 0x8) != 0;
- ppu->windowLayer[(adr - 0x23) * 2 + 1].window1inversed = (val & 0x10) != 0;
- ppu->windowLayer[(adr - 0x23) * 2 + 1].window1enabled = (val & 0x20) != 0;
- ppu->windowLayer[(adr - 0x23) * 2 + 1].window2inversed = (val & 0x40) != 0;
- ppu->windowLayer[(adr - 0x23) * 2 + 1].window2enabled = (val & 0x80) != 0;
+ case 0x23: // W12SEL
+ ppu->windowsel = (ppu->windowsel & ~0xff) | val;
break;
- }
- case 0x26: {
+ case 0x24: // W34SEL
+ ppu->windowsel = (ppu->windowsel & ~0xff00) | (val << 8);
+ break;
+ case 0x25: // WOBJSEL
+ ppu->windowsel = (ppu->windowsel & ~0xff0000) | (val << 16);
+ break;
+ case 0x26:
ppu->window1left = val;
break;
- }
- case 0x27: {
+ case 0x27:
ppu->window1right = val;
break;
- }
- case 0x28: {
+ case 0x28:
ppu->window2left = val;
break;
- }
- case 0x29: {
+ case 0x29:
ppu->window2right = val;
break;
- }
- case 0x2a: {
+ case 0x2a: // WBGLOG
assert(val == 0);
- // maskLogic_always_zero
break;
- }
- case 0x2b: {
+ case 0x2b: // WOBJLOG
assert(val == 0);
- // maskLogic_always_zero
break;
- }
- case 0x2c: {
- ppu->layer[0].screenEnabled[0] = val & 0x1;
- ppu->layer[1].screenEnabled[0] = val & 0x2;
- ppu->layer[2].screenEnabled[0] = val & 0x4;
- ppu->layer[3].screenEnabled[0] = val & 0x8;
- ppu->layer[4].screenEnabled[0] = val & 0x10;
+ case 0x2c: // TM
+ ppu->screenEnabled[0] = val;
break;
- }
- case 0x2d: {
- ppu->layer[0].screenEnabled[1] = val & 0x1;
- ppu->layer[1].screenEnabled[1] = val & 0x2;
- ppu->layer[2].screenEnabled[1] = val & 0x4;
- ppu->layer[3].screenEnabled[1] = val & 0x8;
- ppu->layer[4].screenEnabled[1] = val & 0x10;
+ case 0x2d: // TS
+ ppu->screenEnabled[1] = val;
break;
- }
- case 0x2e: {
- ppu->layer[0].screenWindowed[0] = val & 0x1;
- ppu->layer[1].screenWindowed[0] = val & 0x2;
- ppu->layer[2].screenWindowed[0] = val & 0x4;
- ppu->layer[3].screenWindowed[0] = val & 0x8;
- ppu->layer[4].screenWindowed[0] = val & 0x10;
+ case 0x2e: // TMW
+ ppu->screenWindowed[0] = val;
break;
- }
- case 0x2f: {
- ppu->layer[0].screenWindowed[1] = val & 0x1;
- ppu->layer[1].screenWindowed[1] = val & 0x2;
- ppu->layer[2].screenWindowed[1] = val & 0x4;
- ppu->layer[3].screenWindowed[1] = val & 0x8;
- ppu->layer[4].screenWindowed[1] = val & 0x10;
+ case 0x2f: // TSW
+ ppu->screenWindowed[1] = val;
break;
- }
- case 0x30: {
+ case 0x30: { // CGWSEL
assert((val & 1) == 0); // directColor always zero
ppu->addSubscreen = val & 0x2;
ppu->preventMathMode = (val & 0x30) >> 4;
@@ -1663,15 +1531,13 @@
ppu->clipMode = (val & 0xc0) >> 6;
break;
}
- case 0x31: {
+ case 0x31: { // CGADSUB
ppu->subtractColor = val & 0x80;
ppu->halfColor = val & 0x40;
- for(int i = 0; i < 6; i++) {
- ppu->mathEnabled[i] = val & (1 << i);
- }
+ ppu->mathEnabled = val & 0x3f;
break;
}
- case 0x32: {
+ case 0x32: { // COLDATA
if(val & 0x80) ppu->fixedColorB = val & 0x1f;
if(val & 0x40) ppu->fixedColorG = val & 0x1f;
if(val & 0x20) ppu->fixedColorR = val & 0x1f;
@@ -1679,10 +1545,6 @@
}
case 0x33: {
assert(val == 0);
- ppu->interlace_always_zero = val & 0x1;
- ppu->objInterlace_always_zero = val & 0x2;
- ppu->overscan_always_zero = val & 0x4;
- ppu->pseudoHires_always_zero = val & 0x8;
ppu->m7extBg_always_zero = val & 0x40;
break;
}
--- a/snes/ppu.h
+++ b/snes/ppu.h
@@ -15,27 +15,14 @@
typedef struct BgLayer {
uint16_t hScroll;
uint16_t vScroll;
+ // -- snapshot starts here
bool tilemapWider;
bool tilemapHigher;
uint16_t tilemapAdr;
+ // -- snapshot ends here
uint16_t tileAdr;
- bool bigTiles_always_zero;
- bool mosaicEnabled;
} BgLayer;
-typedef struct Layer {
- bool screenEnabled[2]; // 0 = main, 1 = sub
- bool screenWindowed[2]; // 0 = main, 1 = sub
-} Layer;
-
-typedef struct WindowLayer {
- bool window1enabled;
- bool window2enabled;
- bool window1inversed;
- bool window2inversed;
- uint8_t maskLogic_always_zero;
-} WindowLayer;
-
enum {
kPpuXPixels = 256 + kPpuExtraLeftRight * 2,
};
@@ -67,49 +54,54 @@
uint8_t *renderBuffer;
uint8_t extraLeftCur, extraRightCur, extraLeftRight, extraBottomCur;
float mode7PerspectiveLow, mode7PerspectiveHigh;
- // store 31 extra entries to remove the need for clamp
- uint8_t brightnessMult[32 + 31];
- uint8_t brightnessMultHalf[32 * 2];
- PpuPixelPrioBufs bgBuffers[2];
+
+ // TMW / TSW etc
+ uint8 screenEnabled[2];
+ uint8 screenWindowed[2];
+ uint8 mosaicEnabled;
+ uint8 mosaicSize;
+ // object/sprites
+ uint16_t objTileAdr1;
+ uint16_t objTileAdr2;
+ uint8_t objSize;
+ // Window
+ uint8_t window1left;
+ uint8_t window1right;
+ uint8_t window2left;
+ uint8_t window2right;
+ uint32_t windowsel;
+
+ // color math
+ uint8_t clipMode;
+ uint8_t preventMathMode;
+ bool addSubscreen;
+ bool subtractColor;
+ bool halfColor;
+ uint8 mathEnabled;
+ uint8_t fixedColorR, fixedColorG, fixedColorB;
+ // settings
+ bool forcedBlank;
+ uint8_t brightness;
+ uint8_t mode;
+
// vram access
- uint16_t vram[0x8000];
uint16_t vramPointer;
- bool vramIncrementOnHigh;
uint16_t vramIncrement;
- uint8_t vramRemapMode;
- uint16_t vramReadBuffer;
+ bool vramIncrementOnHigh;
// cgram access
- uint16_t cgram[0x100];
uint8_t cgramPointer;
bool cgramSecondWrite;
uint8_t cgramBuffer;
// oam access
- uint16_t oam[0x100];
- uint8_t highOam[0x20];
- uint8_t oamAdr;
- uint8_t oamAdrWritten;
- bool oamInHigh;
- bool oamInHighWritten;
+ uint16_t oamAdr;
bool oamSecondWrite;
uint8_t oamBuffer;
- // object/sprites
- bool objPriority;
- uint16_t objTileAdr1;
- uint16_t objTileAdr2;
- uint8_t objSize;
- PpuPixelPrioBufs objBuffer;
- uint8 pad[3];
- bool timeOver;
- bool rangeOver;
- bool objInterlace_always_zero;
+
// background layers
BgLayer bgLayer[4];
uint8_t scrollPrev;
uint8_t scrollPrev2;
- uint8_t mosaicSize;
- uint8_t mosaicStartLine;
- // layers
- Layer layer[5];
+
// mode 7
int16_t m7matrix[8]; // a, b, c, d, x, y, h, v
uint8_t m7prev;
@@ -121,45 +113,18 @@
// mode 7 internal
int32_t m7startX;
int32_t m7startY;
- // windows
- WindowLayer windowLayer[6];
- uint8_t window1left;
- uint8_t window1right;
- uint8_t window2left;
- uint8_t window2right;
- // color math
- uint8_t clipMode;
- uint8_t preventMathMode;
- bool addSubscreen;
- bool subtractColor;
- bool halfColor;
- bool mathEnabled[6];
- uint8_t fixedColorR;
- uint8_t fixedColorG;
- uint8_t fixedColorB;
- // settings
- bool forcedBlank;
- uint8_t brightness;
- uint8_t mode;
- bool bg3priority;
- bool evenFrame;
- bool pseudoHires_always_zero;
- bool overscan_always_zero;
- bool frameOverscan_always_zero; // if we are overscanning this frame (determined at 0,225)
- bool interlace_always_zero;
- bool frameInterlace_always_zero; // if we are interlacing this frame (determined at start vblank)
- bool directColor_always_zero;
- // latching
- uint16_t hCount;
- uint16_t vCount;
- bool hCountSecond;
- bool vCountSecond;
- bool countersLatched;
- uint8_t ppu1openBus;
- uint8_t ppu2openBus;
+ uint16_t oam[0x110];
+
+ // store 31 extra entries to remove the need for clamp
+ uint8_t brightnessMult[32 + 31];
+ uint8_t brightnessMultHalf[32 * 2];
+ uint16_t cgram[0x100];
uint8_t mosaicModulo[kPpuXPixels];
uint32_t colorMapRgb[256];
+ PpuPixelPrioBufs bgBuffers[2];
+ PpuPixelPrioBufs objBuffer;
+ uint16_t vram[0x8000];
};
Ppu* ppu_init();
--- a/zelda_cpu_infra.c
+++ b/zelda_cpu_infra.c
@@ -312,7 +312,7 @@
// Copy state into the emulator, we can skip dsp/apu because
// we're not emulating that.
static void EmuSynchronizeWholeState() {
- memcpy(&g_snes->ppu->vram, g_zenv.ppu->vram, offsetof(Ppu, ppu2openBus) + 1 - offsetof(Ppu, vram));
+ *g_snes->ppu = *g_zenv.ppu;
memcpy(g_snes->ram, g_zenv.ram, 0x20000);
memcpy(g_snes->cart->ram, g_zenv.sram, 0x2000);
memcpy(g_snes->dma->channel, g_zenv.dma->channel, sizeof(Dma) - offsetof(Dma, channel));
--- a/zelda_rtl.c
+++ b/zelda_rtl.c
@@ -283,7 +283,6 @@
zelda_apu_write(APUI01, 0);
zelda_apu_write(APUI02, 0);
zelda_apu_write(APUI03, 0);
- zelda_ppu_write(INIDISP, 0x80);
Sound_LoadIntroSongBank();
Startup_InitializeMemory();
@@ -382,7 +381,6 @@
WORD(sram[0x8e5]) = 0;
if (WORD(sram[0xde5]) != 0x55aa)
WORD(sram[0xde5]) = 0;
- zelda_ppu_write(TMW, 0);
INIDISP_copy = 0x80;
flag_update_cgram_in_nmi++;
}