From: slack Date: Mon, 20 Aug 2007 03:32:10 +0000 (+0000) Subject: - Cambiados accesos a memoria de operator[] a read() y write() X-Git-Tag: v0.1~67 X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=dda0d8bd67aa20e615da07bea0b0a41526a7bbf9;p=wenboi.git - Cambiados accesos a memoria de operator[] a read() y write() - Nuevos opcodes: saltos, DI/EI, calls - Corregido bug en check_flag - Creado test_core. Lanza el emulador en plan "a ver que pasa" Primera "ejecucion" de opcodes de gameboy! \o/ git-svn-id: http://slack.codemaniacs.com/wenboi@12 0666ae3d-8926-0410-aeff-ae84559ff337 --- diff --git a/GBMemory.cc b/GBMemory.cc index a5786b3..8538c4e 100644 --- a/GBMemory.cc +++ b/GBMemory.cc @@ -2,40 +2,50 @@ #include "MBC.h" #include "gbcore.h" #include "Logger.h" +#include +#include +#include -u8& GBMemory::operator[](unsigned int addr) +void GBMemory::write(int addr, u8 value) { - if (addr < 0x8000) return (*mbc)[addr]; - else if (addr < 0xA000) return VRAM[addr-0x8000]; - else if (addr < 0xC000) return (*mbc)[addr]; - else if (addr < 0xD000) return WRAM0[addr-0xC000]; - else if (addr < 0xE000) return WRAM1[addr-0xD000]; - else if (addr < 0xFDFF) return (*mbc)[addr-0x2000]; - else if (addr < 0xFEA0) return OAM[addr-0xFDFF]; - else if (addr >= 0xFF00 && addr <= 0xFF7F) - return core->IO.addr[addr-0xFF00]; - else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80]; + if (addr < 0x8000) mbc->write(addr, value); + else if (addr < 0xA000) VRAM [addr - VRAM_BASE] = value; + else if (addr < 0xC000) mbc->write(addr, value); + else if (addr < 0xD000) WRAM0[addr - WRAM0_BASE] = value; + else if (addr < 0xE000) WRAM1[addr - WRAM1_BASE] = value; + else if (addr < 0xFDFF) write(addr-0x2000, value); + else if (addr < 0xFEA0) OAM [addr - OAM_BASE] = value; + else if (addr >= 0xFF00 && addr <= 0xFF7F) { + IO.write(addr,value); + } + else if (addr >= 0xFF80 && addr <= 0xFFFE) HRAM[addr - HRAM_BASE]=value; else { - logger.error("Invalid write address"); - return *(static_cast(0)); + std::ostringstream errmsg; + errmsg << "Invalid write address 0x" << + std::hex << std::setw(4) << std::setfill('0') << addr; + logger.error(errmsg.str()); + std::cout << *(static_cast(0)); } } -u8 GBMemory::operator[](unsigned int addr) const +u8 GBMemory::read(int addr) const { - if (addr < 0x8000) return (*mbc)[addr]; - else if (addr < 0xA000) return VRAM[addr-0x8000]; - else if (addr < 0xC000) return (*mbc)[addr]; - else if (addr < 0xD000) return WRAM0[addr-0xC000]; - else if (addr < 0xE000) return WRAM1[addr-0xD000]; - else if (addr < 0xFDFF) return (*mbc)[addr-0x2000]; - else if (addr < 0xFEA0) return OAM[addr-0xFDFF]; + if (addr < 0x8000) return mbc->read(addr); + else if (addr < 0xA000) return VRAM [addr - VRAM_BASE]; + else if (addr < 0xC000) return mbc->read(addr); + else if (addr < 0xD000) return WRAM0[addr - WRAM0_BASE]; + else if (addr < 0xE000) return WRAM1[addr - WRAM1_BASE]; + else if (addr < 0xFDFF) return read(addr-0x2000); + else if (addr < 0xFEA0) return OAM [addr - OAM_BASE]; else if (addr >= 0xFF00 && addr <= 0xFF7F) - return core->IO.addr[addr-0xFF00]; - else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80]; + return IO.read(addr); + else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr - HRAM_BASE]; else { - logger.error("Invalid write address"); + std::ostringstream errmsg; + errmsg << "Invalid read address 0x" << + std::hex << std::setw(4) << std::setfill('0') << addr; + logger.error(errmsg.str()); return *(static_cast(0)); } } diff --git a/GBMemory.h b/GBMemory.h index 6e02479..f1f979f 100644 --- a/GBMemory.h +++ b/GBMemory.h @@ -6,6 +6,18 @@ class GameBoy; class MBC; +class GBIO +{ + u8 ports[128]; + + public: + static const u16 IO_BASE = 0xFF00; + + u8 read(int addr) const { return ports[addr-IO_BASE]; } + void write(int addr, u8 value) { ports[addr-IO_BASE] = value; } + +}; + class GBMemory { GameBoy *core; @@ -18,15 +30,26 @@ class GBMemory u8 WRAM1[4096]; // D000-DFFF: Work RAM Bank 1 (TODO: In GBC mode switchable bank 1-7) // E000-FDFF: ECHO: Same as C000-DDFF u8 OAM[160]; // FE00-FE9F: Sprite Attribute Table + GBIO IO; // FF00-FF7F: IO ports + u8 HRAM[126]; // FF80-FFFE: High RAM public: - GBMemory(GameBoy *core): core(core), mbc(0) {} + + static const u16 VRAM_BASE = 0x8000; + static const u16 EXTERNAL_RAM_BASE = 0xA000; + static const u16 WRAM0_BASE = 0xC000; + static const u16 WRAM1_BASE = 0xD000; + static const u16 OAM_BASE = 0xFE00; + static const u16 IO_BASE = 0xFF00; + static const u16 HRAM_BASE = 0xFF80; + + GBMemory(GameBoy *core): core(core), mbc(0), IO() {} void init(MBC *mbc) { this->mbc = mbc; } - u8& operator[](unsigned int addr); - u8 operator[](unsigned int addr) const; + u8 read(int addr) const; + void write(int addr, u8 value); }; diff --git a/GBRom.cc b/GBRom.cc index 7ebd8da..a0d7e9d 100644 --- a/GBRom.cc +++ b/GBRom.cc @@ -18,7 +18,8 @@ void log_rom_header(GBRom *rom, Logger::log_level level) out << "Logging ROM header data:" << endl; out << std::hex << std::right << std::setfill('0'); - out << "Entrypoint: 0x" << rom->header.entry_point << endl; + out << "Entrypoint: 0x" << std::setw(8) << + rom->header.entry_point << endl; out << "SGB flag: " << int(rom->header.sgb_flag) << endl; out << "Cartridge type: " << int(rom->header.cartridge_type) << endl; diff --git a/MBC.cc b/MBC.cc index f208f73..6b49b45 100644 --- a/MBC.cc +++ b/MBC.cc @@ -1,6 +1,9 @@ #include "MBC.h" #include "Logger.h" #include +#include +#include +#include using namespace cartridge_types; @@ -16,7 +19,7 @@ MBC *create_MBC(GBRom *rom) } } -u8 NoMBC::operator[](unsigned int addr) const +u8 NoMBC::read(int addr) const { if (addr <= 0x7FFF) return ROM[addr]; @@ -27,12 +30,19 @@ u8 NoMBC::operator[](unsigned int addr) const return 0; } -u8& NoMBC::operator[](unsigned int addr) +void NoMBC::write(int addr, u8 value) { - if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF) - return RAM[addr-0xA000]; - else - logger.error("NoMBC: trying to write in ROM"); - return *(static_cast(0)); // Shouldn't happen + if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF) + { + RAM[addr-0xA000]=value; + return; + } + else + { + std::ostringstream errmsg; + errmsg <<"NoMBC: trying to write in ROM, addr=0x"<(0)); // Shouldn't happen + } } diff --git a/MBC.h b/MBC.h index 81fd79f..3284538 100644 --- a/MBC.h +++ b/MBC.h @@ -7,9 +7,9 @@ class MBC { public: - virtual u8 operator[](unsigned int addr) const=0; - virtual u8& operator[](unsigned int addr)=0; - virtual ~MBC(); + virtual u8 read(int addr) const=0; + virtual void write(int addr, u8 value)=0; + virtual ~MBC() {}; }; class NoMBC: public MBC @@ -19,8 +19,8 @@ class NoMBC: public MBC public: NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); } - u8 operator[](unsigned int addr) const; - u8& operator[](unsigned int addr); + u8 read (int addr) const; + void write(int addr, u8 value); }; diff --git a/Makefile b/Makefile index 63c4f39..09ed32e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ CXXFLAGS=-g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast \ -Woverloaded-virtual +LDFLAGS=-g all: gbcore.o MBC.o GBMemory.o Logger.o GBRom.o tests diff --git a/gbcore.cc b/gbcore.cc index bbed7e7..b02caf8 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -3,11 +3,18 @@ #include "GBRom.h" #include "MBC.h" #include "Logger.h" +#include +#include #include #include GameBoy::GameBoy(std::string rom_name): - memory(this),rom(0), regs(), IO(), IME(1), HALT(0) + memory(this), + rom(0), + regs(), + IME(1), + HALT(0), + cycle_count(0) { logger.info("GameBoy init"); rom = read_gbrom(rom_name); @@ -30,11 +37,11 @@ void GameBoy::run_cycle() { int prefix; int opcode; - opcode = memory[regs.PC++]; + opcode = memory.read(regs.PC++); if (opcode == 0xCB) { prefix=opcode; - opcode=memory[regs.PC++]; + opcode=memory.read(regs.PC++); } switch(opcode) @@ -58,86 +65,86 @@ void GameBoy::run_cycle() for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg) case 0x36: // LD (HL), n - memory[regs.HL] = memory[regs.PC++]; + memory.write(regs.HL, memory.read(regs.PC++)); break; // LD A, mem case 0x0A: // LD A, (BC) - regs.A = memory[regs.BC]; + regs.A = memory.read(regs.BC); break; case 0x1A: // LD A, (DE) - regs.A = memory[regs.DE]; + regs.A = memory.read(regs.DE); break; case 0xFA: // LD A, (nn) - regs.A = memory[memory[regs.PC] + memory[regs.PC+1]<<8]; + regs.A = memory.read(memory.read(regs.PC) + memory.read(regs.PC+1)<<8); regs.PC+=2; break; // LD mem, A case 0x02: // LD (BC), A - memory[regs.BC] = regs.A; + memory.write(regs.BC, regs.A); break; case 0x12: // LD (DE), A - memory[regs.DE] = regs.A; + memory.write(regs.DE, regs.A); break; case 0xEA: // LD (nn), A - memory[memory[regs.PC] + memory[regs.PC+1]<<8] = regs.A; + memory.write(memory.read(regs.PC) + memory.read(regs.PC+1)<<8, regs.A); break; // LD A, (C) case 0xF2: - regs.A = memory[0xFF00 + regs.C]; + regs.A = memory.read(0xFF00 + regs.C); break; // LD (C), A case 0xE2: - memory[0xFF00 + regs.C] = regs.A; + memory.write(0xFF00 + regs.C, regs.A); break; // LD A, (HLD); LD A, (HL-); LDD A,(HL); case 0x3A: - regs.A = memory[regs.HL]; + regs.A = memory.read(regs.HL); --regs.HL; break; // LD (HLD), A; LD (HL-), A; LDD (HL), A; case 0x32: - memory[regs.HL] = regs.A; + memory.write(regs.HL, regs.A); --regs.HL; break; // LD A, (HLI); LD A, (HL+); LDI A, (HL); case 0x2A: - regs.A = memory[regs.HL]; + regs.A = memory.read(regs.HL); ++regs.HL; break; // LD (HLI), A; LD (HL+), A; LDI (HL), A; case 0x22: - memory[regs.HL] = regs.A; + memory.write(regs.HL, regs.A); ++regs.HL; break; // LDH (n), A case 0xE0: - memory[0xFF00 + regs.PC++] = regs.A; + memory.write(0xFF00 + regs.PC++, regs.A); break; // LDH A, (n) case 0xF0: - regs.A = memory[0xFF00 + regs.PC++]; + regs.A = memory.read(0xFF00 + regs.PC++); break; // LD n, nn case 0x01: // LD BC, nn - regs.BC = memory[regs.PC]+(memory[regs.PC+1] << 8); + regs.BC = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8); regs.PC +=2; break; case 0x11: // LD DE, nn - regs.DE = memory[regs.PC]+(memory[regs.PC+1] << 8); + regs.DE = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8); regs.PC +=2; break; case 0x21: // LD HL, nn - regs.HL = memory[regs.PC]+(memory[regs.PC+1] << 8); + regs.HL = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8); regs.PC +=2; break; case 0x31: // LD SP, nn - regs.SP = memory[regs.PC]+(memory[regs.PC+1] << 8); + regs.SP = memory.read(regs.PC)+(memory.read(regs.PC+1) << 8); regs.PC +=2; break; @@ -149,7 +156,7 @@ void GameBoy::run_cycle() // LD HL, SP+n // LDHL SP, n case 0xF8: { - s8 offset = memory[regs.PC++]; + s8 offset = memory.read(regs.PC++); int res = regs.SP + offset; // TODO: Verificar si los flags van asi @@ -165,9 +172,9 @@ void GameBoy::run_cycle() // LD (nn), SP case 0x08: { - int addr = memory[regs.PC] + memory[regs.PC+1] << 8; + int addr = memory.read(regs.PC) + memory.read(regs.PC+1) << 8; regs.PC += 2; - memory[addr] = regs.SP; + memory.write(addr, regs.SP); break; } @@ -188,8 +195,8 @@ void GameBoy::run_cycle() for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg) case 0x86: {// ADD A, (HL) - int res = regs.A + memory[regs.HL]; - int half_res = (regs.A & 0x0F) + (memory[regs.HL] & 0x0F); + int res = regs.A + memory.read(regs.HL); + int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F); regs.A = static_cast(res); reset_flag(ADD_SUB_FLAG); @@ -199,7 +206,7 @@ void GameBoy::run_cycle() break; } case 0xC6: {//ADD A, # - int inm = memory[regs.PC++]; + int inm = memory.read(regs.PC++); int res = regs.A + inm; int half_res = (regs.A & 0x0F) + (inm & 0x0F); regs.A = static_cast(res); @@ -216,8 +223,8 @@ void GameBoy::run_cycle() case 0x8E: {// ADC A, (HL) int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int res = regs.A + memory[regs.HL] + carry; - int half_res = (regs.A & 0x0F) + (memory[regs.HL] & 0x0F) + carry; + int res = regs.A + memory.read(regs.HL) + carry; + int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry; regs.A = static_cast(res); reset_flag(ADD_SUB_FLAG); @@ -228,7 +235,7 @@ void GameBoy::run_cycle() } case 0xCE: {//ADC A, # int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int inm = memory[regs.PC++]; + int inm = memory.read(regs.PC++); int res = regs.A + inm + carry; int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry; regs.A = static_cast(res); @@ -244,8 +251,8 @@ void GameBoy::run_cycle() for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg) case 0x96: {//SUB (HL) - int res = regs.A - memory[regs.HL]; - int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F); + int res = regs.A - memory.read(regs.HL); + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); regs.A = static_cast(res); set_flag(ADD_SUB_FLAG); @@ -256,7 +263,7 @@ void GameBoy::run_cycle() } case 0xD6: {//SUB # - int inm = memory[regs.PC++]; + int inm = memory.read(regs.PC++); int res = regs.A - inm; int half_res = (regs.A & 0x0F) - (inm & 0x0F); regs.A = static_cast(res); @@ -273,8 +280,8 @@ void GameBoy::run_cycle() case 0x9E: {//SBC (HL) int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int res = regs.A - memory[regs.HL] - carry; - int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F) - carry; + int res = regs.A - memory.read(regs.HL) - carry; + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry; regs.A = static_cast(res); set_flag(ADD_SUB_FLAG); @@ -290,7 +297,7 @@ void GameBoy::run_cycle() for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg) case 0xA6: //AND (HL) - regs.A &= memory[regs.HL]; + regs.A &= memory.read(regs.HL); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); set_flag(HALF_CARRY_FLAG); @@ -298,7 +305,7 @@ void GameBoy::run_cycle() break; case 0xE6: //AND inm - regs.A &= memory[regs.PC++]; + regs.A &= memory.read(regs.PC++); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); set_flag(HALF_CARRY_FLAG); @@ -309,7 +316,7 @@ void GameBoy::run_cycle() for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg) case 0xB6: //OR (HL) - regs.A |= memory[regs.HL]; + regs.A |= memory.read(regs.HL); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); reset_flag(HALF_CARRY_FLAG); @@ -317,7 +324,7 @@ void GameBoy::run_cycle() break; case 0xF6: //OR inm - regs.A |= memory[regs.PC++]; + regs.A |= memory.read(regs.PC++); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); reset_flag(HALF_CARRY_FLAG); @@ -328,7 +335,7 @@ void GameBoy::run_cycle() for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg) case 0xAE: //XOR (HL) - regs.A ^= memory[regs.HL]; + regs.A ^= memory.read(regs.HL); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); reset_flag(HALF_CARRY_FLAG); @@ -336,7 +343,7 @@ void GameBoy::run_cycle() break; case 0xEE: //XOR inm - regs.A ^= memory[regs.PC++]; + regs.A ^= memory.read(regs.PC++); if (regs.A == 0) set_flag(ZERO_FLAG); reset_flag(ADD_SUB_FLAG); reset_flag(HALF_CARRY_FLAG); @@ -347,8 +354,8 @@ void GameBoy::run_cycle() for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg) case 0xBE: {//SUB (HL) - int res = regs.A - memory[regs.HL]; - int half_res = (regs.A & 0x0F) - (memory[regs.HL] & 0x0F); + int res = regs.A - memory.read(regs.HL); + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); regs.A = static_cast(res); set_flag(ADD_SUB_FLAG); @@ -359,7 +366,7 @@ void GameBoy::run_cycle() } case 0xFE: {//SUB # - int inm = memory[regs.PC++]; + int inm = memory.read(regs.PC++); int res = regs.A - inm; int half_res = (regs.A & 0x0F) - (inm & 0x0F); regs.A = static_cast(res); @@ -375,10 +382,10 @@ void GameBoy::run_cycle() for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg) case 0x34: {//INC (HL) - int half_res = (memory[regs.HL] & 0x0F) + 1; - ++memory[regs.HL]; + int half_res = (memory.read(regs.HL) & 0x0F) + 1; + memory.write(regs.HL, memory.read(regs.HL) - 1); reset_flag(ADD_SUB_FLAG); - set_flag_if (memory[regs.HL] == 0, ZERO_FLAG); + set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); break; } @@ -387,10 +394,10 @@ void GameBoy::run_cycle() for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg) case 0x35: {//DEC (HL) - int half_res = (memory[regs.HL] & 0x0F) - 1; - --memory[regs.HL]; + int half_res = (memory.read(regs.HL) & 0x0F) - 1; + memory.write(regs.HL, memory.read(regs.HL) - 1); set_flag(ADD_SUB_FLAG); - set_flag_if (memory[regs.HL] == 0, ZERO_FLAG); + set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); set_flag_if (half_res < 0, HALF_CARRY_FLAG); break; } @@ -402,7 +409,7 @@ void GameBoy::run_cycle() // ADD SP, # case 0xE8: { // FIXME: No se que hacer con el half carry, en 4 o en 11? - int n = static_cast(memory[regs.PC++]); + int n = static_cast(memory.read(regs.PC++)); int res = regs.SP + n; regs.SP = static_cast(res); reset_flag(ZERO_FLAG); @@ -420,16 +427,16 @@ void GameBoy::run_cycle() // Miscellaneous instructions // SWAP n case 0xCB: { - int sub_opcode = memory[regs.PC++]; + int sub_opcode = memory.read(regs.PC++); switch(sub_opcode) { for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg) // SWAP (HL) case 0x36: { - u8 tmp = memory[regs.HL]; + u8 tmp = memory.read(regs.HL); tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4); - memory[regs.HL] = tmp; + memory.write(regs.HL, tmp); set_flag_if(tmp==0, ZERO_FLAG); reset_flag(CARRY_FLAG); @@ -501,30 +508,215 @@ void GameBoy::run_cycle() break; // STOP - case 0x10: - int sub_opcode = memory[regs.PC++]; + case 0x10: { + int sub_opcode = memory.read(regs.PC++); if (sub_opcode == 0x00) { HALT = true; } else { logger.critical("Unknown sub-opcode after 0x10"); } + break; + } + + // DI + case 0xF3: + IME = 0; + break; + // EI + case 0xFB: + IME = 1; + break; + + // TODO: Rotates and shifts + // TODO: Bit instructions + + // Jumps + // JP nn + case 0xC3: + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + break; + // JP cc, nn + case 0xC2: { // JP NZ, nn + u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + if (!check_flag(ZERO_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + break; + } + case 0xCA: { // JP Z, nn + u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + if (check_flag(ZERO_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + break; + } + case 0xD2: { // JP NC, nn + u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + if (!check_flag(CARRY_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + break; + } + case 0xDA: { // JP C, nn + u16 dst = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + if (check_flag(CARRY_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + break; + } - + // JP (HL) + case 0xE9: + regs.PC = regs.HL; + break; + // JR n + case 0x18: + // -1 because PC is now pointing past the opcode + regs.PC += static_cast(memory.read(regs.PC)) - 1; + break; + // JR cc, n + case 0x20: { // JR NZ, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (!check_flag(ZERO_FLAG)) // -1 because PC is now pointing past the opcode + regs.PC += offset; + break; + } + case 0x28: { // JR Z, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (check_flag(ZERO_FLAG)) // -1 because PC is now pointing past the opcode + regs.PC += offset; + break; + } + + case 0x30: { // JR NC, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (!check_flag(CARRY_FLAG)) // -1 because PC is now pointing past the opcode + regs.PC += offset; + break; + } + case 0x38: { // JR C, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (check_flag(CARRY_FLAG)) // -1 because PC is now pointing past the opcode + regs.PC += offset; + break; + } + // Calls + // CALL nn + case 0xCD: { + // push, then jump + u16 retaddr = regs.PC+2; + memory.write(regs.SP-1, retaddr >> 8); // high + memory.write(regs.SP-2, retaddr & 0xFF); // low + regs.SP -= 2; + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + break; + } + // CALL cc, nn + case 0xC4: { // CALL NZ, nn + if (!check_flag(ZERO_FLAG)) { + // push, then jump + u16 retaddr = regs.PC+2; + memory.write(regs.SP-1, retaddr >> 8); // high + memory.write(regs.SP-2, retaddr & 0xFF); // low + regs.SP -= 2; + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + } - } + case 0xCC: { // CALL Z, nn + if (check_flag(ZERO_FLAG)) { + // push, then jump + u16 retaddr = regs.PC+2; + memory.write(regs.SP-1, retaddr >> 8); // high + memory.write(regs.SP-2, retaddr & 0xFF); // low + regs.SP -= 2; + + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + } + + case 0xD4: { // CALL NC, nn + if (!check_flag(CARRY_FLAG)) { + // push, then jump + u16 retaddr = regs.PC+2; + memory.write(regs.SP-1, retaddr >> 8); // high + memory.write(regs.SP-2, retaddr & 0xFF); // low + regs.SP -= 2; + + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + } + + case 0xDC: { // CALL C, nn + if (check_flag(CARRY_FLAG)) { + // push, then jump + u16 retaddr = regs.PC+2; + memory.write(regs.SP-1, retaddr >> 8); // high + memory.write(regs.SP-2, retaddr & 0xFF); // low + regs.SP -= 2; + + regs.PC = memory.read(regs.PC) | (memory.read(regs.PC+1)<<8); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + } + + // TODO: Restarts + // TODO: Returns + + default: + std::ostringstream errmsg; + errmsg << "Unknown opcode 0x"; + errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; + errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1; + errmsg << " (cycle count = " << std::dec << cycle_count << ")"; + logger.critical(errmsg.str()); + break; + + } // end switch + + std::ostringstream tracemsg; + tracemsg << "t = " << std::dec << cycle_count << + "\tPC = " << std::hex << std::setw(4) << std::setfill('0') << regs.PC << std::endl << + "A = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.A) << + " B = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.B) << + " C = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.C) << + " D = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.D) << + " E = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.E) << + " H = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.H) << + " L = " << std::hex << std::setw(2) << std::setfill('0') << int(regs.L) << + "\tflags = " << int(regs.flags) << "\tZF = " << check_flag(ZERO_FLAG); + logger.trace(tracemsg.str()); + ++cycle_count; } +void GameBoy::run() +{ +} + + + diff --git a/gbcore.h b/gbcore.h index 5915453..d3c0a8b 100644 --- a/gbcore.h +++ b/gbcore.h @@ -51,22 +51,13 @@ class GameBoy } __attribute__((packed)) regs; - union - { - struct - { - }; - - u8 addr[128]; - - } IO; - u8 IME; // Interrupt master enable flag u8 HALT; // Is the CPU halted waiting for an interrupt? + u32 cycle_count; void set_flag(const u8 f) { regs.flags |= f; } void reset_flag(const u8 f) { regs.flags &= (~f); } - bool check_flag(const u8 f) { return (regs.flags & f != 0); } + bool check_flag(const u8 f) { return ((regs.flags & f) != 0); } public: GameBoy(std::string rom_name); diff --git a/opcodes.h b/opcodes.h index 370afc4..5ab1297 100644 --- a/opcodes.h +++ b/opcodes.h @@ -23,7 +23,7 @@ #define LD_reg_nn(opcode, reg) \ case opcode: \ - regs.reg = memory[regs.PC++]; \ + regs.reg = memory.read(regs.PC++); \ break; #define LD_reg_reg(opcode, reg1, reg2) \ @@ -42,26 +42,26 @@ // LD reg, (HL) #define LD_reg__HL_(opcode, reg) \ case opcode: \ - regs.reg = memory[regs.HL]; \ + regs.reg = memory.read(regs.HL); \ break; // LD (HL), reg #define LD__HL__reg(opcode, reg) \ case opcode: \ - memory[regs.HL] = regs.reg; \ + memory.write(regs.HL, regs.reg); \ break; #define PUSH(opcode, regH, regL) \ case opcode: \ - memory[regs.SP-1] = regs.regH; \ - memory[regs.SP-2] = regs.regL; \ + memory.write(regs.SP-1, regs.regH); \ + memory.write(regs.SP-2, regs.regL); \ regs.SP -= 2; \ break; #define POP(opcode, regH, regL) \ case opcode: \ - regs.regL = memory[regs.SP]; \ - regs.regH = memory[regs.SP+1]; \ + regs.regL = memory.read(regs.SP); \ + regs.regH = memory.read(regs.SP+1); \ regs.SP += 2; \ break; diff --git a/tests/test_core.cc b/tests/test_core.cc new file mode 100644 index 0000000..6a6b257 --- /dev/null +++ b/tests/test_core.cc @@ -0,0 +1,13 @@ +#include "../gbcore.h" +#include + +int main(int argc, char **argv) +{ + GameBoy gb(argv[1]); + while(1) + { + gb.run_cycle(); + } + + +}