prelim mbc work
This commit is contained in:
@@ -12,5 +12,8 @@ add_executable(GBpp src/main.cpp
|
|||||||
src/ppu.cpp
|
src/ppu.cpp
|
||||||
src/timing.cpp
|
src/timing.cpp
|
||||||
src/extendedOpcodeResolver.cpp
|
src/extendedOpcodeResolver.cpp
|
||||||
|
src/mbc.cpp
|
||||||
|
src/addressSpace.cpp
|
||||||
|
src/addressSpace.hpp
|
||||||
)
|
)
|
||||||
target_link_libraries(GBpp ${SDL2_LIBRARIES})
|
target_link_libraries(GBpp ${SDL2_LIBRARIES})
|
||||||
34
src/addressSpace.cpp
Normal file
34
src/addressSpace.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "addressSpace.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bool AddressSpace::getBootromState() const {
|
||||||
|
return bootromLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressSpace::unmapBootrom() {
|
||||||
|
bootromLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressSpace::mapBootrom() {
|
||||||
|
bootromLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressSpace::loadBootrom(const std::string& filename) {
|
||||||
|
std::ifstream file;
|
||||||
|
if (const uintmax_t size = std::filesystem::file_size(filename); size != 256) {
|
||||||
|
std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
file.open(filename, std::ios::binary);
|
||||||
|
file.read(reinterpret_cast<char*>(bootrom), BOOTROM_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressSpace::loadGame(const std::string& filename) {
|
||||||
|
game.open(filename, std::ios::binary);
|
||||||
|
|
||||||
|
if (!game.is_open()) {
|
||||||
|
std::cerr << "Game was not found!\nQuitting!\n" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
game.read(reinterpret_cast<char*>(memoryLayout.romBank1), ROM_BANK_SIZE * 2);
|
||||||
|
}
|
||||||
77
src/addressSpace.hpp
Normal file
77
src/addressSpace.hpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#ifndef ADDRESSSPACE_HPP
|
||||||
|
#define ADDRESSSPACE_HPP
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include "defines.hpp"
|
||||||
|
|
||||||
|
class AddressSpace {
|
||||||
|
bool bootromLoaded = true;
|
||||||
|
Byte bootrom[BOOTROM_SIZE] = {0};
|
||||||
|
std::ifstream game;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddressSpace() {
|
||||||
|
// Initialize the memory to zero
|
||||||
|
memoryLayout = {};
|
||||||
|
std::memset(memoryLayout.memory, 0, sizeof(memoryLayout.memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested union for the memory layout
|
||||||
|
union MemoryLayout {
|
||||||
|
Byte memory[0x10000];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Byte romBank1[ROM_BANK_SIZE]; // Mapped to 0x0000
|
||||||
|
Byte romBankSwitch[ROM_BANK_SIZE]; // Mapped to 0x4000
|
||||||
|
Byte vram[0x2000]; // Mapped to 0x8000
|
||||||
|
Byte externalRam[0x2000]; // Mapped to 0xA000
|
||||||
|
Byte memoryBank1[0x1000]; // Mapped to 0xC000
|
||||||
|
Byte memoryBank2[0x1000]; // Mapped to 0xD000
|
||||||
|
Byte echoRam[0x1E00]; // Mapped to 0xE000 (Echo RAM, mirrors 0xC000 to 0xDFFF)
|
||||||
|
Byte spriteAttributeTable[0xA0]; // Mapped to 0xFE00
|
||||||
|
Byte notUsable[0x60]; // Mapped to 0xFEA0
|
||||||
|
Byte io[0x80]; // Mapped to 0xFF00, 0xFF0F is interrupt flag
|
||||||
|
Byte specialRam[0x7F]; // Mapped to 0xFF80
|
||||||
|
Byte interuptEnableReg; // Mapped to 0xFFFF
|
||||||
|
};
|
||||||
|
} memoryLayout{};
|
||||||
|
|
||||||
|
void unmapBootrom();
|
||||||
|
void mapBootrom();
|
||||||
|
bool getBootromState() const;
|
||||||
|
void loadBootrom(const std::string& filename);
|
||||||
|
void loadGame(const std::string& filename);
|
||||||
|
|
||||||
|
void determineMBCInfo();
|
||||||
|
MBCType MBC = {};
|
||||||
|
uint32_t RomSize = 0;
|
||||||
|
uint32_t RomPages = 0;
|
||||||
|
uint32_t ExternalRamSize = 0;
|
||||||
|
uint32_t ExternalRamPages = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//overload [] for echo ram and bootrom support
|
||||||
|
Byte operator[](const uint32_t address) const {
|
||||||
|
if (address >= 0xE000 && address < 0xFE00)
|
||||||
|
return memoryLayout.echoRam[address - 0x2000];
|
||||||
|
if (address < 0x0100 && bootromLoaded)
|
||||||
|
return bootrom[address];
|
||||||
|
|
||||||
|
return memoryLayout.memory[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte& operator[](const uint32_t address) {
|
||||||
|
if (address >= 0xE000 && address < 0xFE00)
|
||||||
|
return memoryLayout.echoRam[address - 0x2000];
|
||||||
|
if (address < 0x0100 && bootromLoaded)
|
||||||
|
return bootrom[address];
|
||||||
|
|
||||||
|
return memoryLayout.memory[address];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ADDRESSSPACE_HPP
|
||||||
@@ -46,5 +46,50 @@
|
|||||||
#define SCANLINE_OAM_FREQ 80 //PPU_MODE 2
|
#define SCANLINE_OAM_FREQ 80 //PPU_MODE 2
|
||||||
#define SCANLINE_VRAM_FREQ 80 //PPU_MODE 3
|
#define SCANLINE_VRAM_FREQ 80 //PPU_MODE 3
|
||||||
|
|
||||||
|
//two bits per colour
|
||||||
|
enum Colour {
|
||||||
|
black = 0b11,
|
||||||
|
darkGray = 0b10,
|
||||||
|
lightGray = 0b01,
|
||||||
|
white = 0b00
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MBCType {
|
||||||
|
romOnly = 0x00,
|
||||||
|
MBC1 = 0x01,
|
||||||
|
MBC1Ram = 0x02,
|
||||||
|
MBC1RamBattery = 0x03,
|
||||||
|
MBC2 = 0x05,
|
||||||
|
MBC2Battery = 0x06,
|
||||||
|
RomRam = 0x08, //unused
|
||||||
|
RomRamBattery = 0x09, //unused
|
||||||
|
MMM01 = 0x0B, //multigame roms only
|
||||||
|
MMM01Ram = 0x0C,
|
||||||
|
MMM01RamBattery = 0x0D,
|
||||||
|
MBC3TimerBattery = 0x0F,
|
||||||
|
MBC3TimerRamBattery = 0x10,
|
||||||
|
MBC3 = 0x11,
|
||||||
|
MBC3Ram = 0x12, // MBC3 with 64 KiB of SRAM refers to MBC30, used only in Pocket Monsters: Crystal Version.
|
||||||
|
MBC3RamBattery = 0x13,
|
||||||
|
MBC5 = 0x19,
|
||||||
|
MBC5Ram = 0x1A,
|
||||||
|
MBC5RamBattery = 0x1B,
|
||||||
|
MBC5Rumble = 0x1C,
|
||||||
|
MBC5RumbleRam = 0x1D,
|
||||||
|
MBC5RumbleRamBattery = 0x1E,
|
||||||
|
MBC6 = 0x20,
|
||||||
|
MBC7SensorRumbleRamBattery = 0x22,
|
||||||
|
PocketCamera = 0xFC,
|
||||||
|
BandaiTama5 = 0xFD,
|
||||||
|
HuC3 = 0xFE,
|
||||||
|
HuC1RamBattery = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PPUMode {
|
||||||
|
mode0, // Horizontal Blank (Mode 0): No access to video RAM, occurs during horizontal blanking period.
|
||||||
|
mode1, // Vertical Blank (Mode 1): No access to video RAM, occurs during vertical blanking period.
|
||||||
|
mode2, // OAM Search (Mode 2): Access to OAM (Object Attribute Memory) only, sprite evaluation.
|
||||||
|
mode3 // Pixel Transfer (Mode 3): Access to both OAM and video RAM, actual pixel transfer to the screen.
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,38 +1,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "gameboy.hpp"
|
#include "gameboy.hpp"
|
||||||
|
|
||||||
bool AddressSpace::getBootromState() const {
|
|
||||||
return bootromLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddressSpace::unmapBootrom() {
|
|
||||||
bootromLoaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddressSpace::mapBootrom() {
|
|
||||||
bootromLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddressSpace::loadBootrom(const std::string& filename) {
|
|
||||||
std::ifstream file;
|
|
||||||
if (const uintmax_t size = std::filesystem::file_size(filename); size != 256) {
|
|
||||||
std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
file.open(filename, std::ios::binary);
|
|
||||||
file.read(reinterpret_cast<char*>(bootrom), BOOTROM_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddressSpace::loadGame(const std::string& filename) {
|
|
||||||
game.open(filename, std::ios::binary);
|
|
||||||
|
|
||||||
if (!game.is_open()) {
|
|
||||||
std::cerr << "Game was not found!\nQuitting!\n" << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
game.read(reinterpret_cast<char*>(memoryLayout.romBank1), ROM_BANK_SIZE * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoy::addCycles(const uint8_t ticks) {
|
void GameBoy::addCycles(const uint8_t ticks) {
|
||||||
cycles += ticks;
|
cycles += ticks;
|
||||||
if (ppuEnabled) {
|
if (ppuEnabled) {
|
||||||
@@ -54,43 +22,46 @@ void GameBoy::start(std::string bootrom, std::string game) {
|
|||||||
bool display = false;
|
bool display = false;
|
||||||
|
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
// Event loop: Check and handle SDL events
|
// Event loop
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
if (event.type == SDL_QUIT) {
|
if (event.type == SDL_QUIT) {
|
||||||
quit = true; // Set the quit flag when the close button is hit
|
quit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PC > 0xFF && addressSpace.getBootromState()) {
|
while (!rendered) {
|
||||||
addressSpace.unmapBootrom();
|
if (PC > 0xFF && addressSpace.getBootromState()) {
|
||||||
}
|
addressSpace.unmapBootrom();
|
||||||
ppuEnabled = (*LCDC) & 0x80;
|
}
|
||||||
|
ppuEnabled = (*LCDC) & 0x80;
|
||||||
|
|
||||||
// if (PC == 0x100)
|
// if (PC == 0x100)
|
||||||
// display = true;
|
// display = true;
|
||||||
// if (display) {
|
// if (display) {
|
||||||
// printf("Cycles: %lu, Opcode: 0x%.2x PPU cycles: %lu, PPMode: %d\n", cycles, addressSpace[PC],
|
// printf("Cycles: %lu, Opcode: 0x%.2x PPU cycles: %lu, PPMode: %d\n", cycles, addressSpace[PC],
|
||||||
// cyclesSinceLastScanline(), currentMode);
|
// cyclesSinceLastScanline(), currentMode);
|
||||||
// printf("PC:0x%.2x, SP:0x%.2x\n", PC, SP);
|
// printf("PC:0x%.2x, SP:0x%.2x\n", PC, SP);
|
||||||
// printf("AF:0x%.4x, BC:0x%.4x\n", AF.reg, BC.reg);
|
// printf("AF:0x%.4x, BC:0x%.4x\n", AF.reg, BC.reg);
|
||||||
// printf("DE:0x%.4x, HL:0x%.4x\n", DE.reg, HL.reg);
|
// printf("DE:0x%.4x, HL:0x%.4x\n", DE.reg, HL.reg);
|
||||||
// printf("IME:%d IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE));
|
// printf("IME:%d IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE));
|
||||||
// printf("LCDC:%.2x STAT:0x%.2x LY:%d LYC:%d\n", (*LCDC), (*STAT), (*LY), (*LYC));
|
// printf("LCDC:%.2x STAT:0x%.2x LY:%d LYC:%d\n", (*LCDC), (*STAT), (*LY), (*LYC));
|
||||||
// printf("\n");
|
// printf("\n");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
opcodeResolver();
|
opcodeResolver();
|
||||||
interruptHandler();
|
interruptHandler();
|
||||||
timingHandler();
|
timingHandler();
|
||||||
if (ppuEnabled) {
|
if (ppuEnabled) {
|
||||||
ppuUpdate();
|
ppuUpdate();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ppuCycles = 2;
|
ppuCycles = 2;
|
||||||
lastScanline = 0;
|
lastScanline = 0;
|
||||||
lastRefresh = 0;
|
lastRefresh = 0;
|
||||||
(*LY) = 0x00;
|
(*LY) = 0x00;
|
||||||
(*STAT) &= 0xfc;
|
(*STAT) &= 0xfc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
rendered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,21 +9,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
|
#include "addressSpace.hpp"
|
||||||
//two bits per colour
|
|
||||||
enum Colour {
|
|
||||||
black = 0b11,
|
|
||||||
darkGray = 0b10,
|
|
||||||
lightGray = 0b01,
|
|
||||||
white = 0b00
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PPUMode {
|
|
||||||
mode0, // Horizontal Blank (Mode 0): No access to video RAM, occurs during horizontal blanking period.
|
|
||||||
mode1, // Vertical Blank (Mode 1): No access to video RAM, occurs during vertical blanking period.
|
|
||||||
mode2, // OAM Search (Mode 2): Access to OAM (Object Attribute Memory) only, sprite evaluation.
|
|
||||||
mode3 // Pixel Transfer (Mode 3): Access to both OAM and video RAM, actual pixel transfer to the screen.
|
|
||||||
};
|
|
||||||
|
|
||||||
union RegisterPair {
|
union RegisterPair {
|
||||||
Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo)
|
Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo)
|
||||||
@@ -34,64 +20,6 @@ union RegisterPair {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressSpace {
|
|
||||||
bool bootromLoaded = true;
|
|
||||||
Byte bootrom[BOOTROM_SIZE] = {0};
|
|
||||||
std::ifstream game;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AddressSpace() {
|
|
||||||
// Initialize the memory to zero
|
|
||||||
memoryLayout = {};
|
|
||||||
std::memset(memoryLayout.memory, 0, sizeof(memoryLayout.memory));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nested union for the memory layout
|
|
||||||
union MemoryLayout {
|
|
||||||
Byte memory[0x10000];
|
|
||||||
|
|
||||||
struct {
|
|
||||||
Byte romBank1[ROM_BANK_SIZE]; // Mapped to 0x0000
|
|
||||||
Byte romBankSwitch[ROM_BANK_SIZE]; // Mapped to 0x4000
|
|
||||||
Byte vram[0x2000]; // Mapped to 0x8000
|
|
||||||
Byte externalRam[0x2000]; // Mapped to 0xA000
|
|
||||||
Byte memoryBank1[0x1000]; // Mapped to 0xC000
|
|
||||||
Byte memoryBank2[0x1000]; // Mapped to 0xD000
|
|
||||||
Byte echoRam[0x1E00]; // Mapped to 0xE000 (Echo RAM, mirrors 0xC000 to 0xDFFF)
|
|
||||||
Byte spriteAttributeTable[0xA0]; // Mapped to 0xFE00
|
|
||||||
Byte notUsable[0x60]; // Mapped to 0xFEA0
|
|
||||||
Byte io[0x80]; // Mapped to 0xFF00, 0xFF0F is interrupt flag
|
|
||||||
Byte specialRam[0x7F]; // Mapped to 0xFF80
|
|
||||||
Byte interuptEnableReg; // Mapped to 0xFFFF
|
|
||||||
};
|
|
||||||
} memoryLayout{};
|
|
||||||
|
|
||||||
void unmapBootrom();
|
|
||||||
void mapBootrom();
|
|
||||||
bool getBootromState() const;
|
|
||||||
void loadBootrom(const std::string& filename);
|
|
||||||
void loadGame(const std::string& filename);
|
|
||||||
|
|
||||||
//overload [] for echo ram and bootrom support
|
|
||||||
Byte operator[](const uint32_t address) const {
|
|
||||||
if (address >= 0xE000 && address < 0xFE00)
|
|
||||||
return memoryLayout.echoRam[address - 0x2000];
|
|
||||||
if (address < 0x0100 && bootromLoaded)
|
|
||||||
return bootrom[address];
|
|
||||||
|
|
||||||
return memoryLayout.memory[address];
|
|
||||||
}
|
|
||||||
|
|
||||||
Byte& operator[](const uint32_t address) {
|
|
||||||
if (address >= 0xE000 && address < 0xFE00)
|
|
||||||
return memoryLayout.echoRam[address - 0x2000];
|
|
||||||
if (address < 0x0100 && bootromLoaded)
|
|
||||||
return bootrom[address];
|
|
||||||
|
|
||||||
return memoryLayout.memory[address];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class GameBoy {
|
class GameBoy {
|
||||||
//T-cycles not M-cycles (4 T-cycles = 1 M-cycle)
|
//T-cycles not M-cycles (4 T-cycles = 1 M-cycle)
|
||||||
uint64_t cycles = 0;
|
uint64_t cycles = 0;
|
||||||
@@ -103,6 +31,7 @@ class GameBoy {
|
|||||||
uint64_t lastScanline = 0;
|
uint64_t lastScanline = 0;
|
||||||
uint64_t cyclesToStayInHblank = -1;
|
uint64_t cyclesToStayInHblank = -1;
|
||||||
uint64_t lastDivUpdate = 0;
|
uint64_t lastDivUpdate = 0;
|
||||||
|
bool rendered = false;
|
||||||
|
|
||||||
uint8_t IME = 0; //enables interupts
|
uint8_t IME = 0; //enables interupts
|
||||||
|
|
||||||
@@ -120,7 +49,6 @@ class GameBoy {
|
|||||||
|
|
||||||
//General purpose hardware registers
|
//General purpose hardware registers
|
||||||
Byte* const JOYP = &addressSpace[0xFF00];
|
Byte* const JOYP = &addressSpace[0xFF00];
|
||||||
|
|
||||||
Byte* const SB = &addressSpace[0xFF01];
|
Byte* const SB = &addressSpace[0xFF01];
|
||||||
Byte* const SC = &addressSpace[0xFF02];
|
Byte* const SC = &addressSpace[0xFF02];
|
||||||
Byte* const DIV = &addressSpace[0xFF04];
|
Byte* const DIV = &addressSpace[0xFF04];
|
||||||
@@ -223,6 +151,7 @@ class GameBoy {
|
|||||||
//OPCODE FUNCTIONS
|
//OPCODE FUNCTIONS
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ld(T& dest, T src);
|
void ld(T& dest, T src);
|
||||||
|
void ldW(Byte& dest, Word src);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void orBitwise(T& dest, T src);
|
void orBitwise(T& dest, T src);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -249,8 +178,6 @@ class GameBoy {
|
|||||||
void daa();
|
void daa();
|
||||||
void stop();
|
void stop();
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ldW(T dest, T src);
|
|
||||||
template <typename T>
|
|
||||||
void cp(T value);
|
void cp(T value);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void dec(T& reg);
|
void dec(T& reg);
|
||||||
|
|||||||
1
src/mbc.cpp
Normal file
1
src/mbc.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "gameboy.hpp"
|
||||||
@@ -46,19 +46,22 @@ void GameBoy::ret() {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::ld(T& dest, T src) {
|
void GameBoy::ld(T& dest, T src) {
|
||||||
if constexpr (std::is_same_v<T, Byte*>) {
|
if constexpr (std::is_same_v<T, Byte>) {
|
||||||
if (&dest == DIV)
|
if (&dest == DIV) {
|
||||||
*DIV = 0x00;
|
*DIV = 0x00;
|
||||||
lastDivUpdate = cycles;
|
lastDivUpdate = cycles;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest = src;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
//16-bit register pair write
|
||||||
dest = src;
|
dest = src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameBoy::ldW(Byte& dest, const Word src) {
|
||||||
template <typename T>
|
|
||||||
void GameBoy::ldW(T dest, T src) {
|
|
||||||
if (sizeof(src) == sizeof(Word)) {
|
if (sizeof(src) == sizeof(Word)) {
|
||||||
addressSpace[dest] = static_cast<Byte>(src & 0xFF00) >> 8;
|
addressSpace[dest] = static_cast<Byte>(src & 0xFF00) >> 8;
|
||||||
addressSpace[dest + 1] = static_cast<Byte>(src & 0xFF);
|
addressSpace[dest + 1] = static_cast<Byte>(src & 0xFF);
|
||||||
@@ -169,28 +172,22 @@ void GameBoy::sbc(T value) {
|
|||||||
T carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
T carry = getFlag(CARRY_FLAG) ? 1 : 0;
|
||||||
T result = AF.hi - value - carry;
|
T result = AF.hi - value - carry;
|
||||||
|
|
||||||
if (AF.hi < value + carry) {
|
if (AF.hi < value + carry)
|
||||||
setFlag(CARRY_FLAG);
|
setFlag(CARRY_FLAG);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
resetFlag(CARRY_FLAG);
|
resetFlag(CARRY_FLAG);
|
||||||
}
|
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0)
|
||||||
setFlag(ZERO_FLAG);
|
setFlag(ZERO_FLAG);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
resetFlag(ZERO_FLAG);
|
resetFlag(ZERO_FLAG);
|
||||||
}
|
|
||||||
|
|
||||||
setFlag(SUBTRACT_FLAG);
|
setFlag(SUBTRACT_FLAG);
|
||||||
|
|
||||||
if ((AF.hi & 0xF) < (value & 0xF) + carry) {
|
if ((AF.hi & 0xF) < (value & 0xF) + carry)
|
||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
}
|
|
||||||
|
|
||||||
AF.hi = result;
|
AF.hi = result;
|
||||||
}
|
}
|
||||||
@@ -398,7 +395,6 @@ void GameBoy::dec(T& reg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::swap(Byte& value) {
|
void GameBoy::swap(Byte& value) {
|
||||||
// Extract the lower and upper nibbles of the register
|
|
||||||
const Byte lowerNibble = value & 0x0F;
|
const Byte lowerNibble = value & 0x0F;
|
||||||
const Byte upperNibble = (value >> 4) & 0x0F;
|
const Byte upperNibble = (value >> 4) & 0x0F;
|
||||||
|
|
||||||
@@ -734,7 +730,7 @@ void GameBoy::opcodeResolver() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08:
|
case 0x08:
|
||||||
ldW(getWordPC(), SP);
|
ldW(addressSpace[getWordPC()], SP);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
addCycles(20);
|
addCycles(20);
|
||||||
break;
|
break;
|
||||||
@@ -2237,7 +2233,7 @@ void GameBoy::opcodeResolver() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFA:
|
case 0xFA:
|
||||||
ldW(AF.hi, addressSpace[getWordPC()]);
|
ld(AF.hi, addressSpace[getWordPC()]);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
addCycles(16);
|
addCycles(16);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ void GameBoy::SDL2setup() {
|
|||||||
screen = SDL_CreateWindow("GBpp",
|
screen = SDL_CreateWindow("GBpp",
|
||||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
RESOLUTION_X, RESOLUTION_Y,
|
RESOLUTION_X, RESOLUTION_Y,
|
||||||
SDL_WINDOW_OPENGL);
|
0);
|
||||||
|
|
||||||
// Create an SDL renderer to draw on the window
|
// Create an SDL renderer to draw on the window
|
||||||
renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
|
renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
|
||||||
@@ -203,7 +203,8 @@ void GameBoy::SDL2present() {
|
|||||||
if (frameDelay > frameTime) {
|
if (frameDelay > frameTime) {
|
||||||
SDL_Delay(frameDelay - frameTime);
|
SDL_Delay(frameDelay - frameTime);
|
||||||
}
|
}
|
||||||
frameStart = SDL_GetTicks();
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
|
frameStart = SDL_GetTicks();
|
||||||
|
rendered = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user