diff --git a/CHANGES b/CHANGES index 9871f0ccf..989cbd5e9 100644 --- a/CHANGES +++ b/CHANGES @@ -70,6 +70,12 @@ Misc: - PSP2: Use system enter key by default - 3DS: Remove deprecated CSND interface +0.6.3: (2017-04-14) +Bugfixes: + - GB Audio: Revert unsigned audio changes + - GB Video: Fix bad merge (fixes mgba.io/i/1040) + - GBA Video: Fix OBJ blending regression (fixes mgba.io/i/1037) + 0.6.2: (2017-04-03) Bugfixes: - Core: Fix ROM patches not being unloaded when disabled (fixes mgba.io/i/962) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ac90a18..28914dc2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -920,7 +920,7 @@ if(BUILD_PERF) target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB} ${OS_LIB}) set_target_properties(${BINARY_NAME}-perf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") install(TARGETS ${BINARY_NAME}-perf DESTINATION bin COMPONENT ${BINARY_NAME}-perf) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/tools/perf.py DESTINATION "${LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) endif() if(BUILD_TEST) diff --git a/doc/medusa-emu-qt.6 b/doc/medusa-emu-qt.6 index 8e80a5c39..a965f0eb2 100644 --- a/doc/medusa-emu-qt.6 +++ b/doc/medusa-emu-qt.6 @@ -13,6 +13,7 @@ .Nm medusa-emu-qt .Op Fl 123456fg .Op Fl b Ar biosfile +.Op Fl C Ar option Ns = Ns Ar value .Op Fl l Ar loglevel .Op Fl p Ar patchfile .Op Fl s Ar n @@ -40,6 +41,11 @@ If this flag is omitted, .Nm will use the BIOS specified in the configuration file, or a high\(hylevel emulated BIOS if none is specified. +.It Fl C Ar option Ns = Ns Ar value , Fl -config Ar option Ns = Ns Ar value +Override the given config +.Ar option +with +.Ar value . .It Fl f Start the emulator full\(hyscreen. .It Fl g diff --git a/doc/medusa-emu.6 b/doc/medusa-emu.6 index 405c324cd..4829ec87f 100644 --- a/doc/medusa-emu.6 +++ b/doc/medusa-emu.6 @@ -13,6 +13,7 @@ .Nm medusa-emu .Op Fl 123456dfg .Op Fl b Ar biosfile +.Op Fl C Ar option Ns = Ns Ar value .Op Fl c Ar cheatfile .Op Fl l Ar loglevel .Op Fl p Ar patchfile @@ -42,6 +43,11 @@ If this flag is omitted, .Nm will use the BIOS specified in the configuration file, or a high\(hylevel emulated BIOS if none is specified. +.It Fl C Ar option Ns = Ns Ar value , Fl -config Ar option Ns = Ns Ar value +Override the given config +.Ar option +with +.Ar value . .It Fl c Ar cheatfile , Fl -cheats Ar cheatfile Apply cheat codes from .Ar cheatfile . diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index 65ffb88f7..d0e5df0d9 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -62,7 +62,7 @@ enum GBSGBCommand { SGB_PICON_EN, SGB_DATA_SND, SGB_DATA_TRN, - SGB_MLT_REG, + SGB_MLT_REQ, SGB_JUMP, SGB_CHR_TRN, SGB_PCT_TRN, @@ -107,6 +107,8 @@ struct GB { int sgbBit; int currentSgbBits; uint8_t sgbPacket[16]; + uint8_t sgbControllers; + uint8_t sgbCurrentController; struct mCoreCallbacksList coreCallbacks; struct mAVStream* stream; diff --git a/include/mgba/internal/gb/renderers/software.h b/include/mgba/internal/gb/renderers/software.h index 91f7421f4..159d643b8 100644 --- a/include/mgba/internal/gb/renderers/software.h +++ b/include/mgba/internal/gb/renderers/software.h @@ -39,15 +39,9 @@ struct GBVideoSoftwareRenderer { enum GBModel model; int sgbTransfer; - uint8_t sgbPacket[16]; + uint8_t sgbPacket[128]; uint8_t sgbCommandHeader; - int sgbPacketId; - int sgbDataSets; - uint8_t sgbPartialDataSet[15]; bool sgbBorders; - int sgbAttrX; - int sgbAttrY; - int sgbAttrDirection; }; void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index 22c4ccb3f..6e4a943b1 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -258,6 +258,9 @@ DECL_BITS(GBSerializedMemoryFlags, ActiveRtcReg, 5, 3); DECL_BITFIELD(GBSerializedSGBFlags, uint32_t); DECL_BITS(GBSerializedSGBFlags, P1Bits, 0, 2); DECL_BITS(GBSerializedSGBFlags, RenderMode, 2, 2); +DECL_BITS(GBSerializedSGBFlags, BufferIndex, 4, 3); +DECL_BITS(GBSerializedSGBFlags, CurrentController, 7, 2); +DECL_BITS(GBSerializedSGBFlags, ReqControllers, 9, 2); #pragma pack(push, 1) struct GBSerializedState { @@ -388,15 +391,15 @@ struct GBSerializedState { uint8_t vram[GB_SIZE_VRAM]; uint8_t wram[GB_SIZE_WORKING_RAM]; - uint32_t reserved2[0xE0]; + uint32_t reserved2[0xC4]; struct { uint8_t attributes[90]; uint8_t command; uint8_t bits; GBSerializedSGBFlags flags; - uint8_t packet[16]; - uint32_t reserved[4]; + uint8_t inProgressPacket[16]; + uint8_t packet[128]; uint8_t charRam[SGB_SIZE_CHAR_RAM]; uint8_t mapRam[SGB_SIZE_MAP_RAM]; uint8_t palRam[SGB_SIZE_PAL_RAM]; diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h index 7fd731be6..ec7409af9 100644 --- a/include/mgba/internal/gb/video.h +++ b/include/mgba/internal/gb/video.h @@ -143,6 +143,8 @@ struct GBVideo { int ocpIndex; bool ocpIncrement; uint8_t sgbCommandHeader; + int sgbBufferIndex; + uint8_t sgbPacketBuffer[128]; uint16_t dmgPalette[12]; uint16_t palette[64]; diff --git a/src/gb/core.c b/src/gb/core.c index bc891d923..3d9389eb5 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -290,7 +290,9 @@ static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { struct GB* gb = core->board; gb->stream = stream; if (stream && stream->videoDimensionsChanged) { - stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS); + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + stream->videoDimensionsChanged(stream, width, height); } if (stream && stream->videoFrameRateChanged) { stream->videoFrameRateChanged(stream, core->frameCycles(core), core->frequency(core)); diff --git a/src/gb/gb.c b/src/gb/gb.c index b932e9eda..859c1119f 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -446,6 +446,8 @@ void GBReset(struct LR35902Core* cpu) { } gb->sgbBit = -1; + gb->sgbControllers = 0; + gb->sgbCurrentController = 0; gb->currentSgbBits = 0; memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket)); diff --git a/src/gb/io.c b/src/gb/io.c index 88e0f860c..af2bba3a9 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -113,6 +113,9 @@ static void _writeSGBBits(struct GB* gb, int bits) { return; } gb->currentSgbBits = bits; + if (bits == 3) { + gb->sgbCurrentController = (gb->sgbCurrentController + 1) & gb->sgbControllers; + } if (gb->sgbBit == 128 && bits == 2) { GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket); ++gb->sgbBit; @@ -503,10 +506,13 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { static uint8_t _readKeys(struct GB* gb) { uint8_t keys = *gb->keySource; + if (gb->sgbCurrentController != 0) { + keys = 0; + } switch (gb->memory.io[REG_JOYP] & 0x30) { case 0x30: // TODO: Increment - keys = (gb->video.sgbCommandHeader >> 3) == SGB_MLT_REG ? 0xF : 0; + keys = (gb->video.sgbCommandHeader >> 3) == SGB_MLT_REQ ? 0xF - gb->sgbCurrentController : 0; break; case 0x20: keys >>= 4; diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index 92fc927ff..7fe4ad458 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -81,18 +81,12 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) { if (SGBBgAttributesIsXFlip(mapData)) { for (i = 0; i < 8; ++i) { colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; - // The first color of every palette is transparent - if (colorSelector) { - renderer->outputBuffer[base + i] = renderer->palette[paletteBase | colorSelector]; - } + renderer->outputBuffer[base + i] = renderer->palette[paletteBase | colorSelector]; } } else { for (i = 7; i >= 0; --i) { colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; - - if (colorSelector) { - renderer->outputBuffer[base + 7 - i] = renderer->palette[paletteBase | colorSelector]; - } + renderer->outputBuffer[base + 7 - i] = renderer->palette[paletteBase | colorSelector]; } } } @@ -108,12 +102,7 @@ static inline void _setAttribute(uint8_t* sgbAttributes, unsigned x, unsigned y, static void _parseAttrBlock(struct GBVideoSoftwareRenderer* renderer, int start) { uint8_t block[6]; - if (start < 0) { - memcpy(block, renderer->sgbPartialDataSet, -start); - memcpy(&block[-start], renderer->sgbPacket, 6 + start); - } else { - memcpy(block, &renderer->sgbPacket[start], 6); - } + memcpy(block, &renderer->sgbPacket[start], 6); unsigned x0 = block[2]; unsigned x1 = block[4]; unsigned y0 = block[3]; @@ -268,14 +257,16 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; memcpy(softwareRenderer->sgbPacket, data, sizeof(softwareRenderer->sgbPacket)); int i; - if (!(softwareRenderer->sgbCommandHeader & 7)) { - softwareRenderer->sgbCommandHeader = data[0]; - softwareRenderer->sgbPacketId = 0; - softwareRenderer->sgbTransfer = 0; - } - --softwareRenderer->sgbCommandHeader; - ++softwareRenderer->sgbPacketId; + softwareRenderer->sgbCommandHeader = data[0]; + softwareRenderer->sgbTransfer = 0; int set; + int sets; + int attrX; + int attrY; + int attrDirection; + int pBefore; + int pAfter; + int pDiv; switch (softwareRenderer->sgbCommandHeader >> 3) { case SGB_PAL_SET: softwareRenderer->sgbPacket[1] = data[9]; @@ -290,58 +281,96 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render } break; case SGB_ATTR_BLK: - if (softwareRenderer->sgbPacketId == 1) { - softwareRenderer->sgbDataSets = softwareRenderer->sgbPacket[1]; - i = 2; - } else { - i = (9 - softwareRenderer->sgbPacketId) % 3 * -2; - } - for (; i <= 10 && softwareRenderer->sgbDataSets; i += 6, --softwareRenderer->sgbDataSets) { + sets = softwareRenderer->sgbPacket[1]; + i = 2; + for (; i < (softwareRenderer->sgbCommandHeader & 7) << 4 && sets; i += 6, --sets) { _parseAttrBlock(softwareRenderer, i); } - if (i < 16 && softwareRenderer->sgbDataSets) { - memcpy(softwareRenderer->sgbPartialDataSet, &softwareRenderer->sgbPacket[i], 16 - i); + break; + case SGB_ATTR_DIV: + pAfter = softwareRenderer->sgbPacket[1] & 3; + pBefore = (softwareRenderer->sgbPacket[1] >> 2) & 3; + pDiv = (softwareRenderer->sgbPacket[1] >> 4) & 3; + attrX = softwareRenderer->sgbPacket[2]; + if (softwareRenderer->sgbPacket[1] & 0x40) { + if (attrX > GB_VIDEO_VERTICAL_PIXELS / 8) { + attrX = GB_VIDEO_VERTICAL_PIXELS / 8; + } + int j; + for (j = 0; j < attrX; ++j) { + for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, i, j, pBefore); + } + } + if (attrX < GB_VIDEO_VERTICAL_PIXELS / 8) { + for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, i, attrX, pDiv); + } + + } + for (; j < GB_VIDEO_VERTICAL_PIXELS / 8; ++j) { + for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, i, j, pAfter); + } + } + } else { + if (attrX > GB_VIDEO_HORIZONTAL_PIXELS / 8) { + attrX = GB_VIDEO_HORIZONTAL_PIXELS / 8; + } + int j; + for (j = 0; j < attrX; ++j) { + for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, j, i, pBefore); + } + } + if (attrX < GB_VIDEO_HORIZONTAL_PIXELS / 8) { + for (i = 0; i < GB_VIDEO_VERTICAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, attrX, i, pDiv); + } + + } + for (; j < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++j) { + for (i = 0; i < GB_VIDEO_VERTICAL_PIXELS / 8; ++i) { + _setAttribute(renderer->sgbAttributes, j, i, pAfter); + } + } } break; case SGB_ATTR_CHR: - if (softwareRenderer->sgbPacketId == 1) { - softwareRenderer->sgbAttrX = softwareRenderer->sgbPacket[1]; - softwareRenderer->sgbAttrY = softwareRenderer->sgbPacket[2]; - if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { - softwareRenderer->sgbAttrX = 0; - } - if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { - softwareRenderer->sgbAttrY = 0; - } - softwareRenderer->sgbDataSets = softwareRenderer->sgbPacket[3]; - softwareRenderer->sgbDataSets |= softwareRenderer->sgbPacket[4] << 8; - softwareRenderer->sgbAttrDirection = softwareRenderer->sgbPacket[5]; - i = 6; - } else { - i = 0; + attrX = softwareRenderer->sgbPacket[1]; + attrY = softwareRenderer->sgbPacket[2]; + if (attrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { + attrX = 0; } - for (; i < 16 && softwareRenderer->sgbDataSets; ++i) { + if (attrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { + attrY = 0; + } + sets = softwareRenderer->sgbPacket[3]; + sets |= softwareRenderer->sgbPacket[4] << 8; + attrDirection = softwareRenderer->sgbPacket[5]; + i = 6; + for (; i < (softwareRenderer->sgbCommandHeader & 7) << 4 && sets; ++i) { int j; - for (j = 0; j < 4 && softwareRenderer->sgbDataSets; ++j, --softwareRenderer->sgbDataSets) { + for (j = 0; j < 4 && sets; ++j, --sets) { uint8_t p = softwareRenderer->sgbPacket[i] >> (6 - j * 2); - _setAttribute(renderer->sgbAttributes, softwareRenderer->sgbAttrX, softwareRenderer->sgbAttrY, p & 3); - if (softwareRenderer->sgbAttrDirection) { - ++softwareRenderer->sgbAttrY; - if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { - softwareRenderer->sgbAttrY = 0; - ++softwareRenderer->sgbAttrX; + _setAttribute(renderer->sgbAttributes, attrX, attrY, p & 3); + if (attrDirection) { + ++attrY; + if (attrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { + attrY = 0; + ++attrX; } - if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { - softwareRenderer->sgbAttrX = 0; + if (attrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { + attrX = 0; } } else { - ++softwareRenderer->sgbAttrX; - if (softwareRenderer->sgbAttrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { - softwareRenderer->sgbAttrX = 0; - ++softwareRenderer->sgbAttrY; + ++attrX; + if (attrX >= GB_VIDEO_HORIZONTAL_PIXELS / 8) { + attrX = 0; + ++attrY; } - if (softwareRenderer->sgbAttrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { - softwareRenderer->sgbAttrY = 0; + if (attrY >= GB_VIDEO_VERTICAL_PIXELS / 8) { + attrY = 0; } } } @@ -349,23 +378,40 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render break; case SGB_ATRC_EN: - if (softwareRenderer->sgbBorders) { + case SGB_MASK_EN: + if (softwareRenderer->sgbBorders && !renderer->sgbRenderMode) { _regenerateSGBBorder(softwareRenderer); } - break; } } static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; color_t color = mColorFrom555(value); - if (softwareRenderer->model == GB_MODEL_SGB && index < 0x10 && index && !(index & 3)) { - color = softwareRenderer->palette[0]; + if (softwareRenderer->model == GB_MODEL_SGB) { + if (index < 0x10 && index && !(index & 3)) { + color = softwareRenderer->palette[0]; + } else if (index >= 0x40 && !(index & 0xF)) { + color = softwareRenderer->palette[0]; + } } softwareRenderer->palette[index] = color; if (renderer->cache) { mCacheSetWritePalette(renderer->cache, index, color); } + + if (softwareRenderer->model == GB_MODEL_SGB && !index && GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { + renderer->writePalette(renderer, 0x04, value); + renderer->writePalette(renderer, 0x08, value); + renderer->writePalette(renderer, 0x0C, value); + renderer->writePalette(renderer, 0x40, value); + renderer->writePalette(renderer, 0x50, value); + renderer->writePalette(renderer, 0x60, value); + renderer->writePalette(renderer, 0x70, value); + if (softwareRenderer->sgbBorders && !renderer->sgbRenderMode) { + _regenerateSGBBorder(softwareRenderer); + } + } } static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) { @@ -580,7 +626,7 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) case SGB_PAL_TRN: case SGB_CHR_TRN: case SGB_PCT_TRN: - if (softwareRenderer->sgbTransfer > 0 && softwareRenderer->sgbBorders) { + if (softwareRenderer->sgbTransfer > 0 && softwareRenderer->sgbBorders && !renderer->sgbRenderMode) { // Make sure every buffer sees this if we're multibuffering _regenerateSGBBorder(softwareRenderer); } diff --git a/src/gb/serialize.c b/src/gb/serialize.c index 4c54c3e59..c00b7c9fa 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -212,9 +212,13 @@ void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) { GBSerializedSGBFlags flags = 0; flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits); flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode); + flags = GBSerializedSGBFlagsSetBufferIndex(flags, gb->video.sgbBufferIndex); + flags = GBSerializedSGBFlagsSetReqControllers(flags, gb->sgbControllers); + flags = GBSerializedSGBFlagsSetCurrentController(flags, gb->sgbCurrentController); STORE_32LE(flags, 0, &state->sgb.flags); - memcpy(state->sgb.packet, gb->sgbPacket, sizeof(state->sgb.packet)); + memcpy(state->sgb.packet, gb->video.sgbPacketBuffer, sizeof(state->sgb.packet)); + memcpy(state->sgb.inProgressPacket, gb->sgbPacket, sizeof(state->sgb.inProgressPacket)); if (gb->video.renderer->sgbCharRam) { memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam)); @@ -241,8 +245,12 @@ void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) { LOAD_32LE(flags, 0, &state->sgb.flags); gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags); gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags); + gb->video.sgbBufferIndex = GBSerializedSGBFlagsGetBufferIndex(flags); + gb->sgbControllers = GBSerializedSGBFlagsGetReqControllers(flags); + gb->sgbCurrentController = GBSerializedSGBFlagsGetCurrentController(flags); - memcpy(gb->sgbPacket, state->sgb.packet, sizeof(state->sgb.packet)); + memcpy(gb->video.sgbPacketBuffer, state->sgb.packet, sizeof(state->sgb.packet)); + memcpy(gb->sgbPacket, state->sgb.inProgressPacket, sizeof(state->sgb.inProgressPacket)); if (!gb->video.renderer->sgbCharRam) { gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM); @@ -267,5 +275,4 @@ void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) { memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes)); GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 }); - GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket); } diff --git a/src/gb/video.c b/src/gb/video.c index 667191300..be92537f4 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -113,6 +113,7 @@ void GBVideoReset(struct GBVideo* video) { video->renderer->sgbAttributes = malloc(90 * 45); memset(video->renderer->sgbAttributes, 0, 90 * 45); video->sgbCommandHeader = 0; + video->sgbBufferIndex = 0; } video->palette[0] = video->dmgPalette[0]; @@ -580,6 +581,7 @@ void GBVideoDisableCGB(struct GBVideo* video) { void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { int i; if (!(video->sgbCommandHeader & 7)) { + video->sgbBufferIndex = 0; if ((data[0] >> 3) > SGB_OBJ_TRN) { video->sgbCommandHeader = 0; return; @@ -587,20 +589,25 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { video->sgbCommandHeader = data[0]; } --video->sgbCommandHeader; + memcpy(&video->sgbPacketBuffer[video->sgbBufferIndex << 4], data, 16); + ++video->sgbBufferIndex; + if (video->sgbCommandHeader & 7) { + return; + } switch (video->sgbCommandHeader >> 3) { case SGB_PAL01: - video->palette[0] = data[1] | (data[2] << 8); - video->palette[1] = data[3] | (data[4] << 8); - video->palette[2] = data[5] | (data[6] << 8); - video->palette[3] = data[7] | (data[8] << 8); + video->palette[0] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[1] = video->sgbPacketBuffer[3] | (video->sgbPacketBuffer[4] << 8); + video->palette[2] = video->sgbPacketBuffer[5] | (video->sgbPacketBuffer[6] << 8); + video->palette[3] = video->sgbPacketBuffer[7] | (video->sgbPacketBuffer[8] << 8); - video->palette[4] = data[1] | (data[2] << 8); - video->palette[5] = data[9] | (data[10] << 8); - video->palette[6] = data[11] | (data[12] << 8); - video->palette[7] = data[13] | (data[14] << 8); + video->palette[4] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[5] = video->sgbPacketBuffer[9] | (video->sgbPacketBuffer[10] << 8); + video->palette[6] = video->sgbPacketBuffer[11] | (video->sgbPacketBuffer[12] << 8); + video->palette[7] = video->sgbPacketBuffer[13] | (video->sgbPacketBuffer[14] << 8); - video->palette[8] = data[1] | (data[2] << 8); - video->palette[12] = data[1] | (data[2] << 8); + video->palette[8] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[12] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); video->renderer->writePalette(video->renderer, 0, video->palette[0]); video->renderer->writePalette(video->renderer, 1, video->palette[1]); @@ -614,13 +621,13 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { video->renderer->writePalette(video->renderer, 12, video->palette[12]); break; case SGB_PAL23: - video->palette[9] = data[3] | (data[4] << 8); - video->palette[10] = data[5] | (data[6] << 8); - video->palette[11] = data[7] | (data[8] << 8); + video->palette[9] = video->sgbPacketBuffer[3] | (video->sgbPacketBuffer[4] << 8); + video->palette[10] = video->sgbPacketBuffer[5] | (video->sgbPacketBuffer[6] << 8); + video->palette[11] = video->sgbPacketBuffer[7] | (video->sgbPacketBuffer[8] << 8); - video->palette[13] = data[9] | (data[10] << 8); - video->palette[14] = data[11] | (data[12] << 8); - video->palette[15] = data[13] | (data[14] << 8); + video->palette[13] = video->sgbPacketBuffer[9] | (video->sgbPacketBuffer[10] << 8); + video->palette[14] = video->sgbPacketBuffer[11] | (video->sgbPacketBuffer[12] << 8); + video->palette[15] = video->sgbPacketBuffer[13] | (video->sgbPacketBuffer[14] << 8); video->renderer->writePalette(video->renderer, 9, video->palette[9]); video->renderer->writePalette(video->renderer, 10, video->palette[10]); video->renderer->writePalette(video->renderer, 11, video->palette[11]); @@ -629,18 +636,18 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { video->renderer->writePalette(video->renderer, 15, video->palette[15]); break; case SGB_PAL03: - video->palette[0] = data[1] | (data[2] << 8); - video->palette[1] = data[3] | (data[4] << 8); - video->palette[2] = data[5] | (data[6] << 8); - video->palette[3] = data[7] | (data[8] << 8); + video->palette[0] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[1] = video->sgbPacketBuffer[3] | (video->sgbPacketBuffer[4] << 8); + video->palette[2] = video->sgbPacketBuffer[5] | (video->sgbPacketBuffer[6] << 8); + video->palette[3] = video->sgbPacketBuffer[7] | (video->sgbPacketBuffer[8] << 8); - video->palette[4] = data[1] | (data[2] << 8); - video->palette[8] = data[1] | (data[2] << 8); + video->palette[4] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[8] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); - video->palette[12] = data[1] | (data[2] << 8); - video->palette[13] = data[9] | (data[10] << 8); - video->palette[14] = data[11] | (data[12] << 8); - video->palette[15] = data[13] | (data[14] << 8); + video->palette[12] = video->sgbPacketBuffer[1] | (video->sgbPacketBuffer[2] << 8); + video->palette[13] = video->sgbPacketBuffer[9] | (video->sgbPacketBuffer[10] << 8); + video->palette[14] = video->sgbPacketBuffer[11] | (video->sgbPacketBuffer[12] << 8); + video->palette[15] = video->sgbPacketBuffer[13] | (video->sgbPacketBuffer[14] << 8); video->renderer->writePalette(video->renderer, 0, video->palette[0]); video->renderer->writePalette(video->renderer, 1, video->palette[1]); video->renderer->writePalette(video->renderer, 2, video->palette[2]); @@ -653,13 +660,13 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { video->renderer->writePalette(video->renderer, 15, video->palette[15]); break; case SGB_PAL12: - video->palette[5] = data[3] | (data[4] << 8); - video->palette[6] = data[5] | (data[6] << 8); - video->palette[7] = data[7] | (data[8] << 8); + video->palette[5] = video->sgbPacketBuffer[3] | (video->sgbPacketBuffer[4] << 8); + video->palette[6] = video->sgbPacketBuffer[5] | (video->sgbPacketBuffer[6] << 8); + video->palette[7] = video->sgbPacketBuffer[7] | (video->sgbPacketBuffer[8] << 8); - video->palette[9] = data[9] | (data[10] << 8); - video->palette[10] = data[11] | (data[12] << 8); - video->palette[11] = data[13] | (data[14] << 8); + video->palette[9] = video->sgbPacketBuffer[9] | (video->sgbPacketBuffer[10] << 8); + video->palette[10] = video->sgbPacketBuffer[11] | (video->sgbPacketBuffer[12] << 8); + video->palette[11] = video->sgbPacketBuffer[13] | (video->sgbPacketBuffer[14] << 8); video->renderer->writePalette(video->renderer, 5, video->palette[5]); video->renderer->writePalette(video->renderer, 6, video->palette[6]); video->renderer->writePalette(video->renderer, 7, video->palette[7]); @@ -669,7 +676,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { break; case SGB_PAL_SET: for (i = 0; i < 4; ++i) { - uint16_t entry = (data[2 + (i * 2)] << 8) | data[1 + (i * 2)]; + uint16_t entry = (video->sgbPacketBuffer[2 + (i * 2)] << 8) | video->sgbPacketBuffer[1 + (i * 2)]; if (entry >= 0x200) { mLOG(GB, STUB, "Unimplemented SGB palette overflow: %03X", entry); continue; @@ -685,6 +692,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { } break; case SGB_ATTR_BLK: + case SGB_ATTR_DIV: case SGB_ATTR_CHR: case SGB_PAL_TRN: case SGB_ATRC_EN: @@ -693,16 +701,17 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { case SGB_ATTR_TRN: case SGB_ATTR_SET: break; - case SGB_MLT_REG: + case SGB_MLT_REQ: + video->p->sgbControllers = video->sgbPacketBuffer[1] & 0x3; return; case SGB_MASK_EN: - video->renderer->sgbRenderMode = data[1] & 0x3; + video->renderer->sgbRenderMode = video->sgbPacketBuffer[1] & 0x3; break; default: - mLOG(GB, STUB, "Unimplemented SGB command: %02X", data[0] >> 3); + mLOG(GB, STUB, "Unimplemented SGB command: %02X", video->sgbPacketBuffer[0] >> 3); return; } - video->renderer->writeSGBPacket(video->renderer, data); + video->renderer->writeSGBPacket(video->renderer, video->sgbPacketBuffer); } static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model, bool borders) {