diff --git a/libgambatte/libgambatte.vcxproj b/libgambatte/libgambatte.vcxproj
index e0e201771f..9934cb6173 100644
--- a/libgambatte/libgambatte.vcxproj
+++ b/libgambatte/libgambatte.vcxproj
@@ -167,6 +167,7 @@
+
@@ -204,6 +205,7 @@
+
diff --git a/libgambatte/libgambatte.vcxproj.filters b/libgambatte/libgambatte.vcxproj.filters
index 504d75698f..318ef9d04d 100644
--- a/libgambatte/libgambatte.vcxproj.filters
+++ b/libgambatte/libgambatte.vcxproj.filters
@@ -135,6 +135,9 @@
Header Files
+
+ Header Files
+
@@ -218,5 +221,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp
index fb3588dc1b..64b6825ffe 100644
--- a/libgambatte/src/initstate.cpp
+++ b/libgambatte/src/initstate.cpp
@@ -1330,4 +1330,12 @@ void gambatte::setInitState(SaveState &state, const bool cgb) {
state.rtc.dataM = 0;
state.rtc.dataS = 0;
state.rtc.lastLatchData = false;
+
+ state.huc3.haltTime = state.time.seconds;
+ state.huc3.dataTime = 0;
+ state.huc3.writingTime = 0;
+ state.huc3.halted = false;
+ state.huc3.shift = 0;
+ state.huc3.ramValue = 1;
+ state.huc3.modeflag = 2; // huc3_none
}
diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
index c0dacca575..3424ffe96a 100644
--- a/libgambatte/src/mem/cartridge.cpp
+++ b/libgambatte/src/mem/cartridge.cpp
@@ -437,6 +437,95 @@ public:
}
};
+class HuC3 : public DefaultMbc {
+public:
+ HuC3(MemPtrs& memptrs, HuC3Chip* const huc3)
+ : memptrs_(memptrs)
+ , huc3_(huc3)
+ , rombank_(1)
+ , rambank_(0)
+ , ramflag_(0)
+ {
+ }
+
+ virtual unsigned char curRomBank() const {
+ return rombank_;
+ }
+
+ virtual bool disabledRam() const {
+ return false;
+ }
+
+ virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) {
+ switch (p >> 13 & 3) {
+ case 0:
+ ramflag_ = data;
+ //printf("[HuC3] set ramflag to %02X\n", data);
+ setRambank();
+ break;
+ case 1:
+ //printf("[HuC3] set rombank to %02X\n", data);
+ rombank_ = data;
+ setRombank();
+ break;
+ case 2:
+ //printf("[HuC3] set rambank to %02X\n", data);
+ rambank_ = data;
+ setRambank();
+ break;
+ case 3:
+ // GEST: "programs will write 1 here"
+ break;
+ }
+ }
+
+ virtual void SyncState(NewState *ns, bool isReader)
+ {
+ NSS(rombank_);
+ NSS(rambank_);
+ NSS(ramflag_);
+ }
+
+ virtual void loadState(SaveState::Mem const& ss) {
+ rombank_ = ss.rombank;
+ rambank_ = ss.rambank;
+ ramflag_ = ss.HuC3RAMflag;
+ setRambank();
+ setRombank();
+ }
+
+private:
+ MemPtrs& memptrs_;
+ HuC3Chip* const huc3_;
+ unsigned char rombank_;
+ unsigned char rambank_;
+ unsigned char ramflag_;
+
+ void setRambank() const {
+ huc3_->setRamflag(ramflag_);
+
+ unsigned flags;
+ if (ramflag_ >= 0x0B && ramflag_ < 0x0F) {
+ // System registers mode
+ flags = MemPtrs::read_en | MemPtrs::write_en | MemPtrs::rtc_en;
+ }
+ else if (ramflag_ == 0x0A || ramflag_ > 0x0D) {
+ // Read/write mode
+ flags = MemPtrs::read_en | MemPtrs::write_en;
+ }
+ else {
+ // Read-only mode ??
+ flags = MemPtrs::read_en;
+ }
+
+ memptrs_.setRambank(flags, rambank_ & (rambanks(memptrs_) - 1));
+ }
+
+ void setRombank() const {
+ memptrs_.setRombank(std::max(rombank_ & (rombanks(memptrs_) - 1), 1u));
+ }
+};
+
class Mbc5 : public DefaultMbc {
public:
explicit Mbc5(MemPtrs &memptrs)
@@ -578,6 +667,7 @@ int asHex(char c) {
Cartridge::Cartridge()
: rtc_(time_)
+, huc3_(time_)
{
}
@@ -588,7 +678,9 @@ void Cartridge::setStatePtrs(SaveState &state) {
}
void Cartridge::loadState(SaveState const &state) {
+ huc3_.loadState(state);
rtc_.loadState(state);
+ time_.loadState(state);
mbc_->loadState(state.mem);
}
@@ -613,7 +705,8 @@ LoadRes Cartridge::loadROM(char const *romfiledata, unsigned romfilelength, bool
type_mbc2,
type_mbc3,
type_mbc5,
- type_huc1 };
+ type_huc1,
+ type_huc3 };
Cartridgetype type = type_plain;
unsigned rambanks = 1;
unsigned rombanks = 2;
@@ -656,7 +749,7 @@ LoadRes Cartridge::loadROM(char const *romfiledata, unsigned romfilelength, bool
case 0x22: return LOADRES_UNSUPPORTED_MBC_MBC7;
case 0xFC: return LOADRES_UNSUPPORTED_MBC_POCKET_CAMERA;
case 0xFD: return LOADRES_UNSUPPORTED_MBC_TAMA5;
- case 0xFE: return LOADRES_UNSUPPORTED_MBC_HUC3;
+ case 0xFE: type = type_huc3; break;
case 0xFF: type = type_huc1; break;
default: return LOADRES_BAD_FILE_OR_UNKNOWN_MBC;
}
@@ -686,6 +779,7 @@ LoadRes Cartridge::loadROM(char const *romfiledata, unsigned romfilelength, bool
mbc_.reset();
memptrs_.reset(rombanks, rambanks, cgb ? 8 : 2);
rtc_.set(false, 0);
+ huc3_.set(false);
std::memcpy(memptrs_.romdata(), romfiledata, (filesize / rombank_size() * rombank_size()));
std::memset(memptrs_.romdata() + filesize / rombank_size() * rombank_size(),
@@ -708,6 +802,10 @@ LoadRes Cartridge::loadROM(char const *romfiledata, unsigned romfilelength, bool
break;
case type_mbc5: mbc_.reset(new Mbc5(memptrs_)); break;
case type_huc1: mbc_.reset(new HuC1(memptrs_)); break;
+ case type_huc3:
+ huc3_.set(true);
+ mbc_.reset(new HuC3(memptrs_, &huc3_));
+ break;
}
return LOADRES_OK;
@@ -798,6 +896,7 @@ bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) cons
SYNCFUNC(Cartridge)
{
+ SSS(huc3_);
SSS(memptrs_);
SSS(time_);
SSS(rtc_);
diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
index 2260c31349..9c575148fe 100644
--- a/libgambatte/src/mem/cartridge.h
+++ b/libgambatte/src/mem/cartridge.h
@@ -23,6 +23,7 @@
#include "memptrs.h"
#include "time.h"
#include "rtc.h"
+#include "huc3.h"
#include "savestate.h"
#include
#include
@@ -82,11 +83,15 @@ public:
bool getMemoryArea(int which, unsigned char **data, int *length) const;
LoadRes loadROM(char const *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
char const * romTitle() const { return reinterpret_cast(memptrs_.romdata() + 0x134); }
+ bool isHuC3() const { return huc3_.isHuC3(); }
+ unsigned char HuC3Read(unsigned p, unsigned long const cc) { return huc3_.read(p, cc); }
+ void HuC3Write(unsigned p, unsigned data, unsigned long const cc) { huc3_.write(p, data, cc); }
private:
MemPtrs memptrs_;
Time time_;
Rtc rtc_;
+ HuC3Chip huc3_;
std::unique_ptr mbc_;
public:
diff --git a/libgambatte/src/mem/huc3.cpp b/libgambatte/src/mem/huc3.cpp
new file mode 100644
index 0000000000..785555fd53
--- /dev/null
+++ b/libgambatte/src/mem/huc3.cpp
@@ -0,0 +1,201 @@
+//
+// Copyright (C) 2007 by sinamas
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License version 2 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// version 2 along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#include "huc3.h"
+#include "../savestate.h"
+#include
+
+namespace gambatte {
+
+HuC3Chip::HuC3Chip(Time &time)
+: time_(time)
+, haltTime_(0)
+, dataTime_(0)
+, writingTime_(0)
+, ramValue_(0)
+, shift_(0)
+, ramflag_(0)
+, modeflag_(HUC3_NONE)
+, irBaseCycle_(0)
+, enabled_(false)
+, lastLatchData_(false)
+, halted_(false)
+, irReceivingPulse_(false)
+{
+}
+
+void HuC3Chip::doLatch(unsigned long const cc) {
+ std::uint32_t tmp = time(cc);
+
+ unsigned minute = (tmp / 60) % 1440;
+ unsigned day = (tmp / 86400) & 0xFFF;
+ dataTime_ = (day << 12) | minute;
+}
+
+//void HuC3Chip::setStatePtrs(SaveState &state) {
+// state.huc3.haltTime.set(haltTime_, sizeof haltTime_);
+// state.huc3.dataTime.set(dataTime_, sizeof dataTime_);
+// state.huc3.writingTime.set(writingTime_, sizeof writingTime_);
+// state.huc3.irBaseCycle.set(irBaseCycle_, sizeof irBaseCycle_);
+// state.huc3.halted.set(halted_, sizeof halted_);
+// state.huc3.shift.set(shift_, sizeof shift_);
+// state.huc3.ramValue.set(ramValue_, sizeof ramValue_);
+// state.huc3.modeflag.set(modeflag_, sizeof modeflag_);
+// state.huc3.irReceivingPulse.set(irReceivingPulse_, sizeof irReceivingPulse_);
+//}
+
+void HuC3Chip::loadState(SaveState const &state) {
+ haltTime_ = state.huc3.haltTime;
+ dataTime_ = state.huc3.dataTime;
+ ramValue_ = state.huc3.ramValue;
+ shift_ = state.huc3.shift;
+ halted_ = state.huc3.halted;
+ modeflag_ = state.huc3.modeflag;
+ writingTime_ = state.huc3.writingTime;
+ irBaseCycle_ = state.huc3.irBaseCycle;
+ irReceivingPulse_ = state.huc3.irReceivingPulse;
+}
+
+unsigned char HuC3Chip::read(unsigned /*p*/, unsigned long const cc) {
+ // should only reach here with ramflag = 0B-0E
+ if(ramflag_ == 0x0E) {
+ // INFRARED
+ if(!irReceivingPulse_) {
+ irReceivingPulse_ = true;
+ irBaseCycle_ = cc;
+ }
+ unsigned long cyclesSinceStart = cc - irBaseCycle_;
+ unsigned char modulation = (cyclesSinceStart/105) & 1; // 4194304 Hz CPU, 40000 Hz remote signal
+ unsigned long timeUs = cyclesSinceStart*36/151; // actually *1000000/4194304
+ // sony protocol
+ if(timeUs < 10000) {
+ // initialization allowance
+ return 0;
+ }
+ else if(timeUs < 10000 + 2400) {
+ // initial mark
+ return modulation;
+ }
+ else if(timeUs < 10000 + 2400 + 600) {
+ // initial space
+ return 0;
+ }
+ else {
+ // send data
+ timeUs -= 13000;
+ // write 20 bits (any 20 seem to do)
+ unsigned int data = 0xFFFFF;
+ for(unsigned long mask = 1UL << (20-1); mask; mask >>= 1) {
+ unsigned int markTime = (data & mask) ? 1200 : 600;
+ if(timeUs < markTime) { return modulation; }
+ timeUs -= markTime;
+ if(timeUs < 600) { return 0; }
+ timeUs -= 600;
+ }
+
+ return 0;
+ }
+ }
+ if(ramflag_ < 0x0B || ramflag_ > 0x0D) {
+ //printf("[HuC3] error, hit huc3 read with ramflag=%02X\n", ramflag_);
+ return 0xFF;
+ }
+ if(ramflag_ == 0x0D) return 1;
+ else return ramValue_;
+}
+
+void HuC3Chip::write(unsigned /*p*/, unsigned data, unsigned long const cc) {
+ // as above
+ if(ramflag_ == 0x0B) {
+ // command
+ switch(data & 0xF0) {
+ case 0x10:
+ // read time
+ doLatch(cc);
+ if(modeflag_ == HUC3_READ) {
+ ramValue_ = (dataTime_ >> shift_) & 0x0F;
+ shift_ += 4;
+ if(shift_ > 24) shift_ = 0;
+ }
+ break;
+ case 0x30:
+ // write time
+ if(modeflag_ == HUC3_WRITE) {
+ if(shift_ == 0) writingTime_ = 0;
+ if(shift_ < 24) {
+ writingTime_ |= (data & 0x0F) << shift_;
+ shift_ += 4;
+ if(shift_ == 24) {
+ updateTime(cc);
+ modeflag_ = HUC3_READ;
+ }
+ }
+ }
+ break;
+ case 0x40:
+ // some kind of mode shift
+ switch(data & 0x0F) {
+ case 0x0:
+ // shift reset?
+ shift_ = 0;
+ break;
+ case 0x3:
+ // write time?
+ modeflag_ = HUC3_WRITE;
+ shift_ = 0;
+ break;
+ case 0x7:
+ modeflag_ = HUC3_READ;
+ shift_ = 0;
+ break;
+ // others are unimplemented so far
+ }
+ break;
+ case 0x50:
+ // ???
+ break;
+ case 0x60:
+ modeflag_ = HUC3_READ; // ???
+ break;
+ }
+ }
+ // do nothing for 0C/0D yet
+}
+
+void HuC3Chip::updateTime(unsigned long const cc) {
+ unsigned minute = (writingTime_ & 0xFFF) % 1440;
+ unsigned day = (writingTime_ & 0xFFF000) >> 12;
+ std::uint32_t seconds = minute*60 + day*86400;
+ time_.reset(seconds, cc);
+ haltTime_ = seconds;
+
+}
+SYNCFUNC(HuC3Chip)
+{
+ NSS(haltTime_);
+ NSS(dataTime_);
+ NSS(writingTime_);
+ NSS(ramValue_);
+ NSS(shift_);
+ NSS(halted_);
+ NSS(modeflag_);
+ NSS(irBaseCycle_);
+ NSS(irReceivingPulse_);
+}
+}
+
diff --git a/libgambatte/src/mem/huc3.h b/libgambatte/src/mem/huc3.h
new file mode 100644
index 0000000000..00b0db38a0
--- /dev/null
+++ b/libgambatte/src/mem/huc3.h
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2007 by sinamas
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License version 2 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// version 2 along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#ifndef HuC3Chip_H
+#define HuC3Chip_H
+
+enum
+{
+ HUC3_READ = 0,
+ HUC3_WRITE = 1,
+ HUC3_NONE = 2
+};
+
+#include "time.h"
+
+namespace gambatte {
+
+ struct SaveState;
+
+ class HuC3Chip {
+ public:
+ HuC3Chip(Time &time);
+ //void setStatePtrs(SaveState &);
+ void loadState(SaveState const& state);
+ void setRamflag(unsigned char ramflag) { ramflag_ = ramflag; irReceivingPulse_ = false; }
+ bool isHuC3() const { return enabled_; }
+
+ void set(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ unsigned char read(unsigned p, unsigned long const cc);
+ void write(unsigned p, unsigned data, unsigned long cycleCounter);
+
+ private:
+ Time &time_;
+ std::uint32_t haltTime_;
+ unsigned dataTime_;
+ unsigned writingTime_;
+ unsigned char ramValue_;
+ unsigned char shift_;
+ unsigned char ramflag_;
+ unsigned char modeflag_;
+ unsigned long irBaseCycle_;
+ bool enabled_;
+ bool lastLatchData_;
+ bool halted_;
+ bool irReceivingPulse_;
+
+ void doLatch(unsigned long cycleCounter);
+ void updateTime(unsigned long cycleCounter);
+
+ std::uint32_t time(unsigned long const cc) {
+ return halted_ ? haltTime_ : time_.get(cc);
+ }
+ public:
+ templatevoid SyncState(NewState* ns);
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
index 9873a0080d..9714cd1489 100644
--- a/libgambatte/src/memory.cpp
+++ b/libgambatte/src/memory.cpp
@@ -514,7 +514,9 @@ void Memory::updateOamDma(unsigned long const cc) {
startOamDma(lastOamDmaUpdate_);
if (oamDmaPos_ < oam_size) {
- ioamhram_[oamDmaPos_] = ((oamDmaSrc) ? oamDmaSrc[oamDmaPos_] : cart_.rtcRead());
+ if (oamDmaSrc) ioamhram_[oamDmaPos_] = oamDmaSrc[oamDmaPos_];
+ else if (cart_.isHuC3()) ioamhram_[oamDmaPos_] = cart_.HuC3Read(oamDmaPos_, cc);
+ else ioamhram_[oamDmaPos_] = cart_.rtcRead();
}
else if (oamDmaPos_ == oam_size) {
endOamDma(lastOamDmaUpdate_);
@@ -667,6 +669,9 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
if (cart_.rsrambankptr())
return cart_.rsrambankptr()[p];
+ if (cart_.isHuC3())
+ return cart_.HuC3Read(p, cc);
+
return cart_.rtcRead();
}
@@ -1200,6 +1205,8 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
else if (p < mm_wram_begin) {
if (cart_.wsrambankptr())
cart_.wsrambankptr()[p] = data;
+ else if (cart_.isHuC3())
+ cart_.HuC3Write(p, data, cc);
else
cart_.rtcWrite(data, cc);
}
diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h
index e07908cacf..64388e247d 100644
--- a/libgambatte/src/savestate.h
+++ b/libgambatte/src/savestate.h
@@ -77,6 +77,7 @@ struct SaveState {
unsigned char rambank;
unsigned char oamDmaPos;
unsigned char haltHdmaState;
+ unsigned char HuC3RAMflag;
unsigned char /*bool*/ IME;
unsigned char /*bool*/ halted;
unsigned char /*bool*/ enableRam;
@@ -205,6 +206,18 @@ struct SaveState {
unsigned char dataS;
unsigned char /*bool*/ lastLatchData;
} rtc;
+
+ struct HuC3 {
+ unsigned long haltTime;
+ unsigned long dataTime;
+ unsigned long writingTime;
+ unsigned long irBaseCycle;
+ unsigned char /*bool*/ halted;
+ unsigned char shift;
+ unsigned char ramValue;
+ unsigned char modeflag;
+ unsigned char /*bool*/ irReceivingPulse;
+ } huc3;
};
}
diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp
index 23dffe870e..9c09069276 100644
--- a/libgambatte/src/video/ppu.cpp
+++ b/libgambatte/src/video/ppu.cpp
@@ -563,8 +563,11 @@ namespace M3Loop {
p.xpos = xpos;
}
- void doFullTilesUnrolledCgb(PPUPriv& p, int const xend, uint_least32_t* const dbufline,
- unsigned char const* const tileMapLine, unsigned const tileline, unsigned tileMapXpos) {
+ void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t* const dbufline,
+ unsigned char const *const tileMapLine, unsigned const tileline, unsigned tileMapXpos) {
+ int const tileIndexSign = p.lcdc & lcdc_tdsel ? 0 : tile_pattern_table_size / tile_size / 2;
+ unsigned char const* const tileDataLine = p.vram + 2 * tile_size * tileIndexSign
+ + tileline * tile_line_size;
int xpos = p.xpos;
unsigned char const* const vram = p.vram;
unsigned const tdoffset = tileline * tile_line_size
@@ -620,7 +623,16 @@ namespace M3Loop {
uint_least32_t* const dstend = dst + n;
xpos += n;
- do {
+ if (!lcdcBgEn(p) && p.cgbDmg) {
+ do { *dst++ = p.bgPalette[0]; } while (dst != dstend);
+ tileMapXpos += n / (1u * tile_len);
+
+ unsigned const tno = tileMapLine[(tileMapXpos - 1) % tile_map_len];
+ int const ts = tile_size;
+ ntileword = expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[0]]
+ + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2;
+ }
+ else do {
unsigned long const* const bgPalette = p.bgPalette
+ (nattrib & attr_cgbpalno) * num_palette_entries;
dst[0] = bgPalette[ntileword & tile_bpp_mask];
@@ -659,7 +671,7 @@ namespace M3Loop {
}
uint_least32_t* const dst = dbufline + (xpos - tile_len);
- unsigned const tileword = p.ntileword;
+ unsigned const tileword = ((p.lcdc & 1u * lcdc_bgen) | !p.cgbDmg) * p.ntileword;;
unsigned const attrib = p.nattrib;
unsigned long const* const bgPalette = p.bgPalette
+ (attrib & attr_cgbpalno) * num_palette_entries;
@@ -870,7 +882,7 @@ namespace M3Loop {
p.winDrawState |= win_draw_start;
}
- unsigned const twdata = tileword & ((p.lcdc & lcdc_bgen) | p.cgb) * tile_bpp_mask;
+ unsigned const twdata = tileword & ((p.lcdc & lcdc_bgen) | (p.cgb * !p.cgbDmg)) * tile_bpp_mask;
unsigned long pixel = p.bgPalette[twdata + (p.attrib & attr_cgbpalno) * num_palette_entries];
int i = static_cast(p.nextSprite) - 1;
diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll
index 6d541404eb..ae21e029c5 100644
Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index ab64c6dc6e..562555a4cb 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -310,6 +310,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
case 0x1D: return "MBC5 ROM+RUMBLE+RAM"; // = MBC5; break;
case 0x1E: return "MBC5 ROM+RUMBLE+RAM+BATTERY"; // = MBC5; break;
case 0xFF: return "HuC1 ROM+RAM+BATTERY"; // = HUC1; break;
+ case 0xFE: return "HuC3 ROM+RAM+BATTERY";
default: return "UNKNOWN";
}
}
@@ -361,7 +362,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
case 0xfc: throw new UnsupportedGameException("\"Pocket Camera\" Mapper not supported!");
case 0xfd: throw new UnsupportedGameException("\"Bandai TAMA5\" Mapper not supported!");
- case 0xfe: throw new UnsupportedGameException("\"HuC3\" Mapper not supported!");
+ case 0xfe: break;
case 0xff: break;
default: throw new UnsupportedGameException($"Unknown mapper: {romdata[0x147]:x2}");
}