You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
8.4 KiB
242 lines
8.4 KiB
/* GameBoyInstance.h |
|
* |
|
* A GameBoy core for Plip. |
|
*/ |
|
|
|
#pragma once |
|
|
|
#include "../PlipCore.h" |
|
#include "../../Cpu/SharpLr35902/SharpLr35902.h" |
|
#include "../../Memory/PlipMemoryMap.h" |
|
#include "../../Memory/PlipMemoryRam.h" |
|
#include "../../Memory/PlipMemoryRom.h" |
|
|
|
namespace Plip::Core::GameBoy { |
|
class GameBoyInstance : public PlipCore { |
|
public: |
|
GameBoyInstance(PlipAudio *audio, PlipInput *input, PlipVideo *video, PlipConfig *config); |
|
~GameBoyInstance(); |
|
|
|
void ClearBreakpoint() override; |
|
void Delta(long ns) override; |
|
std::string DumpRegisters() override; |
|
PlipError Load(const std::string &path) override; |
|
void Redraw() override; |
|
void SetBreakpoint(uint32_t pc) override; |
|
|
|
const int BaseClockRate = 4194304; |
|
const int InputRight = 0; |
|
const int InputLeft = 1; |
|
const int InputUp = 2; |
|
const int InputDown = 3; |
|
const int InputA = 4; |
|
const int InputB = 5; |
|
const int InputSelect = 6; |
|
const int InputStart = 7; |
|
|
|
private: |
|
inline void Plot(uint8_t color, int pos) { |
|
if(m_lcdBlankFrame) color = 0b00; |
|
|
|
switch(color) { |
|
case 0b00: |
|
// White |
|
m_videoFmt.plot(m_videoBuffer, pos, 255, 255, 255, 255); |
|
break; |
|
case 0b01: |
|
// Light Gray |
|
m_videoFmt.plot(m_videoBuffer, pos, 172, 172, 172, 255); |
|
break; |
|
case 0b10: |
|
// Dark Gray |
|
m_videoFmt.plot(m_videoBuffer, pos, 86, 86, 86, 255); |
|
break; |
|
case 0b11: |
|
// Black |
|
m_videoFmt.plot(m_videoBuffer, pos, 0, 0, 0, 255); |
|
break; |
|
default: |
|
// Huh. Okay, make it pretty obvious that something's up. |
|
m_videoFmt.plot(m_videoBuffer, pos, 255, 0, 0, 255); |
|
break; |
|
} |
|
} |
|
|
|
void BootRomFlagHandler(); |
|
uint16_t GetRomBankCount(); |
|
void InitCartRam(); |
|
void InputRegisterHandler(); |
|
void ReadCartFeatures(); |
|
void ReadInput(); |
|
void RegisterInput(); |
|
|
|
// GameBoyInstance.Mbc.cpp |
|
void MbcInit(); |
|
void MbcCycle(PlipMemoryValue lastWrite); |
|
void Mbc1Cycle(PlipMemoryValue lastWrite); |
|
|
|
// GameBoyInstance.timer.cpp |
|
void TimerExecute(); |
|
[[nodiscard]] static uint8_t TimerFallingEdgeBit(uint8_t tac); |
|
[[nodiscard]] bool TimerFallingEdgeDetection(uint8_t bit) const; |
|
void TimerIncreaseTima(); |
|
void TimerTima(); |
|
|
|
// GameBoyInstance.Video.cpp |
|
void VideoCycle(); |
|
void VideoExecute(); |
|
[[nodiscard]] bool VideoHBlank() const; |
|
void VideoModePostTransition(); |
|
void VideoModePreTransition(); |
|
void VideoOamDmaTransfer(); |
|
void VideoOamDmaTransferEnd(); |
|
void VideoOamDmaTransferStart(); |
|
[[nodiscard]] bool VideoOamSearch(); |
|
void VideoSetMemoryPermissions(); |
|
[[nodiscard]] bool VideoVBlank(); |
|
[[nodiscard]] bool VideoVidGen(); |
|
void VideoVidGenDraw(); |
|
|
|
// Core |
|
bool m_bootRomFlag = false; |
|
uint32_t m_bp = 0xFFFFFFFF; |
|
std::string m_bootRomPath; |
|
Plip::Cpu::SharpLr35902 *m_cpu; |
|
long m_cycleRemaining = 0; |
|
int m_dotCyclesRemaining = 0; |
|
const int m_dotsPerCycle = 4; |
|
PlipMemoryValue m_lastWrite {}; |
|
uint8_t *m_videoBuffer; |
|
size_t m_videoBufferSize; |
|
PlipVideoFormatInfo m_videoFmt {}; |
|
|
|
// Cartridge Information |
|
enum MemoryBankController { |
|
None, |
|
Mbc1, |
|
Mbc2, |
|
Mbc3, |
|
Mbc5, |
|
Mbc6, |
|
Mbc7, |
|
Mmm01, |
|
PocketCamera, |
|
BandaiTama5, |
|
HuC1, |
|
HuC3 |
|
}; |
|
|
|
MemoryBankController m_mbc = None; |
|
bool m_hasBattery = false; |
|
bool m_hasCamera = false; |
|
bool m_hasRam = false; |
|
bool m_hasRtc = false; |
|
bool m_hasSensor = false; |
|
|
|
uint16_t m_romBanks = 0; |
|
uint16_t m_cartRamBanks = 0; |
|
|
|
// MBC |
|
uint8_t m_mbcMode = 0; |
|
uint8_t m_mbcRomBank = 0; |
|
uint8_t m_mbcRamBank = 0; |
|
bool m_mbcRamEnabled = false; |
|
|
|
// Memory |
|
Plip::PlipMemoryRom *m_bootRom = nullptr; |
|
Plip::PlipMemoryRom *m_rom = nullptr; |
|
uint8_t m_unusableContents[0x60] {}; |
|
Plip::PlipMemoryRom *m_unusable; |
|
|
|
Plip::PlipMemoryRam *m_cartRam = nullptr; |
|
Plip::PlipMemoryRam *m_workRam; |
|
Plip::PlipMemoryRam *m_videoRam; |
|
Plip::PlipMemoryRam *m_oam; |
|
Plip::PlipMemoryRam *m_ioRegisters; |
|
Plip::PlipMemoryRam *m_highRam; |
|
|
|
static const uint32_t m_addrRom = 0x0000; |
|
static const uint32_t m_addrBankedRom = 0x4000; |
|
static const uint32_t m_addrVideoRam = 0x8000; |
|
static const uint32_t m_addrWorkRam = 0xC000; |
|
static const uint32_t m_addrCartRam = 0xA000; |
|
static const uint32_t m_addrEchoRam = 0xE000; |
|
static const uint32_t m_addrOam = 0xFE00; |
|
static const uint32_t m_addrUnusable = 0xFEA0; |
|
static const uint32_t m_addrRegisters = 0xFF00; |
|
static const uint32_t m_addrHighRam = 0xFF80; |
|
|
|
// Boot |
|
static const uint32_t m_addrBootRomDisable = 0xFF50 - m_addrRegisters; |
|
|
|
// Input |
|
uint8_t m_keypad = 0; |
|
|
|
const uint32_t m_regJoypad = 0xFF00 - m_addrRegisters; |
|
|
|
// Timer |
|
static const uint32_t m_regDivider = 0xFF04 - m_addrRegisters; |
|
static const uint32_t m_regTima = 0xFF05 - m_addrRegisters; |
|
static const uint32_t m_regTma = 0xFF06 - m_addrRegisters; |
|
static const uint32_t m_regTac = 0xFF07 - m_addrRegisters; |
|
|
|
uint16_t m_timer = 0; |
|
uint16_t m_timerLast = 0; |
|
uint8_t m_timerTacLast = 0; |
|
bool m_timerTimaOverflow = false; |
|
|
|
// Video |
|
static const uint32_t m_regLcdControl = 0xFF40 - m_addrRegisters; |
|
static const uint32_t m_regLcdcStatus = 0xFF41 - m_addrRegisters; |
|
static const uint32_t m_regScy = 0xFF42 - m_addrRegisters; // R/W scroll Y |
|
static const uint32_t m_regScx = 0xFF43 - m_addrRegisters; // R/W - scroll X |
|
static const uint32_t m_regLy = 0xFF44 - m_addrRegisters; // R |
|
static const uint32_t m_regLyCompare = 0xFF45 - m_addrRegisters; // R/W |
|
static const uint32_t m_regOamDmaTransfer = 0xFF46 - m_addrRegisters; // R/W |
|
static const uint32_t m_regBgp = 0xFF47 - m_addrRegisters; // R/W - BG/window palette |
|
static const uint32_t m_regObp0 = 0xFF48 - m_addrRegisters; // R/W - object palette 0 |
|
static const uint32_t m_regObp1 = 0xFF49 - m_addrRegisters; // R/W - object palette 0 |
|
static const uint32_t m_regWy = 0xFF4A - m_addrRegisters; // R/W - window Y |
|
static const uint32_t m_regWx = 0xFF7B - m_addrRegisters; // R/W - window X - 7 |
|
|
|
static const uint32_t m_vramTileBase = 0x8000 - m_addrVideoRam; |
|
static const uint32_t m_vramTileBlockOffset = 0x0800; |
|
static const uint32_t m_vramBgBase = 0x9800 - m_addrVideoRam; |
|
static const uint32_t m_vramBgBlockOffset = 0x0400; |
|
|
|
static const uint8_t m_maxSpritesPerScanline = 10; |
|
static const uint8_t m_maxSpritesInOam = 40; |
|
|
|
static const uint32_t m_videoHBlankTime = 0; |
|
static const uint32_t m_videoOamScanTime = 80; |
|
static const uint32_t m_videoScanlineTime = 376; |
|
static const uint32_t m_videoVBlankTime = 4560; |
|
|
|
static const uint32_t m_videoModeHBlank = 0; |
|
static const uint32_t m_videoModeVBlank = 1; |
|
static const uint32_t m_videoModeOamSearch = 2; |
|
static const uint32_t m_videoModePicGen = 3; |
|
|
|
static const uint32_t m_screenWidth = 160; |
|
static const uint32_t m_screenHeight = 144; |
|
|
|
enum VidGenStage { |
|
BackgroundScrolling, |
|
Drawing |
|
}; |
|
|
|
int m_dotCount = 0; |
|
bool m_lcdBlankFrame = false; |
|
uint8_t *m_spriteList; |
|
uint8_t *m_spriteListSorted; |
|
uint8_t m_spriteListIdx = 0; |
|
int m_videoCoincidence = 0; |
|
int m_videoOamDmaTransferIdx = -1; |
|
int m_videoMode = 0; |
|
uint8_t m_videoLastLcdc = 0; |
|
int m_videoLx = 0; |
|
int m_videoLy = 0; |
|
VidGenStage m_vidGenStage = BackgroundScrolling; |
|
int m_vidGenTick = 0; |
|
}; |
|
}
|
|
|