Sameboy progress
This commit is contained in:
parent
87f7183a27
commit
34e68c589f
|
@ -921,7 +921,8 @@ namespace BizHawk.Client.Common
|
|||
if (!Global.Config.GB_AsSGB)
|
||||
{
|
||||
//core = CoreInventory.Instance["GB", "Pizza Boy"];
|
||||
core = CoreInventory.Instance["GB", "Gambatte"];
|
||||
//core = CoreInventory.Instance["GB", "Gambatte"];
|
||||
core = CoreInventory.Instance["GB", "SameBoy"];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -538,7 +538,9 @@
|
|||
<Compile Include="Consoles\Nintendo\Gameboy\IGameboyCommon.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\LibPizza.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\LibSameboy.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\Pizza.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\Sameboy.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\ArmV4Disassembler.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\GBA.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\IGBAGPUViewable.cs" />
|
||||
|
@ -1309,6 +1311,8 @@
|
|||
<None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" />
|
||||
<None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" />
|
||||
<None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" />
|
||||
<None Include="Resources\cgb_boot.bin.gz" />
|
||||
<None Include="Resources\dmg_boot.bin.gz" />
|
||||
<None Include="Resources\sgb-cart-present.spc.gz" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||
{
|
||||
public abstract class LibSameboy : LibWaterboxCore
|
||||
{
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init(bool cgb);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Properties;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||
{
|
||||
[Core("SameBoy", "LIJI32", true, false, "efc11783c7fb6da66e1dd084e41ba6a85c0bd17e",
|
||||
"https://sameboy.github.io/", false)]
|
||||
public class Sameboy : WaterboxCore, IGameboyCommon
|
||||
{
|
||||
/// <summary>
|
||||
/// the nominal length of one frame
|
||||
/// </summary>
|
||||
private const int TICKSPERFRAME = 35112;
|
||||
|
||||
/// <summary>
|
||||
/// number of ticks per second (GB, CGB)
|
||||
/// </summary>
|
||||
private const int TICKSPERSECOND = 2097152;
|
||||
|
||||
/// <summary>
|
||||
/// number of ticks per second (SGB)
|
||||
/// </summary>
|
||||
private const int TICKSPERSECOND_SGB = 2147727;
|
||||
|
||||
private LibSameboy _core;
|
||||
private bool _cgb;
|
||||
|
||||
[CoreConstructor("GB")]
|
||||
public Sameboy(CoreComm comm, byte[] rom)
|
||||
: base(comm, new Configuration
|
||||
{
|
||||
DefaultWidth = 160,
|
||||
DefaultHeight = 144,
|
||||
MaxWidth = 256,
|
||||
MaxHeight = 224,
|
||||
MaxSamples = 1024,
|
||||
DefaultFpsNumerator = TICKSPERSECOND,
|
||||
DefaultFpsDenominator = TICKSPERFRAME,
|
||||
SystemId = "GB"
|
||||
})
|
||||
{
|
||||
_core = PreInit<LibSameboy>(new PeRunnerOptions
|
||||
{
|
||||
Filename = "sameboy.wbx",
|
||||
SbrkHeapSizeKB = 128,
|
||||
InvisibleHeapSizeKB = 16 * 1024,
|
||||
SealedHeapSizeKB = 5 * 1024,
|
||||
PlainHeapSizeKB = 4096,
|
||||
MmapHeapSizeKB = 34 * 1024
|
||||
});
|
||||
|
||||
_cgb = (rom[0x143] & 0xc0) == 0xc0;
|
||||
Console.WriteLine("Automaticly detected CGB to " + _cgb);
|
||||
var bios = Util.DecompressGzipFile(new MemoryStream(
|
||||
_cgb ? Resources.SameboyCgbBoot : Resources.SameboyDmgBoot));
|
||||
|
||||
_exe.AddReadonlyFile(rom, "game.rom");
|
||||
_exe.AddReadonlyFile(bios, "boot.rom");
|
||||
|
||||
if (!_core.Init(_cgb))
|
||||
{
|
||||
throw new InvalidOperationException("Core rejected the rom!");
|
||||
}
|
||||
|
||||
_exe.RemoveReadonlyFile("game.rom");
|
||||
_exe.RemoveReadonlyFile("boot.rom");
|
||||
|
||||
PostInit();
|
||||
}
|
||||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
return new LibSameboy.FrameInfo
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
public bool IsCGBMode() => _cgb;
|
||||
}
|
||||
}
|
|
@ -60,6 +60,26 @@ namespace BizHawk.Emulation.Cores.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] SameboyCgbBoot {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("SameboyCgbBoot", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] SameboyDmgBoot {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("SameboyDmgBoot", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
|
|
|
@ -118,6 +118,12 @@
|
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="SameboyCgbBoot" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\cgb_boot.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="SameboyDmgBoot" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\dmg_boot.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="SgbCartPresent_SPC" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -10,7 +10,11 @@ extern "C" {
|
|||
// mark an entry point or callback pointer
|
||||
#define ECL_ENTRY
|
||||
// mark a visible symbol
|
||||
#ifdef __cplusplus
|
||||
#define ECL_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#else
|
||||
#define ECL_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
// allocate memory from the "sealed" pool. this memory can never be freed,
|
||||
// and can only be allocated or written to during the init phase. after that, the host
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false
|
||||
}
|
|
@ -11,7 +11,7 @@ CCFLAGS:=$(FLAGS) -Ilib \
|
|||
-std=gnu99 \
|
||||
-DLSB_FIRST -D_GNU_SOURCE -DGB_INTERNAL
|
||||
|
||||
CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS
|
||||
CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS -std=c++0x
|
||||
|
||||
TARGET = sameboy.wbx
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
#include <stdint.h>
|
||||
#include "../emulibc/emulibc.h"
|
||||
#include "../emulibc/waterboxcore.h"
|
||||
|
||||
#define _Static_assert static_assert
|
||||
|
||||
extern "C" {
|
||||
#include "gb.h"
|
||||
#include "joypad.h"
|
||||
#include "apu.h"
|
||||
}
|
||||
|
||||
static GB_gameboy_t GB;
|
||||
|
||||
static void VBlankCallback(GB_gameboy_t *gb)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void LogCallback(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
|
||||
{
|
||||
fputs(string, stdout);
|
||||
}
|
||||
|
||||
static uint32_t RgbEncodeCallback(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return b | g << 8 | r << 16 | 0xff000000;
|
||||
}
|
||||
|
||||
static void InfraredCallback(GB_gameboy_t *gb, bool on, long cycles_since_last_update)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void RumbleCallback(GB_gameboy_t *gb, bool rumble_on)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void SerialStartCallback(GB_gameboy_t *gb, uint8_t byte_to_send)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static uint8_t SerialEndCallback(GB_gameboy_t *gb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ECL_EXPORT bool Init(bool cgb)
|
||||
{
|
||||
if (cgb)
|
||||
GB_init_cgb(&GB);
|
||||
else
|
||||
GB_init(&GB);
|
||||
if (GB_load_boot_rom(&GB, "boot.rom") != 0)
|
||||
return false;
|
||||
|
||||
if (GB_load_rom(&GB, "game.rom") != 0)
|
||||
return false;
|
||||
|
||||
GB_set_vblank_callback(&GB, VBlankCallback);
|
||||
GB_set_log_callback(&GB, LogCallback);
|
||||
GB_set_rgb_encode_callback(&GB, RgbEncodeCallback);
|
||||
GB_set_infrared_callback(&GB, InfraredCallback);
|
||||
GB_set_rumble_callback(&GB, RumbleCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MyFrameInfo : public FrameInfo
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
ECL_EXPORT void FrameAdvance(MyFrameInfo &f)
|
||||
{
|
||||
GB_set_pixels_output(&GB, f.VideoBuffer);
|
||||
// void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed);
|
||||
GB_run_frame(&GB);
|
||||
f.Samples = 735;
|
||||
f.Width = 160;
|
||||
f.Height = 144;
|
||||
}
|
||||
|
||||
static void SetMemoryArea(MemoryArea *m, GB_direct_access_t access, const char* name, int32_t flags)
|
||||
{
|
||||
size_t size;
|
||||
m->Name = name;
|
||||
m->Data = GB_get_direct_access(&GB, access, &size, nullptr);
|
||||
m->Size = size;
|
||||
m->Flags = flags;
|
||||
}
|
||||
|
||||
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
|
||||
{
|
||||
// TODO: "System Bus"
|
||||
SetMemoryArea(m + 0, GB_DIRECT_ACCESS_RAM, "WRAM", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY);
|
||||
SetMemoryArea(m + 1, GB_DIRECT_ACCESS_ROM, "ROM", MEMORYAREA_FLAGS_WORDSIZE1);
|
||||
SetMemoryArea(m + 2, GB_DIRECT_ACCESS_VRAM, "VRAM", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
SetMemoryArea(m + 3, GB_DIRECT_ACCESS_CART_RAM, "CartRAM", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
SetMemoryArea(m + 4, GB_DIRECT_ACCESS_OAM, "OAM", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
SetMemoryArea(m + 5, GB_DIRECT_ACCESS_HRAM, "HRAM", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
SetMemoryArea(m + 6, GB_DIRECT_ACCESS_IO, "IO", MEMORYAREA_FLAGS_WORDSIZE1);
|
||||
SetMemoryArea(m + 7, GB_DIRECT_ACCESS_BOOTROM, "BOOTROM", MEMORYAREA_FLAGS_WORDSIZE1);
|
||||
SetMemoryArea(m + 8, GB_DIRECT_ACCESS_BGP, "BGP", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
SetMemoryArea(m + 8, GB_DIRECT_ACCESS_OBP, "OBP", MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE);
|
||||
}
|
||||
|
||||
ECL_EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,32 +0,0 @@
|
|||
#ifndef debugger_h
|
||||
#define debugger_h
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "gb_struct_def.h"
|
||||
#include "symbol_hash.h"
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_handle_async_commands(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr);
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr);
|
||||
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
||||
#endif
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
bool /* Returns true if debugger waits for more commands. Not relevant for non-GB_INTERNAL */
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
GB_debugger_execute_command(GB_gameboy_t *gb, char *input); /* Destroys input. */
|
||||
|
||||
|
||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
||||
const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr);
|
||||
bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank); /* result_bank is -1 if unused. */
|
||||
void GB_debugger_break(GB_gameboy_t *gb);
|
||||
bool GB_debugger_is_stopped(GB_gameboy_t *gb);
|
||||
void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled);
|
||||
#endif /* debugger_h */
|
|
@ -67,7 +67,7 @@ static char *default_input_callback(GB_gameboy_t *gb)
|
|||
|
||||
static char *default_async_input_callback(GB_gameboy_t *gb)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#if 0
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(STDIN_FILENO, &set);
|
||||
|
@ -260,12 +260,10 @@ exit:
|
|||
|
||||
void GB_run(GB_gameboy_t *gb)
|
||||
{
|
||||
GB_debugger_run(gb);
|
||||
GB_cpu_run(gb);
|
||||
if (gb->vblank_just_occured) {
|
||||
GB_update_joyp(gb);
|
||||
GB_rtc_run(gb);
|
||||
GB_debugger_handle_async_commands(gb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "apu.h"
|
||||
#include "camera.h"
|
||||
#include "debugger.h"
|
||||
#include "display.h"
|
||||
#include "joypad.h"
|
||||
#include "mbc.h"
|
||||
|
@ -179,9 +178,6 @@ typedef struct {
|
|||
long delay;
|
||||
} GB_ir_queue_item_t;
|
||||
|
||||
struct GB_breakpoint_s;
|
||||
struct GB_watchpoint_s;
|
||||
|
||||
/* When state saving, each section is dumped independently of other sections.
|
||||
This allows adding data to the end of the section without worrying about future compatibility.
|
||||
Some other changes might be "safe" as well.
|
||||
|
@ -445,10 +441,6 @@ struct GB_gameboy_internal_s {
|
|||
GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE];
|
||||
size_t ir_queue_length;
|
||||
|
||||
/*** Debugger ***/
|
||||
volatile bool debug_stopped, debug_disable;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
|
||||
/* Breakpoints */
|
||||
uint16_t n_breakpoints;
|
||||
struct GB_breakpoint_s *breakpoints;
|
||||
|
@ -467,10 +459,6 @@ struct GB_gameboy_internal_s {
|
|||
uint16_t addr;
|
||||
} backtrace_returns[0x200];
|
||||
|
||||
/* Watchpoints */
|
||||
uint16_t n_watchpoints;
|
||||
struct GB_watchpoint_s *watchpoints;
|
||||
|
||||
/* Symbol tables */
|
||||
GB_symbol_map_t *bank_symbols[0x200];
|
||||
GB_reversed_symbol_map_t reversed_symbol_map;
|
||||
|
|
|
@ -268,9 +268,6 @@ static GB_read_function_t * const read_map[] =
|
|||
|
||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (gb->n_watchpoints) {
|
||||
GB_debugger_test_read_watchpoint(gb, addr);
|
||||
}
|
||||
if (is_addr_in_dma_use(gb, addr)) {
|
||||
addr = gb->dma_current_src;
|
||||
}
|
||||
|
@ -677,9 +674,6 @@ static GB_write_function_t * const write_map[] =
|
|||
|
||||
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (gb->n_watchpoints) {
|
||||
GB_debugger_test_write_watchpoint(gb, addr, value);
|
||||
}
|
||||
if (is_addr_in_dma_use(gb, addr)) {
|
||||
/* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */
|
||||
return;
|
||||
|
|
|
@ -125,8 +125,6 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
|||
}
|
||||
}
|
||||
|
||||
gb->debugger_ticks += cycles;
|
||||
|
||||
if (gb->cgb_double_speed) {
|
||||
cycles >>=1;
|
||||
}
|
||||
|
|
|
@ -701,7 +701,6 @@ static void ret_cc(GB_gameboy_t *gb, uint8_t opcode)
|
|||
{
|
||||
/* Todo: Verify timing */
|
||||
if (condition_code(gb, opcode)) {
|
||||
GB_debugger_ret_hook(gb);
|
||||
GB_advance_cycles(gb, 8);
|
||||
gb->pc = GB_read_memory(gb, gb->registers[GB_REGISTER_SP]);
|
||||
GB_advance_cycles(gb, 4);
|
||||
|
@ -768,8 +767,6 @@ static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
|
|||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = addr;
|
||||
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
else {
|
||||
GB_advance_cycles(gb, 12);
|
||||
|
@ -938,12 +935,10 @@ static void rst(GB_gameboy_t *gb, uint8_t opcode)
|
|||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = opcode ^ 0xC7;
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
|
||||
static void ret(GB_gameboy_t *gb, uint8_t opcode)
|
||||
{
|
||||
GB_debugger_ret_hook(gb);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = GB_read_memory(gb, gb->registers[GB_REGISTER_SP]);
|
||||
GB_advance_cycles(gb, 4);
|
||||
|
@ -972,7 +967,6 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
|
|||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = addr;
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
|
||||
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode)
|
||||
|
|
|
@ -1,788 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "gb.h"
|
||||
|
||||
|
||||
typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc);
|
||||
|
||||
static void ill(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, ".BYTE $%02x\n", opcode);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void nop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "NOP\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void stop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t next = GB_read_memory(gb, (*pc)++);
|
||||
if (next) {
|
||||
GB_log(gb, "CORRUPTED STOP (%02x)\n", next);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "STOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
static char *register_names[] = {"af", "bc", "de", "hl", "sp"};
|
||||
|
||||
static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
uint16_t value;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
value = GB_read_memory(gb, (*pc)++);
|
||||
value |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, value);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD %s, %s ; =$%04x\n", register_names[register_id], symbol, value);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD %s, $%04x\n", register_names[register_id], value);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD [%s], a\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "INC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][0]);
|
||||
|
||||
}
|
||||
static void dec_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][0]);
|
||||
}
|
||||
|
||||
static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
GB_log(gb, "LD %c, $%02x\n", register_names[register_id][0], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rlca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLCA\n");
|
||||
}
|
||||
|
||||
static void rla(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLA\n");
|
||||
}
|
||||
|
||||
static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc){
|
||||
uint16_t addr;
|
||||
(*pc)++;
|
||||
addr = GB_read_memory(gb, (*pc)++);
|
||||
addr |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD [%s], sp ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD [$%04x], sp\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = (opcode >> 4) + 1;
|
||||
GB_log(gb, "ADD hl, %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD a, [%s]\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void dec_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "DEC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
static void dec_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
|
||||
static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
GB_log(gb, "LD %c, $%02x\n", register_names[register_id][1], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rrca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "RRCA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void rra(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "RRA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void jr_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR $%04x\n", addr);
|
||||
}
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static const char *condition_code(uint8_t opcode)
|
||||
{
|
||||
switch ((opcode >> 3) & 0x3) {
|
||||
case 0:
|
||||
return "nz";
|
||||
case 1:
|
||||
return "z";
|
||||
case 2:
|
||||
return "nc";
|
||||
case 3:
|
||||
return "c";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1;
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void daa(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "DAA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void cpl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "CPL\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void scf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "SCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ccf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "CCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD [hli], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD [hld], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD a, [hli]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "LD a, [hld]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "INC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
GB_log(gb, "DEC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD [hl], $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static const char *get_src_name(uint8_t opcode)
|
||||
{
|
||||
uint8_t src_register_id;
|
||||
uint8_t src_low;
|
||||
src_register_id = ((opcode >> 1) + 1) & 3;
|
||||
src_low = (opcode & 1);
|
||||
if (src_register_id == GB_REGISTER_AF) {
|
||||
return src_low? "a": "[hl]";
|
||||
}
|
||||
if (src_low) {
|
||||
return register_names[src_register_id] + 1;
|
||||
}
|
||||
static const char *high_register_names[] = {"a", "b", "d", "h"};
|
||||
return high_register_names[src_register_id];
|
||||
}
|
||||
|
||||
static const char *get_dst_name(uint8_t opcode)
|
||||
{
|
||||
uint8_t dst_register_id;
|
||||
uint8_t dst_low;
|
||||
dst_register_id = ((opcode >> 4) + 1) & 3;
|
||||
dst_low = opcode & 8;
|
||||
if (dst_register_id == GB_REGISTER_AF) {
|
||||
return dst_low? "a": "[hl]";
|
||||
}
|
||||
if (dst_low) {
|
||||
return register_names[dst_register_id] + 1;
|
||||
}
|
||||
static const char *high_register_names[] = {"a", "b", "d", "h"};
|
||||
return high_register_names[dst_register_id];
|
||||
}
|
||||
|
||||
static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD %s, %s\n", get_dst_name(opcode), get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void add_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADD %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SUB %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SBC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void and_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "AND %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "XOR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void or_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "OR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "CP %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void halt(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "HALT\n");
|
||||
}
|
||||
|
||||
static void ret_cc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "RET %s\n", condition_code(opcode));
|
||||
}
|
||||
|
||||
static void pop_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "POP %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void jp_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "JP %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "JP $%04x\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "CALL %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "CALL %s, $%04x\n", condition_code(opcode), addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void push_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "PUSH %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADD $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "ADC $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SUB $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SBC $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "AND $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "XOR $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "OR $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "CP $%02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rst(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RST $%02x\n", opcode ^ 0xC7);
|
||||
|
||||
}
|
||||
|
||||
static void ret(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RET\n");
|
||||
}
|
||||
|
||||
static void reti(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RETI\n");
|
||||
}
|
||||
|
||||
static void call_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "CALL %s ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "CALL $%04x\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t addr = GB_read_memory(gb, (*pc)++);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LDH [%s & $FF], a ; =$%02x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LDH [$%02x], a\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint8_t addr = GB_read_memory(gb, (*pc)++);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LDH a, [%s & $FF] ; =$%02x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LDH a, [$%02x]\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LDH [c], a\n");
|
||||
}
|
||||
|
||||
static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LDH a, [c]\n");
|
||||
}
|
||||
|
||||
static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "ADD SP, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void jp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "JP hl\n");
|
||||
}
|
||||
|
||||
static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD [%s], a ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD [$%04x], a\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8);
|
||||
const char *symbol = GB_debugger_name_for_address(gb, addr);
|
||||
if (symbol) {
|
||||
GB_log(gb, "LD a, [%s] ; =$%04x\n", symbol, addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "LD a, [$%04x]\n", addr);
|
||||
}
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void di(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "DI\n");
|
||||
}
|
||||
|
||||
static void ei(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "EI\n");
|
||||
}
|
||||
|
||||
static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "LD hl, sp, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "LD sp, hl\n");
|
||||
}
|
||||
|
||||
static void rlc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rrc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RRC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rr_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sla_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SLA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sra_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SRA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void srl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "SRL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void swap_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
GB_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void bit_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
uint8_t bit;
|
||||
(*pc)++;
|
||||
bit = ((opcode >> 3) & 7);
|
||||
if ((opcode & 0xC0) == 0x40) { /* Bit */
|
||||
GB_log(gb, "BIT %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0x80) { /* res */
|
||||
GB_log(gb, "RES %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0xC0) { /* set */
|
||||
GB_log(gb, "SET %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
opcode = GB_read_memory(gb, ++*pc);
|
||||
switch (opcode >> 3) {
|
||||
case 0:
|
||||
rlc_r(gb, opcode, pc);
|
||||
break;
|
||||
case 1:
|
||||
rrc_r(gb, opcode, pc);
|
||||
break;
|
||||
case 2:
|
||||
rl_r(gb, opcode, pc);
|
||||
break;
|
||||
case 3:
|
||||
rr_r(gb, opcode, pc);
|
||||
break;
|
||||
case 4:
|
||||
sla_r(gb, opcode, pc);
|
||||
break;
|
||||
case 5:
|
||||
sra_r(gb, opcode, pc);
|
||||
break;
|
||||
case 6:
|
||||
swap_r(gb, opcode, pc);
|
||||
break;
|
||||
case 7:
|
||||
srl_r(gb, opcode, pc);
|
||||
break;
|
||||
default:
|
||||
bit_r(gb, opcode, pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GB_opcode_t *opcodes[256] = {
|
||||
/* X0 X1 X2 X3 X4 X5 X6 X7 */
|
||||
/* X8 X9 Xa Xb Xc Xd Xe Xf */
|
||||
nop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rlca, /* 0X */
|
||||
ld_da16_sp, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rrca,
|
||||
stop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rla, /* 1X */
|
||||
jr_r8, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rra,
|
||||
jr_cc_r8, ld_rr_d16, ld_dhli_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, daa, /* 2X */
|
||||
jr_cc_r8, add_hl_rr, ld_a_dhli, dec_rr, inc_lr, dec_lr, ld_lr_d8, cpl,
|
||||
jr_cc_r8, ld_rr_d16, ld_dhld_a, inc_rr, inc_dhl, dec_dhl, ld_dhl_d8, scf, /* 3X */
|
||||
jr_cc_r8, add_hl_rr, ld_a_dhld, dec_rr, inc_hr, dec_hr, ld_hr_d8, ccf,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 4X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 5X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 6X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, halt, ld_r_r, /* 7X */
|
||||
ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r,
|
||||
add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, /* 8X */
|
||||
adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r,
|
||||
sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, /* 9X */
|
||||
sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r,
|
||||
and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, /* aX */
|
||||
xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r,
|
||||
or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, /* bX */
|
||||
cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r,
|
||||
ret_cc, pop_rr, jp_cc_a16, jp_a16, call_cc_a16,push_rr, add_a_d8, rst, /* cX */
|
||||
ret_cc, ret, jp_cc_a16, cb_prefix, call_cc_a16,call_a16, adc_a_d8, rst,
|
||||
ret_cc, pop_rr, jp_cc_a16, ill, call_cc_a16,push_rr, sub_a_d8, rst, /* dX */
|
||||
ret_cc, reti, jp_cc_a16, ill, call_cc_a16,ill, sbc_a_d8, rst,
|
||||
ld_da8_a, pop_rr, ld_dc_a, ill, ill, push_rr, and_a_d8, rst, /* eX */
|
||||
add_sp_r8, jp_hl, ld_da16_a, ill, ill, ill, xor_a_d8, rst,
|
||||
ld_a_da8, pop_rr, ld_a_dc, di, ill, push_rr, or_a_d8, rst, /* fX */
|
||||
ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst,
|
||||
};
|
||||
|
||||
|
||||
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count)
|
||||
{
|
||||
const GB_bank_symbol_t *function_symbol = GB_debugger_find_symbol(gb, pc);
|
||||
|
||||
if (function_symbol && pc - function_symbol->addr > 0x1000) {
|
||||
function_symbol = NULL;
|
||||
}
|
||||
|
||||
if (function_symbol && pc != function_symbol->addr) {
|
||||
GB_log(gb, "%s:\n", function_symbol->name);
|
||||
}
|
||||
|
||||
uint16_t current_function = function_symbol? function_symbol->addr : 0;
|
||||
|
||||
while (count--) {
|
||||
function_symbol = GB_debugger_find_symbol(gb, pc);
|
||||
if (function_symbol && function_symbol->addr == pc) {
|
||||
if (current_function != function_symbol->addr) {
|
||||
GB_log(gb, "\n");
|
||||
}
|
||||
GB_log(gb, "%s:\n", function_symbol->name);
|
||||
}
|
||||
if (function_symbol) {
|
||||
GB_log(gb, "%s%04x <+%03x>: ", pc == gb->pc? " ->": " ", pc, pc - function_symbol->addr);
|
||||
}
|
||||
else {
|
||||
GB_log(gb, "%s%04x: ", pc == gb->pc? " ->": " ", pc);
|
||||
}
|
||||
uint8_t opcode = GB_read_memory(gb, pc);
|
||||
opcodes[opcode](gb, opcode, &pc);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue