ragb/gb/esil.c

88 lines
2.2 KiB
C

#include <gb.h>
#include <r_esil.h>
static bool gb_custom_op_halt (REsil *esil) {
GB *gb = esil->user;
ut64 ime = 0ULL;
if (R_UNLIKELY (!r_esil_reg_read (esil, "ime", &ime, NULL))) {
return false;
}
if (!ime) {
//pandocs says to also check for pending interrupts
//but https://github.com/nitro2k01/little-things-gb/tree/main/double-halt-cancel doesn't mention this
//so, wat du?
gb->mode = GB_MODE_HALT_DOUBLE_BYTE_FETCH;
return true;
}
if (gb->interrupts.flags & (0x1 << GB_INTERRUPT_ENABLE_WAIT)) {
gb->mode = GB_MODE_HALT_ENTER;
return true;
}
gb->mode = GB_MODE_HALT;
return true;
}
static bool gb_custom_op_stop (REsil *esil) {
GB *gb = esil->user;
//check if any button is held
if (((gb->joypad.data & 0x30) ^ 0x30) && ((gb->joypad.data & 0x0f) ^ 0x0f)) {
//check for pending interrupts
ut32 i;
for (i = 0; i < GB_INTERRUPT_N; i++) {
const ut32 imask = (0x1 << i) | (0x1 << (i + GB_INTERRUPT_N));
if ((gb->interrupts.flags & imask) == imask) {
return true;
}
}
#if 0
gb->mode = GB_MODE_HALT;
return r_reg_setv (esil->anal->reg, "pc"
r_reg_getv (esil->anal->reg, "pc") + 1);
#else
ut64 pc = 0ULL;
if (R_UNLIKELY (!r_esil_reg_read (esil, "pc", &pc, NULL))) {
return false;
}
pc = (pc + 1) & 0xffff;
if (R_UNLIKELY (!r_esil_reg_write (esil, "pc", pc))) {
return false;
}
gb->mode = GB_MODE_HALT;
return true;
#endif
}
gb->mode = GB_MODE_STOP;
gb_timers_reset_div (&gb->timers);
ut32 i;
for (i = 0; i < GB_INTERRUPT_N; i++) {
const ut32 imask = (0x1 << i) | (0x1 << (i + GB_INTERRUPT_N));
if ((gb->interrupts.flags & imask) == imask) {
return true;
}
}
ut64 pc = 0ULL;
if (R_UNLIKELY (!r_esil_reg_read (esil, "pc", &pc, NULL))) {
return false;
}
pc = (pc + 1) & 0xffff;
if (R_UNLIKELY (!r_esil_reg_write (esil, "pc", pc))) {
return false;
}
return true;
}
bool gb_esil_setup (GB *gb) {
if (!gb) {
return false;
}
gb->esil = r_esil_new (4096, 0, 1);
if (!gb->esil) {
return false;
}
r_esil_setup (gb->esil, gb->anal, false, false, false);
gb->esil->user = gb;
r_esil_set_op (gb->esil, "halt", gb_custom_op_halt, 0, 0, R_ESIL_OP_TYPE_CUSTOM);
r_esil_set_op (gb->esil, "stop", gb_custom_op_stop, 0, 0, R_ESIL_OP_TYPE_CUSTOM);
return true;
}