diff --git a/components/gbc/gnuboy/src/loader.c b/components/gbc/gnuboy/src/loader.c index 72e5238b..beb1cfdd 100644 --- a/components/gbc/gnuboy/src/loader.c +++ b/components/gbc/gnuboy/src/loader.c @@ -236,8 +236,17 @@ void rtc_load() void loader_unload() { sram_save(); + // Free the cart SRAM allocated in rom_load(). Previously this static buffer + // was never freed, leaking ~ramsize KB of PSRAM and fragmenting it across + // cart switches; it was also reused as-is on the next ROM via the + // `if (!sram_ptr)` guard, so a larger-ramsize cart would overflow it. + // Freeing (and NULLing) here makes each ROM reallocate at its own size. + if (sram_ptr) { + heap_caps_free(sram_ptr); + sram_ptr = NULL; + } + ram.sbank = NULL; // rom.bank = NULL; - // ram.sbank = NULL; mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0; } diff --git a/components/gbc/include/gbc_shared_memory.hpp b/components/gbc/include/gbc_shared_memory.hpp index 41028dc2..c98c9491 100644 --- a/components/gbc/include/gbc_shared_memory.hpp +++ b/components/gbc/include/gbc_shared_memory.hpp @@ -3,6 +3,15 @@ #include #include +// Game Boy (Color) audio sizing. The shared PCM buffer allocation (in +// gbc_shared_memory.cpp) and pcm.len (in gameboy.cpp) BOTH derive from these, +// so they cannot diverge: if pcm.len implies a larger buffer than is allocated, +// the gnuboy sound mixer overruns it and corrupts the heap. +#define GAMEBOY_AUDIO_SAMPLE_RATE 32768 +// Size (in bytes) of the shared PCM buffer: ~1/5 second of stereo (2ch), +// 16-bit (2 byte) audio. pcm.len = GBC_AUDIO_BUFFER_SIZE / sizeof(int16_t). +#define GBC_AUDIO_BUFFER_SIZE (GAMEBOY_AUDIO_SAMPLE_RATE * 2 * 2 / 5) + #ifdef __cplusplus extern "C" { #endif diff --git a/components/gbc/src/gameboy.cpp b/components/gbc/src/gameboy.cpp index ce860d96..fe1c644d 100644 --- a/components/gbc/src/gameboy.cpp +++ b/components/gbc/src/gameboy.cpp @@ -11,7 +11,7 @@ static const size_t GAMEBOY_SCREEN_WIDTH = 160; static const size_t GAMEBOY_SCREEN_HEIGHT = 144; -static const int GAMEBOY_AUDIO_SAMPLE_RATE = 32768; +// GAMEBOY_AUDIO_SAMPLE_RATE / GBC_AUDIO_BUFFER_SIZE come from gbc_shared_memory.hpp extern "C" { #include @@ -116,7 +116,8 @@ void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_ lcd->vbank = vram; ram.ibank = wram; pcm.buf = reinterpret_cast(audio); - static constexpr int GBC_AUDIO_BUFFER_SIZE = GAMEBOY_AUDIO_SAMPLE_RATE * 2 * 2 / 5; // TODO: 5 is a hack to make it work + // GBC_AUDIO_BUFFER_SIZE (bytes) is the size actually allocated for pcm.buf in + // gbc_shared_memory.cpp, so pcm.len matches the buffer exactly. pcm.len = GBC_AUDIO_BUFFER_SIZE / sizeof(int16_t); // set native size diff --git a/components/gbc/src/gbc_shared_memory.cpp b/components/gbc/src/gbc_shared_memory.cpp index 369a3ca3..d365a5b2 100644 --- a/components/gbc/src/gbc_shared_memory.cpp +++ b/components/gbc/src/gbc_shared_memory.cpp @@ -22,7 +22,8 @@ extern "C" { // GBC memory sizes #define GBC_VRAM_SIZE (16 * 1024) // 16KB VRAM #define GBC_WRAM_SIZE (32 * 1024) // 32KB WRAM -#define GBC_AUDIO_BUFFER_SIZE (2048 * sizeof(int16_t)) // 2048 samples at 16-bit per sample +// GBC_AUDIO_BUFFER_SIZE comes from gbc_shared_memory.hpp so the allocation here +// always matches pcm.len in gameboy.cpp (a mismatch overruns the PCM buffer). // Static pointers to shared memory regions static uint8_t* vram_ptr = nullptr;