Add project files.
This commit is contained in:
parent
d40149497b
commit
54d6fc8c1e
33 changed files with 50685 additions and 0 deletions
81
include/bus.hpp
Normal file
81
include/bus.hpp
Normal 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
110
include/cpu.hpp
Normal 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
129
include/lcd.hpp
Normal 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
19
include/mbcs/Imbc.hpp
Normal 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
29
include/mbcs/mbc0.hpp
Normal 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
70
include/mbcs/mbc1.hpp
Normal 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
37
include/rom.hpp
Normal 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
19
include/util.hpp
Normal 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;
|
Loading…
Add table
Add a link
Reference in a new issue