ks_nes_draw: slight score improvements, document draw struct members (best guess)

This commit is contained in:
Cuyler36
2025-10-28 04:55:42 -04:00
parent 25f38fbfb6
commit b4166122df
4 changed files with 472 additions and 363 deletions
+126 -44
View File
@@ -13,6 +13,15 @@ extern "C" {
#define KS_NES_WIDTH 256
#define KS_NES_HEIGHT 228
#define KS_NES_SCANLINE_COUNT 240 // 228 visible + 8 pre-render + 8 post-render
#define KS_NES_SCANLINE_SPRITE_OVERDRAW_COUNT (KS_NES_SCANLINE_COUNT + 32) // 272
#define KS_NES_CENTER_X (KS_NES_WIDTH / 2)
#define KS_NES_CENTER_Y (KS_NES_SCANLINE_SPRITE_OVERDRAW_COUNT / 2)
#define KS_NES_OAM_TABLE_SIZE 64
#define CHR_TO_I8_BUF_SIZE 0x100000
#define KS_NES_NESFILE_HEADER_SIZE 0x10
#define KS_NES_PRGROM_SIZE 0x80000 // 512kb for MMC3
@@ -31,9 +40,44 @@ extern "C" {
#define KS_NES_BYTES_PER_KB (1024)
#define KS_NES_TO_KB(b) ((f32)b * (1.0f / (f32)KS_NES_BYTES_PER_KB))
#define KS_NES_PPU_STATUS_FLG_SPRITE_OVERFLOW (1 << 5)
#define KS_NES_PPU_STATUS_FLG_SPRITE_ZERO_HIT (1 << 6)
#define KS_NES_PPU_STATUS_FLG_VBLANK (1 << 7)
// NES PPU Control Register ($2000) flags
#define KS_NES_PPU_CTRL_NAMETABLE_MASK 0x03 // Nametable select (0-3)
#define KS_NES_PPU_CTRL_NAMETABLE_0 0x00 // Nametable at $2000
#define KS_NES_PPU_CTRL_NAMETABLE_1 0x01 // Nametable at $2400
#define KS_NES_PPU_CTRL_NAMETABLE_2 0x02 // Nametable at $2800
#define KS_NES_PPU_CTRL_NAMETABLE_3 0x03 // Nametable at $2C00
#define KS_NES_PPU_CTRL_VRAM_INCREMENT 0x04 // VRAM address increment (0=add 1 across, 1=add 32 down)
#define KS_NES_PPU_CTRL_SPRITE_PATTERN 0x08 // Sprite pattern table for 8x8 sprites (0=$0000, 1=$1000)
#define KS_NES_PPU_CTRL_BG_PATTERN 0x10 // Background pattern table (0=$0000, 1=$1000)
#define KS_NES_PPU_CTRL_SPRITE_SIZE 0x20 // Sprite size (0=8x8, 1=8x16)
#define KS_NES_PPU_CTRL_MASTER_SLAVE 0x40 // PPU master/slave select
#define KS_NES_PPU_CTRL_NMI_ENABLE 0x80 // Generate NMI at start of vertical blanking
// Sprite sizes
#define KS_NES_PPU_CTRL_SPRITE_SIZE_8x8 0x00 // 8x8 sprite size
#define KS_NES_PPU_CTRL_SPRITE_SIZE_8x16 0x20 // 8x16 sprite size
// NES PPU Mask Register ($2001) flags
#define KS_NES_PPU_MASK_GREYSCALE 0x01 // Greyscale mode
#define KS_NES_PPU_MASK_SHOW_BG_LEFT 0x02 // Show background in leftmost 8 pixels
#define KS_NES_PPU_MASK_SHOW_SPRITES_LEFT 0x04 // Show sprites in leftmost 8 pixels
#define KS_NES_PPU_MASK_SHOW_BG 0x08 // Enable background rendering
#define KS_NES_PPU_MASK_SHOW_SPRITES 0x10 // Enable sprite rendering
#define KS_NES_PPU_MASK_EMPHASIZE_RED 0x20 // Emphasize red channel
#define KS_NES_PPU_MASK_EMPHASIZE_GREEN 0x40 // Emphasize green channel
#define KS_NES_PPU_MASK_EMPHASIZE_BLUE 0x80 // Emphasize blue channel
// NES PPU Status Register ($2002) flags
#define KS_NES_PPU_STATUS_FLG_SPRITE_OVERFLOW (1 << 5) // 0x20
#define KS_NES_PPU_STATUS_FLG_SPRITE_ZERO_HIT (1 << 6) // 0x40
#define KS_NES_PPU_STATUS_FLG_VBLANK (1 << 7) // 0x80
// Combined masks used in the codebase
// All color modification bits (greyscale + RGB emphasis)
#define KS_NES_PPU_MASK_COLOR_EFFECTS (KS_NES_PPU_MASK_GREYSCALE | KS_NES_PPU_MASK_EMPHASIZE_RED | KS_NES_PPU_MASK_EMPHASIZE_GREEN | KS_NES_PPU_MASK_EMPHASIZE_BLUE) // 0xE1
// Sprites enabled + leftmost sprites
#define KS_NES_PPU_MASK_SPRITES_COMBINED (KS_NES_PPU_MASK_SHOW_SPRITES_LEFT | KS_NES_PPU_MASK_SHOW_SPRITES) // 0x14
// Timer IRQ control register @ 0x4022
#define KS_NES_FDS_TIMER_CTRL_FLG_IRQ_REPEAT (1 << 0) // 0 = don't repeat, 1 = repeat
@@ -53,50 +97,88 @@ extern "C" {
#define KS_NES_FDS_CTRL_FLG_CRC_ENABLE (1 << 6) // 0 = disable/reset, 1 = enable
#define KS_NES_FDS_CTRL_FLG_INTERRUPT_ENABLE (1 << 7) // 1 = generate IRQ every time byte transfer flag is raised
typedef struct _0B40_struct {
u8* _00;
u8* _04;
// u8* _08;
u8 _08[4]; // idk how many elements this should be
u32 _0C;
u32 _10;
u32 _14;
u8 _18;
u8 _19;
u8 _1A;
u8 _1B;
u8 _1C;
u8 _1D;
u8 _1E;
u8 _1F;
} B40_struct; // size == 0x20
// OAM Tile/Index Flags
#define KS_NES_OAM_TILE_BANK 0x01
#define KS_NES_OAM_TILE_IDX 0xFE
typedef struct _0340_struct {
u8 _00[0x20];
} _0340_struct; // size = 0x20
// OAM Attribute Flags
#define KS_NES_OAM_ATTR_PALETTE_MASK 0x03
#define KS_NES_OAM_ATTR_PRIORITY (1 << 5) // 0x20, 0 = in front of background, 1 = behind background
#define KS_NES_OAM_ATTR_FLIP_HORIZONTAL (1 << 6) // 0x40, 0 = normal, 1 = flip horizontally
#define KS_NES_OAM_ATTR_FLIP_VERTICAL (1 << 7) // 0x80, 0 = normal, 1 = flip vertically
typedef struct ksNesWorkPriv2940_struct {
u8 _00;
u8 _01;
u8 _02;
u8 _03;
} ksNesWorkPriv2940_struct;
// Misc
#define KS_NES_SPRITES_PER_SCANLINE 8
typedef struct ksNesCommonWorkPriv {
/* 0x0000 */ u8 _0000[0x200];
/* 0x0200 */ u8 _0200[0xF0];
/* 0x02F0 */ u8 _pad_02F0[0x10];
/* 0x0300 */ u8 _0300[0x40];
/* 0x0340 */ _0340_struct _0340[0x40];
/* 0x0B40 */ B40_struct _0B40[240];
/* 0x2940 */ ksNesWorkPriv2940_struct _2940[64];
/* 0x2A40 */ u8 _2A40[0x800];
/* 0x3240 */ u8 _3240[0x4800];
/* 0x7840 */ u8 _7840[0x1400];
/* 0x8E40 */ u8 _8E40[0x80]; // 4x16 texture IA8
/* 0x8EC0 */ u8 _8EC0[0x28]; // 8x4 texture IA8
// Mapper definitions
#define KS_NES_MAPPER_NROM 0
#define KS_NES_MAPPER_MMC1 1
#define KS_NES_MAPPER_UxROM 2
#define KS_NES_MAPPER_CNROM 3
#define KS_NES_MAPPER_MMC3 4
#define KS_NES_MAPPER_MMC5 5
#define KS_NES_MAPPER_MMC2 9
#define KS_NES_MAPPER_MMC4 10
#define KS_NES_MAPPER_KONAMI_VRC6A 24
#define KS_NES_MAPPER_KONAMI_VRC6B 26
// Emulator flags
#define KS_NES_FLAG_NINES_OVER_MODE (1 << 13) // 0x2000, enables "nines over" mode which allows drawing more than 8 sprites per scanline
typedef struct ksNesPPUScanlineState {
u8* nametable_ptrs[2];
// Either chr_bank_sprite or chr_bank_bg_mmc3 is used depending on mapper type and CPU cycle
union {
u8 chr_bank_sprite[4]; // lower four bytes are unused when not in MMC3 mode
u32 chr_bank_bg_mmc3[2]; // used in ksNesDrawMakeBGIndTex when the scanline column is >= 9.
};
u32 chr_bank_bg[2];
u8 ppu_ctrl;
u8 ppumask_flags;
u8 fine_x_and_next;
u8 vram_addr_coarse_x;
u8 vram_addr_y;
// MMC5-only state
u8 mmc5_ext_mode;
u8 chr_bank_ext_upper_sprite;
u8 chr_bank_ext_upper_bg;
} ksNesPPUScanlineState; // size == 0x20
typedef struct ksNesSpriteQuadData {
u8 y_and_v_pairs[32]; // Pairs of (Y position, texture V coord) for quad segments
// Each quad segment uses 4 bytes: y_top, v_top, y_bottom, v_bottom
// Supports up to 8 quad segments per sprite
} ksNesSpriteQuadData; // size = 0x20
typedef struct ksNesOAMEntry {
u8 y_pos;
u8 tile_index;
u8 attributes;
u8 x_pos;
} ksNesOAMEntry;
typedef struct ksNesDrawCtx {
/* 0x0000 */ union {
u8 sprite_scanline_limit[KS_NES_SCANLINE_COUNT]; // tracks the number of sprites that have been drawn on each scanline
u8 scanline_y_coords[2 * 256]; // tracks the Y coordinate of the top & bottom of each scanline
};
/* 0x0200 */ u8 mmc2_scanline_latch_tiles[KS_NES_SCANLINE_COUNT]; // tracks which tiles should be accessible on each scanline based on MMC2 latch settings
/* 0x02F0 */ u8 _pad_02F0[0x10]; // might be included in mmc2_scanline_latch_tiles
/* 0x0300 */ u8 sprite_vertex_count[KS_NES_OAM_TABLE_SIZE];
/* 0x0340 */ ksNesSpriteQuadData sprite_quad_data[KS_NES_OAM_TABLE_SIZE];
/* 0x0B40 */ ksNesPPUScanlineState ppu_scanline_regs[KS_NES_SCANLINE_COUNT];
/* 0x2940 */ ksNesOAMEntry OAMTable[KS_NES_OAM_TABLE_SIZE];
/* 0x2A40 */ u8 post_process_lut[0x800];
/* 0x3240 */ u8 bg_tile_index_texture[(36 * 256) * 2]; // IA8 texture, holds information about the background tile indices and pattern table data
/* 0x7840 */ u8 bg_palette_attr_texture[(40 * 256) / 2]; // I4 texture, holds background palette attributes
/* 0x8E40 */ u8 sprite_indirect_lut[(16 * 4) * 2]; // 4x16 texture IA8, handles indirect tex coords, for mirroring and sized sprites
/* 0x8EC0 */ u8 sprite_chr_bank_lut[(5 * 4) * 2]; // 8x4 IA8 sprite CHR bank lookup table -- @ BUG - this is setup as a 5x4 IA8 texture, but gets loaded as 8x4.
/* 0x8EE8 */ Mtx34 draw_mtx;
} ksNesCommonWorkPriv;
} ksNesDrawCtx;
typedef struct ksNesCommonWorkObj {
/* 0x0000 */ u8* nesromp;
@@ -117,7 +199,7 @@ typedef struct ksNesCommonWorkObj {
/* 0x003C */ u8 _003C[0x0048 - 0x003C];
/* 0x0048 */ size_t prg_size;
/* 0x004C */ u8 _004C[0x0060 - 0x004C];
/* 0x0060 */ ksNesCommonWorkPriv work_priv;
/* 0x0060 */ ksNesDrawCtx draw_ctx;
} ksNesCommonWorkObj;
typedef struct ksNesStateObj {
+3 -3
View File
@@ -2134,8 +2134,8 @@ static int famicom_rom_load() {
if (reset_res != 0) {
OSReport("err code=%d (0x%x), %x,%x,%x,%x,%x,%x\n",
reset_res, reset_res, famicomCommon.wp, famicomCommon.sp,
famicomCommon.wp->work_priv._0000, famicomCommon.wp->work_priv._0B40,
famicomCommon.wp->work_priv._2A40, famicomCommon.sp->ppu_chr_banks
famicomCommon.wp->draw_ctx.sprite_scanline_limit, famicomCommon.wp->draw_ctx.ppu_scanline_regs,
famicomCommon.wp->draw_ctx.post_process_lut, famicomCommon.sp->ppu_chr_banks
);
OSReport("NES emu reset failed!!");
}
@@ -2479,7 +2479,7 @@ extern void famicom_1frame() {
}
if (nines_over_mode) {
flags |= 0x2000;
flags |= KS_NES_FLAG_NINES_OVER_MODE;
}
+76 -70
View File
@@ -753,7 +753,7 @@ void* ksNesMapperInitFuncTbl[185][5] = {
ksNesLinecntIrqDefault,
ksNesLinecntIrqDefault,
ksNesLinecntIrqDefault,
}
},
};
typedef struct {
@@ -2318,13 +2318,13 @@ void ksNesDrawMakeOBJIndTex(ksNesCommonWorkObj* wp) {
#define TO_IND1(x) (((x) / 4) * 32) + (((x) % 4) * 8)
#define TO_IND2(x) (((x) / 4) * 32) + (((x) % 4) * 2)
for (j = 0; j < 4; j++) {
wp->work_priv._8E40[TO_IND1(i) + TO_IND2(j)] = (i >> 3) & 1;
wp->work_priv._8E40[TO_IND1(i) + TO_IND2(j) + 1] = array[i & 7] << 2;
wp->draw_ctx.sprite_indirect_lut[TO_IND1(i) + TO_IND2(j)] = (i >> 3) & 1;
wp->draw_ctx.sprite_indirect_lut[TO_IND1(i) + TO_IND2(j) + 1] = array[i & 7] << 2;
}
}
#undef TO_IND1
#undef TO_IND2
DCFlushRangeNoSync(wp->work_priv._8E40, sizeof(wp->work_priv._8E40));
DCFlushRangeNoSync(wp->draw_ctx.sprite_indirect_lut, sizeof(wp->draw_ctx.sprite_indirect_lut));
}
void ksNesDrawMakeOBJIndTexMMC5(ksNesCommonWorkObj* wp) {
@@ -2333,13 +2333,13 @@ void ksNesDrawMakeOBJIndTexMMC5(ksNesCommonWorkObj* wp) {
for (u32 i = 0; i < 16; i++) {
for (u32 j = 0; j < 4; j++) {
static const u8 array[] = { 0x00, 0x01, 0x02, 0x03 };
wp->work_priv._8E40[TO_IND1(i) + TO_IND2(j)] = 0;
wp->work_priv._8E40[TO_IND1(i) + TO_IND2(j) + 1] = array[i % 4] * 4;
wp->draw_ctx.sprite_indirect_lut[TO_IND1(i) + TO_IND2(j)] = 0;
wp->draw_ctx.sprite_indirect_lut[TO_IND1(i) + TO_IND2(j) + 1] = array[i % 4] * 4;
}
}
#undef TO_IND1
#undef TO_IND2
DCFlushRangeNoSync(&wp->work_priv._8E40, sizeof(wp->work_priv._8E40));
DCFlushRangeNoSync(&wp->draw_ctx.sprite_indirect_lut, sizeof(wp->draw_ctx.sprite_indirect_lut));
}
void ksNesConvertChrToI8(ksNesCommonWorkObj* wp, const u8* data, u32 flags) {
@@ -2650,8 +2650,8 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
// looks like we're checking memory alignment.
// maybe done for performance reasons?
if ((uint)wp & 0x1f || (uint)sp & 0x1f || (uint)&wp->work_priv & 0x1f || (uint)&wp->work_priv._0B40 & 0x1f ||
(uint)sp->ppu_chr_banks & 0x03 || (uint)&wp->work_priv._2A40 & 0x1f) {
if ((uint)wp & 0x1f || (uint)sp & 0x1f || (uint)&wp->draw_ctx & 0x1f || (uint)&wp->draw_ctx.ppu_scanline_regs & 0x1f ||
(uint)sp->ppu_chr_banks & 0x03 || (uint)&wp->draw_ctx.post_process_lut & 0x1f) {
return 0x515;
}
@@ -2673,7 +2673,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
if (flags & 1) {
// temporarily save the work ram state.
memcpy(&wp->work_priv._0000, &sp->wram, KS_NES_WRAM_SIZE);
memcpy(&wp->draw_ctx, &sp->wram, KS_NES_WRAM_SIZE);
}
// zero out the state struct.
@@ -2681,7 +2681,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
if (flags & 1) {
// restore the previously saved work ram state.
memcpy(&sp->wram, &wp->work_priv._0000, KS_NES_WRAM_SIZE);
memcpy(&sp->wram, &wp->draw_ctx, KS_NES_WRAM_SIZE);
} else {
// fill ram with a predetermined pattern.
@@ -2696,7 +2696,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
}
// zero out the private work struct
memset(&wp->work_priv, 0, sizeof(ksNesCommonWorkPriv));
memset(&wp->draw_ctx, 0, sizeof(ksNesDrawCtx));
for (i = 0; i < 0x18; i++) {
sp->ppu_chr_bank_pointers[i] = &sp->ppu_nametable_ram[table[i & 0xf] * 0x100];
@@ -2731,7 +2731,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
// extract the chr ram/rom size from the ines header and convert it from 8k chunks to bytes.
sp->chr_size = (size_t)sp->nesromp[0x5] << 0xd;
if ((sp->chr_size > 0x40000) && ((sp->mapper != 5 || (wp->chr_to_i8_buf_size < sp->chr_size << 2)))) {
if ((sp->chr_size > 0x40000) && ((sp->mapper != KS_NES_MAPPER_MMC5 || (wp->chr_to_i8_buf_size < sp->chr_size << 2)))) {
return 0x584;
}
@@ -2744,7 +2744,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
sp->reset_flags = flags;
if (sp->mapper == 5) {
if (sp->mapper == KS_NES_MAPPER_MMC5) {
ksNesDrawMakeOBJIndTexMMC5(wp);
} else {
ksNesDrawMakeOBJIndTex(wp);
@@ -2763,8 +2763,8 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
}
for (i = 0; i < 0xf0; i++) {
wp->work_priv._0B40[i]._00 = sp->ppu_nametable_pointers[0];
wp->work_priv._0B40[i]._04 = sp->ppu_nametable_pointers[1];
wp->draw_ctx.ppu_scanline_regs[i].nametable_ptrs[0] = sp->ppu_nametable_pointers[0];
wp->draw_ctx.ppu_scanline_regs[i].nametable_ptrs[1] = sp->ppu_nametable_pointers[1];
}
for (i = 0; i < 8; i++) {
@@ -2782,7 +2782,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
sp->chrramp = chrramp;
sp->chr_size = 0x2000;
if (((flags & 8) != 0) && (sp->mapper == 5)) {
if (((flags & 8) != 0) && (sp->mapper == KS_NES_MAPPER_MMC5)) {
sp->chr_size = 0x20000;
}
@@ -2793,7 +2793,7 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
} else {
sp->chrramp = sp->prgromp + sp->prg_size;
if (sp->mapper == 5) {
if (sp->mapper == KS_NES_MAPPER_MMC5) {
for (uVar4 = 0; uVar4 < sp->chr_size; uVar4 = uVar4 + 0x10) {
ksNesConvertChrToI8MMC5(wp, sp->chrramp + uVar4, uVar4 >> 4);
}
@@ -2902,11 +2902,11 @@ int ksNesReset(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags, u8* chrramp
Sound_SetE000(&sp->cpu_e000_ffff[0xe000]);
switch (sp->mapper) {
case 5: // Nintendo's MMC5
case KS_NES_MAPPER_MMC5: // Nintendo's MMC5
Sound_SetMMC(0);
break;
case 24: // Konami's VRC6a
case 26: // Konami's VRC6b
case KS_NES_MAPPER_KONAMI_VRC6A: // Konami's VRC6a
case KS_NES_MAPPER_KONAMI_VRC6B: // Konami's VRC6b
Sound_SetMMC(1);
Sound_Write(0x5015, 7, 0);
break;
@@ -2976,6 +2976,9 @@ void ksNesEmuFrame(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 flags) {
#define REGISTER_FLAG_OVERFLOW r21
#define REGISTER_FLAG_NEGATIVE r22
#define REGISTER_CYCLE_COUNT r25
// r26 is reused for various purposes throughout the code
#define REGISTER_SCANLINE_STATE r26
#define REGISTER_TEMP_26 r26
#define WRAM r31
// clang-format off
@@ -3300,7 +3303,7 @@ asm void ksNesEmuFrameAsm(register ksNesCommonWorkObj* work_arg, register ksNesS
stw r3, 0x08(r1)
stw r4, 0x0c(r1)
mr state_temp, state_arg
addi r7, work_arg, work_arg->work_priv._0B40
addi r7, work_arg, work_arg->draw_ctx.ppu_scanline_regs
stw r7, 0xf4(r1)
lwz r7, 0x14(r3)
stw r7, 0xf0(r1)
@@ -3476,7 +3479,7 @@ ksNesMainLoop1:
somewhere:
lha r3, state_temp->ppu_scanline_counter
clrlslwi. r7, REGISTER_CYCLE_COUNT, 30, 3
clrlslwi. r7, REGISTER_CYCLE_COUNT, 30, 3 // r7 = (REGISTER_CYCLE_COUNT & 0x3) << 3
lha r9, state_temp->cpu_cycles_per_vblank_scanline
rlwimi REGISTER_CYCLE_COUNT, REGISTER_CYCLE_COUNT, 31, 30, 31
beq LAB_8003b2f0
@@ -3488,24 +3491,27 @@ somewhere:
cmpwi r3, 0xf0
bge LAB_8003b3b4
// r7 holds the cycle count % 4 multiplied by 8 to get the index to write the ppu_chr_banks into the scanline state's registers
// this is done to accomodate different mapper implementations
lwz r9, 0xf4(r1)
slwi r8, r3, 5
lwz r0, state_temp->ppu_chr_banks[0]
lwz r10, state_temp->ppu_chr_banks[4]
add r26, r8, r9
stwux r0, r7, r26
add REGISTER_SCANLINE_STATE, r8, r9 // r26 holds a pointer to the current scanline state struct
stwux r0, r7, REGISTER_SCANLINE_STATE // store ((u32*)ppu_chr_banks)[0] to wp->draw_ctx.ppu_scanline_regs[state_temp->ppu_scanline_counter]._00[cycle_count & 3][0]
andi. r0, REGISTER_CYCLE_COUNT, 0x1
stw r10, 0x4(r7)
stw r10, (ksNesPPUScanlineState.nametable_ptrs[1])(r7) // store ((u32*)ppu_chr_banks)[4] to wp->draw_ctx.ppu_scanline_regs[r3]._00[cycle_count & 3][1]
bne ksNesMainLoop1
lhz r0, state_temp->ppu_register_cache[0]
lbz r8, state_temp->_17C6
lbz r7, state_temp->mapper
rlwimi r0, r8, 0x9, 0x10, 0x11
sth r0, 0x18(r26)
cmpwi r7, 0x5
sth r0, (ksNesPPUScanlineState.ppu_ctrl)(REGISTER_SCANLINE_STATE) // update both ppu_ctrl and ppumask_flags (PPUCTRL and PPUMASK regs)
cmpwi r7, KS_NES_MAPPER_MMC5
bne LAB_8003b19c
// handle MMC5 specific logic
lbz r7, state_temp->_17C7
stb r0, state_temp->_17C7
xor r9, r7, r0
@@ -3519,7 +3525,7 @@ somewhere:
add r8, r8, r7
stb r9, state_temp->_17C6
rlwimi r0, r9, 0x9, 0x10, 0x11
sth r0, 0x18(r26)
sth r0, (ksNesPPUScanlineState.ppu_ctrl)(REGISTER_SCANLINE_STATE)
add r9, r9, r7
lswi r3, r8, 0x10
addi r8, r8, 0x10
@@ -3597,7 +3603,7 @@ LAB_8003afb0:
cmpw r7, r0
bne LAB_8003afb0
LAB_8003afc4:
stb r10, 0x1e(r26)
stb r10, (ksNesPPUScanlineState.chr_bank_ext_upper_sprite)(REGISTER_SCANLINE_STATE)
lbz r0, state_temp->ppu_register_cache[0]
andi. r0, r0, 0x20
beq LAB_8003b134
@@ -3609,7 +3615,7 @@ LAB_8003afc4:
cmpwi r7, 0x0
bne LAB_8003b01c
rlwinm r9, r9, 0x3, 0x0, 0x1c
addi r6, r26, 0xf
addi r6, REGISTER_SCANLINE_STATE, 0xf
and r9, r9, r8
addi r0, r6, 0x8
LAB_8003b000:
@@ -3622,7 +3628,7 @@ LAB_8003b000:
b LAB_8003b138
LAB_8003b01c:
rlwinm r9, r9, 0x2, 0x0, 0x1d
addi r6, r26, 0x10
addi r6, REGISTER_SCANLINE_STATE, 0x10
and r9, r9, r8
addi r0, r6, 0x4
LAB_8003b02c:
@@ -3641,20 +3647,20 @@ LAB_8003b054:
bne LAB_8003b0b0
rlwinm r9, r9, 0x1, 0x0, 0x1e
and r9, r9, r8
stb r9, 0x12(r26)
stb r9, 0x16(r26)
stb r9, 0x12(REGISTER_SCANLINE_STATE)
stb r9, 0x16(REGISTER_SCANLINE_STATE)
addi r9, r9, 0x1
stb r9, 0x13(r26)
stb r9, 0x17(r26)
stb r9, 0x13(REGISTER_SCANLINE_STATE)
stb r9, 0x17(REGISTER_SCANLINE_STATE)
rlwinm r10, r9, 0x1d, 0x1a, 0x1a
lbz r9, 0x17a9(state_temp)
lbz r9, state_temp->_17A9
rlwinm r9, r9, 0x1, 0x0, 0x1e
and r9, r9, r8
stb r9, 0x10(r26)
stb r9, 0x14(r26)
stb r9, 0x10(REGISTER_SCANLINE_STATE)
stb r9, 0x14(REGISTER_SCANLINE_STATE)
addi r9, r9, 0x1
stb r9, 0x11(r26)
stb r9, 0x15(r26)
stb r9, 0x11(REGISTER_SCANLINE_STATE)
stb r9, 0x15(REGISTER_SCANLINE_STATE)
rlwimi r10, r8, 0x1f, 0x18, 0x18
rlwinm r9, r10, 0x1f, 0x1, 0x1f
or r10, r10, r9
@@ -3663,18 +3669,18 @@ LAB_8003b054:
LAB_8003b0b0:
lbz r10, state_temp->mapper_chr_bank_ext[11]
and r9, r9, r8
stb r9, 0x13(r26)
lbz r9, 0x17aa(state_temp)
stb r9, 0x13(REGISTER_SCANLINE_STATE)
lbz r9, state_temp->_17AA
and r9, r9, r8
stb r9, 0x12(r26)
lbz r9, 0x17a9(state_temp)
stb r9, 0x12(REGISTER_SCANLINE_STATE)
lbz r9, state_temp->_17A9
and r9, r9, r8
stb r9, 0x11(r26)
lbz r9, 0x17a8(state_temp)
stb r9, 0x11(REGISTER_SCANLINE_STATE)
lbz r9, state_temp->_17A8
and r9, r9, r8
stb r9, 0x10(r26)
lwz r9, 0x10(r26)
stw r9, 0x14(r26)
stb r9, 0x10(REGISTER_SCANLINE_STATE)
lwz r9, (ksNesPPUScanlineState.chr_bank_bg[0])(REGISTER_SCANLINE_STATE)
stw r9, (ksNesPPUScanlineState.chr_bank_bg[1])(REGISTER_SCANLINE_STATE)
lbz r9, state_temp->mapper_chr_bank_ext[10]
subi r10, r10, 0x1
lbz r8, state_temp->mapper_chr_bank_ext[9]
@@ -3695,9 +3701,9 @@ LAB_8003b0b0:
or r10, r10, r0
b LAB_8003b138
LAB_8003b134:
lbz r10, 0x1e(r26)
lbz r10, (ksNesPPUScanlineState.chr_bank_ext_upper_sprite)(REGISTER_SCANLINE_STATE)
LAB_8003b138:
stb r10, 0x1f(r26)
stb r10, (ksNesPPUScanlineState.chr_bank_ext_upper_bg)(REGISTER_SCANLINE_STATE)
lhz r7, state_temp->ppu_vram_addr_v_hi
addi r0, state_temp, state_temp->ppu_nametable_pointers
xori r9, r7, 0x100
@@ -3720,9 +3726,9 @@ LAB_8003b174:
bne LAB_8003b188
ori r10, r10, 0x20
LAB_8003b188:
stb r10, 0x1d(r26)
stw r8, 0x0(r26)
stw r9, 0x4(r26)
stb r10, (ksNesPPUScanlineState.mmc5_ext_mode)(REGISTER_SCANLINE_STATE)
stw r8, (ksNesPPUScanlineState.nametable_ptrs[0])(REGISTER_SCANLINE_STATE)
stw r9, (ksNesPPUScanlineState.nametable_ptrs[1])(REGISTER_SCANLINE_STATE)
andi. r4, r7, 0x7
b LAB_8003b1dc
LAB_8003b19c:
@@ -3733,8 +3739,8 @@ LAB_8003b19c:
rlwinm r9, r9, 0x1a, 0x1c, 0x1d
lwzx r8, r8, r0
lwzx r9, r9, r0
stw r8, 0x0(r26)
stw r9, 0x4(r26)
stw r8, (ksNesPPUScanlineState.nametable_ptrs[0])(REGISTER_SCANLINE_STATE)
stw r9, (ksNesPPUScanlineState.nametable_ptrs[1])(REGISTER_SCANLINE_STATE)
rlwinm r8, r7, 0x1e, 0x1f, 0x1f
rlwinm r9, r7, 0x1, 0x0, 0x1e
xor r10, r7, r8
@@ -3743,11 +3749,11 @@ LAB_8003b19c:
rlwimi r8, r9, 0x0, 0x1d, 0x1d
or r4, r8, r10
LAB_8003b1dc:
stb r7, 0x1c(r26)
stb r7, (ksNesPPUScanlineState.vram_addr_y)(REGISTER_SCANLINE_STATE)
add r4, state_temp, r4
addi r8, r7, 0x1
andi. r0, r7, 0x300
lbz r10, 0x174c(r4)
lbz r10, (ksNesStateObj.ppu_render_latches)(r4)
andi. r8, r8, 0xff
cmpwi r8, 0xf0
lbz r9, state_temp->ppu_fine_x_scroll
@@ -3755,22 +3761,22 @@ LAB_8003b1dc:
xori r0, r0, 0x200
li r8, 0x0
LAB_8003b208:
sth r9, 0x1a(r26)
sth r9, (ksNesPPUScanlineState.fine_x_and_next)(REGISTER_SCANLINE_STATE)
or r8, r8, r0
sth r8, state_temp->ppu_vram_addr_v_hi
subic. r10, r10, 0x80
lbz r9, 0x175c(r4)
lbz r9, (ksNesStateObj.ppu_render_latches + 0x10)(r4)
beq LAB_8003b230
stb r10, 0x174c(r4)
stb r3, 0x1754(r4)
stb r3, 0x175c(r4)
stb r10, (ksNesStateObj.ppu_render_latches)(r4)
stb r3, (ksNesStateObj.ppu_render_latches + 0x08)(r4)
stb r3, (ksNesStateObj.ppu_render_latches + 0x10)(r4)
b LAB_8003b244
LAB_8003b230:
subf r8, r9, r3
stb r3, 0x175c(r4)
stb r3, (ksNesStateObj.ppu_render_latches + 0x10)(r4)
rlwinm r8, r8, 0x5, 0x0, 0x1a
subf r8, r8, r26
stb r3, 0x1a(r8)
subf r8, r8, REGISTER_SCANLINE_STATE
stb r3, (ksNesPPUScanlineState.fine_x_and_next)(r8)
LAB_8003b244:
lbz r8, 0x1020(state_temp)
lbz r10, state_temp->sprite0_hit_scanline
@@ -3978,7 +3984,7 @@ LAB_8003b4fc:
li r9, 0x0
stswi r8, r7, 0x8
lbz r8, state_temp->mapper
cmpwi r8, 0x5
cmpwi r8, KS_NES_MAPPER_MMC5
bne LAB_8003b54c
li r7, 0x40
stb r7, state_temp->mmc5_scanline_irq_status
@@ -5115,7 +5121,7 @@ entry ksNesStore2006
rlwinm r7, r8, 30, 22, 28
rlwimi r7, r8, 20, 30, 31
lbz r9, state_temp->mapper
cmpwi r9, 0x5
cmpwi r9, KS_NES_MAPPER_MMC5
bne L_8003C0D4
andi. r7, r7, 0x7ffe
L_8003C0D4:
@@ -5163,7 +5169,7 @@ L_8003C130:
lbz r7, state_temp->mapper
clrrwi r9, r9, 4
add r4, r8, r9
cmpwi r7, 0x5
cmpwi r7, KS_NES_MAPPER_MMC5
beq L_8003C180
bl ksNesConvertChrToI8
b L_8003C184
File diff suppressed because it is too large Load Diff