diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 2b75eef7a4..85df4edfe6 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -73,8 +73,8 @@ public: mem_.setLinkCallback(callback); } - LoadRes load(char const *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat) { - return mem_.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat); + LoadRes load(char const *romfiledata, unsigned romfilelength, unsigned flags) { + return mem_.loadROM(romfiledata, romfilelength, flags); } bool loaded() const { return mem_.loaded(); } @@ -94,7 +94,6 @@ public: void setRtcDivisorOffset(long const rtcDivisorOffset) { mem_.setRtcDivisorOffset(rtcDivisorOffset); } void setBios(char const *buffer, std::size_t size) { mem_.setBios(buffer, size); } - bool gbIsCgb() { return mem_.gbIsCgb(); } unsigned char externalRead(unsigned short addr) {return mem_.peek(addr); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index 0bc0639a76..50a3447fce 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -88,7 +88,7 @@ void GB::reset() { SaveState state; p_->cpu.setStatePtrs(state); - setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB); + setInitState(state, !(p_->loadflags & FORCE_DMG)); p_->cpu.loadState(state); if (length > 0) { @@ -139,13 +139,13 @@ void GB::setRtcDivisorOffset(long const rtcDivisorOffset) { } LoadRes GB::load(char const *romfiledata, unsigned romfilelength, unsigned const flags) { - LoadRes const loadres = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT); + LoadRes const loadres = p_->cpu.load(romfiledata, romfilelength, flags); if (loadres == LOADRES_OK) { SaveState state; p_->cpu.setStatePtrs(state); p_->loadflags = flags; - setInitState(state, !(flags & FORCE_DMG), flags & GBA_CGB); + setInitState(state, !(flags & FORCE_DMG)); p_->cpu.loadState(state); } diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp index d71543e0ad..fb3588dc1b 100644 --- a/libgambatte/src/initstate.cpp +++ b/libgambatte/src/initstate.cpp @@ -1147,7 +1147,7 @@ static void setInitialDmgIoamhram(unsigned char ioamhram[]) { } // anon namespace -void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode) { +void gambatte::setInitState(SaveState &state, const bool cgb) { static unsigned char const cgbObjpDump[0x40] = { 0x00, 0x00, 0xF2, 0xAB, 0x61, 0xC2, 0xD9, 0xBA, @@ -1182,8 +1182,6 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM state.cpu.prefetched = false; state.cpu.skip = false; state.mem.biosMode = true; - state.mem.cgbSwitching = false; - state.mem.agbMode = gbaCgbMode; std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.size()); @@ -1222,7 +1220,6 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM state.mem.enableRam = false; state.mem.rambankMode = false; state.mem.hdmaTransfer = false; - state.mem.gbIsCgb = cgb; state.mem.stopped = false; @@ -1269,7 +1266,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM state.ppu.nextM0Irq = 0; state.ppu.oldWy = state.mem.ioamhram.get()[0x14A]; state.ppu.pendingLcdstatIrq = false; - state.ppu.isCgb = cgb; + state.ppu.notCgbDmg = true; // spu.cycleCounter >> 12 & 7 represents the frame sequencer position. state.spu.cycleCounter = state.cpu.cycleCounter >> 1; diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h index 0e31dd35bb..13b0f28e16 100644 --- a/libgambatte/src/initstate.h +++ b/libgambatte/src/initstate.h @@ -23,7 +23,7 @@ namespace gambatte { -void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode); +void setInitState(struct SaveState &state, bool cgb); } #endif diff --git a/libgambatte/src/mem/time.cpp b/libgambatte/src/mem/time.cpp index 87ffb7e10c..f85433bea9 100644 --- a/libgambatte/src/mem/time.cpp +++ b/libgambatte/src/mem/time.cpp @@ -43,7 +43,7 @@ void Time::loadState(SaveState const &state) { lastTime_.tv_sec = state.time.lastTimeSec; lastTime_.tv_usec = state.time.lastTimeUsec; lastCycles_ = state.time.lastCycles; - ds_ = state.ppu.isCgb & state.mem.ioamhram.get()[0x14D] >> 7; + ds_ = state.mem.ioamhram.get()[0x14D] >> 7; } std::uint32_t Time::get(unsigned long const cc) { diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 95a02ea4a4..3b255d7d62 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -17,6 +17,7 @@ // #include "memory.h" +#include "gambatte.h" #include "savestate.h" #include "sound.h" #include "video.h" @@ -80,9 +81,6 @@ void Memory::setStatePtrs(SaveState &state) { void Memory::loadState(SaveState const &state) { biosMode_ = state.mem.biosMode; - cgbSwitching_ = state.mem.cgbSwitching; - agbMode_ = state.mem.agbMode; - gbIsCgb_ = state.mem.gbIsCgb; stopped_ = state.mem.stopped; psg_.loadState(state); lcd_.loadState(state, state.mem.oamDmaPos < oam_size ? cart_.rdisabledRam() : ioamhram_); @@ -1014,17 +1012,17 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long oamDmaInitSetup(); return; case 0x47: - if (!isCgb()) + if (!isCgb() || isCgbDmg()) lcd_.dmgBgPaletteChange(data, cc); break; case 0x48: - if (!isCgb()) + if (!isCgb() || isCgbDmg()) lcd_.dmgSpPalette1Change(data, cc); break; case 0x49: - if (!isCgb()) + if (!isCgb() || isCgbDmg()) lcd_.dmgSpPalette2Change(data, cc); break; @@ -1033,25 +1031,34 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long break; case 0x4B: lcd_.wxChange(data, cc); + break; + case 0x4C: + if (!biosMode_) + return; + break; case 0x4D: - if (isCgb()) + if (isCgb() && !isCgbDmg()) ioamhram_[0x14D] = (ioamhram_[0x14D] & ~1u) | (data & 1); return; case 0x4F: - if (isCgb()) { + if (isCgb() && !isCgbDmg()) { cart_.setVrambank(data & 1); ioamhram_[0x14F] = 0xFE | data; } return; case 0x50: - biosMode_ = false; - if(cgbSwitching_) { + if (!biosMode_) + return; + + if (isCgb() && (ioamhram_[0x14C] & 0x04)) { lcd_.copyCgbPalettesToDmg(); - lcd_.setCgb(false); + lcd_.setCgbDmg(true); } + + biosMode_ = false; return; case 0x51: dmaSource_ = data << 8 | (dmaSource_ & 0xFF); @@ -1120,14 +1127,12 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long return; case 0x6C: - if (isCgb()) { + if (isCgb()) ioamhram_[0x16C] = data | 0xFE; - cgbSwitching_ = true; - } return; case 0x70: - if (isCgb()) { + if (isCgb() && !isCgbDmg()) { cart_.setWrambank(data & 0x07 ? data & 0x07 : 1); ioamhram_[0x170] = data | 0xF8; } @@ -1211,13 +1216,18 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo ioamhram_[p - mm_oam_begin] = data; } -LoadRes Memory::loadROM(char const *romfiledata, unsigned romfilelength, const bool forceDmg, const bool multicartCompat) { +LoadRes Memory::loadROM(char const *romfiledata, unsigned romfilelength, unsigned const flags) { + bool const forceDmg = flags & GB::LoadFlag::FORCE_DMG; + bool const multicartCompat = flags & GB::LoadFlag::MULTICART_COMPAT; + if (LoadRes const fail = cart_.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat)) return fail; psg_.init(cart_.isCgb()); lcd_.reset(ioamhram_, cart_.vramdata(), cart_.isCgb()); + agbMode_ = flags & GB::LoadFlag::GBA_CGB; + return LOADRES_OK; } @@ -1300,9 +1310,6 @@ SYNCFUNC(Memory) NSS(serialCnt_); NSS(blanklcd_); NSS(biosMode_); - NSS(cgbSwitching_); - NSS(agbMode_); - NSS(gbIsCgb_); NSS(stopped_); NSS(LINKCABLE_); NSS(linkClockTrigger_); diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index babf029853..601c0bf0c9 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -55,12 +55,12 @@ public: memcpy(bios_, buffer, size); biosSize_ = size; } - bool gbIsCgb() { return gbIsCgb_; } bool getMemoryArea(int which, unsigned char **data, int *length); unsigned long stop(unsigned long cycleCounter, bool& skip); bool isCgb() const { return lcd_.isCgb(); } + bool isCgbDmg() const { return lcd_.isCgbDmg(); } bool ime() const { return intreq_.ime(); } bool halted() const { return intreq_.halted(); } unsigned long nextEventTime() const { return intreq_.minEventTime(); } @@ -226,7 +226,7 @@ public: unsigned long event(unsigned long cycleCounter); unsigned long resetCounters(unsigned long cycleCounter); - LoadRes loadROM(char const *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat); + LoadRes loadROM(char const *romfiledata, unsigned romfilelength, unsigned flags); void setInputGetter(unsigned (*getInput)()) { getInput_ = getInput; @@ -299,9 +299,7 @@ private: unsigned char serialCnt_; bool blanklcd_; bool biosMode_; - bool cgbSwitching_; bool agbMode_; - bool gbIsCgb_; unsigned long basetime_; bool stopped_; enum HdmaState { hdma_low, hdma_high, hdma_requested } haltHdmaState_; diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h index 5e5bf02349..e07908cacf 100644 --- a/libgambatte/src/savestate.h +++ b/libgambatte/src/savestate.h @@ -36,7 +36,7 @@ struct SaveState { void set(T *p, std::size_t size) { ptr = p; size_ = size; } friend class SaverList; - friend void setInitState(SaveState &, bool, bool); + friend void setInitState(SaveState &, bool); private: T *ptr; std::size_t size_; @@ -83,9 +83,6 @@ struct SaveState { unsigned char /*bool*/ rambankMode; unsigned char /*bool*/ hdmaTransfer; unsigned char /*bool*/ biosMode; - unsigned char /*bool*/ cgbSwitching; - unsigned char /*bool*/ agbMode; - unsigned char /*bool*/ gbIsCgb; unsigned char /*bool*/ stopped; } mem; @@ -122,7 +119,7 @@ struct SaveState { unsigned char wscx; unsigned char /*bool*/ weMaster; unsigned char /*bool*/ pendingLcdstatIrq; - unsigned char /*bool*/ isCgb; + unsigned char /*bool*/ notCgbDmg; } ppu; struct SPU { diff --git a/libgambatte/src/sound/channel4.cpp b/libgambatte/src/sound/channel4.cpp index 2b3f99533c..17c7fde5a1 100644 --- a/libgambatte/src/sound/channel4.cpp +++ b/libgambatte/src/sound/channel4.cpp @@ -96,6 +96,7 @@ inline void Channel4::Lfsr::event() { void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) { updateBackupCounter(cc); nr3_ = newNr3; + counter_ = cc; } void Channel4::Lfsr::nr4Init(unsigned long cc) { diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp index ce58c4a392..732d5e4572 100644 --- a/libgambatte/src/video.cpp +++ b/libgambatte/src/video.cpp @@ -24,8 +24,8 @@ using namespace gambatte; unsigned long LCD::gbcToRgb32(const unsigned bgr15) { - unsigned long const r = bgr15 & 0x1F; - unsigned long const g = bgr15 >> 5 & 0x1F; + unsigned long const r = bgr15 & 0x1F; + unsigned long const g = bgr15 >> 5 & 0x1F; unsigned long const b = bgr15 >> 10 & 0x1F; return cgbColorsRgb32_[bgr15 & 0x7FFF]; @@ -69,18 +69,13 @@ namespace { && cc >= m0TimeOfCurrentLy; } - void doCgbColorChange(unsigned char* pdata, - unsigned long* palette, unsigned index, unsigned data, bool trueColor) { - pdata[index] = data; - index /= 2; - palette[index] = gbcToRgb32(pdata[index * 2] | pdata[index * 2 + 1] * 0x100l); - } - } // unnamed namespace. void LCD::setDmgPalette(unsigned long palette[], const unsigned long dmgColors[], unsigned data) { - for (int i = 0; i < num_palette_entries; ++i, data /= num_palette_entries) - palette[i] = gbcToRgb32(dmgColors[data % num_palette_entries]); + palette[0] = dmgColors[data & 3]; + palette[1] = dmgColors[data >> 2 & 3]; + palette[2] = dmgColors[data >> 4 & 3]; + palette[3] = dmgColors[data >> 6 & 3]; } void LCD::setCgbPalette(unsigned *lut) { @@ -114,10 +109,6 @@ void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb refreshPalettes(); } -void LCD::setCgb(bool cgb) { - ppu_.setCgb(cgb); -} - void LCD::setStatePtrs(SaveState &state) { state.ppu.bgpData.set( bgpData_, sizeof bgpData_); state.ppu.objpData.set(objpData_, sizeof objpData_); @@ -162,7 +153,7 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) { } void LCD::refreshPalettes() { - if (ppu_.cgb()) { + if (isCgb() && !isCgbDmg()) { for (int i = 0; i < max_num_palettes * num_palette_entries; ++i) { ppu_.bgPalette()[i] = gbcToRgb32(bgpData_[2 * i] | bgpData_[2 * i + 1] * 0x100l); ppu_.spPalette()[i] = gbcToRgb32(objpData_[2 * i] | objpData_[2 * i + 1] * 0x100l); @@ -186,7 +177,7 @@ void LCD::copyCgbPalettesToDmg() { namespace { template -static void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) { +void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) { unsigned lines = 144; while (lines--) { @@ -856,6 +847,4 @@ SYNCFUNC(LCD) SSS(lycIrq_); SSS(nextM0Time_); NSS(statReg_); - NSS(m2IrqStatReg_); - NSS(m1IrqStatReg_); } diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h index cedd2cf86a..ab8b25475c 100644 --- a/libgambatte/src/video.h +++ b/libgambatte/src/video.h @@ -50,13 +50,13 @@ public: LCD(unsigned char const *oamram, unsigned char const *vram, VideoInterruptRequester memEventRequester); void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb); + void setCgbDmg(bool enabled) { ppu_.setCgbDmg(enabled); } void setStatePtrs(SaveState &state); void loadState(SaveState const &state, unsigned char const *oamram); void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); void setCgbPalette(unsigned *lut); void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch); void setLayers(unsigned mask) { ppu_.setLayers(mask); } - void setCgb(bool cgb); void copyCgbPalettesToDmg(); int debugGetLY() const { return ppu_.lyCounter().ly(); } @@ -147,6 +147,7 @@ public: bool hdmaIsEnabled() const { return eventTimes_(memevent_hdma) != disabled_time; } void update(unsigned long cycleCounter); bool isCgb() const { return ppu_.cgb(); } + bool isCgbDmg() const { return ppu_.cgbDmg(); } bool isDoubleSpeed() const { return ppu_.lyCounter().isDoubleSpeed(); } unsigned long *bgPalette() { return ppu_.bgPalette(); } diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp index 257a7906a3..61a8e470db 100644 --- a/libgambatte/src/video/ppu.cpp +++ b/libgambatte/src/video/ppu.cpp @@ -140,6 +140,13 @@ inline void nextCall(int const cycles, PPUState const &state, PPUPriv &p) { p.nextCallPtr = &state; } +inline unsigned long const* cgbSpPalette(PPUPriv const& p, unsigned const attrib) { + if (!p.cgbDmg) + return p.spPalette + (attrib & attr_cgbpalno) * num_palette_entries; + else + return p.spPalette + (attrib & attr_dmgpalno ? num_palette_entries : 0); +} + namespace M2_Ly0 { void f0(PPUPriv& p) { p.weMaster = lcdcWinEn(p) && 0 == p.wy; @@ -444,6 +451,7 @@ namespace M3Loop { + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2; } while (dst != dstend); + p.ntileword = ntileword; continue; } @@ -455,6 +463,7 @@ namespace M3Loop { p.cycles = cycles; } + uint_least32_t* const dst = dbufline + (xpos - tile_len); unsigned const tileword = -(p.lcdc & 1u * lcdc_bgen) & p.ntileword; @@ -541,6 +550,7 @@ namespace M3Loop { } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); } + unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; int const ts = tile_size; tileMapXpos = tileMapXpos % tile_map_len + 1; @@ -766,6 +776,7 @@ namespace M3Loop { } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); } + { unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; unsigned const nattrib = tileMapLine[tileMapXpos % tile_map_len + vram_bank_size]; @@ -786,7 +797,6 @@ namespace M3Loop { p.xpos = xpos; } - void doFullTilesUnrolled(PPUPriv& p) { int xpos = p.xpos; int const xend = p.wx < p.xpos || p.wx >= xpos_end @@ -1768,6 +1778,7 @@ void PPU::loadState(SaveState const& ss, unsigned char const* const oamram) { void PPU::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb) { p_.vram = vram; p_.cgb = cgb; + p_.cgbDmg = false; p_.spriteMapper.reset(oamram, cgb); } diff --git a/libgambatte/src/video/ppu.h b/libgambatte/src/video/ppu.h index 927613b3f1..b711cea3dd 100644 --- a/libgambatte/src/video/ppu.h +++ b/libgambatte/src/video/ppu.h @@ -150,7 +150,6 @@ public: unsigned long * spPalette() { return p_.spPalette; } void update(unsigned long cc); void setLayers(unsigned mask) { p_.layersMask = mask; } - void setCgb(bool cgb) { p_.cgb = cgb; } private: PPUPriv p_;