diff --git a/Info.plist b/Info.plist index 40a8bce..772168d 100644 --- a/Info.plist +++ b/Info.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 0.7.0 + 0.7.1 NSPrincipalClass OEGameCoreController OEGameCoreClass diff --git a/src/gb/gb.c b/src/gb/gb.c index 508483c..038401c 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -202,7 +202,7 @@ void GBResizeSram(struct GB* gb, size_t size) { if (gb->memory.sram == (void*) -1) { gb->memory.sram = NULL; } - } else { + } else if (size) { uint8_t* newSram = anonymousMemoryMap(size); if (gb->memory.sram) { if (size > gb->sramSize) { diff --git a/src/gb/serialize.c b/src/gb/serialize.c index 4eef6ae..7a4f5de 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -113,7 +113,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { error = true; } LOAD_16LE(check16, 0, &state->video.x); - if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) { + if (check16 < -7 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) { mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range"); error = true; } @@ -138,7 +138,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { if (error) { return false; } - gb->timing.root = NULL; + mTimingClear(&gb->timing); LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles); gb->cpu->a = state->cpu.a; diff --git a/src/gba/dma.c b/src/gba/dma.c index 2eded79..96b1038 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -182,7 +182,7 @@ void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { dma->nextCount = 0; bool noRepeat = !GBADMARegisterIsRepeat(dma->reg); noRepeat |= GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_NOW; - noRepeat |= memory->activeDMA == 3 && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM; + noRepeat |= memory->activeDMA == 3 && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM && gba->video.vcount == VIDEO_VERTICAL_PIXELS + 1; if (noRepeat) { dma->reg = GBADMARegisterClearEnable(dma->reg); @@ -237,9 +237,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { gba->cpuBlocked = true; if (info->count == info->nextCount) { - if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { - cycles += 2; - } if (width == 4) { cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion]; } else { @@ -263,8 +260,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } gba->bus = memory->dmaTransferRegister; cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0); - memory->dmaTransferRegister &= 0xFFFF0000; - memory->dmaTransferRegister |= memory->dmaTransferRegister >> 16; } else { if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) { if (memory->savedata.type == SAVEDATA_AUTODETECT) { @@ -272,10 +267,10 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { GBASavedataInitEEPROM(&memory->savedata); } memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata); - } else { - if (source) { - memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0); - } + memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; + } else if (source) { + memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0); + memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; } if (destRegion == REGION_CART2_EX) { if (memory->savedata.type == SAVEDATA_AUTODETECT) { @@ -289,7 +284,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0); } - memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; gba->bus = memory->dmaTransferRegister; } int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width; @@ -306,6 +300,9 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { info->nextDest = dest; if (!wordsRemaining) { info->nextCount |= 0x80000000; + if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { + info->when += 2; + } } GBADMAUpdate(gba); } diff --git a/src/gba/gba.c b/src/gba/gba.c index 9441105..92e4e31 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -232,7 +232,8 @@ void GBASkipBIOS(struct GBA* gba) { } else { cpu->gprs[ARM_PC] = BASE_WORKING_RAM; } - gba->memory.io[REG_VCOUNT >> 1] = 0x7E; + gba->video.vcount = 0x7D; + gba->memory.io[REG_VCOUNT >> 1] = 0x7D; gba->memory.io[REG_POSTFLG >> 1] = 1; int currentCycles = 0; ARM_WRITE_PC; diff --git a/src/gba/memory.c b/src/gba/memory.c index 53fd573..c779853 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -1647,6 +1647,10 @@ void _pristineCow(struct GBA* gba) { } void GBAPrintFlush(struct GBA* gba) { + if (!gba->memory.agbPrintBuffer) { + return; + } + char oolBuf[0x101]; size_t i; for (i = 0; gba->memory.agbPrintCtx.get != gba->memory.agbPrintCtx.put && i < 0x100; ++i) { @@ -1688,8 +1692,8 @@ static void _agbPrintStore(struct GBA* gba, uint32_t address, int16_t value) { static int16_t _agbPrintLoad(struct GBA* gba, uint32_t address) { struct GBAMemory* memory = &gba->memory; - int16_t value = 0xFFFF; - if (address < AGB_PRINT_TOP) { + int16_t value = address >> 1; + if (address < AGB_PRINT_TOP && memory->agbPrintBuffer) { LOAD_16(value, address & (SIZE_AGB_PRINT - 1), memory->agbPrintBuffer); } else if ((address & 0x00FFFFF8) == (AGB_PRINT_STRUCT & 0x00FFFFF8)) { value = (&memory->agbPrintCtx.request)[(address & 7) >> 1]; diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 615e13c..ad846ac 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -27,9 +27,6 @@ } \ } \ for (; outX < condition; ++outX, inX += xOffset) { \ - if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ - continue; \ - } \ int localX = inX - xOffset * (outX % mosaicH); \ if (localX < 0 || localX > width - 1) { \ continue; \ @@ -43,9 +40,6 @@ unsigned widthMask = ~(width - 1); \ unsigned heightMask = ~(height - 1); \ for (; outX < condition; ++outX, ++inX) { \ - if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ - continue; \ - } \ renderer->spriteCyclesRemaining -= 2; \ xAccum += mat.a; \ yAccum += mat.c; \ @@ -151,9 +145,6 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) { return 0; } - if (renderer->spriteCyclesRemaining <= 0) { - return 0; - } int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed); int variant = renderer->target1Obj && diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 0f82d44..f31239d 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -727,7 +727,8 @@ static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool ac if (!active) { renderer->bg[bg].enabled = 0; } else if (!wasActive && active) { - if (renderer->nextY == 0) { + if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) { + // TODO: Investigate in more depth how switching background works in different modes renderer->bg[bg].enabled = 4; } else { renderer->bg[bg].enabled = 1; @@ -809,7 +810,6 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { int w; - renderer->end = 0; int spriteLayers = 0; if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) { if (renderer->oamDirty) { @@ -818,31 +818,34 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH; int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1; int mosaicY = y - (y % mosaicV); - for (w = 0; w < renderer->nWindows; ++w) { - renderer->start = renderer->end; - renderer->end = renderer->windows[w].endX; - renderer->currentWindow = renderer->windows[w].control; - if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) { + int i; + for (i = 0; i < renderer->oamMax; ++i) { + struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i]; + int localY = y; + renderer->end = 0; + if (GBAObjAttributesAIsMosaic(sprite->obj.a)) { + localY = mosaicY; + } + if ((localY < sprite->y && (sprite->endY - 256 < 0 || localY >= sprite->endY - 256)) || localY >= sprite->endY) { continue; } - int i; - int drawn; - - for (i = 0; i < renderer->oamMax; ++i) { - int localY = y; + for (w = 0; w < renderer->nWindows; ++w) { if (renderer->spriteCyclesRemaining <= 0) { break; } - struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i]; - if (GBAObjAttributesAIsMosaic(sprite->obj.a)) { - localY = mosaicY; - } - if ((localY < sprite->y && (sprite->endY - 256 < 0 || localY >= sprite->endY - 256)) || localY >= sprite->endY) { + renderer->currentWindow = renderer->windows[w].control; + renderer->start = renderer->end; + renderer->end = renderer->windows[w].endX; + if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) { continue; } - drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY); + + int drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY); spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c); } + if (renderer->spriteCyclesRemaining <= 0) { + break; + } } } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 72cdd45..781b608 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -128,7 +128,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { if (error) { return false; } - gba->timing.root = NULL; + mTimingClear(&gba->timing); LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles); size_t i; diff --git a/src/gba/sio.c b/src/gba/sio.c index d620be5..800af8a 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -164,6 +164,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { } break; case SIO_MULTI: + value &= 0xFF83; value |= 0xC; break; default: