Fix LCDC for DMG on CGB
This commit is contained in:
parent
23c1c74030
commit
0a6a221653
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace gambatte {
|
||||
|
||||
void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
|
||||
void setInitState(struct SaveState &state, bool cgb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<typename T>
|
||||
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_);
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
|
Loading…
Reference in New Issue