Ports from Upstream GSR for Babs and Robopon (squashed #2091)

This commit is contained in:
TiKevin83 2020-06-05 06:27:19 -04:00 committed by GitHub
parent 89789b4358
commit 81628bf109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 439 additions and 9 deletions

View File

@ -167,6 +167,7 @@
<ClInclude Include="src\interruptrequester.h" />
<ClInclude Include="src\memory.h" />
<ClInclude Include="src\mem\cartridge.h" />
<ClInclude Include="src\mem\huc3.h" />
<ClInclude Include="src\mem\memptrs.h" />
<ClInclude Include="src\mem\rtc.h" />
<ClInclude Include="src\mem\time.h" />
@ -204,6 +205,7 @@
<ClCompile Include="src\interruptrequester.cpp" />
<ClCompile Include="src\memory.cpp" />
<ClCompile Include="src\mem\cartridge.cpp" />
<ClCompile Include="src\mem\huc3.cpp" />
<ClCompile Include="src\mem\memptrs.cpp" />
<ClCompile Include="src\mem\rtc.cpp" />
<ClCompile Include="src\mem\time.cpp" />

View File

@ -135,6 +135,9 @@
<ClInclude Include="src\video\lcddef.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\mem\huc3.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\cinterface.cpp">
@ -218,5 +221,8 @@
<ClCompile Include="src\Interrupter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\mem\huc3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

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

View File

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

View File

@ -23,6 +23,7 @@
#include "memptrs.h"
#include "time.h"
#include "rtc.h"
#include "huc3.h"
#include "savestate.h"
#include <memory>
#include <string>
@ -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<char const *>(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> mbc_;
public:

View File

@ -0,0 +1,201 @@
//
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
//
// 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 <stdio.h>
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_);
}
}

View File

@ -0,0 +1,76 @@
//
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
//
// 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:
template<bool isReader>void SyncState(NewState* ns);
};
}
#endif

View File

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

View File

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

View File

@ -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<int>(p.nextSprite) - 1;

Binary file not shown.

View File

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