mirror of
https://github.com/mlaux/gb6.git
synced 2026-04-21 16:16:56 +00:00
optimize register usage for write, add patch system
This commit is contained in:
+17
-23
@@ -29,26 +29,26 @@ void compile_slow_dmg_write(struct code_block *block, uint8_t val_reg)
|
||||
static void compile_inline_dmg_write(struct code_block *block, uint8_t val_reg)
|
||||
{
|
||||
// Fast path: check write page table
|
||||
// move.w d1, d0 ; 2 bytes [0-1]
|
||||
emit_move_w_dn_dn(block, REG_68K_D_SCRATCH_1, REG_68K_D_SCRATCH_0);
|
||||
// lsr.w #8, d0 ; 2 bytes [2-3]
|
||||
emit_lsr_w_imm_dn(block, 8, REG_68K_D_SCRATCH_0);
|
||||
// lsl.w #2, d0 ; 2 bytes [4-5]
|
||||
emit_lsl_w_imm_dn(block, 2, REG_68K_D_SCRATCH_0);
|
||||
// movea.l (a6,d0.w), a0 ; 4 bytes [6-9]
|
||||
emit_movea_l_idx_an_an(block, 0, REG_68K_A_WRITE_PAGE, REG_68K_D_SCRATCH_0, REG_68K_A_SCRATCH_1);
|
||||
// move.w d1, d3 ; 2 bytes [0-1]
|
||||
emit_move_w_dn_dn(block, REG_68K_D_SCRATCH_1, REG_68K_D_NEXT_PC);
|
||||
// lsr.w #8, d3 ; 2 bytes [2-3]
|
||||
emit_lsr_w_imm_dn(block, 8, REG_68K_D_NEXT_PC);
|
||||
// lsl.w #2, d3 ; 2 bytes [4-5]
|
||||
emit_lsl_w_imm_dn(block, 2, REG_68K_D_NEXT_PC);
|
||||
// movea.l (a6,d3.w), a0 ; 4 bytes [6-9]
|
||||
emit_movea_l_idx_an_an(block, 0, REG_68K_A_WRITE_PAGE, REG_68K_D_NEXT_PC, REG_68K_A_SCRATCH_1);
|
||||
// cmpa.w #0, a0 ; 4 bytes [10-13]
|
||||
emit_cmpa_w_imm_an(block, 0, REG_68K_A_SCRATCH_1);
|
||||
// beq.s slow_path (+12) ; 2 bytes [14-15] -> offset 28
|
||||
emit_beq_b(block, 12);
|
||||
|
||||
// Page hit (offset 16):
|
||||
// move.w d1, d0 ; 2 bytes [16-17]
|
||||
emit_move_w_dn_dn(block, REG_68K_D_SCRATCH_1, REG_68K_D_SCRATCH_0);
|
||||
// andi.w #$ff, d0 ; 4 bytes [18-21]
|
||||
emit_andi_w_dn(block, REG_68K_D_SCRATCH_0, 0x00ff);
|
||||
// move.b val_reg, (a0,d0.w) ; 4 bytes [22-25]
|
||||
emit_move_b_dn_idx_an(block, val_reg, REG_68K_A_SCRATCH_1, REG_68K_D_SCRATCH_0);
|
||||
// move.w d1, d3 ; 2 bytes [16-17]
|
||||
emit_move_w_dn_dn(block, REG_68K_D_SCRATCH_1, REG_68K_D_NEXT_PC);
|
||||
// andi.w #$ff, d3 ; 4 bytes [18-21]
|
||||
emit_andi_w_dn(block, REG_68K_D_NEXT_PC, 0x00ff);
|
||||
// move.b val_reg, (a0,d3.w) ; 4 bytes [22-25]
|
||||
emit_move_b_dn_idx_an(block, val_reg, REG_68K_A_SCRATCH_1, REG_68K_D_NEXT_PC);
|
||||
// bra.s done (+24) ; 2 bytes [26-27] -> offset 52
|
||||
emit_bra_b(block, 24);
|
||||
|
||||
@@ -67,20 +67,14 @@ void compile_call_dmg_write_a(struct code_block *block)
|
||||
// Call dmg_write(dmg, addr, val) - addr in D1, val is immediate
|
||||
void compile_call_dmg_write_imm(struct code_block *block, uint8_t val)
|
||||
{
|
||||
emit_move_b_dn(block, 3, val);
|
||||
compile_inline_dmg_write(block, 3);
|
||||
// emit_move_b_dn(block, 0, val);
|
||||
// compile_slow_dmg_write(block, 0);
|
||||
emit_move_b_dn(block, 0, val);
|
||||
compile_inline_dmg_write(block, 0);
|
||||
}
|
||||
|
||||
// Call dmg_write(dmg, addr, val) - addr in D1, val in D0
|
||||
void compile_call_dmg_write_d0(struct code_block *block)
|
||||
{
|
||||
// uses d0 as scratch so need to move to d3, but it's so long that
|
||||
// what's one more instruction...
|
||||
emit_move_b_dn_dn(block, 0, 3);
|
||||
compile_inline_dmg_write(block, 3);
|
||||
// compile_slow_dmg_write(block, 0);
|
||||
compile_inline_dmg_write(block, 0);
|
||||
}
|
||||
|
||||
// Emit slow path call to dmg_read - expects address in D1, returns in D0
|
||||
|
||||
@@ -58,6 +58,7 @@ void dmg_init_pages(struct dmg *dmg)
|
||||
for (k = 0x40; k <= 0x7f; k++) {
|
||||
dmg->read_page[k] = &dmg->rom->data[k << 8];
|
||||
}
|
||||
dmg->current_rom_bank = 1;
|
||||
|
||||
// video RAM: 0x8000-0x9fff (pages 0x80-0x9f)
|
||||
// Uses bank 0 initially, cgb_update_vram_bank() can switch for CGB
|
||||
@@ -106,7 +107,14 @@ void dmg_init_pages(struct dmg *dmg)
|
||||
void dmg_update_rom_bank(struct dmg *dmg, int bank)
|
||||
{
|
||||
int k;
|
||||
u8 *bank_base = &dmg->rom->data[bank * 0x4000];
|
||||
u8 *bank_base;
|
||||
|
||||
if (dmg->current_rom_bank == bank) {
|
||||
return;
|
||||
}
|
||||
dmg->current_rom_bank = bank;
|
||||
|
||||
bank_base = &dmg->rom->data[bank * 0x4000];
|
||||
for (k = 0x40; k <= 0x7f; k++) {
|
||||
dmg->read_page[k] = &bank_base[(k - 0x40) << 8];
|
||||
}
|
||||
@@ -363,9 +371,9 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
||||
u8 *page = dmg->write_page[address >> 8];
|
||||
if (page) {
|
||||
page[address & 0xff] = data;
|
||||
return;
|
||||
} else {
|
||||
dmg_write_slow(dmg, address, data);
|
||||
}
|
||||
dmg_write_slow(dmg, address, data);
|
||||
}
|
||||
|
||||
u16 dmg_read16(void *_dmg, u16 address)
|
||||
|
||||
@@ -68,6 +68,9 @@ struct dmg {
|
||||
|
||||
// for TIMA timer
|
||||
u32 timer_cycles;
|
||||
|
||||
// current ROM bank (to avoid redundant page table updates)
|
||||
int current_rom_bank;
|
||||
};
|
||||
|
||||
void dmg_new(struct dmg *dmg, struct rom *rom, struct lcd *lcd);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <string.h>
|
||||
#include "patches.h"
|
||||
|
||||
// Pokemon Red/Blue: fix terrible frame rate in menus
|
||||
// make HandleMenuInput and WaitForTextScrollButtonPress halt instead of spin
|
||||
static const u8 pokemon_red_patch0[] = { 0xd5 }; /* jr $3ad9 -> jr $3ad6 */
|
||||
static const u8 pokemon_red_patch1[] = { 0xd7, 0x3d }; /* call $3e6d -> call $3dd7 */
|
||||
|
||||
static const struct rom_patch pokemon_red_patches[] = {
|
||||
{ 0x3b00, 1, NULL, pokemon_red_patch0 },
|
||||
{ 0x3889, 2, NULL, pokemon_red_patch1 },
|
||||
};
|
||||
|
||||
static const struct rom_patch_list all_patches[] = {
|
||||
{ "POKEMON RED", pokemon_red_patches, 2 },
|
||||
{ "POKEMON BLUE", pokemon_red_patches, 2 },
|
||||
};
|
||||
|
||||
#define PATCH_LIST_COUNT (sizeof(all_patches) / sizeof(all_patches[0]))
|
||||
|
||||
const struct rom_patch_list *patches_find(const char *title)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < PATCH_LIST_COUNT; k++) {
|
||||
if (strcmp(title, all_patches[k].game_title) == 0) {
|
||||
return &all_patches[k];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int patches_apply(u8 *rom_data, u32 rom_length, const struct rom_patch_list *list)
|
||||
{
|
||||
int k, applied = 0;
|
||||
const struct rom_patch *p;
|
||||
|
||||
for (k = 0; k < list->patch_count; k++) {
|
||||
p = &list->patches[k];
|
||||
|
||||
if (p->address + p->length > rom_length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->original != NULL) {
|
||||
if (memcmp(rom_data + p->address, p->original, p->length) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(rom_data + p->address, p->replacement, p->length);
|
||||
applied++;
|
||||
}
|
||||
|
||||
return applied;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef _PATCHES_H
|
||||
#define _PATCHES_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct rom_patch {
|
||||
u16 address;
|
||||
u16 length;
|
||||
const u8 *original; /* NULL = don't verify, just apply */
|
||||
const u8 *replacement;
|
||||
};
|
||||
|
||||
struct rom_patch_list {
|
||||
const char *game_title;
|
||||
const struct rom_patch *patches;
|
||||
int patch_count;
|
||||
};
|
||||
|
||||
/* Find patches for a game by title. Returns NULL if no patches found. */
|
||||
const struct rom_patch_list *patches_find(const char *title);
|
||||
|
||||
/* Apply all patches from a patch list to ROM data. Returns number of patches applied. */
|
||||
int patches_apply(u8 *rom_data, u32 rom_length, const struct rom_patch_list *list);
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,7 @@ add_application("Gray Brick"
|
||||
../src/cgb.c
|
||||
../src/audio.c
|
||||
../src/rom.c
|
||||
../src/patches.c
|
||||
../src/mbc.c
|
||||
../compiler/compiler.c
|
||||
../compiler/emitters.c
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mbc.h"
|
||||
#include "audio.h"
|
||||
#include "cgb.h"
|
||||
#include "patches.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "dialogs.h"
|
||||
@@ -526,6 +527,17 @@ int LoadRom(Str63 fileName, short vRefNum)
|
||||
FSRead(fileNo, &amtRead, rom.data);
|
||||
FSClose(fileNo);
|
||||
|
||||
{
|
||||
char title[17];
|
||||
const struct rom_patch_list *patch_list;
|
||||
|
||||
rom_get_title(&rom, title);
|
||||
patch_list = patches_find(title);
|
||||
if (patch_list) {
|
||||
patches_apply(rom.data, rom.length, patch_list);
|
||||
}
|
||||
}
|
||||
|
||||
// Read CGB flag from ROM header byte 0x143
|
||||
rom.cgb_flag = rom.data[0x143];
|
||||
|
||||
|
||||
@@ -332,6 +332,8 @@ int jit_run(struct dmg *dmg)
|
||||
}
|
||||
|
||||
// sync hardware with cycles accumulated by compiled code
|
||||
// sprintf(buf, "%lu %lu", dmg->frame_cycles, jit_regs.d2);
|
||||
// set_status_bar(buf);
|
||||
dmg_sync_hw(dmg, jit_regs.d2);
|
||||
if (dmg->interrupt_enable) {
|
||||
check_interrupts(dmg);
|
||||
|
||||
Reference in New Issue
Block a user