From 178e2145738822b8f7b75f2777c6ee6cbe75bc24 Mon Sep 17 00:00:00 2001 From: Daid Date: Tue, 28 Jul 2020 07:18:48 +0200 Subject: [PATCH] Daid's changes for rgbds-live See https://github.com/daid/binjgb * Added functionality for rgbds-live * Fix get_F * Implement extra functions for rgbds-live * Add direct hram/wram access functions. * Add function to read memory from emulator * Show the current palettes in the vram output. * Send serial data to web frontend. * Add write mem function. * Add write mem function. * Fix json --- CMakeLists.txt | 5 + src/emscripten/exported.json | 18 +++- src/emulator.c | 182 +++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 825c25f..1655cee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) option(WERROR "Build with warnings as errors" OFF) option(WASM "Build for WebAssembly" OFF) +option(RGBDS_LIVE "Build for rgbds-live (Wasm only)" OFF) if (MSVC) add_definitions(-W3 -D_CRT_SECURE_NO_WARNINGS) @@ -146,6 +147,10 @@ else (EMSCRIPTEN) set(EXPORTED_JSON ${PROJECT_SOURCE_DIR}/src/emscripten/exported.json) target_include_directories(binjgb PUBLIC ${PROJECT_SOURCE_DIR}/src) + if (RGBDS_LIVE) + target_compile_definitions(binjgb PUBLIC RGBDS_LIVE) + endif () + set(LINK_FLAGS --memory-init-file 0 -s EXPORTED_FUNCTIONS=\"@${EXPORTED_JSON}\" diff --git a/src/emscripten/exported.json b/src/emscripten/exported.json index 7ca8d61..7f2cf7e 100644 --- a/src/emscripten/exported.json +++ b/src/emscripten/exported.json @@ -42,5 +42,21 @@ "_set_joyp_select", "_set_joyp_start", "_set_joyp_up", -"_set_log_apu_writes" +"_set_log_apu_writes", +"_emulator_get_PC", +"_emulator_get_SP", +"_emulator_get_A", +"_emulator_get_BC", +"_emulator_get_DE", +"_emulator_get_HL", +"_emulator_get_F", +"_emulator_set_PC", +"_emulator_set_breakpoint", +"_emulator_clear_breakpoints", +"_emulator_render_vram", +"_emulator_render_background", +"_emulator_get_wram_ptr", +"_emulator_get_hram_ptr", +"_emulator_read_mem", +"_emulator_write_mem" ] diff --git a/src/emulator.c b/src/emulator.c index d60819e..215b13d 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -8,6 +8,9 @@ #include #include #include +#if RGBDS_LIVE +#include +#endif #include "emulator.h" @@ -709,6 +712,9 @@ struct Emulator { PaletteRGBA sgb_pal[4]; CgbColorCurve cgb_color_curve; ApuLog apu_log; +#ifdef RGBDS_LIVE + Bool breakpoint[0x10000]; +#endif }; @@ -1122,6 +1128,9 @@ static Result get_cart_info(FileData* file_data, size_t offset, for (i = LOGO_START_ADDR; i <= LOGO_END_ADDR; ++i) { logo_checksum = (logo_checksum << 1) ^ data[i]; } +#if RGBDS_LIVE + if (offset == 0) { require_logo_checksum = FALSE; } +#endif CHECK(!require_logo_checksum || logo_checksum == 0xe06c8834); cart_info->offset = offset; cart_info->data = data; @@ -2583,6 +2592,9 @@ static void write_io(Emulator* e, MaskedAddress addr, u8 value) { case IO_SB_ADDR: serial_synchronize(e); SERIAL.sb = value; +#if RGBDS_LIVE + EM_ASM({emulator.serialCallback($0);}, value); +#endif break; case IO_SC_ADDR: serial_synchronize(e); @@ -4621,6 +4633,11 @@ static void emulator_step_internal(Emulator* e) { return; } execute_instruction(e); +#ifdef RGBDS_LIVE + if (e->breakpoint[REG.PC]) { + e->state.event |= EMULATOR_EVENT_BREAKPOINT; + } +#endif } else { tick(e); hdma_copy_byte(e); @@ -5064,3 +5081,168 @@ ApuLog* emulator_get_apu_log(Emulator* e) { void emulator_reset_apu_log(Emulator* e) { e->apu_log.write_count = 0; } + +u16 emulator_get_PC(Emulator* e) { + return REG.PC; +} + +u8 emulator_get_A(Emulator* e) { + return REG.A; +} + +u16 emulator_get_BC(Emulator* e) { + return REG.BC; +} + +u16 emulator_get_DE(Emulator* e) { + return REG.DE; +} + +u16 emulator_get_HL(Emulator* e) { + return REG.HL; +} + +u8 emulator_get_F(Emulator* e) { + return PACK(REG.F.Z, CPU_FLAG_Z) | PACK(REG.F.N, CPU_FLAG_N) | + PACK(REG.F.H, CPU_FLAG_H) | PACK(REG.F.C, CPU_FLAG_C); +} + +u16 emulator_get_SP(Emulator* e) { + return REG.SP; +} + +void emulator_set_PC(Emulator* e, u16 pc) { + REG.PC = pc; +} + +u8* emulator_get_wram_ptr(Emulator* e) { + return WRAM.data; +} + +u8* emulator_get_hram_ptr(Emulator* e) { + return HRAM; +} + +u8 emulator_read_mem(Emulator* e, u16 addr) { + return read_u8_raw(e, addr); +} + +void emulator_write_mem(Emulator* e, u16 addr, u8 data) { + write_u8_raw(e, addr, data); +} + +#ifdef RGBDS_LIVE +void emulator_set_breakpoint(Emulator* e, Address addr) { + e->breakpoint[addr] = TRUE; +} + +void emulator_clear_breakpoints(Emulator* e) { + ZERO_MEMORY(e->breakpoint); +} + +void emulator_render_vram(Emulator* e, u32* buffer) { + memset(buffer, 0, sizeof(u32) * 256 * 256); + for (int ty = 0; ty < 24; ty++) { + for (int bank = 0; bank < 2; bank++) { + for (int tx = 0; tx < 16; tx++) { + for (int row = 0; row < 8; row++) { + int n = tx * 16 + ty * 16 * 16 + row * 2 + (bank << 13); + u8 a = VRAM.data[n]; + u8 b = VRAM.data[n + 1]; + for (int x = 0; x < 8; x++) { + u32 color = 0xFFC2F0C4; + u8 bit = (0x80 >> x); + if ((a & bit) && (b & bit)) { + color = 0xFF001B2D; + } else if (a & bit) { + color = 0xFFA8B95A; + } else if (b & bit) { + color = 0xFF6E601E; + } else if (x == 7 || row == 7) { + color = 0xFFB2E0B4; + } + buffer[(tx * 8 + x + bank * 128) + (ty * 8 + row) * 256] = color; + } + } + } + } + } + if (IS_CGB) { + for (int idx = 0; idx < 8; idx++) { + for (int col = 0; col < PALETTE_COLOR_COUNT; col++) { + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + buffer[x + idx * 8 + (200 + col * 8 + y) * 256] = + PPU.bgcp.palettes[idx].color[col]; + buffer[x + idx * 8 + (200 + col * 8 + y) * 256 + 128] = + PPU.obcp.palettes[idx].color[col]; + } + } + } + } + } else { + for (int type = 0; type < PALETTE_TYPE_COUNT; type++) { + for (int col = 0; col < PALETTE_COLOR_COUNT; col++) { + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + buffer[x + type * 8 + (200 + col * 8 + y) * 256] = + e->pal[type].color[col]; + } + } + } + } + } +} + +void emulator_render_background(Emulator* e, u32* buffer, int type) { + memset(buffer, 0, sizeof(u32) * 256 * 256); + int bank = 0; + int tile_map = (type & 1) ? 0x400 : 0; + for (int ty = 0; ty < 32; ty++) { + for (int tx = 0; tx < 32; tx++) { + for (int row = 0; row < 8; row++) { + int tile = VRAM.data[0x1800 + tile_map + tx + ty * 32]; + // TODO: LCDC bit 4 + int n = tile * 16 + row * 2; + u8 a = VRAM.data[n]; + u8 b = VRAM.data[n + 1]; + for (int x = 0; x < 8; x++) { + u32 color = 0xFFC2F0C4; + u8 bit = (0x80 >> x); + if ((a & bit) && (b & bit)) { + color = 0xFF001B2D; + } else if (a & bit) { + color = 0xFFA8B95A; + } else if (b & bit) { + color = 0xFF6E601E; + } else if (x == 7 || row == 7) { + color = 0xFFB2E0B4; + } + buffer[(tx * 8 + x) + (ty * 8 + row) * 256] = color; + } + } + } + } + for (int x = 0; x < SCREEN_WIDTH; x++) { + buffer[((PPU.scx + x) % 256) + (PPU.scy * 256)] &= 0xFF7F7F7F; + buffer[((PPU.scx + x) % 256) + + ((PPU.scy + SCREEN_HEIGHT - 1) % 256) * 256] &= 0xFF7F7F7F; + } + for (int y = 0; y < SCREEN_HEIGHT; y++) { + buffer[PPU.scx + ((PPU.scy + y) % 256) * 256] &= 0xFF7F7F7F; + buffer[((PPU.scx + SCREEN_WIDTH) % 256) + ((PPU.scy + y) % 256) * 256] &= + 0xFF7F7F7F; + } +} + +#else // !RGBDS_LIVE + +void emulator_set_breakpoint(Emulator* e, Address addr) {} + +void emulator_clear_breakpoints(Emulator* e) {} + +void emulator_render_vram(Emulator* e, u32* buffer) {} + +void emulator_render_background(Emulator* e, u32* buffer, int type) {} + +#endif