Fix LCDC for DMG on CGB

This commit is contained in:
TiKevin83 2020-02-16 21:45:04 -05:00 committed by Travis
parent 23c1c74030
commit 0a6a221653
13 changed files with 62 additions and 63 deletions

View File

@ -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); }

View File

@ -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);
}

View File

@ -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;

View File

@ -23,7 +23,7 @@
namespace gambatte {
void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
void setInitState(struct SaveState &state, bool cgb);
}
#endif

View File

@ -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) {

View File

@ -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_);

View File

@ -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_;

View File

@ -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 {

View File

@ -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) {

View File

@ -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_);
}

View File

@ -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(); }

View File

@ -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);
}

View File

@ -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_;