From: slack Date: Tue, 21 Aug 2007 03:36:08 +0000 (+0000) Subject: MOAR OPCODES!!! X-Git-Tag: v0.1~66 X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=447d001cdd832bc79cb384de81022b85da94a187;p=wenboi.git MOAR OPCODES!!! git-svn-id: http://slack.codemaniacs.com/wenboi@13 0666ae3d-8926-0410-aeff-ae84559ff337 --- diff --git a/GBMemory.cc b/GBMemory.cc index 8538c4e..17b4ef4 100644 --- a/GBMemory.cc +++ b/GBMemory.cc @@ -19,6 +19,7 @@ void GBMemory::write(int addr, u8 value) IO.write(addr,value); } else if (addr >= 0xFF80 && addr <= 0xFFFE) HRAM[addr - HRAM_BASE]=value; + else if (addr == 0xFFFF) IE=value; else { std::ostringstream errmsg; errmsg << "Invalid write address 0x" << diff --git a/GBMemory.h b/GBMemory.h index f1f979f..7591513 100644 --- a/GBMemory.h +++ b/GBMemory.h @@ -33,6 +33,7 @@ class GBMemory GBIO IO; // FF00-FF7F: IO ports u8 HRAM[126]; // FF80-FFFE: High RAM + u8 IE; // FFFF : Interrupt Enable public: @@ -44,7 +45,7 @@ class GBMemory static const u16 IO_BASE = 0xFF00; static const u16 HRAM_BASE = 0xFF80; - GBMemory(GameBoy *core): core(core), mbc(0), IO() {} + GBMemory(GameBoy *core): core(core), mbc(0), IO(), IE(0) {} void init(MBC *mbc) { this->mbc = mbc; } diff --git a/gbcore.cc b/gbcore.cc index b02caf8..515c9c5 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -8,7 +8,8 @@ #include #include -GameBoy::GameBoy(std::string rom_name): +GameBoy::GameBoy(std::string rom_name, GameBoyType type): + gameboy_type(type), memory(this), rom(0), regs(), @@ -28,7 +29,48 @@ GameBoy::GameBoy(std::string rom_name): void GameBoy::reset() { logger.info("GameBoy reset"); - regs.PC = 0x100; + regs.PC = 0x0100; + regs.AF = 0x01B0; + regs.BC = 0x0013; + regs.DE = 0x00D8; + regs.HL = 0x014D; + regs.SP = 0xFFFE; + + memory.write(0xFF05, 0x00); // TIMA + memory.write(0xFF06, 0x00); // TMA + memory.write(0xFF07, 0x00); // TAC + memory.write(0xFF10, 0x80); // NR10 + memory.write(0xFF11, 0xBF); // NR11 + memory.write(0xFF12, 0xF3); // NR12 + memory.write(0xFF14, 0xBF); // NR14 + memory.write(0xFF16, 0x3F); // NR21 + memory.write(0xFF17, 0x00); // NR22 + memory.write(0xFF19, 0xBF); // NR24 + memory.write(0xFF1A, 0x7F); // NR30 + memory.write(0xFF1B, 0xFF); // NR31 + memory.write(0xFF1C, 0x9F); // NR32 + memory.write(0xFF1E, 0xBF); // NR33 + memory.write(0xFF20, 0xFF); // NR41 + memory.write(0xFF21, 0x00); // NR42 + memory.write(0xFF22, 0x00); // NR43 + memory.write(0xFF23, 0xBF); // NR30 + memory.write(0xFF24, 0x77); // NR50 + memory.write(0xFF25, 0xF3); // NR51 + // NR52 + if (gameboy_type == SUPERGAMEBOY) + memory.write(0xFF26, 0xF0); + else + memory.write(0xFF26, 0xF1); + memory.write(0xFF40, 0x91); // LCDC + memory.write(0xFF42, 0x00); // SCY + memory.write(0xFF43, 0x00); // SCX + memory.write(0xFF45, 0x00); // LYC + memory.write(0xFF47, 0xFC); // BGP + memory.write(0xFF48, 0xFF); // OBP0 + memory.write(0xFF49, 0xFF); // OBP1 + memory.write(0xFF4A, 0x00); // WY + memory.write(0xFF4B, 0x00); // WX + memory.write(0xFFFF, 0x00); // IE } #include "opcodes.h" @@ -89,6 +131,7 @@ void GameBoy::run_cycle() break; case 0xEA: // LD (nn), A memory.write(memory.read(regs.PC) + memory.read(regs.PC+1)<<8, regs.A); + regs.PC+=2; break; // LD A, (C) @@ -122,12 +165,13 @@ void GameBoy::run_cycle() break; // LDH (n), A - case 0xE0: - memory.write(0xFF00 + regs.PC++, regs.A); + case 0xE0: { + memory.write(0xFF00 + memory.read(regs.PC++), regs.A); break; + } // LDH A, (n) case 0xF0: - regs.A = memory.read(0xFF00 + regs.PC++); + regs.A = memory.read(0xFF00 + memory.read(regs.PC++)); break; // LD n, nn @@ -425,11 +469,11 @@ void GameBoy::run_cycle() for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16) // Miscellaneous instructions - // SWAP n case 0xCB: { int sub_opcode = memory.read(regs.PC++); switch(sub_opcode) { + // SWAP n for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg) // SWAP (HL) @@ -444,6 +488,68 @@ void GameBoy::run_cycle() reset_flag(ADD_SUB_FLAG); break; } + + // RLC n + for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg) + + // RLC (HL) + case 0x06: { + u8 value = memory.read(regs.HL); + u8 bit7 = value >> 7; + value = (value << 1) | bit7; + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + + // RL n (through carry) + for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, RL_reg) + + // RL (HL) (through carry) + case 0x16: { + u8 value = memory.read(regs.HL); + u8 bit7 = value >> 7; + value = (value << 1) | check_flag(CARRY_FLAG); + memory.write(regs.HL, value); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + + // RRC n + for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, RRC_reg) + + // RRC (HL) + case 0x0E: { + u8 value = memory.read(regs.HL); + u8 bit0 = value & 1; + value = (value >> 1) | (bit0 << 7); + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + + // RR n (through carry) + for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg) + + // RR (HL) (through carry) + case 0x16: { + u8 value = memory.read(regs.HL); + u8 bit0 = value & 1; + value = (value >> 1) | (check_flag(CARRY_FLAG) << 7); + memory.write(regs.HL, value); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } } break; } @@ -528,7 +634,64 @@ void GameBoy::run_cycle() IME = 1; break; - // TODO: Rotates and shifts + // Rotates and shifts + // RLCA + case 0x07: { + u8 bit7 = regs.A >>7; + regs.A = (regs.A << 1) | bit7; + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + // TODO: Check which of GBCPUman.pdf or + // worldofspectrum z80 reference is correct + // + //set_flag_if(bit7, CARRY_FLAG); + break; + } + + // RLA (through carry) + case 0x17: { + u8 bit7 = regs.A >> 7; + regs.A = (regs.A << 1) | check_flag(CARRY_FLAG); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + + // RRCA + case 0x0F: { + u8 bit0 = regs.A & 1; + regs.A = (regs.A >> 1) | (bit0 << 7); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + // TODO: Check which of GBCPUman.pdf or + // worldofspectrum z80 reference is correct + // + //set_flag_if(bit0, CARRY_FLAG); + break; + } + + // RRA (through carry) + case 0x1F: { + u8 bit0 = regs.A & 1; + regs.A = (regs.A >> 1) | (check_flag(CARRY_FLAG) << 7); + set_flag_if(bit0, CARRY_FLAG); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + + + + + + + + // TODO: Bit instructions // Jumps @@ -684,9 +847,66 @@ void GameBoy::run_cycle() } } - // TODO: Restarts - // TODO: Returns + // Restarts + RST(0xC7, 0x00) + RST(0xCF, 0x08) + RST(0xD7, 0x10) + RST(0xDF, 0x18) + RST(0xE7, 0x20) + RST(0xEF, 0x28) + RST(0xF7, 0x30) + RST(0xFF, 0x38) + + // Returns + // RET + case 0xC9: { + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + + // RET cc + case 0xC0: // RET NZ + if (!check_flag(ZERO_FLAG)) { + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + break; + + case 0xC8: // RET Z + if (check_flag(ZERO_FLAG)) { + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + break; + + case 0xD0: // RET NC + if (!check_flag(CARRY_FLAG)) { + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + break; + case 0xD8: // RET C + if (check_flag(CARRY_FLAG)) { + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + break; + + // RETI + case 0xD9: { + // RET && EI + u16 retaddr = (memory.read(regs.SP+1)<<8) | memory.read(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + IME=1; + } + default: std::ostringstream errmsg; errmsg << "Unknown opcode 0x"; diff --git a/gbcore.h b/gbcore.h index d3c0a8b..55c58c4 100644 --- a/gbcore.h +++ b/gbcore.h @@ -9,6 +9,8 @@ union GBRom; class GameBoy { + enum GameBoyType { GAMEBOY, GAMEBOYCOLOR, SUPERGAMEBOY } gameboy_type; + friend class GBMemory; GBMemory memory; GBRom *rom; @@ -60,7 +62,7 @@ class GameBoy bool check_flag(const u8 f) { return ((regs.flags & f) != 0); } public: - GameBoy(std::string rom_name); + GameBoy(std::string rom_name, GameBoyType type=GAMEBOY); void reset(); void run_cycle(); diff --git a/opcodes.h b/opcodes.h index 5ab1297..d66382c 100644 --- a/opcodes.h +++ b/opcodes.h @@ -210,6 +210,66 @@ reset_flag(ADD_SUB_FLAG); \ break; +#define RST(opcode, n) \ + case opcode: \ + memory.write(regs.SP-1, regs.PC >> 8); \ + memory.write(regs.SP-2, regs.PC & 0xFF); \ + regs.SP -= 2; \ + regs.PC = n; \ + break; + + +// TODO: Check which of GBCPUman.pdf or +// worldofspectrum z80 reference is correct +//set_flag_if(bit7, CARRY_FLAG); +// +#define RLC_reg(opcode, reg) \ + case opcode: {\ + u8 bit7 = regs.reg >> 7; \ + regs.reg = (regs.reg << 1) | bit7; \ + set_flag_if(regs.reg == 0, ZERO_FLAG); \ + reset_flag(ADD_SUB_FLAG); \ + reset_flag(HALF_CARRY_FLAG); \ + break; + } + +#define RL_reg(opcode, reg) \ + case opcode: { + u8 bit7 = regs.reg >> 7; + regs.reg = (regs.reg << 1) | check_flag(CARRY_FLAG); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + +// TODO: Check which of GBCPUman.pdf or +// worldofspectrum z80 reference is correct +//set_flag_if(bit7, CARRY_FLAG); +// +#define RRC_reg(opcode, reg) \ + case opcode: {\ + u8 bit0 = regs.reg & 1; \ + regs.reg = (regs.reg >> 1) | (bit0 << 7); \ + set_flag_if(regs.reg == 0, ZERO_FLAG); \ + reset_flag(ADD_SUB_FLAG); \ + reset_flag(HALF_CARRY_FLAG); \ + break; + } + +#define RR_reg(opcode, reg) \ + case opcode: { + u8 bit0 = regs.reg & 1; + regs.reg = (regs.reg >> 1) | (check_flag(CARRY_FLAG) << 7); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + break; + } + +