From: slack Date: Tue, 1 Jul 2008 01:56:26 +0000 (+0200) Subject: Interrupt hell. Breakpoints added X-Git-Tag: v0.1~40 X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=6f3c4d7a67f29d12facd124b2606e9b88cfa6dd4;p=wenboi.git Interrupt hell. Breakpoints added --- diff --git a/GBVideo.cc b/GBVideo.cc index 5e93566..75120ec 100644 --- a/GBVideo.cc +++ b/GBVideo.cc @@ -1,5 +1,6 @@ #include "GBVideo.h" #include "gbcore.h" +#include "Logger.h" #include "util.h" #include @@ -10,7 +11,7 @@ GBVideo::GBVideo(GameBoy *core): frames_rendered(0) { SDL_Init(SDL_INIT_VIDEO); - display=SDL_SetVideoMode(160,144,32,SDL_SWSURFACE); + display=SDL_SetVideoMode(320,288,32,SDL_HWSURFACE | SDL_DOUBLEBUF); colors[0] = SDL_MapRGB(display->format, 0xFF, 0xFF, 0xFF); colors[1] = SDL_MapRGB(display->format, 0xAA, 0xAA, 0xAA); @@ -80,21 +81,29 @@ void GBVideo::update() u32 *pixels = static_cast(display->pixels); u32 pixels_per_line = display->pitch/display->format->BytesPerPixel; + int LCDC = core->memory.read(GBIO::LCDC); int STAT = core->memory.read(GBIO::STAT); int LYC = core->memory.read(GBIO::LYC); int t = core->cycle_count % 70224; int hline_t=-1; int LY = t/456; - //std::cout << t << std::endl; + + logger.trace("EI=", int(core->memory.read(0xFFFF)), " LY=", LY, " LYC=", LYC); if (t >= 65664) { if (t == 65664) { + logger.trace("Requesting IRQ_VBLANK"); + core->irq(GameBoy::IRQ_VBLANK); + //STAT = set_bit(STAT,4); + if (check_bit(STAT,4)) - core->irq(GameBoy::IRQ_VBLANK); - SDL_UpdateRect(display, 0, 0, 0, 0); + { + core->irq(GameBoy::IRQ_LCD_STAT); + } + SDL_Flip(display); frames_rendered++; char buf[50]; sprintf(buf, "%d", frames_rendered); @@ -107,11 +116,15 @@ void GBVideo::update() else { hline_t = t%456; + logger.trace("hline_t=", hline_t); if (LY == LYC) { STAT = set_bit(STAT, 2); // set coincidence flag if (hline_t == 0 && check_bit(STAT, 6)) + { + logger.trace("Requesting IRQ_LCD_STAT"); core->irq(GameBoy::IRQ_LCD_STAT); + } } if (hline_t < 80) @@ -144,7 +157,6 @@ void GBVideo::update() // Draw at hline_t == 80, when the app cannot write to neither VRAM nor OAM if (hline_t == 80) { - int LCDC = core->memory.read(GBIO::LCDC); int BGP = core->memory.read(GBIO::BGP); int pallette[4]; pallette[0] = BGP & 3; @@ -155,7 +167,7 @@ void GBVideo::update() if (check_bit(LCDC, 0)) // is BG display active? { u16 tile_map_addr = check_bit(LCDC,3) ? 0x1C00 : 0x1800; - u16 tile_data_addr = check_bit(LCDC,4) ? 0x0800 : 0x0000; + u16 tile_data_addr = check_bit(LCDC,4) ? 0x0000 : 0x0800; int tile_data_base = (tile_data_addr == 0x0800) ? -128 : 127; // (vx , vy ) -> position of the pixel in the 256x256 bg @@ -178,13 +190,21 @@ void GBVideo::update() u8 color = ((current_row_high >> tile_x)&1) << 1 | ((current_row_low >> tile_x)&1); - pixels[LY*pixels_per_line+x] = colors[pallette[color]]; + pixels[2*(LY*pixels_per_line+x)] = colors[pallette[color]]; + pixels[2*(LY*pixels_per_line+x)+1] = colors[pallette[color]]; + pixels[2*(LY*pixels_per_line+x)+320] = colors[pallette[color]]; + pixels[2*(LY*pixels_per_line+x)+321] = colors[pallette[color]]; } } else { for (int x=0; x<160; x++) - pixels[LY*pixels_per_line+x] = colors[0]; + { + pixels[2*(LY*pixels_per_line+x)] = colors[0]; + pixels[2*(LY*pixels_per_line+x)+1] = colors[0]; + pixels[2*(LY*pixels_per_line+x)+320] = colors[0]; + pixels[2*(LY*pixels_per_line+x)+321] = colors[0]; + } } } diff --git a/disasm.h b/disasm.h index 51b2132..3bf5b1c 100644 --- a/disasm.h +++ b/disasm.h @@ -150,6 +150,15 @@ break; +// Special routine for JR +#define dis_JR(opcode, name) \ + case opcode: { \ + s8 offset = memory.read(PC++); \ + result << name << " " << std::dec << int(offset) << "\t[0x" \ + << std::hex << std::setw(2) << int(PC+offset) << "]"; \ + break; \ + } + //////////////////////////////////////////////////////////// diff --git a/gbcore.cc b/gbcore.cc index 1dce04d..07396f8 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -16,7 +16,9 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type): regs(), IME(1), HALT(0), - cycle_count(0) + cycle_count(0), + breakpoints(), + last_breakpoint_id(0) { logger.info("GameBoy init"); rom = read_gbrom(rom_name); @@ -74,52 +76,31 @@ void GameBoy::reset() memory.write(0xFFFF, 0x00); // IE } -#include "opcodes.h" +int GameBoy::set_breakpoint(u16 addr) +{ + breakpoints[++last_breakpoint_id] = Breakpoint(addr, true); + return last_breakpoint_id; +} -GameBoy::run_status GameBoy::run_cycle() +void GameBoy::delete_breakpoint(int id) { - video.update(); + breakpoints.erase(id); +} - // Check for interrupts before opcode fetching - u8 IE; - if (IME && (IE=memory.read(0xFFFF))) - { - u8 IF = memory.read(0xFF0F); - if (IF) - { - if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK)) - { - IME = 0; - IF &= (~IRQ_VBLANK); - do_call(0x40); - } - else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT)) - { - IME = 0; - IF &= (~IRQ_LCD_STAT); - do_call(0x48); - } - else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER)) - { - IME = 0; - IF &= (~IRQ_TIMER); - do_call(0x50); - } - else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL)) - { - IME = 0; - IF &= (~IRQ_SERIAL); - do_call(0x58); - } - else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD)) - { - IME = 0; - IF &= (~IRQ_JOYPAD); - do_call(0x60); - } - } - } +void GameBoy::enable_breakpoint(int id) +{ + breakpoints[id].enabled = true; +} + +void GameBoy::disable_breakpoint(int id) +{ + breakpoints[id].enabled = false; +} + +#include "opcodes.h" +GameBoy::run_status GameBoy::run_cycle() +{ int opcode; opcode = memory.read(regs.PC++); @@ -942,8 +923,66 @@ GameBoy::run_status GameBoy::run_cycle() } // end switch ++cycle_count; - //std::cout << "cycle_count " << cycle_count << std::endl; + + video.update(); + // Check for interrupts before opcode fetching + u8 IE=memory.read(0xFFFF); + logger.trace("IME=", int(IME), " IE=", int(IE)); + if (IME && IE) + { + u8 IF = memory.read(0xFF0F); + logger.trace("Dispatching interrupts: IE=", int(IE), " IF=", int(IF)); + if (IF) + { + if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK)) + { + IME = 0; + IF &= (~IRQ_VBLANK); + do_call(0x40); + logger.trace("VBLANK IRQ"); + } + else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT)) + { + IME = 0; + IF &= (~IRQ_LCD_STAT); + do_call(0x48); + logger.trace("LCD STAT IRQ"); + } + else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER)) + { + IME = 0; + IF &= (~IRQ_TIMER); + do_call(0x50); + logger.trace("TIMER IRQ"); + } + else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL)) + { + IME = 0; + IF &= (~IRQ_SERIAL); + do_call(0x58); + logger.trace("SERIAL IRQ"); + } + else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD)) + { + IME = 0; + IF &= (~IRQ_JOYPAD); + do_call(0x60); + logger.trace("JOYPAD IRQ"); + } + } + memory.write(0xFF0F, IF); + } + + + for(BreakpointMap::iterator i=breakpoints.begin(); + i != breakpoints.end(); + i++) + { + if (i->second.addr == regs.PC && i->second.enabled) + return BREAKPOINT; + } + return NORMAL; } @@ -956,12 +995,21 @@ GameBoy::run_status GameBoy::run() { while (video.poll_event(&ev)) { - if (ev.type == SDL_KEYDOWN) + switch(ev.type) { - if (ev.key.keysym.sym == SDLK_ESCAPE) - { - return PAUSED; - } + case SDL_KEYDOWN: + switch(ev.key.keysym.sym) + { + case SDLK_ESCAPE: + return PAUSED; + case SDLK_q: + return QUIT; + default: + break; + } + break; + case SDL_QUIT: + return QUIT; } } status = run_cycle(); @@ -1263,11 +1311,11 @@ void GameBoy::disassemble_opcode(u16 addr, std::string &instruction, int &length dis_inm16(0xDA, "JP C") dis(0xE9, "JP (HL)") - dis_inm8(0x18, "JR") - dis_inm8(0x20, "JR NZ") - dis_inm8(0x28, "JR Z") - dis_inm8(0x30, "JR NC") - dis_inm8(0x38, "JR C") + dis_JR(0x18, "JR") + dis_JR(0x20, "JR NZ") + dis_JR(0x28, "JR Z") + dis_JR(0x30, "JR NC") + dis_JR(0x38, "JR C") // Calls dis_inm16(0xCD, "CALL") diff --git a/gbcore.h b/gbcore.h index 48543ae..42bef04 100644 --- a/gbcore.h +++ b/gbcore.h @@ -5,6 +5,7 @@ #include "GBMemory.h" #include "GBVideo.h" #include +#include union GBRom; @@ -13,11 +14,11 @@ class GameBoy public: enum GameBoyType { GAMEBOY, GAMEBOYCOLOR, SUPERGAMEBOY } gameboy_type; enum InterruptRequest { - IRQ_VBLANK = 0x00, - IRQ_LCD_STAT = 0x01, - IRQ_TIMER = 0x02, - IRQ_SERIAL = 0x04, - IRQ_JOYPAD = 0x08 + IRQ_VBLANK = 0x01, + IRQ_LCD_STAT = 0x02, + IRQ_TIMER = 0x04, + IRQ_SERIAL = 0x08, + IRQ_JOYPAD = 0x10, }; enum Flag @@ -85,10 +86,11 @@ class GameBoy enum run_status { NORMAL = 0, - BREAKPOINT = 1, - WATCHPOINT = 2, - TRACEPOINT = 3, - PAUSED = 4, + BREAKPOINT, + WATCHPOINT, + TRACEPOINT, + PAUSED, + QUIT, }; // Constructors @@ -102,6 +104,12 @@ class GameBoy // debug methods void disassemble_opcode(u16 addr, std::string &instruction, int &length) const; + + int set_breakpoint (u16 addr); + void delete_breakpoint (int id); + void enable_breakpoint (int id); + void disable_breakpoint(int id); + std::string status_string() const; std::string get_port_name(int port) const; @@ -109,6 +117,21 @@ class GameBoy private: GameBoy(const GameBoy&); GameBoy operator=(const GameBoy&); + + // debug things + struct Breakpoint { + int addr; + bool enabled; + + Breakpoint(int a, bool e): addr(a), enabled(e) {} + Breakpoint(): addr(-1), enabled(false) {} + }; + + typedef std::map BreakpointMap; + + BreakpointMap breakpoints; + int last_breakpoint_id; + }; #endif diff --git a/tests/test_core.cc b/tests/test_core.cc index b6ef4c3..2c38105 100644 --- a/tests/test_core.cc +++ b/tests/test_core.cc @@ -13,6 +13,18 @@ using std::endl; using std::string; using std::vector; +int str2int(string s) +{ + if (s[0] == '0') { + if (s[1] == 'x') + return strtol(s.c_str()+2, NULL, 16); + else if (s[1] >= '0' && s[1] <= '9') + return strtol(s.c_str()+1, NULL, 8); + else return 0; + } + return strtol(s.c_str(), NULL, 10); +} + int main(int argc, char **argv) { if (argc != 2) { @@ -44,7 +56,7 @@ int main(int argc, char **argv) } } - if (command == "step") + if (command == "step" || command == "s") { gb.run_cycle(); cout << gb.status_string() << endl; @@ -52,13 +64,25 @@ int main(int argc, char **argv) else if (command == "run" || command == "r") { int status = gb.run(); - cout << "run returned with status " << status << endl; + if (status == GameBoy::QUIT) + { + break; + } + else if (status == GameBoy::BREAKPOINT) + { + cout << "Breakpoint hit at " << gb.regs.PC << endl; + cout << gb.status_string() << endl; + } + else + { + cout << "run returned with status " << status << endl; + } } else if (command == "quit" || command == "q") { break; } - else if (command == "disasm") + else if (command == "disasm" || command == "d") { int start, end, pos; switch(arguments.size()) @@ -68,13 +92,13 @@ int main(int argc, char **argv) end = start + 30; break; case 1: - start = atoi(arguments[0].c_str()); + start = str2int(arguments[0]); end = start + 30; break; case 2: default: - start = atoi(arguments[0].c_str()); - end = atoi(arguments[1].c_str()); + start = str2int(arguments[0]); + end = str2int(arguments[1]); break; } @@ -95,6 +119,36 @@ int main(int argc, char **argv) } } + else if (command == "x") + { + int addr = str2int(arguments[0]); + cout << "[" << std::hex << std::setw(4) << std::setfill('0') << + addr << "]\t"; + if (arguments.size() > 1) + { + if (arguments[1] == "d") + cout << std::dec << int(gb.memory.read(addr)) << endl; + } + cout<< int(gb.memory.read(addr)) << endl; + } + else if (command == "break" || command == "b") + { + int addr = str2int(arguments[0]); + cout << "breakpoint #" << gb.set_breakpoint(addr) << + " set at 0x" << std::hex << std::setw(4) << std::setfill('0') << addr << endl; + } + else if (command == "delete") + { + gb.delete_breakpoint(str2int(arguments[0])); + } + else if (command == "enable") + { + gb.enable_breakpoint(str2int(arguments[0])); + } + else if (command == "disable") + { + gb.disable_breakpoint(str2int(arguments[0])); + } else { cout << "Unknown command '" << command << "'" << endl;