passed json tests
This commit is contained in:
24765
src/3rdParty/json.hpp
vendored
Normal file
24765
src/3rdParty/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -45,3 +45,7 @@ void AddressSpace::loadGame(const std::string& filename) {
|
||||
memoryLayout.romBank0 = game.data();
|
||||
memoryLayout.romBankSwitch = game.data() + ROM_BANK_SIZE;
|
||||
}
|
||||
|
||||
void AddressSpace::setTesting(const bool state) {
|
||||
testing = state;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ class AddressSpace {
|
||||
bool bootromLoaded = true;
|
||||
Byte bootrom[BOOTROM_SIZE] = {0};
|
||||
std::vector<Byte> game;
|
||||
bool testing;
|
||||
Byte testRam[0xFFFF];
|
||||
Byte* cartridgeRam = nullptr;
|
||||
|
||||
public:
|
||||
AddressSpace() {
|
||||
@@ -20,8 +23,6 @@ public:
|
||||
memoryLayout = {};
|
||||
}
|
||||
|
||||
Byte* cartridgeRam = nullptr;
|
||||
|
||||
struct {
|
||||
Byte* romBank0; //[ROM_BANK_SIZE] Mapped to 0x0000
|
||||
Byte* romBankSwitch; //[ROM_BANK_SIZE] Mapped to 0x4000
|
||||
@@ -117,8 +118,12 @@ public:
|
||||
Byte latchClockData = 0x00;
|
||||
Byte ramBankRTCRegister = 0x00;
|
||||
|
||||
void setTesting(bool state);
|
||||
|
||||
//read
|
||||
Byte operator[](const Word address) const {
|
||||
if (testing)
|
||||
return testRam[address];
|
||||
if (address < 0x0100 && bootromLoaded)
|
||||
return bootrom[address];
|
||||
if (address < 0x4000)
|
||||
@@ -248,6 +253,8 @@ public:
|
||||
|
||||
//write
|
||||
Byte& operator[](const Word address) {
|
||||
if (testing)
|
||||
return testRam[address];
|
||||
if (address < 0x0100 && bootromLoaded)
|
||||
return bootrom[address];
|
||||
if (address < 0x8000)
|
||||
|
||||
@@ -767,7 +767,7 @@ void GameBoy::extendedOpcodeResolver() {
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
bit(3, AF.hi);
|
||||
bit(7, AF.hi);
|
||||
PC += 1;
|
||||
addCycles(8);
|
||||
break;
|
||||
|
||||
@@ -9,6 +9,42 @@ void GameBoy::addCycles(const uint8_t ticks) {
|
||||
lastOpTicks = ticks;
|
||||
}
|
||||
|
||||
GameboyTestState GameBoy::runTest(GameboyTestState initial) {
|
||||
addressSpace.setTesting(true);
|
||||
|
||||
PC = initial.PC;
|
||||
SP = initial.SP;
|
||||
AF.hi = initial.A;
|
||||
AF.lo = initial.F;
|
||||
BC.hi = initial.B;
|
||||
BC.lo = initial.C;
|
||||
DE.hi = initial.D;
|
||||
DE.lo = initial.E;
|
||||
HL.hi = initial.H;
|
||||
HL.lo = initial.L;
|
||||
addressSpace.memoryLayout.IE = 1;
|
||||
|
||||
for (const auto& [addr, val] : initial.RAM) {
|
||||
addressSpace[addr] = val;
|
||||
}
|
||||
|
||||
opcodeResolver();
|
||||
|
||||
std::vector<std::tuple<Word, Byte>> returnRAM;
|
||||
for (const auto& [addr, val] : initial.RAM) {
|
||||
returnRAM.emplace_back(addr, addressSpace[addr]);
|
||||
}
|
||||
return {
|
||||
PC, SP,
|
||||
AF.hi, AF.lo,
|
||||
BC.hi, BC.lo,
|
||||
DE.hi, DE.lo,
|
||||
HL.hi, HL.lo,
|
||||
returnRAM
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void GameBoy::start(std::string bootrom, std::string game) {
|
||||
addressSpace.loadBootrom(bootrom);
|
||||
addressSpace.loadGame(game);
|
||||
@@ -20,7 +56,7 @@ void GameBoy::start(std::string bootrom, std::string game) {
|
||||
addressSpace.memoryLayout.SC = 0x7E;
|
||||
|
||||
bool quit = false;
|
||||
|
||||
bool setIME = false;
|
||||
bool display = false;
|
||||
|
||||
while (!quit) {
|
||||
@@ -69,6 +105,14 @@ void GameBoy::start(std::string bootrom, std::string game) {
|
||||
addressSpace.memoryLayout.LY = 0x00;
|
||||
addressSpace.memoryLayout.STAT &= 0xfc;
|
||||
}
|
||||
if (setIME) {
|
||||
IME = 1;
|
||||
setIME = false;
|
||||
}
|
||||
if (IME_togge) {
|
||||
setIME = true;
|
||||
IME_togge = false;
|
||||
}
|
||||
}
|
||||
rendered = false;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
#include "defines.hpp"
|
||||
#include "addressSpace.hpp"
|
||||
#include "testing.hpp"
|
||||
|
||||
union RegisterPair {
|
||||
Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo)
|
||||
@@ -34,6 +32,9 @@ class GameBoy {
|
||||
bool rendered = false;
|
||||
|
||||
uint8_t IME = 0; //enables interupts
|
||||
// EI is actually "disable interrupts for one instruction, then enable them"
|
||||
// This keeps track of that
|
||||
bool IME_togge = false;
|
||||
|
||||
//Accumulator and flags
|
||||
RegisterPair AF = {0};
|
||||
@@ -97,7 +98,7 @@ class GameBoy {
|
||||
//OPCODE FUNCTIONS
|
||||
template <typename T>
|
||||
void ld(T& dest, T src);
|
||||
void ldW(Byte& dest, Word src);
|
||||
void ldW(Word destAddr, Word src);
|
||||
template <typename T>
|
||||
void orBitwise(T& dest, T src);
|
||||
template <typename T>
|
||||
@@ -123,20 +124,16 @@ class GameBoy {
|
||||
void halt();
|
||||
void daa();
|
||||
void stop();
|
||||
template <typename T>
|
||||
void cp(T value);
|
||||
void cp(Byte value);
|
||||
template <typename T>
|
||||
void dec(T& reg);
|
||||
template <typename T>
|
||||
bool jrZ(T offset);
|
||||
template <typename T>
|
||||
void sub(T value);
|
||||
template <class T>
|
||||
void sbc(T value);
|
||||
void sub(Byte value);
|
||||
void sbc(Byte value);
|
||||
template <typename T>
|
||||
void jr(T OFFSET);
|
||||
template <typename T>
|
||||
void push(T reg);
|
||||
void push(Word reg);
|
||||
void rl(Byte& reg);
|
||||
void sla(Byte& reg);
|
||||
void sra(uint8_t& reg);
|
||||
@@ -155,8 +152,7 @@ class GameBoy {
|
||||
void ret();
|
||||
template <typename T>
|
||||
void add(T& reg, T value);
|
||||
template <class T>
|
||||
void adc(T& reg, T value);
|
||||
void adc(Byte value);
|
||||
void cpl();
|
||||
void scf();
|
||||
void ccf();
|
||||
@@ -166,6 +162,8 @@ public:
|
||||
void start(std::string bootrom, std::string game);
|
||||
void SDL2setup();
|
||||
void SDL2destroy() const;
|
||||
|
||||
GameboyTestState runTest(GameboyTestState initial);
|
||||
};
|
||||
|
||||
#endif //GBPP_SRC_GAMEBOY_HPP_
|
||||
|
||||
79
src/main.cpp
79
src/main.cpp
@@ -1,12 +1,89 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include "3rdParty/json.hpp"
|
||||
#include "gameboy.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using json = nlohmann::json;
|
||||
|
||||
void runJSONTests(GameBoy* gb);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto* gb = new GameBoy();
|
||||
gb->SDL2setup();
|
||||
gb->start("../dmg_boot.bin", "../roms/03-op_sp,hl.gb");
|
||||
//runJSONTests(gb);
|
||||
gb->start("../dmg_boot.bin", "../roms/07-jr,jp,call,ret,rst.gb");
|
||||
gb->SDL2destroy();
|
||||
delete gb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void runJSONTests(GameBoy* gb) {
|
||||
std::string path = "../tests/sm83/v1";
|
||||
std::vector<std::string> testFiles;
|
||||
int failed = 0;
|
||||
for (const auto& entry : fs::directory_iterator(path))
|
||||
testFiles.emplace_back(entry.path());
|
||||
|
||||
|
||||
for (const auto& testFile : testFiles) {
|
||||
std::ifstream file(testFile);
|
||||
std::cout << "Running test: " << testFile << std::endl;
|
||||
const json tests = json::parse(file);
|
||||
|
||||
for (auto& test : tests) {
|
||||
//create state
|
||||
std::vector<std::tuple<Word, Byte>> initialRAM;
|
||||
for (int i = 0; i < test["initial"]["ram"].size(); i++)
|
||||
initialRAM.emplace_back(test["initial"]["ram"][i][0], test["initial"]["ram"][i][1]);
|
||||
|
||||
GameboyTestState initialState = {
|
||||
test["initial"]["pc"],
|
||||
test["initial"]["sp"],
|
||||
test["initial"]["a"],
|
||||
test["initial"]["f"],
|
||||
test["initial"]["b"],
|
||||
test["initial"]["c"],
|
||||
test["initial"]["d"],
|
||||
test["initial"]["e"],
|
||||
test["initial"]["h"],
|
||||
test["initial"]["l"],
|
||||
initialRAM
|
||||
};
|
||||
|
||||
//run
|
||||
GameboyTestState result = gb->runTest(initialState);
|
||||
|
||||
//compare new state to expected
|
||||
std::vector<std::tuple<Word, Byte>> finalRAM;
|
||||
for (int i = 0; i < test["final"]["ram"].size(); i++)
|
||||
finalRAM.emplace_back(test["final"]["ram"][i][0], test["final"]["ram"][i][1]);
|
||||
|
||||
GameboyTestState finalState = {
|
||||
test["final"]["pc"],
|
||||
test["final"]["sp"],
|
||||
test["final"]["a"],
|
||||
test["final"]["f"],
|
||||
test["final"]["b"],
|
||||
test["final"]["c"],
|
||||
test["final"]["d"],
|
||||
test["final"]["e"],
|
||||
test["final"]["h"],
|
||||
test["final"]["l"],
|
||||
finalRAM
|
||||
};
|
||||
|
||||
if (finalState != result) {
|
||||
std::cout << "Test " << testFile << " failed!" << std::endl;
|
||||
failed += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!failed)
|
||||
std::cout << "Success!" << std::endl;
|
||||
else
|
||||
std::cout << failed << "/" << testFiles.size() << " failed!" << std::endl;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ Byte GameBoy::getByteSP() {
|
||||
}
|
||||
|
||||
void GameBoy::ret() {
|
||||
pop(PC);
|
||||
PC = readOnlyAddressSpace[SP++];
|
||||
PC |= readOnlyAddressSpace[SP++] << 8;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -61,22 +62,18 @@ void GameBoy::ld(T& dest, T src) {
|
||||
}
|
||||
}
|
||||
|
||||
void GameBoy::ldW(Byte& dest, const Word src) {
|
||||
if (sizeof(src) == sizeof(Word)) {
|
||||
addressSpace[dest] = static_cast<Byte>(src & 0xFF00) >> 8;
|
||||
addressSpace[dest + 1] = static_cast<Byte>(src & 0xFF);
|
||||
}
|
||||
void GameBoy::ldW(const Word destAddr, const Word src) {
|
||||
addressSpace[destAddr] = static_cast<Byte>(src & 0xFF);
|
||||
addressSpace[destAddr + 1] = static_cast<Byte>((src & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::add(T& reg, T value) {
|
||||
if (sizeof(reg) == sizeof(Byte)) {
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
@@ -84,12 +81,10 @@ void GameBoy::add(T& reg, T value) {
|
||||
}
|
||||
|
||||
if (sizeof(reg) == sizeof(Word)) {
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) == 0x1000)
|
||||
if (((value & 0xFFF) + (reg & 0xFFF)) & 0x1000)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((static_cast<unsigned>(value) + static_cast<unsigned>(reg)) & 0x10000)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
@@ -108,39 +103,22 @@ void GameBoy::add(T& reg, T value) {
|
||||
resetFlag(SUBTRACT_FLAG);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::adc(T& reg, T value) {
|
||||
T carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
||||
void GameBoy::adc(const Byte value) {
|
||||
Byte carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
||||
|
||||
if (sizeof(reg) == sizeof(Byte)) {
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
resetFlag(CARRY_FLAG);
|
||||
}
|
||||
if ((AF.hi & 0xF) + (value & 0xF) + carry > 0xF)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
if ((value & 0xFF) + (AF.hi & 0xFF) + carry > 0xFF)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
resetFlag(CARRY_FLAG);
|
||||
|
||||
if (sizeof(reg) == sizeof(Word)) {
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) == 0x1000)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
||||
if ((((value & 0xFFFF) + (reg & 0xFFFF)) & 0x10000) == 0x10000)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
resetFlag(CARRY_FLAG);
|
||||
}
|
||||
|
||||
reg += value + carry;
|
||||
AF.hi += value + carry;
|
||||
|
||||
if (reg == 0)
|
||||
if (AF.hi == 0)
|
||||
setFlag(ZERO_FLAG);
|
||||
else
|
||||
resetFlag(ZERO_FLAG);
|
||||
@@ -148,33 +126,30 @@ void GameBoy::adc(T& reg, T value) {
|
||||
resetFlag(SUBTRACT_FLAG);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::sub(T value) {
|
||||
if (AF.hi < value) {
|
||||
void GameBoy::sub(const Byte value) {
|
||||
if (AF.hi < value)
|
||||
setFlag(CARRY_FLAG);
|
||||
resetFlag(ZERO_FLAG);
|
||||
}
|
||||
else if (AF.hi == value) {
|
||||
setFlag(ZERO_FLAG);
|
||||
else
|
||||
resetFlag(CARRY_FLAG);
|
||||
}
|
||||
if (AF.hi == value)
|
||||
setFlag(ZERO_FLAG);
|
||||
else
|
||||
resetFlag(ZERO_FLAG);
|
||||
if ((AF.hi & 0xf) < (value & 0xf))
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
|
||||
AF.hi -= value;
|
||||
|
||||
setFlag(SUBTRACT_FLAG);
|
||||
//halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/
|
||||
if (0 > (((AF.hi) & 0xf) - (value & 0xf)))
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::sbc(T value) {
|
||||
T carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
||||
T result = AF.hi - value - carry;
|
||||
void GameBoy::sbc(const Byte value) {
|
||||
const Byte carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
||||
const Byte result = AF.hi - value - carry;
|
||||
|
||||
if (AF.hi < value + carry)
|
||||
if ((static_cast<unsigned>(AF.hi) - static_cast<unsigned>(value) - carry) > 0xFF)
|
||||
setFlag(CARRY_FLAG);
|
||||
else
|
||||
resetFlag(CARRY_FLAG);
|
||||
@@ -184,14 +159,14 @@ void GameBoy::sbc(T value) {
|
||||
else
|
||||
resetFlag(ZERO_FLAG);
|
||||
|
||||
setFlag(SUBTRACT_FLAG);
|
||||
|
||||
if ((AF.hi & 0xF) < (value & 0xF) + carry)
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
|
||||
AF.hi = result;
|
||||
|
||||
setFlag(SUBTRACT_FLAG);
|
||||
}
|
||||
|
||||
//https://gbdev.gg8.se/wiki/articles/DAA
|
||||
@@ -361,25 +336,23 @@ void GameBoy::call(T address) {
|
||||
PC = address;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::cp(T value) //compare
|
||||
void GameBoy::cp(const Byte value) //compare
|
||||
{
|
||||
resetFlag(ZERO_FLAG);
|
||||
resetFlag(CARRY_FLAG);
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
|
||||
if (AF.hi == value) {
|
||||
setFlag(ZERO_FLAG);
|
||||
}
|
||||
if ((AF.hi & 0xF) < (value & 0xF)) {
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
}
|
||||
if (AF.hi < value) {
|
||||
setFlag(CARRY_FLAG);
|
||||
resetFlag(ZERO_FLAG);
|
||||
}
|
||||
else if (AF.hi == value) {
|
||||
setFlag(ZERO_FLAG);
|
||||
resetFlag(CARRY_FLAG);
|
||||
}
|
||||
|
||||
setFlag(SUBTRACT_FLAG);
|
||||
|
||||
//halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/
|
||||
if (0 > (((AF.hi) & 0xf) - (value & 0xf)))
|
||||
setFlag(HALFCARRY_FLAG);
|
||||
else
|
||||
resetFlag(HALFCARRY_FLAG);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -639,16 +612,10 @@ void GameBoy::pop(T& reg) {
|
||||
AF.reg &= 0xFFF0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::push(T reg) {
|
||||
void GameBoy::push(const Word reg) {
|
||||
//little endian
|
||||
RegisterPair temp = {0};
|
||||
temp.lo = reg & 0xFF;
|
||||
temp.hi = reg >> 8;
|
||||
SP -= 1;
|
||||
addressSpace[SP] = temp.hi;
|
||||
SP -= 1;
|
||||
addressSpace[SP] = temp.lo;
|
||||
addressSpace[--SP] = reg >> 8;
|
||||
addressSpace[--SP] = reg & 0xFF;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -658,6 +625,7 @@ void GameBoy::jp(T address) {
|
||||
|
||||
template <typename T>
|
||||
void GameBoy::rst(T address) {
|
||||
PC += 1;
|
||||
push(PC);
|
||||
PC = address;
|
||||
}
|
||||
@@ -739,7 +707,7 @@ void GameBoy::opcodeResolver() {
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
ldW(addressSpace[getWordPC()], SP);
|
||||
ldW(getWordPC(), SP);
|
||||
PC += 3;
|
||||
addCycles(20);
|
||||
break;
|
||||
@@ -840,7 +808,7 @@ void GameBoy::opcodeResolver() {
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
add(HL.reg, BC.reg);
|
||||
add(HL.reg, DE.reg);
|
||||
PC += 1;
|
||||
addCycles(8);
|
||||
break;
|
||||
@@ -1530,49 +1498,49 @@ void GameBoy::opcodeResolver() {
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
adc(AF.hi, BC.hi);
|
||||
adc(BC.hi);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
adc(AF.hi, BC.lo);
|
||||
adc(BC.lo);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x8A:
|
||||
adc(AF.hi, DE.hi);
|
||||
adc(DE.hi);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
adc(AF.hi, DE.lo);
|
||||
adc(DE.lo);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x8C:
|
||||
adc(AF.hi, HL.hi);
|
||||
adc(HL.hi);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x8D:
|
||||
adc(AF.hi, HL.lo);
|
||||
adc(HL.lo);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
case 0x8E:
|
||||
adc(AF.hi, readOnlyAddressSpace[HL.reg]);
|
||||
adc(readOnlyAddressSpace[HL.reg]);
|
||||
PC += 1;
|
||||
addCycles(8);
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
adc(AF.hi, AF.hi);
|
||||
adc(AF.hi);
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
@@ -1970,7 +1938,7 @@ void GameBoy::opcodeResolver() {
|
||||
break;
|
||||
|
||||
case 0xCE:
|
||||
adc(AF.hi, getBytePC());
|
||||
adc(getBytePC());
|
||||
PC += 2;
|
||||
addCycles(8);
|
||||
break;
|
||||
@@ -2246,10 +2214,10 @@ void GameBoy::opcodeResolver() {
|
||||
addCycles(16);
|
||||
break;
|
||||
|
||||
//should not actually enable until the next opcode
|
||||
//EI (0xFB) then DI (0xF3) does not allow interrupts to happen
|
||||
//EI (0xFB) then DI (0xF3) never allows interrupts to happen
|
||||
case 0xFB:
|
||||
IME = 1;
|
||||
IME = 0;
|
||||
IME_togge = true;
|
||||
PC += 1;
|
||||
addCycles(4);
|
||||
break;
|
||||
|
||||
43
src/testing.hpp
Normal file
43
src/testing.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef TESTING_HPP
|
||||
#define TESTING_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include "defines.hpp"
|
||||
|
||||
struct GameboyTestState {
|
||||
Word PC;
|
||||
Word SP;
|
||||
Byte A;
|
||||
Byte F;
|
||||
Byte B;
|
||||
Byte C;
|
||||
Byte D;
|
||||
Byte E;
|
||||
Byte H;
|
||||
Byte L;
|
||||
//Byte IME;
|
||||
//Byte IE;
|
||||
std::vector<std::tuple<Word, Byte>> RAM;
|
||||
};
|
||||
|
||||
inline bool operator==(const GameboyTestState& lhs, const GameboyTestState& rhs) {
|
||||
for (int i = 0; i < lhs.RAM.size(); i++) {
|
||||
if (std::get<1>(lhs.RAM[i]) != std::get<1>(rhs.RAM[i]))
|
||||
return false;
|
||||
}
|
||||
return (lhs.A == rhs.A &&
|
||||
lhs.F == rhs.F &&
|
||||
lhs.B == rhs.B &&
|
||||
lhs.C == rhs.C &&
|
||||
lhs.D == rhs.D &&
|
||||
lhs.E == rhs.E &&
|
||||
lhs.H == rhs.H &&
|
||||
lhs.L == rhs.L);
|
||||
}
|
||||
|
||||
#endif //TESTING_HPP
|
||||
Reference in New Issue
Block a user