mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
c144b40709
3
CHANGES
3
CHANGES
|
@ -54,15 +54,18 @@ Features:
|
|||
Emulation fixes:
|
||||
- ARM7: Fix unsigned multiply timing
|
||||
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
|
||||
- GB Serialize: Fix loading MBC1 states that affect bank 0 (fixes mgba.io/i/2402)
|
||||
- GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339)
|
||||
- GBA: Improve timing when not booting from BIOS
|
||||
- GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059)
|
||||
- GBA BIOS: Initial HLE timing estimation of UnLz77 functions (fixes mgba.io/i/2141)
|
||||
- GBA DMA: Fix DMA source direction bits being cleared (fixes mgba.io/i/2410)
|
||||
- GBA I/O: Redo internal key input, enabling edge-based key IRQs
|
||||
- GBA I/O: Disable open bus behavior on invalid register 06A
|
||||
- GBA Memory: Fix misaligned 32-bit I/O loads (fixes mgba.io/i/2307)
|
||||
- GBA Video: Fix OpenGL rendering on M1 Macs
|
||||
- GBA Video: Ignore horizontally off-screen sprite timing (fixes mgba.io/i/2391)
|
||||
- GBA Video: Fix Hblank timing (fixes mgba.io/i/2131, mgba.io/i/2310)
|
||||
Other fixes:
|
||||
- Core: Don't attempt to restore rewind diffs past start of rewind
|
||||
- FFmpeg: Fix crash when encoding audio with some containers
|
||||
|
|
|
@ -72,6 +72,7 @@ if(NOT LIBMGBA_ONLY)
|
|||
set(BUILD_TEST OFF CACHE BOOL "Build testing harness")
|
||||
set(BUILD_SUITE OFF CACHE BOOL "Build test suite")
|
||||
set(BUILD_CINEMA OFF CACHE BOOL "Build video tests suite")
|
||||
set(BUILD_ROM_TEST OFF CACHE BOOL "Build ROM test tool")
|
||||
set(BUILD_EXAMPLE OFF CACHE BOOL "Build example frontends")
|
||||
set(BUILD_PYTHON OFF CACHE BOOL "Build Python bindings")
|
||||
set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
|
||||
|
@ -1250,12 +1251,14 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY)
|
|||
message(STATUS "Frontends:")
|
||||
message(STATUS " Qt: ${BUILD_QT}")
|
||||
message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}")
|
||||
message(STATUS " Python bindings: ${BUILD_PYTHON}")
|
||||
message(STATUS " Examples: ${BUILD_EXAMPLE}")
|
||||
message(STATUS "Test tools:")
|
||||
message(STATUS " Profiling: ${BUILD_PERF}")
|
||||
message(STATUS " Test harness: ${BUILD_TEST}")
|
||||
message(STATUS " Test suite: ${BUILD_SUITE}")
|
||||
message(STATUS " Video test suite: ${BUILD_CINEMA}")
|
||||
message(STATUS " Python bindings: ${BUILD_PYTHON}")
|
||||
message(STATUS " Examples: ${BUILD_EXAMPLE}")
|
||||
message(STATUS " ROM tester: ${BUILD_ROM_TEST}")
|
||||
message(STATUS "Cores:")
|
||||
message(STATUS " Libretro core: ${BUILD_LIBRETRO}")
|
||||
if(APPLE)
|
||||
|
|
|
@ -46,6 +46,9 @@ struct GBAVideoSoftwareBackground {
|
|||
uint16_t mapCache[64];
|
||||
color_t* extPalette;
|
||||
color_t* variantPalette;
|
||||
uint32_t flags;
|
||||
uint32_t objwinFlags;
|
||||
bool variant;
|
||||
int32_t offsetX;
|
||||
int32_t offsetY;
|
||||
bool highlight;
|
||||
|
|
|
@ -18,9 +18,8 @@ mLOG_DECLARE_CATEGORY(GBA_VIDEO);
|
|||
|
||||
enum {
|
||||
VIDEO_HBLANK_PIXELS = 68,
|
||||
VIDEO_HDRAW_LENGTH = 960,
|
||||
VIDEO_HBLANK_LENGTH = 272,
|
||||
VIDEO_HBLANK_FLIP = 46,
|
||||
VIDEO_HDRAW_LENGTH = 1008,
|
||||
VIDEO_HBLANK_LENGTH = 224,
|
||||
VIDEO_HORIZONTAL_LENGTH = 1232,
|
||||
|
||||
VIDEO_VBLANK_PIXELS = 68,
|
||||
|
|
|
@ -820,7 +820,7 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
memory->mbcState.mbc1.bankHi = memory->currentBank >> memory->mbcState.mbc1.multicartStride;
|
||||
}
|
||||
if (memory->mbcState.mbc1.mode) {
|
||||
GBMBCSwitchBank0(gb, memory->mbcState.mbc1.bankHi);
|
||||
GBMBCSwitchBank0(gb, memory->mbcState.mbc1.bankHi << memory->mbcState.mbc1.multicartStride);
|
||||
}
|
||||
break;
|
||||
case GB_MBC3_RTC:
|
||||
|
|
|
@ -536,6 +536,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
|||
case REGION_WORKING_RAM:
|
||||
case REGION_WORKING_IRAM:
|
||||
case REGION_VRAM:
|
||||
useStall = true;
|
||||
_unLz77(gba, immediate == GBA_SWI_LZ77_UNCOMP_WRAM ? 1 : 2);
|
||||
break;
|
||||
}
|
||||
|
@ -644,7 +645,8 @@ static void _unLz77(struct GBA* gba, int width) {
|
|||
struct ARMCore* cpu = gba->cpu;
|
||||
uint32_t source = cpu->gprs[0];
|
||||
uint32_t dest = cpu->gprs[1];
|
||||
int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8;
|
||||
int32_t cycles = 20;
|
||||
int remaining = (cpu->memory.load32(cpu, source, &cycles) & 0xFFFFFF00) >> 8;
|
||||
// We assume the signature byte (0x10) is correct
|
||||
int blockheader = 0; // Some compilers warn if this isn't set, even though it's trivially provably always set
|
||||
source += 4;
|
||||
|
@ -654,14 +656,17 @@ static void _unLz77(struct GBA* gba, int width) {
|
|||
int byte;
|
||||
int halfword = 0;
|
||||
while (remaining > 0) {
|
||||
cycles += 14;
|
||||
if (blocksRemaining) {
|
||||
cycles += 18;
|
||||
if (blockheader & 0x80) {
|
||||
// Compressed
|
||||
int block = cpu->memory.load8(cpu, source + 1, 0) | (cpu->memory.load8(cpu, source, 0) << 8);
|
||||
int block = cpu->memory.load8(cpu, source + 1, &cycles) | (cpu->memory.load8(cpu, source, &cycles) << 8);
|
||||
source += 2;
|
||||
disp = dest - (block & 0x0FFF) - 1;
|
||||
bytes = (block >> 12) + 3;
|
||||
while (bytes--) {
|
||||
cycles += 10;
|
||||
if (remaining) {
|
||||
--remaining;
|
||||
} else {
|
||||
|
@ -673,35 +678,36 @@ static void _unLz77(struct GBA* gba, int width) {
|
|||
}
|
||||
}
|
||||
if (width == 2) {
|
||||
byte = (int16_t) cpu->memory.load16(cpu, disp & ~1, 0);
|
||||
byte = (int16_t) cpu->memory.load16(cpu, disp & ~1, &cycles);
|
||||
if (dest & 1) {
|
||||
byte >>= (disp & 1) * 8;
|
||||
halfword |= byte << 8;
|
||||
cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
|
||||
cpu->memory.store16(cpu, dest ^ 1, halfword, &cycles);
|
||||
} else {
|
||||
byte >>= (disp & 1) * 8;
|
||||
halfword = byte & 0xFF;
|
||||
}
|
||||
cycles += 4;
|
||||
} else {
|
||||
byte = cpu->memory.load8(cpu, disp, 0);
|
||||
cpu->memory.store8(cpu, dest, byte, 0);
|
||||
byte = cpu->memory.load8(cpu, disp, &cycles);
|
||||
cpu->memory.store8(cpu, dest, byte, &cycles);
|
||||
}
|
||||
++disp;
|
||||
++dest;
|
||||
}
|
||||
} else {
|
||||
// Uncompressed
|
||||
byte = cpu->memory.load8(cpu, source, 0);
|
||||
byte = cpu->memory.load8(cpu, source, &cycles);
|
||||
++source;
|
||||
if (width == 2) {
|
||||
if (dest & 1) {
|
||||
halfword |= byte << 8;
|
||||
cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
|
||||
cpu->memory.store16(cpu, dest ^ 1, halfword, &cycles);
|
||||
} else {
|
||||
halfword = byte;
|
||||
}
|
||||
} else {
|
||||
cpu->memory.store8(cpu, dest, byte, 0);
|
||||
cpu->memory.store8(cpu, dest, byte, &cycles);
|
||||
}
|
||||
++dest;
|
||||
--remaining;
|
||||
|
@ -709,7 +715,7 @@ static void _unLz77(struct GBA* gba, int width) {
|
|||
blockheader <<= 1;
|
||||
--blocksRemaining;
|
||||
} else {
|
||||
blockheader = cpu->memory.load8(cpu, source, 0);
|
||||
blockheader = cpu->memory.load8(cpu, source, &cycles);
|
||||
++source;
|
||||
blocksRemaining = 8;
|
||||
}
|
||||
|
@ -717,6 +723,7 @@ static void _unLz77(struct GBA* gba, int width) {
|
|||
cpu->gprs[0] = source;
|
||||
cpu->gprs[1] = dest;
|
||||
cpu->gprs[3] = 0;
|
||||
gba->biosStall = cycles;
|
||||
}
|
||||
|
||||
DECL_BITFIELD(HuffmanNode, uint8_t);
|
||||
|
|
|
@ -26,7 +26,7 @@ const uint8_t hleBios[SIZE_BIOS] = {
|
|||
0x48, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
|
||||
0x48, 0x03, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||
|
|
|
@ -137,8 +137,6 @@ GetBiosChecksum:
|
|||
BgAffineSet:
|
||||
ObjAffineSet:
|
||||
BitUnPack:
|
||||
Lz77UnCompWram:
|
||||
Lz77UnCompVram:
|
||||
HuffmanUnComp:
|
||||
RlUnCompWram:
|
||||
RlUnCompVram:
|
||||
|
@ -308,6 +306,8 @@ DivArm:
|
|||
Sqrt:
|
||||
ArcTan:
|
||||
ArcTan2:
|
||||
Lz77UnCompWram:
|
||||
Lz77UnCompVram:
|
||||
|
||||
StallCall:
|
||||
subs r11, #4
|
||||
|
|
|
@ -747,19 +747,12 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer
|
|||
|
||||
unsigned xBase;
|
||||
|
||||
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND;
|
||||
flags |= FLAG_TARGET_2 * background->target2;
|
||||
int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed));
|
||||
objwinFlags |= flags;
|
||||
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed));
|
||||
if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) {
|
||||
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
|
||||
objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
|
||||
}
|
||||
uint32_t flags = background->flags;
|
||||
uint32_t objwinFlags = background->objwinFlags;
|
||||
bool variant = background->variant;
|
||||
|
||||
uint32_t screenBase;
|
||||
uint32_t charBase;
|
||||
int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
|
||||
color_t* mainPalette = renderer->normalPalette;
|
||||
if (background->multipalette && background->extPalette) {
|
||||
mainPalette = background->extPalette;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#define VIDEO_CHECKS true
|
||||
#endif
|
||||
|
||||
#define ENABLED_MAX 4
|
||||
|
||||
void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer,
|
||||
struct GBAVideoSoftwareBackground* background, int y);
|
||||
void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer,
|
||||
|
@ -191,19 +193,9 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
|
|||
localY += background->sy + startX * background->dy; \
|
||||
} \
|
||||
\
|
||||
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
|
||||
flags |= FLAG_TARGET_2 * background->target2; \
|
||||
int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
||||
GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \
|
||||
objwinFlags |= flags; \
|
||||
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
||||
GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \
|
||||
if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) { \
|
||||
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
||||
objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
||||
} \
|
||||
int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && \
|
||||
(renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \
|
||||
uint32_t flags = background->flags; \
|
||||
uint32_t objwinFlags = background->objwinFlags; \
|
||||
bool variant = background->variant; \
|
||||
color_t* palette = renderer->normalPalette; \
|
||||
if (renderer->d.highlightAmount && background->highlight) { \
|
||||
palette = renderer->highlightPalette; \
|
||||
|
@ -219,7 +211,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
|
|||
|
||||
#define TEST_LAYER_ENABLED(X) \
|
||||
!softwareRenderer->d.disableBG[X] && \
|
||||
(softwareRenderer->bg[X].enabled == 4 && \
|
||||
(softwareRenderer->bg[X].enabled == ENABLED_MAX && \
|
||||
(GBAWindowControlIsBg ## X ## Enable(softwareRenderer->currentWindow.packed) || \
|
||||
(GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (softwareRenderer->objwin.packed))) && \
|
||||
softwareRenderer->bg[X].priority == priority)
|
||||
|
|
|
@ -36,6 +36,7 @@ static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackgroun
|
|||
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
|
||||
|
||||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static void _updateFlags(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg);
|
||||
|
||||
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y);
|
||||
static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win);
|
||||
|
@ -563,11 +564,11 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
|||
|
||||
if (!dirty) {
|
||||
if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
|
||||
if (softwareRenderer->bg[2].enabled == 4) {
|
||||
if (softwareRenderer->bg[2].enabled == ENABLED_MAX) {
|
||||
softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
|
||||
softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
|
||||
}
|
||||
if (softwareRenderer->bg[3].enabled == 4) {
|
||||
if (softwareRenderer->bg[3].enabled == ENABLED_MAX) {
|
||||
softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
|
||||
softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
|
||||
}
|
||||
|
@ -603,6 +604,40 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
|||
softwareRenderer->start = softwareRenderer->end;
|
||||
softwareRenderer->end = softwareRenderer->windows[w].endX;
|
||||
softwareRenderer->currentWindow = softwareRenderer->windows[w].control;
|
||||
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
|
||||
case 0:
|
||||
if (softwareRenderer->bg[0].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[0]);
|
||||
}
|
||||
if (softwareRenderer->bg[1].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[1]);
|
||||
}
|
||||
// Fall through
|
||||
case 2:
|
||||
if (softwareRenderer->bg[3].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[3]);
|
||||
}
|
||||
// Fall through
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
if (softwareRenderer->bg[2].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[2]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (softwareRenderer->bg[0].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[0]);
|
||||
}
|
||||
if (softwareRenderer->bg[1].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[1]);
|
||||
}
|
||||
if (softwareRenderer->bg[2].enabled == ENABLED_MAX) {
|
||||
_updateFlags(softwareRenderer, &softwareRenderer->bg[2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (priority = 0; priority < 4; ++priority) {
|
||||
if (spriteLayers & (1 << priority)) {
|
||||
GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority);
|
||||
|
@ -649,29 +684,29 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
|||
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
|
||||
|
||||
if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
|
||||
if (softwareRenderer->bg[2].enabled == 4) {
|
||||
if (softwareRenderer->bg[2].enabled == ENABLED_MAX) {
|
||||
softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
|
||||
softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
|
||||
}
|
||||
if (softwareRenderer->bg[3].enabled == 4) {
|
||||
if (softwareRenderer->bg[3].enabled == ENABLED_MAX) {
|
||||
softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
|
||||
softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
|
||||
}
|
||||
}
|
||||
|
||||
if (softwareRenderer->bg[0].enabled != 0 && softwareRenderer->bg[0].enabled < 4) {
|
||||
if (softwareRenderer->bg[0].enabled != 0 && softwareRenderer->bg[0].enabled < ENABLED_MAX) {
|
||||
++softwareRenderer->bg[0].enabled;
|
||||
DIRTY_SCANLINE(softwareRenderer, y);
|
||||
}
|
||||
if (softwareRenderer->bg[1].enabled != 0 && softwareRenderer->bg[1].enabled < 4) {
|
||||
if (softwareRenderer->bg[1].enabled != 0 && softwareRenderer->bg[1].enabled < ENABLED_MAX) {
|
||||
++softwareRenderer->bg[1].enabled;
|
||||
DIRTY_SCANLINE(softwareRenderer, y);
|
||||
}
|
||||
if (softwareRenderer->bg[2].enabled != 0 && softwareRenderer->bg[2].enabled < 4) {
|
||||
if (softwareRenderer->bg[2].enabled != 0 && softwareRenderer->bg[2].enabled < ENABLED_MAX) {
|
||||
++softwareRenderer->bg[2].enabled;
|
||||
DIRTY_SCANLINE(softwareRenderer, y);
|
||||
}
|
||||
if (softwareRenderer->bg[3].enabled != 0 && softwareRenderer->bg[3].enabled < 4) {
|
||||
if (softwareRenderer->bg[3].enabled != 0 && softwareRenderer->bg[3].enabled < ENABLED_MAX) {
|
||||
++softwareRenderer->bg[3].enabled;
|
||||
DIRTY_SCANLINE(softwareRenderer, y);
|
||||
}
|
||||
|
@ -717,16 +752,16 @@ static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* rendere
|
|||
softwareRenderer->bg[3].sy = softwareRenderer->bg[3].refy;
|
||||
|
||||
if (softwareRenderer->bg[0].enabled > 0) {
|
||||
softwareRenderer->bg[0].enabled = 4;
|
||||
softwareRenderer->bg[0].enabled = ENABLED_MAX;
|
||||
}
|
||||
if (softwareRenderer->bg[1].enabled > 0) {
|
||||
softwareRenderer->bg[1].enabled = 4;
|
||||
softwareRenderer->bg[1].enabled = ENABLED_MAX;
|
||||
}
|
||||
if (softwareRenderer->bg[2].enabled > 0) {
|
||||
softwareRenderer->bg[2].enabled = 4;
|
||||
softwareRenderer->bg[2].enabled = ENABLED_MAX;
|
||||
}
|
||||
if (softwareRenderer->bg[3].enabled > 0) {
|
||||
softwareRenderer->bg[3].enabled = 4;
|
||||
softwareRenderer->bg[3].enabled = ENABLED_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,22 +784,22 @@ static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer,
|
|||
static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool active) {
|
||||
int wasActive = renderer->bg[bg].enabled;
|
||||
if (!active) {
|
||||
if (renderer->nextY == 0 || (wasActive > 0 && wasActive < 4)) {
|
||||
if (renderer->nextY == 0 || (wasActive > 0 && wasActive < ENABLED_MAX)) {
|
||||
renderer->bg[bg].enabled = 0;
|
||||
} else if (wasActive == 4) {
|
||||
} else if (wasActive == ENABLED_MAX) {
|
||||
renderer->bg[bg].enabled = -2;
|
||||
}
|
||||
} else if (!wasActive && active) {
|
||||
if (renderer->nextY == 0) {
|
||||
// TODO: Investigate in more depth how switching background works in different modes
|
||||
renderer->bg[bg].enabled = 4;
|
||||
renderer->bg[bg].enabled = ENABLED_MAX;
|
||||
} else if (GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
|
||||
renderer->bg[bg].enabled = 2;
|
||||
} else {
|
||||
renderer->bg[bg].enabled = 1;
|
||||
}
|
||||
} else if (wasActive < 0 && active) {
|
||||
renderer->bg[bg].enabled = 4;
|
||||
renderer->bg[bg].enabled = ENABLED_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -788,6 +823,8 @@ static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer*
|
|||
bg->size = GBARegisterBGCNTGetSize(value);
|
||||
bg->control = value;
|
||||
bg->yCache = -1;
|
||||
|
||||
_updateFlags(renderer, bg);
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererWriteBGX_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
|
||||
|
@ -1037,3 +1074,27 @@ static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _updateFlags(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background) {
|
||||
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND;
|
||||
if (background->target2) {
|
||||
flags |= FLAG_TARGET_2;
|
||||
}
|
||||
uint32_t objwinFlags = flags;
|
||||
if (renderer->blendEffect == BLEND_ALPHA) {
|
||||
if (renderer->blda == 0x10 && renderer->bldb == 0) {
|
||||
flags &= ~FLAG_TARGET_2;
|
||||
objwinFlags &= ~FLAG_TARGET_2;
|
||||
} else if (background->target1) {
|
||||
if (GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)) {
|
||||
flags |= FLAG_TARGET_1;
|
||||
}
|
||||
if (GBAWindowControlIsBlendEnable(renderer->objwin.packed)) {
|
||||
objwinFlags |= FLAG_TARGET_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
background->flags = flags;
|
||||
background->objwinFlags = objwinFlags;
|
||||
background->variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ static void GBAVideoDummyRendererGetPixels(struct GBAVideoRenderer* renderer, si
|
|||
static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
|
||||
|
||||
static void _startHblank(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||
static void _midHblank(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||
static void _startHdraw(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||
|
||||
static uint16_t _zeroes[0x2000] = {0};
|
||||
|
@ -161,15 +160,6 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer*
|
|||
}
|
||||
}
|
||||
|
||||
void _midHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct GBAVideo* video = context;
|
||||
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
|
||||
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
||||
video->event.callback = _startHdraw;
|
||||
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_FLIP - cyclesLate);
|
||||
}
|
||||
|
||||
void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct GBAVideo* video = context;
|
||||
video->event.callback = _startHblank;
|
||||
|
@ -186,6 +176,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
}
|
||||
|
||||
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
|
||||
if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
|
||||
dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
|
||||
if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
|
||||
|
@ -227,8 +218,8 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
|
||||
void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct GBAVideo* video = context;
|
||||
video->event.callback = _midHblank;
|
||||
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - VIDEO_HBLANK_FLIP - cyclesLate);
|
||||
video->event.callback = _startHdraw;
|
||||
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - cyclesLate);
|
||||
|
||||
// Begin Hblank
|
||||
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||
|
@ -244,7 +235,7 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
GBADMARunDisplayStart(video->p, -cyclesLate);
|
||||
}
|
||||
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
|
||||
GBARaiseIRQ(video->p, IRQ_HBLANK, cyclesLate);
|
||||
GBARaiseIRQ(video->p, IRQ_HBLANK, cyclesLate - 6); // TODO: Where does this fudge factor come from?
|
||||
}
|
||||
video->shouldStall = 0;
|
||||
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
||||
|
@ -366,8 +357,6 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState*
|
|||
flags = GBASerializedVideoFlagsSetMode(flags, 1);
|
||||
} else if (video->event.callback == _startHblank) {
|
||||
flags = GBASerializedVideoFlagsSetMode(flags, 2);
|
||||
} else if (video->event.callback == _midHblank) {
|
||||
flags = GBASerializedVideoFlagsSetMode(flags, 3);
|
||||
}
|
||||
STORE_32(flags, 0, &state->video.flags);
|
||||
STORE_32(video->frameCounter, 0, &state->video.frameCounter);
|
||||
|
@ -407,7 +396,7 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState
|
|||
video->shouldStall = 1;
|
||||
break;
|
||||
case 3:
|
||||
video->event.callback = _midHblank;
|
||||
video->event.callback = _startHdraw;
|
||||
break;
|
||||
}
|
||||
uint32_t when;
|
||||
|
|
|
@ -9,11 +9,17 @@
|
|||
#include <mgba/core/config.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/serialize.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/sm83/sm83.h>
|
||||
#endif
|
||||
|
||||
#include <mgba/feature/commandline.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define ROM_TEST_OPTIONS "S:R:"
|
||||
|
@ -48,6 +54,21 @@ void (*_armSwi16)(struct ARMCore* cpu, int immediate);
|
|||
void (*_armSwi32)(struct ARMCore* cpu, int immediate);
|
||||
#endif
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
enum GBReg {
|
||||
GB_REG_A = 16,
|
||||
GB_REG_F,
|
||||
GB_REG_B,
|
||||
GB_REG_C,
|
||||
GB_REG_D,
|
||||
GB_REG_E,
|
||||
GB_REG_H,
|
||||
GB_REG_L
|
||||
};
|
||||
|
||||
static void _romTestGBCallback(void* context);
|
||||
#endif
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
signal(SIGINT, _romTestShutdown);
|
||||
|
||||
|
@ -82,17 +103,22 @@ int main(int argc, char * argv[]) {
|
|||
|
||||
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
|
||||
|
||||
bool cleanExit = false;
|
||||
struct mCoreCallbacks callbacks = {0};
|
||||
callbacks.context = core;
|
||||
switch (core->platform(core)) {
|
||||
#ifdef M_CORE_GBA
|
||||
if (core->platform(core) == mPLATFORM_GBA) {
|
||||
case mPLATFORM_GBA:
|
||||
((struct GBA*) core->board)->hardCrash = false;
|
||||
if (romTestOpts.returnCodeRegister >= 16) {
|
||||
goto loadError;
|
||||
}
|
||||
|
||||
_exitSwiImmediate = romTestOpts.exitSwiImmediate;
|
||||
_returnCodeRegister = romTestOpts.returnCodeRegister;
|
||||
|
||||
if (_exitSwiImmediate == 3) {
|
||||
// Hook into SWI 3 (shutdown)
|
||||
struct mCoreCallbacks callbacks = {0};
|
||||
callbacks.context = core;
|
||||
callbacks.shutdown = _romTestSwi3Callback;
|
||||
core->addCoreCallbacks(core, &callbacks);
|
||||
} else {
|
||||
|
@ -102,12 +128,25 @@ int main(int argc, char * argv[]) {
|
|||
_armSwi32 = ((struct GBA*) core->board)->cpu->irqh.swi32;
|
||||
((struct GBA*) core->board)->cpu->irqh.swi32 = _romTestSwi32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
case mPLATFORM_GB:
|
||||
if (romTestOpts.returnCodeRegister < GB_REG_A) {
|
||||
goto loadError;
|
||||
}
|
||||
|
||||
_returnCodeRegister = romTestOpts.returnCodeRegister;
|
||||
|
||||
callbacks.shutdown = _romTestGBCallback;
|
||||
core->addCoreCallbacks(core, &callbacks);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto loadError;
|
||||
}
|
||||
|
||||
bool cleanExit = true;
|
||||
if (!mCoreLoadFile(core, args.fname)) {
|
||||
cleanExit = false;
|
||||
goto loadError;
|
||||
}
|
||||
if (args.patch) {
|
||||
|
@ -142,6 +181,7 @@ int main(int argc, char * argv[]) {
|
|||
} while (!_dispatchExiting);
|
||||
|
||||
core->unloadROM(core);
|
||||
cleanExit = true;
|
||||
|
||||
loadError:
|
||||
freeArguments(&args);
|
||||
|
@ -182,6 +222,41 @@ static void _romTestSwi32(struct ARMCore* cpu, int immediate) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
static void _romTestGBCallback(void* context) {
|
||||
struct mCore* core = context;
|
||||
struct SM83Core* cpu = core->cpu;
|
||||
|
||||
switch (_returnCodeRegister) {
|
||||
case GB_REG_A:
|
||||
_exitCode = cpu->a;
|
||||
break;
|
||||
case GB_REG_B:
|
||||
_exitCode = cpu->b;
|
||||
break;
|
||||
case GB_REG_C:
|
||||
_exitCode = cpu->c;
|
||||
break;
|
||||
case GB_REG_D:
|
||||
_exitCode = cpu->d;
|
||||
break;
|
||||
case GB_REG_E:
|
||||
_exitCode = cpu->e;
|
||||
break;
|
||||
case GB_REG_F:
|
||||
_exitCode = cpu->f.packed;
|
||||
break;
|
||||
case GB_REG_H:
|
||||
_exitCode = cpu->h;
|
||||
break;
|
||||
case GB_REG_L:
|
||||
_exitCode = cpu->l;
|
||||
break;
|
||||
}
|
||||
_dispatchExiting = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool _parseRomTestOpts(struct mSubParser* parser, int option, const char* arg) {
|
||||
struct RomTestOpts* opts = parser->opts;
|
||||
errno = 0;
|
||||
|
@ -206,8 +281,63 @@ static bool _parseSwi(const char* swiStr, int* oSwi) {
|
|||
}
|
||||
|
||||
static bool _parseNamedRegister(const char* regStr, unsigned int* oRegister) {
|
||||
if (regStr[0] == 'r' || regStr[0] == 'R') {
|
||||
#ifdef M_CORE_GB
|
||||
static const enum GBReg gbMapping[] = {
|
||||
['a' - 'a'] = GB_REG_A,
|
||||
['b' - 'a'] = GB_REG_B,
|
||||
['c' - 'a'] = GB_REG_C,
|
||||
['d' - 'a'] = GB_REG_D,
|
||||
['e' - 'a'] = GB_REG_E,
|
||||
['f' - 'a'] = GB_REG_F,
|
||||
['h' - 'a'] = GB_REG_H,
|
||||
['l' - 'a'] = GB_REG_L,
|
||||
};
|
||||
#endif
|
||||
|
||||
switch (regStr[0]) {
|
||||
case 'r':
|
||||
case 'R':
|
||||
++regStr;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
break;
|
||||
#ifdef M_CORE_GB
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'h':
|
||||
case 'l':
|
||||
if (regStr[1] != '\0') {
|
||||
return false;
|
||||
}
|
||||
*oRegister = gbMapping[regStr[0] - 'a'];
|
||||
break;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'H':
|
||||
case 'L':
|
||||
if (regStr[1] != '\0') {
|
||||
return false;
|
||||
}
|
||||
*oRegister = gbMapping[regStr[0] - 'A'];
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
char* parseEnd;
|
||||
|
|
Loading…
Reference in New Issue