diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca6e4e8..b655e4e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,21 +8,25 @@ on: - main pull_request: +env: + EM_VERSION: 4.0.8 + EM_CACHE_FOLDER: 'emsdk-cache' + jobs: build: name: build runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v5 with: python-version: '3.x' - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - - name: install packages (linux) run: | sudo apt-get update @@ -38,7 +42,7 @@ jobs: if: matrix.os == 'windows-latest' - name: download sdl2 (windows) - uses: albin-johansson/download-sdl2@v1 + uses: albin-johansson/download-sdl2@v2 with: version: 2.0.14 sources_destination: . @@ -65,35 +69,46 @@ jobs: python scripts/tester.py -vv --exe bin/binjgb-tester if: matrix.os != 'windows-latest' - build-wasm: - name: build-wasm + build-wasm-variants: + name: build-${{ matrix.target }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: [wasm, rgbds-live, gbstudio] + include: + - target: wasm + cmake_flags: "" + - target: rgbds-live + cmake_flags: '-DWERROR=ON -DTHIRDPARTY_HOOKS=ON -DCMAKE_C_FLAGS="-DBREAKPOINTS_MAX_BANKS_NUMBER=256"' + - target: gbstudio + cmake_flags: "-DWERROR=ON -DGBSTUDIO=ON" + steps: - - uses: actions/checkout@v1 - with: - submodules: true + - uses: actions/checkout@v4 + with: + submodules: true - - name: install packages - run: sudo apt-get install ninja-build + - name: install packages + run: sudo apt-get install ninja-build - - name: emsdk install - run: | - mkdir $HOME/emsdk - git clone --depth 1 https://github.com/emscripten-core/emsdk.git $HOME/emsdk - $HOME/emsdk/emsdk update-tags - $HOME/emsdk/emsdk install tot - $HOME/emsdk/emsdk activate tot + - name: setup cache + uses: actions/cache@v4 + with: + path: ${{ env.EM_CACHE_FOLDER }} + key: ${{ env.EM_VERSION }}-${{ runner.os }} - - name: update path - run: echo "PATH=$PATH:$HOME/emsdk" >> $GITHUB_ENV + - name: emsdk install + uses: mymindstorm/setup-emsdk@v14 + with: + version: ${{ env.EM_VERSION }} + actions-cache-folder: ${{ env.EM_CACHE_FOLDER }} - - name: mkdir - run: mkdir -p out + - name: mkdir + run: mkdir -p out - - name: cmake - run: cmake -S . -B out -G Ninja -DCMAKE_TOOLCHAIN_FILE=$HOME/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DWASM=true + - name: cmake + run: emcmake cmake -S . -B out -G Ninja -DCMAKE_BUILD_TYPE=Release -DWASM=true ${{ matrix.cmake_flags }} - - name: build - run: | - source $HOME/emsdk/emsdk_env.sh - cmake --build out + - name: build + run: emmake cmake --build out diff --git a/CMakeLists.txt b/CMakeLists.txt index 1865c52..34ce7a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,43 +143,50 @@ else (EMSCRIPTEN) add_executable(binjgb src/memory.c src/common.c - src/emulator.c src/joypad.c src/rewind.c src/emscripten/wrapper.c) 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(BINJGB_THIRDPARTY_HOOKS_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten/thirdparty-default-hooks.c" + CACHE FILEPATH "Path to the emulator hooks implementation file") if (GBSTUDIO) - # If GBSTUDIO is set, set RGBDS_LIVE too - target_compile_definitions(binjgb PUBLIC GBSTUDIO RGBDS_LIVE) + set(THIRDPARTY_HOOKS ON) + target_compile_definitions(binjgb PUBLIC GBSTUDIO) endif () - set(LINK_FLAGS - -s EXPORTED_FUNCTIONS=\"@${EXPORTED_JSON}\" - -s MALLOC=emmalloc - -s ASSERTIONS=0 - -s ENVIRONMENT=web - -s FILESYSTEM=0 - -s EXIT_RUNTIME=0 - -s MODULARIZE=1 - -s EXPORT_NAME="Binjgb" - ) + if (THIRDPARTY_HOOKS) + target_sources(binjgb PRIVATE ${BINJGB_THIRDPARTY_HOOKS_FILE}) + else() + target_sources(binjgb PRIVATE src/emulator.c) + endif() + + if(NOT BINJGB_LINKER_OPTIONS) + set(BINJGB_LINKER_OPTIONS + -sMALLOC=emmalloc + -sASSERTIONS=0 + -sENVIRONMENT=web + -sFILESYSTEM=0 + -sEXIT_RUNTIME=0 + -sMODULARIZE=1 + -sEXPORT_NAME=Binjgb + ) + endif() + if (WASM) - set(LINK_FLAGS ${LINK_FLAGS} -s WASM=1) - else () - set(LINK_FLAGS ${LINK_FLAGS} -s WASM=0) + list(APPEND BINJGB_LINKER_OPTIONS -sWASM=1) + else() + list(APPEND BINJGB_LINKER_OPTIONS -sWASM=0) endif () - string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}") + list(APPEND BINJGB_LINKER_OPTIONS -sEXPORTED_FUNCTIONS=@${EXPORTED_JSON}) + + target_link_options(binjgb PRIVATE ${BINJGB_LINKER_OPTIONS}) set_target_properties(binjgb PROPERTIES - LINK_FLAGS "${LINK_FLAGS_STR}" LINK_DEPENDS "${EXPORTED_JSON}" ) endif () diff --git a/scripts/build_tests.py b/scripts/build_tests.py index c3c7122..573d417 100755 --- a/scripts/build_tests.py +++ b/scripts/build_tests.py @@ -56,7 +56,7 @@ def BuildWlaGb(): Run('cmake', '-G', 'NMake Makefiles', '-DCMAKE_BUILD_TYPE=Release', WLA_DX_DIR, cwd=WLA_DX_BUILD_DIR) Run('nmake', cwd=WLA_DX_BUILD_DIR) else: - Run('cmake', WLA_DX_DIR, cwd=WLA_DX_BUILD_DIR) + Run('cmake', '-DCMAKE_POLICY_VERSION_MINIMUM=3.5', '-DCMAKE_C_FLAGS=-Wno-strict-prototypes', WLA_DX_DIR, cwd=WLA_DX_BUILD_DIR) Run('make', cwd=WLA_DX_BUILD_DIR) # Test that wla-gb was build OK. Run(os.path.join(WLA_DX_BIN_DIR, 'wla-gb')) diff --git a/src/emscripten/exported.json b/src/emscripten/exported.json index ff2b2ea..745f006 100644 --- a/src/emscripten/exported.json +++ b/src/emscripten/exported.json @@ -1,9 +1,7 @@ [ -"_emulator_clear_breakpoints", "_emulator_delete", "_emulator_get_A", "_emulator_get_BC", -"_emulator_get_banked_PC", "_emulator_get_DE", "_emulator_get_F", "_emulator_get_HL", @@ -16,10 +14,7 @@ "_emulator_read_ext_ram", "_emulator_read_mem", "_emulator_read_state", -"_emulator_render_background", -"_emulator_render_vram", "_emulator_run_until_f64", -"_emulator_set_breakpoint", "_emulator_set_builtin_palette", "_emulator_set_bw_palette_simple", "_emulator_set_default_joypad_callback", @@ -54,7 +49,6 @@ "_rewind_get_oldest_ticks_f64", "_rewind_new_simple", "_rewind_to_ticks_wrapper", -"_set_audio_channel_mute", "_set_joyp_A", "_set_joyp_B", "_set_joyp_down", diff --git a/src/emscripten/thirdparty-default-hooks.c b/src/emscripten/thirdparty-default-hooks.c new file mode 100644 index 0000000..c0b9ab2 --- /dev/null +++ b/src/emscripten/thirdparty-default-hooks.c @@ -0,0 +1,208 @@ +#include "common.h" +#include "emulator.h" + +#include + +// hooks we wana implement +#define IS_SPEC_emulator_step_after ~,1 +#define IS_SPEC_serial_write ~,1 + +//fallback to default/dummy "implementations" +#define HOOK_SELECT_INNER(...) HOOK_SELECT_GET_3(__VA_ARGS__) +#define HOOK_SELECT_GET_3(a, b, slot, ...) slot + +#define HOOK_VOID_CALL(name, e, f, ...) HOOK_##name(e, f, ##__VA_ARGS__) +#define HOOK_VOID_IGNORE(...) ((void)0) + +#define HOOK_BOOL_CALL(name, e, f, ...) HOOK_##name(e, f) +#define HOOK_BOOL_IGNORE(...) (FALSE) +#define HOOK0(name) \ + HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_VOID_CALL, HOOK_VOID_IGNORE)(name, e, __func__) + +#define HOOK(name, ...) \ + HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_VOID_CALL, HOOK_VOID_IGNORE)(name, e, __func__, __VA_ARGS__) + +#define HOOK0_FALSE(name) \ + HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_BOOL_CALL, HOOK_BOOL_IGNORE)(name, e, __func__) + + +#ifndef BREAKPOINTS_MAX_BANKS_NUMBER + #define BREAKPOINTS_MAX_BANKS_NUMBER 1 +#endif + +typedef uint32_t breakpoints_type; +#define MEMORY_SIZE (64 * 1024) +#define BREAKPOINTS_BIT_SIZE (sizeof(breakpoints_type) * 8) +#define BREAKPOINTS_SIZE ((BREAKPOINTS_MAX_BANKS_NUMBER * MEMORY_SIZE) / BREAKPOINTS_BIT_SIZE) +#define BREAKPOINTS_SHIFT (__builtin_ctz(BREAKPOINTS_BIT_SIZE)) +#define BREAKPOINTS_MASK (BREAKPOINTS_BIT_SIZE - 1) +#define BREAKPOINTS_BANK_SHIFT (16 - BREAKPOINTS_SHIFT) + +#define EMULATOR_FIELDS_HOOK breakpoints_type breakpoint[BREAKPOINTS_SIZE] __attribute__((aligned(8))); + +static void HOOK_emulator_step_after(Emulator*, const char* func_name); +static void HOOK_serial_write(Emulator*, const char* func_name, u8 value); + +#include "emulator.c" + +static inline uint32_t emulator_get_banked_PC_inline(Emulator *e) { + #if BREAKPOINTS_MAX_BANKS_NUMBER > 1 + uint16_t pc = REG.PC; + if (pc < 0x4000) { + return (MMAP_STATE.rom_base[0] << (16 - ROM_BANK_SHIFT)) | pc; + } else if (pc < 0x8000) { + return (MMAP_STATE.rom_base[1] << (16 - ROM_BANK_SHIFT)) | pc; + } else if (pc < 0xA000) { + return (e->state.vram.bank << 16) | pc; + } else if (pc < 0xC000) { + return (MMAP_STATE.ext_ram_base << (16 - EXT_RAM_BANK_SHIFT)) | pc; + } else if (pc < 0xE000) { + return (e->state.wram.bank << 16) | pc; + } + return pc; + #else + return REG.PC; + #endif +} + +static inline bool is_breakpoint(Emulator* e, uint32_t banked_pc) { + uint32_t idx = banked_pc >> BREAKPOINTS_SHIFT; + return (e->breakpoint[idx] & ((breakpoints_type)1 << (banked_pc & BREAKPOINTS_MASK))); +} + + +void HOOK_serial_write(Emulator* e, const char* func_name, u8 value) { + EM_ASM({emulator.serialCallback($0);}, value); +} + +void HOOK_emulator_step_after(Emulator* e, const char* func_name) { + uint32_t banked_pc = emulator_get_banked_PC_inline(e); + if (is_breakpoint(e, banked_pc)) { + e->state.event |= EMULATOR_EVENT_BREAKPOINT; + } +} + +EMSCRIPTEN_KEEPALIVE +void emulator_set_breakpoint(Emulator* e, uint32_t addr) { + uint32_t idx = addr >> BREAKPOINTS_SHIFT; + e->breakpoint[idx] |= ((breakpoints_type)1 << (addr & BREAKPOINTS_MASK)); +} + +EMSCRIPTEN_KEEPALIVE +void emulator_clear_breakpoints(Emulator* e) { + ZERO_MEMORY(e->breakpoint); +} + +EMSCRIPTEN_KEEPALIVE +uint32_t emulator_get_banked_PC(Emulator *e) { + return emulator_get_banked_PC_inline(e); +} + +EMSCRIPTEN_KEEPALIVE +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]; + } + } + } + } + } +} + +EMSCRIPTEN_KEEPALIVE +void emulator_render_background(Emulator* e, u32* buffer, int type) { + memset(buffer, 0, sizeof(u32) * 256 * 256); + int bank = 0; + int tile_map = 0x1800 + ((type & 1) ? 0x400 : 0); + for (int ty = 0; ty < 32; ty++) { + for (int tx = 0; tx < 32; tx++) { + u8 tile = VRAM.data[tile_map + tx + ty * 32]; + int offset = 0; + if(tile < 128) + offset = (LCDC.bg_tile_data_select == TILE_DATA_8000_8FFF) ? 0 : 0x1000; + for (int row = 0; row < 8; row++) { + int n = offset + 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; + } +} + +#ifdef GBSTUDIO + EMSCRIPTEN_KEEPALIVE + Bool set_audio_channel_mute(Emulator *e, int channel, Bool muted) { + EmulatorConfig emu_config = emulator_get_config(e); + emu_config.disable_sound[channel] = muted; + emulator_set_config(e, &emu_config); + return emu_config.disable_sound[channel]; + } +#endif \ No newline at end of file diff --git a/src/emulator-debug.c b/src/emulator-debug.c index 0fa3245..f0fb66b 100644 --- a/src/emulator-debug.c +++ b/src/emulator-debug.c @@ -120,6 +120,8 @@ static void HOOK_read_rom_ib(Emulator*, const char* func_name, u32 rom_addr, static void HOOK_exec_op_ai(Emulator*, const char* func_name, Address, u8 opcode); static void HOOK_exec_cb_op_i(Emulator*, const char* func_name, u8 opcode); +static inline void HOOK_emulator_step_after(Emulator* e, const char* f) { (void)e; (void)f; } +static inline void HOOK_serial_write(Emulator* e, const char* f, u8 v) { (void)e; (void)f; (void)v; } FOREACH_LOG_HOOKS(DECLARE_LOG_HOOK) diff --git a/src/emulator.c b/src/emulator.c index 481f6ed..1e57c16 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -8,9 +8,6 @@ #include #include #include -#if RGBDS_LIVE -#include -#endif #include "emulator.h" @@ -692,17 +689,8 @@ typedef struct { } EmulatorState; const size_t s_emulator_state_size = sizeof(EmulatorState); -#ifdef RGBDS_LIVE -#ifndef BREAKPOINTS_MAX_BANKS_NUMBER 1 -#define BREAKPOINTS_MAX_BANKS_NUMBER 1 -#endif -typedef uint32_t breakpoints_type; -#define MEMORY_SIZE (64 * 1024) -#define BREAKPOINTS_BIT_SIZE (sizeof(breakpoints_type) * 8) -#define BREAKPOINTS_SIZE ((BREAKPOINTS_MAX_BANKS_NUMBER * MEMORY_SIZE) / BREAKPOINTS_BIT_SIZE) -#define BREAKPOINTS_SHIFT (__builtin_ctz(BREAKPOINTS_BIT_SIZE)) -#define BREAKPOINTS_MASK (BREAKPOINTS_BIT_SIZE - 1) -#define BREAKPOINTS_BANK_SHIFT (16 - BREAKPOINTS_SHIFT) +#ifndef EMULATOR_FIELDS_HOOK +#define EMULATOR_FIELDS_HOOK #endif struct Emulator { EmulatorConfig config; @@ -723,9 +711,7 @@ struct Emulator { PaletteRGBA sgb_pal[4]; CgbColorCurve cgb_color_curve; ApuLog apu_log; -#ifdef RGBDS_LIVE - breakpoints_type breakpoint[BREAKPOINTS_SIZE] __attribute__((aligned(8))); -#endif + EMULATOR_FIELDS_HOOK }; @@ -1140,9 +1126,6 @@ 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; @@ -2613,9 +2596,7 @@ 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 + HOOK(serial_write, value); break; case IO_SC_ADDR: serial_synchronize(e); @@ -4648,45 +4629,13 @@ static void execute_instruction(Emulator* e) { REG.PC = new_pc; } -#ifdef RGBDS_LIVE -static inline uint32_t emulator_get_banked_PC_inline(Emulator *e) { - #if BREAKPOINTS_MAX_BANKS_NUMBER > 1 - uint16_t pc = REG.PC; - if (pc < 0x4000) { - return (MMAP_STATE.rom_base[0] << (16 - ROM_BANK_SHIFT)) | pc; - } else if (pc < 0x8000) { - return (MMAP_STATE.rom_base[1] << (16 - ROM_BANK_SHIFT)) | pc; - } else if (pc < 0xA000) { - return (e->state.vram.bank << 16) | pc; - } else if (pc < 0xC000) { - return (MMAP_STATE.ext_ram_base << (16 - EXT_RAM_BANK_SHIFT)) | pc; - } else if (pc < 0xE000) { - return (e->state.wram.bank << 16) | pc; - } - return pc; - #else - return REG.PC - #endif -} - -static inline bool is_breakpoint(Emulator* e, uint32_t banked_pc) { - uint32_t idx = banked_pc >> BREAKPOINTS_SHIFT; - return (e->breakpoint[idx] & ((breakpoints_type)1 << (banked_pc & BREAKPOINTS_MASK))); -} -#endif - static void emulator_step_internal(Emulator* e) { if (HDMA.state == DMA_INACTIVE) { if (HOOK0_FALSE(emulator_step)) { return; } execute_instruction(e); -#ifdef RGBDS_LIVE - uint32_t banked_pc = emulator_get_banked_PC_inline(e); - if (is_breakpoint(e, banked_pc)) { - e->state.event |= EMULATOR_EVENT_BREAKPOINT; - } -#endif + HOOK0(emulator_step_after); } else { tick(e); hdma_copy_byte(e); @@ -5182,144 +5131,3 @@ u8 emulator_read_mem(Emulator* e, u16 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, uint32_t addr) { - uint32_t idx = addr >> BREAKPOINTS_SHIFT; - e->breakpoint[idx] |= ((breakpoints_type)1 << (addr & BREAKPOINTS_MASK)); -} - -void emulator_clear_breakpoints(Emulator* e) { - ZERO_MEMORY(e->breakpoint); -} - -uint32_t emulator_get_banked_PC(Emulator *e) { - return emulator_get_banked_PC_inline(e); -} - -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 = 0x1800 + ((type & 1) ? 0x400 : 0); - for (int ty = 0; ty < 32; ty++) { - for (int tx = 0; tx < 32; tx++) { - u8 tile = VRAM.data[tile_map + tx + ty * 32]; - int offset = 0; - if(tile < 128) - offset = (LCDC.bg_tile_data_select == TILE_DATA_8000_8FFF) ? 0 : 0x1000; - for (int row = 0; row < 8; row++) { - int n = offset + 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) {} - -uint32_t emulator_get_banked_PC(Emulator *e) { return REG.PC; } - -#endif - -#ifdef GBSTUDIO -Bool set_audio_channel_mute(Emulator *e, int channel, Bool muted) { - EmulatorConfig emu_config = emulator_get_config(e); - emu_config.disable_sound[channel] = muted; - emulator_set_config(e, &emu_config); - return emu_config.disable_sound[channel]; -} - -#else // !GBSTUDIO - -Bool set_audio_channel_mute(Emulator *e, int channel, Bool muted) { - return FALSE; -} - -#endif