#include #include 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; } #if 0 gb->esil = r_esil_new (4096, 0, 1); if (!gb->esil) { return false; } #else gb->esil = gb->anal->esil; #endif gb->anal->arch->esil = gb->anal->esil; r_esil_setup (gb->esil, gb->anal, false, false, false); r_arch_esilcb (gb->anal->arch, R_ARCH_ESIL_ACTION_INIT); 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; }