Add project files.

This commit is contained in:
Robert 2021-07-12 04:54:24 +02:00
parent d40149497b
commit 54d6fc8c1e
33 changed files with 50685 additions and 0 deletions

81
include/bus.hpp Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include <array>
#include "util.hpp"
#include "cpu.hpp"
#include "lcd.hpp"
#include "rom.hpp"
typedef union
{
BYTE b;
struct
{
BYTE select : 2;
BYTE enable : 1;
BYTE padding : 5;
} w;
} TimerControl;
typedef union
{
BYTE b;
struct
{
BYTE rightA : 1;
BYTE leftB : 1;
BYTE upSelect : 1;
BYTE downStart : 1;
BYTE selectDirKeys : 1;
BYTE selectButtonKeys : 1;
BYTE unused : 2;
} w;
} JoypadReg;
struct Joypad
{
bool a, b, up, down, left, right, start, select;
};
class Bus
{
public:
Bus();
~Bus();
void AttachCPU(CPU& cpu);
void AttachLCD(LCD& lcd);
void InsertROM(ROM& rom);
bool Tick();
bool Execute();
bool Frame();
BYTE Read(WORD addr);
void Write(WORD addr, BYTE val);
BYTE Fetch(WORD addr);
private:
BYTE& GetReference(WORD addr);
public:
ROM* rom;
CPU* cpu;
LCD* lcd;
BYTE invalid;
BYTE div;
BYTE tima;
BYTE tma;
BYTE dmg_rom;
JoypadReg joypadReg;
TimerControl tac;
size_t internalCounter = 0;
Joypad joypad;
// std::array<BYTE, 0x2000> vram;
std::array<BYTE, 0x2000> wram;
std::array<BYTE, 0x80> hram;
};

110
include/cpu.hpp Normal file
View file

@ -0,0 +1,110 @@
#pragma once
#include <array>
#include <string>
#include "util.hpp"
class Bus;
struct Register
{
union
{
WORD w;
struct
{
BYTE lo, hi;
} b;
};
char name[3];
};
typedef union {
BYTE b;
struct
{
BYTE vblank : 1;
BYTE lcd_stat : 1;
BYTE timer : 1;
BYTE serial : 1;
BYTE joypad : 1;
BYTE padding : 3;
} flags;
} Interrupt;
typedef union
{
BYTE b;
struct
{
BYTE unused : 4;
BYTE carry : 1;
BYTE halfCarry : 1;
BYTE negative : 1;
BYTE zero : 1;
} f;
} StatusFlag;
typedef union
{
BYTE b;
struct
{
BYTE z : 3;
BYTE y : 3;
BYTE x : 2;
} xyz;
struct
{
BYTE padding1 : 3;
BYTE q : 1;
BYTE p : 2;
BYTE padding2 : 2;
} pq;
} Opcode;
class CPU
{
public:
void Powerup();
void Tick();
friend class Bus;
public:
Interrupt interruptEnable;
Interrupt interruptFlag;
size_t totalCycles;
BYTE cycles;
Register AF; // Acc & Flags
Register BC;
Register DE;
Register HL;
Register SP; // Stack pointer
Register PC; // Program counter
StatusFlag* flag;
Opcode opcode;
std::array<Register*, 4> rp;
std::array<Register*, 4> rp2;
BYTE ime;
Bus* bus;
bool stopped;
bool halted;
bool justHaltedWithDI;
private:
void WriteToRegister(BYTE reg, BYTE val);
BYTE ReadFromRegister(BYTE reg);
void ALU(BYTE operation, BYTE operand);
void CBPrefixed();
};

129
include/lcd.hpp Normal file
View file

@ -0,0 +1,129 @@
#pragma once
#include <array>
#include "util.hpp"
class Bus;
typedef union
{
BYTE b;
struct
{
BYTE mode : 2;
BYTE coincidence : 1;
BYTE mode0 : 1;
BYTE mode1 : 1;
BYTE mode2 : 1;
BYTE lyc : 1;
} w;
} STAT;
typedef union
{
BYTE b;
struct
{
BYTE priority : 1;
BYTE obj_enable : 1;
BYTE obj_size : 1;
BYTE bg_tilemap : 1;
BYTE tiledata : 1;
BYTE window : 1;
BYTE window_tilemap : 1;
BYTE enable : 1;
} w;
} LCDC;
typedef union
{
WORD w;
struct
{
BYTE lo, hi;
} b;
} LCDRegister;
typedef struct
{
WORD sprite;
WORD highByte, lowByte;
WORD full;
} PixelFIFO;
typedef struct
{
WORD tile;
BYTE cycle;
BYTE x, y;
BYTE lo, hi;
} PixelFetcher;
typedef union
{
QWORD q;
struct
{
BYTE y;
BYTE x;
BYTE idx;
struct
{
BYTE padding : 4;
BYTE palette : 1;
BYTE xFlip : 1;
BYTE yFlip : 1;
BYTE bgPriority : 1;
} attr;
} b;
} OAMEntry;
class LCD
{
public:
void Setup();
void Tick();
BYTE& GetReferenceToAddress(WORD addr, bool& handled);
bool Read(WORD addr, BYTE& val);
bool Write(WORD addr, BYTE val);
DWORD cycles;
WORD scanlineCycles;
friend class Bus;
friend class CPU;
public:
std::array<BYTE, 160 * 144> display;
std::array<BYTE, 0x2000> vram;
std::array<BYTE, 0xA0> oam;
public:
Bus* bus;
// Registers
LCDC lcdc;
STAT stat;
BYTE scy;
BYTE scx;
BYTE ly;
BYTE lyc;
BYTE wy;
BYTE wx;
BYTE bgp;
BYTE obp0;
BYTE obp1;
BYTE dma;
PixelFetcher fetcher;
PixelFIFO bgFIFO;
PixelFIFO spriteFIFO;
BYTE x;
BYTE dmaCycles;
};

19
include/mbcs/Imbc.hpp Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "util.hpp"
class IMBC
{
public:
IMBC(WORD romBanks, WORD ramBanks, WORD ramSize) :
romBanks(romBanks), ramBanks(ramBanks), ramSize(ramSize)
{ }
virtual ~IMBC() {}
virtual bool GetMappedRead(WORD address, DWORD& mappedAddr) = 0;
virtual bool GetMappedWrite(WORD address, BYTE val, DWORD& mappedAddr) = 0;
protected:
WORD romBanks, ramBanks, ramSize;
};

29
include/mbcs/mbc0.hpp Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "Imbc.hpp"
class MBC0 : public IMBC
{
public:
MBC0(WORD ramBanks) : IMBC(2, ramBanks, 8) {}
virtual bool GetMappedRead(WORD address, DWORD& mappedAddress) override;
virtual bool GetMappedWrite(WORD address, BYTE val, DWORD& mappedAddress) override;
private:
};
inline bool MBC0::GetMappedRead(WORD address, DWORD& mappedAddress)
{
mappedAddress = address;
return (address < 0x8000);
}
inline bool MBC0::GetMappedWrite(WORD address, BYTE val, DWORD& mappedAddress)
{
if (ramBanks && 0xA000 <= address && address < 0xC000)
{
mappedAddress = address;
return true;
}
return false;
}

70
include/mbcs/mbc1.hpp Normal file
View file

@ -0,0 +1,70 @@
#pragma once
#include "Imbc.hpp"
class MBC1 : public IMBC
{
public:
MBC1(WORD romBanks, WORD ramBanks, WORD ramSize) : IMBC(romBanks, ramBanks, ramSize) {}
virtual bool GetMappedRead(WORD address, DWORD& mappedAddr) override;
virtual bool GetMappedWrite(WORD address, BYTE val, DWORD& mappedAddr) override;
private:
BYTE RamEnable = 0x00;
BYTE RomBankNumber = 0x01;
BYTE RamBankNumber = 0x00;
BYTE ModeSelect = 0x00;
};
inline bool MBC1::GetMappedRead(WORD address, DWORD& mappedAddr)
{
if (address < 0x4000)
{
mappedAddr = address;
return true;
}
else if(0x4000 <= address && address < 0x8000)
{
mappedAddr = ((DWORD)((RamBankNumber << (5 * !ModeSelect)) | RomBankNumber) * 0x4000) + (address & 0x3FFF);
return true;
}
else if (0xA000 <= address && address < 0xC000)
{
mappedAddr = (DWORD)((RamBankNumber * ModeSelect) * 0x2000) + (address & 0x1FFF);
return true;
}
return false;
}
inline bool MBC1::GetMappedWrite(WORD address, BYTE val, DWORD& mappedAddr)
{
if (0x0000 <= address && address < 0x2000)
{
RamEnable = val;
return false;
}
else if (0x2000 <= address && address < 0x4000)
{
RomBankNumber = val;
if (RomBankNumber == 0x00 || RomBankNumber == 0x20 || RomBankNumber == 0x40 || RomBankNumber == 0x60)
RomBankNumber += 1;
return false;
}
else if (0x4000 <= address && address < 0x6000)
{
RamBankNumber = val;
return false;
}
else if (0x6000 <= address && address < 0x8000)
{
ModeSelect = val;
return false;
}
else if (ramBanks == 0 && 0xA000 <= address && address < 0xC000)
return false;
mappedAddr = (DWORD)((RamBankNumber * ModeSelect) * 0x2000) + (address & 0x1FFF);
return true;
}

37
include/rom.hpp Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include <vector>
#include <memory>
#include "util.hpp"
#include "mbcs/Imbc.hpp"
class Bus;
struct MemoryBankController
{
BYTE w;
struct
{
BYTE ROMBankNumber : 5;
BYTE RAMBankNumber : 2;
BYTE Mode : 1;
} b;
};
class ROM
{
public:
ROM(FILE* f);
BYTE Read(WORD addr);
void Write(WORD addr, BYTE val);
friend class Bus;
private:
Bus* bus;
std::unique_ptr<IMBC> mbc;
std::vector<BYTE> data, ram;
};

19
include/util.hpp Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned long long QWORD;
#define EXIT_MSG(msg, ...) { \
fprintf(stderr, (msg), __VA_ARGS__); \
fprintf(stderr, "\n"); \
fprintf(stderr, "%s\n", strerror(errno)); \
fprintf(stderr, "Exiting.\n"); \
}
inline BYTE undefined;