Sameboy progress

This commit is contained in:
nattthebear 2017-07-16 14:53:03 -04:00
parent 87f7183a27
commit 34e68c589f
20 changed files with 266 additions and 2701 deletions

View File

@ -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
{

View File

@ -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" />

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}
}