From a3b837f3290c6332b8969552e36df3102679d1c7 Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sun, 12 Oct 2025 00:33:48 +0200 Subject: [PATCH] a bit more speedup --- .../gameboy/include/cardboy/apps/peanut_gb.h | 11 +++-- Firmware/sdk/apps/gameboy/src/gameboy_app.cpp | 46 ++++++++++++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/Firmware/sdk/apps/gameboy/include/cardboy/apps/peanut_gb.h b/Firmware/sdk/apps/gameboy/include/cardboy/apps/peanut_gb.h index 95369c1..54884b0 100644 --- a/Firmware/sdk/apps/gameboy/include/cardboy/apps/peanut_gb.h +++ b/Firmware/sdk/apps/gameboy/include/cardboy/apps/peanut_gb.h @@ -568,7 +568,6 @@ union cart_rtc } reg; uint8_t bytes[5]; }; -extern "C" uint8_t gb_rom_read(struct gb_s*, const uint_fast32_t); /** * Emulator context. @@ -730,9 +729,14 @@ struct gb_s /* Implementation defined data. Set to NULL if not required. */ void *priv; + const uint8_t* rom; } direct; }; +__attribute__((always_inline)) inline uint8_t gb_rom_read(struct gb_s* s, const uint_fast32_t addr) { + return s->direct.rom[addr]; +} + #ifndef PEANUT_GB_HEADER_ONLY #define IO_JOYP 0x00 @@ -3687,7 +3691,7 @@ enum gb_init_error_e gb_init(struct gb_s *gb, uint8_t (*gb_cart_ram_read)(struct gb_s*, const uint_fast32_t), void (*gb_cart_ram_write)(struct gb_s*, const uint_fast32_t, const uint8_t), void (*gb_error)(struct gb_s*, const enum gb_error_e, const uint16_t), - void *priv) + void *priv, const uint8_t* rom_data) { const uint16_t mbc_location = 0x0147; const uint16_t bank_count_location = 0x0148; @@ -3726,6 +3730,7 @@ enum gb_init_error_e gb_init(struct gb_s *gb, gb->gb_cart_ram_write = gb_cart_ram_write; gb->gb_error = gb_error; gb->direct.priv = priv; + gb->direct.rom = rom_data; /* Initialise serial transfer function to NULL. If the front-end does * not provide serial support, Peanut-GB will emulate no cable connected @@ -3879,7 +3884,7 @@ enum gb_init_error_e gb_init(struct gb_s *gb, uint8_t (*gb_cart_ram_read)(struct gb_s*, const uint_fast32_t), void (*gb_cart_ram_write)(struct gb_s*, const uint_fast32_t, const uint8_t), void (*gb_error)(struct gb_s*, const enum gb_error_e, const uint16_t), - void *priv); + void *priv, const uint8_t* rom_data); /** * Executes the emulator and runs for the duration of time equal to one frame. diff --git a/Firmware/sdk/apps/gameboy/src/gameboy_app.cpp b/Firmware/sdk/apps/gameboy/src/gameboy_app.cpp index c3edd72..72fb692 100644 --- a/Firmware/sdk/apps/gameboy/src/gameboy_app.cpp +++ b/Firmware/sdk/apps/gameboy/src/gameboy_app.cpp @@ -76,6 +76,29 @@ static constexpr LUTFull buildNibbleLUT() { inline constexpr LUTFull kNibbleLUT = buildNibbleLUT(); +static constexpr LUTFull buildFullHeightWideByteLUT() { + LUTFull L{}; + for (int yp = 0; yp < 2; ++yp) + for (int xp = 0; xp < 2; ++xp) + for (int p = 0; p < 256; ++p) { + const uint8_t p0 = static_cast(p & 0x03); + const uint8_t p1 = static_cast((p >> 2) & 0x03); + const uint8_t p2 = static_cast((p >> 4) & 0x03); + const uint8_t p3 = static_cast((p >> 6) & 0x03); + + const uint8_t p4a = static_cast(p0 | (p0 << 2) | (p1 << 4) | (p1 << 6)); + const uint8_t p4b = static_cast(p2 | (p2 << 2) | (p3 << 4) | (p3 << 6)); + + const uint8_t n0 = makeNibble(p4a, xp, yp); + const uint8_t n1 = makeNibble(p4b, xp, yp); + + L[yp][xp][p] = static_cast((n0 << 4) | (n1 & 0x0F)); + } + return L; +} + +inline constexpr LUTFull kFullHeightWideByteLUT = buildFullHeightWideByteLUT(); + namespace apps { namespace { @@ -869,8 +892,8 @@ private: } std::memset(&gb, 0, sizeof(gb)); - const auto initResult = - gb_init(&gb, &GameboyApp::cartRamRead, &GameboyApp::cartRamWrite, &GameboyApp::errorCallback, this); + const auto initResult = gb_init(&gb, &GameboyApp::cartRamRead, &GameboyApp::cartRamWrite, + &GameboyApp::errorCallback, this, romDataView); if (initResult != GB_INIT_NO_ERROR) { setStatus(initErrorToString(initResult)); romData.clear(); @@ -1276,23 +1299,17 @@ private: CARDBOY_CHECK(yEnd > yStart); CARDBOY_CHECK((kFullHeightWideOffsetX % 8) == 0); + const int xParityBase = kFullHeightWideOffsetX & 1; + for (int dstY = yStart; dstY < yEnd; ++dstY) { const int yParity = dstY & 1; int dstX = kFullHeightWideOffsetX; for (int srcX = 0; srcX < LCD_WIDTH; srcX += 4) { - const uint8_t p0 = pixels[srcX + 0]; - const uint8_t p1 = pixels[srcX + 1]; - const uint8_t p2 = pixels[srcX + 2]; - const uint8_t p3 = pixels[srcX + 3]; + const uint8_t packIndex = static_cast((pixels[srcX + 0]) | ((pixels[srcX + 1]) << 2) | + ((pixels[srcX + 2]) << 4) | ((pixels[srcX + 3]) << 6)); - const uint8_t p4a = static_cast(p0 | (p0 << 2) | (p1 << 4) | (p1 << 6)); - const uint8_t p4b = static_cast(p2 | (p2 << 2) | (p3 << 4) | (p3 << 6)); - - const int xParity = dstX & 1; - const uint8_t n0 = kNibbleLUT[yParity][xParity][p4a]; - const uint8_t n1 = kNibbleLUT[yParity][xParity][p4b]; - const uint8_t pack = static_cast((n0 << 4) | (n1 & 0x0F)); + const uint8_t pack = kFullHeightWideByteLUT[yParity][xParityBase][packIndex]; fb.drawBits8(dstX, dstY, pack); dstX += 8; @@ -1403,9 +1420,6 @@ private: } }; -extern "C" __attribute__((always_inline)) uint8_t gb_rom_read(struct gb_s* gb, const uint_fast32_t addr) { - return GameboyApp::romRead(gb, addr); -} class GameboyAppFactory final : public cardboy::sdk::IAppFactory { public: const char* name() const override { return kGameboyAppName; }