Skip to content

Commit

Permalink
GB: MBC7 - Accelerometer and eeprom support
Browse files Browse the repository at this point in the history
  • Loading branch information
SourMesen committed Jul 7, 2024
1 parent 9ca0fe5 commit 8f94cbe
Show file tree
Hide file tree
Showing 22 changed files with 497 additions and 63 deletions.
2 changes: 2 additions & 0 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
<ClInclude Include="Debugger\StepBackManager.h" />
<ClInclude Include="Gameboy\APU\GbChannelDac.h" />
<ClInclude Include="Gameboy\APU\GbEnvelope.h" />
<ClInclude Include="Gameboy\Carts\Eeprom93Lc56.h" />
<ClInclude Include="Gameboy\Carts\GbHuc1.h" />
<ClInclude Include="Gameboy\Carts\GbMbc3Rtc.h" />
<ClInclude Include="Gameboy\Carts\GbMbc6.h" />
<ClInclude Include="Gameboy\Carts\GbMbc7.h" />
<ClInclude Include="Gameboy\Carts\GbMbc7Accelerometer.h" />
<ClInclude Include="Gameboy\Carts\GbWisdomTree.h" />
<ClInclude Include="Gameboy\GbxFooter.h" />
<ClInclude Include="GBA\APU\GbaApu.h" />
Expand Down
6 changes: 6 additions & 0 deletions Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -2817,6 +2817,12 @@
<ClInclude Include="Gameboy\Carts\GbWisdomTree.h">
<Filter>Gameboy\Carts</Filter>
</ClInclude>
<ClInclude Include="Gameboy\Carts\Eeprom93Lc56.h">
<Filter>Gameboy\Carts</Filter>
</ClInclude>
<ClInclude Include="Gameboy\Carts\GbMbc7Accelerometer.h">
<Filter>Gameboy\Carts</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Shared\Video\RotateFilter.cpp">
Expand Down
181 changes: 181 additions & 0 deletions Core/Gameboy/Carts/Eeprom93Lc56.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#pragma once
#include "pch.h"
#include "Utilities/ISerializable.h"
#include "Utilities/Serializer.h"

class Eeprom93Lc56 final : public ISerializable
{
private:
enum class Mode
{
Idle,
Command,
ReadCommand,
WriteCommand,
WriteAllCommand
};

uint8_t* _saveRam = nullptr;

Mode _mode = Mode::Idle;

bool _chipSelect = false;
bool _clk = false;
uint8_t _dataIn = 0;
bool _writeEnabled = false;

uint16_t _commandId = 0;
uint8_t _bitCount = 0;

uint8_t _readAddress = 0;
int8_t _readCounter = -1;

uint16_t _writeData = 0;
uint8_t _writeCounter = 0;

public:
void SetRam(uint8_t* saveRam)
{
_saveRam = saveRam;
}

uint8_t Read()
{
uint8_t result = (
(_chipSelect ? 0x80 : 0) |
(_clk ? 0x40 : 0) |
(_dataIn ? 0x02 : 0)
);

if(_mode == Mode::ReadCommand) {
if(_readCounter < 0) {
return result | 0x01;
}
return result | ((_saveRam[(_readAddress << 1) + (_readCounter >= 8 ? 0 : 1)] >> (7 - (_readCounter & 0x07))) & 0x01);
} else {
return result | (_mode == Mode::Idle ? 1 : 0);
}
}

void Write(uint8_t value)
{
uint8_t prevClk = _clk;
bool clk = (value & 0x40);
_dataIn = (value & 0x02) >> 1;
_chipSelect = value & 0x80;
_clk = clk;

if(!_chipSelect) {
//Chip select is disabled, force idle
_mode = Mode::Idle;
return;
}


if(!clk || prevClk) {
//Not a rising clock
return;
}

switch(_mode) {
case Mode::Idle:
if(_dataIn) {
_mode = Mode::Command;
_commandId = 0;
_bitCount = 0;
_writeCounter = 0;
_writeData = 0;
_readCounter = -1;
_readAddress = 0;
}
break;

case Mode::Command:
_commandId <<= 1;
_commandId |= _dataIn;
_bitCount++;

if(_bitCount >= 10) {
uint8_t id = _commandId >> 6;
if((id & 0b1100) == 0b1000) {
_mode = Mode::ReadCommand;
_readAddress = _commandId & 0x7F;
} else if((id & 0b1100) == 0b0100) {
_mode = Mode::WriteCommand;
} else if((id & 0b1100) == 0b1100) {
if(_writeEnabled) {
uint8_t addr = _commandId & 0x7F;
_saveRam[addr << 1] = 0xFF;
_saveRam[(addr << 1) + 1] = 0xFF;
}
_mode = Mode::Idle;
} else if((id & 0b1111) == 0b0000) {
//Disable writes (EWDS)
_writeEnabled = false;
_mode = Mode::Idle;
} else if((id & 0b1111) == 0b0011) {
//Enable writes (EWEN)
_writeEnabled = true;
_mode = Mode::Idle;
} else if((id & 0b1111) == 0b0010) {
//Erase all (ERAL)
if(_writeEnabled) {
memset(_saveRam, 0xFF, 256);
}
_mode = Mode::Idle;
} else if((id & 0b1111) == 0b0001) {
//Write all (WRAL)
_mode = Mode::WriteAllCommand;
}
}
break;

case Mode::ReadCommand:
_readCounter++;
if(_readCounter == 16) {
_readAddress = (_readAddress + 1) & 0x7F;
_readCounter = 0;
_mode = Mode::Idle;
}
break;

case Mode::WriteAllCommand:
case Mode::WriteCommand: {
_writeData <<= 1;
_writeData |= _dataIn;
_writeCounter++;
if(_writeCounter >= 16) {
if(_writeEnabled) {
if(_mode == Mode::WriteAllCommand) {
for(int i = 0; i < 0x80; i++) {
_saveRam[i << 1] = _writeData;
_saveRam[(i << 1) + 1] = _writeData >> 8;
}
} else {
uint8_t addr = _commandId & 0x7F;
_saveRam[addr << 1] = _writeData;
_saveRam[(addr << 1) + 1] = _writeData >> 8;
}
}
_mode = Mode::Idle;
}
break;
}
}
}

void Serialize(Serializer& s)
{
SV(_mode);
SV(_chipSelect);
SV(_clk);
SV(_dataIn);
SV(_writeEnabled);
SV(_commandId);
SV(_bitCount);
SV(_readAddress);
SV(_readCounter);
SV(_writeData);
SV(_writeCounter);
}
};
50 changes: 19 additions & 31 deletions Core/Gameboy/Carts/GbMbc7.h
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
#pragma once
#include "pch.h"
#include "Gameboy/Carts/GbCart.h"
#include "Gameboy/Carts/Eeprom93Lc56.h"
#include "Gameboy/Carts/GbMbc7Accelerometer.h"
#include "Gameboy/GbMemoryManager.h"
#include "Utilities/Serializer.h"

class GbMbc7 : public GbCart
{
private:
shared_ptr<GbMbc7Accelerometer> _accelerometer;
Eeprom93Lc56 _eeprom;
bool _ramEnabled = false;
bool _ramEnabled2 = false;
uint16_t _prgBank = 1;

uint16_t _xAccel = 0x8000;
uint16_t _yAccel = 0x8000;
bool _latched = false;

public:
void InitCart() override
{
_accelerometer.reset(new GbMbc7Accelerometer(_gameboy->GetEmulator()));
_gameboy->GetControlManager()->AddSystemControlDevice(_accelerometer);

_eeprom.SetRam(_cartRam);
_memoryManager->MapRegisters(0x0000, 0x5FFF, RegisterAccess::Write);
}

Expand All @@ -36,20 +40,19 @@ class GbMbc7 : public GbCart
}

switch(addr & 0xF0) {
case 0x20: return _xAccel & 0xFF;
case 0x30: return (_xAccel >> 8) & 0xFF;
case 0x40: return _yAccel & 0xFF;
case 0x50: return (_yAccel >> 8) & 0xFF;
case 0x20:
case 0x30:
case 0x40:
case 0x50:
return _accelerometer->Read(addr);

//Always 0
case 0x60: return 0;

//TODO EEPROM
case 0x80: return 0x01;
case 0x80: return _eeprom.Read();

default: return 0xFF;
}

}

void WriteRegister(uint16_t addr, uint8_t value) override
Expand All @@ -63,27 +66,13 @@ class GbMbc7 : public GbCart
RefreshMappings();
} else {
switch(addr & 0xF0) {
//Reset accelerometer latch
case 0x00:
if(value == 0x55) {
_xAccel = 0x8000;
_yAccel = 0x8000;
_latched = false;
}
break;

//Latch accelerometer value
case 0x10:
if(!_latched && value == 0xAA) {
//TODO accelerometer
_xAccel = 0x81D0;
_yAccel = 0x81D0;
_latched = true;
}
_accelerometer->Write(addr, value);
break;

case 0x80:
//TODO EEPROM
_eeprom.Write(value);
break;
}
}
Expand All @@ -94,8 +83,7 @@ class GbMbc7 : public GbCart
SV(_ramEnabled);
SV(_ramEnabled2);
SV(_prgBank);
SV(_xAccel);
SV(_yAccel);
SV(_latched);
SV(_eeprom);
SV(_accelerometer);
}
};
};
Loading

0 comments on commit 8f94cbe

Please sign in to comment.