Core simulates instruction cycle cost. Optimizations.
authorJorge Gorbe Moya <jgorbe@dsic.upv.es>
Wed, 2 Jul 2008 18:42:08 +0000 (20:42 +0200)
committerJorge Gorbe Moya <jgorbe@dsic.upv.es>
Wed, 2 Jul 2008 18:42:08 +0000 (20:42 +0200)
Now distortion.gb runs at ~66 FPS :D

GBVideo.cc
GBVideo.h
gbcore.cc
gbcore.h
opcodes.h
tests/test_core.cc

index af461fc851ed1ca66e70bb98c2eb577fee62c41e..bf640cd9dc1be937eb9a00b9308a85c1bf482318 100644 (file)
@@ -9,12 +9,14 @@ GBVideo::GBVideo(GameBoy *core):
        display(0),
        core(core),
        frames_rendered(0),
-       cycles_until_next_update(0),
+       t0(0),
        mode(2),
        display_mode(NORMAL)
 {
        SDL_Init(SDL_INIT_VIDEO);
-       display=SDL_SetVideoMode(320,288,32,SDL_HWSURFACE | SDL_DOUBLEBUF);
+       display=SDL_SetVideoMode(320,288,32,SDL_SWSURFACE | SDL_DOUBLEBUF);
+
+       t0 = SDL_GetTicks();
 
        colors[0] = SDL_MapRGB(display->format, 192,192,0);
        colors[1] = SDL_MapRGB(display->format, 139,139,21);
@@ -88,7 +90,7 @@ void GBVideo::write_OAM (int addr, u8 value)
 
 #endif
 
-void GBVideo::update()
+u32 GBVideo::update()
 {
        //Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and 3
        //about 169-175 clks. A complete cycle through these states takes 456
@@ -106,103 +108,103 @@ void GBVideo::update()
        // mode 0 starts at 252, 708, 1164...
        // vblank starts at 65664
 
-       if (cycles_until_next_update == 0)
+       int cycles_until_next_update=0;
+       int STAT = core->memory.high[GBMemory::I_STAT];
+       int LYC  = core->memory.high[GBMemory::I_LYC];
+       int LY  = core->memory.high[GBMemory::I_LY];
+
+       switch (mode)
        {
-               int STAT = core->memory.high[GBMemory::I_STAT];
-               int LYC  = core->memory.high[GBMemory::I_LYC];
-               int LY  = core->memory.high[GBMemory::I_LY];
+               case 0:
+                       // HBlank (preserve bits 2-6, mode = 0)
+                       STAT = (STAT&0xFC);
+                       if (check_bit(STAT, 3))
+                       {
+                               logger.trace("Requesting IRQ_LCD_STAT -- HBLANK");
+                               core->irq(GameBoy::IRQ_LCD_STAT);
+                       }
+                       cycles_until_next_update = 204;
+                       if (LY == 143)
+                               mode = 1;
+                       else
+                               mode = 2;
+                       break;
+               case 1:
+                       if (LY == 144)
+                       {
+                               logger.trace("Requesting IRQ_VBLANK");
+                               core->irq(GameBoy::IRQ_VBLANK);
 
-               switch (mode)
-               {
-                       case 0:
-                               // HBlank (preserve bits 2-6, mode = 0)
-                               STAT = (STAT&0xFC);
-                               if (check_bit(STAT, 3))
+                               if (check_bit(STAT,4))
                                {
-                                       logger.trace("Requesting IRQ_LCD_STAT -- HBLANK");
+                                       logger.trace("Requesting IRQ_LCD_STAT -- VBLANK");
                                        core->irq(GameBoy::IRQ_LCD_STAT);
                                }
-                               cycles_until_next_update = 204;
-                               if (LY == 143)
-                                       mode = 1;
-                               else
-                                       mode = 2;
-                               break;
-                       case 1:
-                               if (LY == 144)
+                               SDL_Flip(display);
+                               frames_rendered++;
+                               u32 t1 = SDL_GetTicks();
+                               if (t1-t0 > 1000)
                                {
-                                       logger.trace("Requesting IRQ_VBLANK");
-                                       core->irq(GameBoy::IRQ_VBLANK);
-
-                                       if (check_bit(STAT,4))
-                                       {
-                                               logger.trace("Requesting IRQ_LCD_STAT -- VBLANK");
-                                               core->irq(GameBoy::IRQ_LCD_STAT);
-                                       }
-                                       SDL_Flip(display);
-                                       frames_rendered++;
-                                       if (frames_rendered % 10 == 0)
-                                       {
-                                               char buf[50];
-                                               sprintf(buf, "%d", frames_rendered);
-                                               SDL_WM_SetCaption(buf, 0);
-                                       }
-
-                                       // preserve bits 3-6, set mode to 1 (VBlank) and coincidence to 0
-                                       STAT = (STAT&0xF8) | 1;
-                               }
-                               cycles_until_next_update = 456;
-                               if (LY == 153)
-                                       mode = 2;
-                               else
-                                       mode = 1;
-                               break;
-                       case 2: {
-                               if (LY == LYC)
-                               {
-                                       STAT = set_bit(STAT, 2); // set coincidence flag
-                                       if (check_bit(STAT, 6))
-                                       {
-                                               logger.trace("Requesting IRQ_LCD_STAT -- LY = LYC = ", LY, " EI=", int(core->memory.IE), 
-                                                               " IME =", int(core->IME));
-                                               core->irq(GameBoy::IRQ_LCD_STAT);
-                                       }
+                                       char buf[50];
+                                       sprintf(buf, "%f FPS", frames_rendered/(0.001f*(t1-t0)));
+                                       SDL_WM_SetCaption(buf, 0);
+                                       t0=t1;
+                                       frames_rendered=0;
                                }
 
-                               if (check_bit(STAT, 5)) 
+                               // preserve bits 3-6, set mode to 1 (VBlank) and coincidence to 0
+                               STAT = (STAT&0xF8) | 1;
+                       }
+                       cycles_until_next_update = 456;
+                       if (LY == 153)
+                               mode = 2;
+                       else
+                               mode = 1;
+                       break;
+               case 2: {
+                       if (LY == LYC)
+                       {
+                               STAT = set_bit(STAT, 2); // set coincidence flag
+                               if (check_bit(STAT, 6))
                                {
-                                       logger.trace("Requesting IRQ_LCD_STAT -- Mode 2");
+                                       logger.trace("Requesting IRQ_LCD_STAT -- LY = LYC = ", LY, " EI=", int(core->memory.IE), 
+                                                       " IME =", int(core->IME));
                                        core->irq(GameBoy::IRQ_LCD_STAT);
                                }
+                       }
 
-                               // preserve bits 2-6, set mode 2
-                               STAT = (STAT&0xFC) | 2;
-                               cycles_until_next_update = 80;
-                               mode = 3;
-                               break;
+                       if (check_bit(STAT, 5)) 
+                       {
+                               logger.trace("Requesting IRQ_LCD_STAT -- Mode 2");
+                               core->irq(GameBoy::IRQ_LCD_STAT);
                        }
-                       case 3:
-                               draw();
-                               // preserve bits 2-6, set mode 3
-                               STAT = (STAT&0xFC) | 3;
-                               cycles_until_next_update = 172;
-                               mode = 0;
-                               break;
-               }
-               
-               if (mode == 1 || mode == 2)
-               {
-                       LY = (LY+1)%154;
-                       logger.trace(LY);
-                       core->memory.high[GBMemory::I_LY] = LY;
+
+                       // preserve bits 2-6, set mode 2
+                       STAT = (STAT&0xFC) | 2;
+                       cycles_until_next_update = 80;
+                       mode = 3;
+                       break;
                }
+               case 3:
+                       draw();
+                       // preserve bits 2-6, set mode 3
+                       STAT = (STAT&0xFC) | 3;
+                       cycles_until_next_update = 172;
+                       mode = 0;
+                       break;
+       }
+       
+       if (mode == 1 || mode == 2)
+       {
+               LY = (LY+1)%154;
+               logger.trace(LY);
+               core->memory.high[GBMemory::I_LY] = LY;
+       }
 
 
-               core->memory.high[GBMemory::I_STAT] = STAT;
-       }
+       core->memory.high[GBMemory::I_STAT] = STAT;
 
-       --cycles_until_next_update;
-       return;
+       return cycles_until_next_update;
 }
 
 void GBVideo::draw()
index 31741ebd061f371b85ffc64656aabace0f0eef4a..54cfbe6f5d6d0664203f68b9f9887b1b444c5f58 100644 (file)
--- a/GBVideo.h
+++ b/GBVideo.h
@@ -16,8 +16,8 @@ class GBVideo
 
        u32 colors[4];
        u32 frames_rendered;
+       u32 t0;
 
-       int cycles_until_next_update;
        int mode;
 
        public:
@@ -47,7 +47,7 @@ class GBVideo
 
        // drawing control
        void draw();
-       void update();
+       u32 update();
        void set_display_mode(DisplayMode mode) { display_mode = mode; }
 
        // event processing
index 9be77057b9cfb077a2b8b377e2cb852d3697a672..d86d402105fea6f03b32bb47760ad731974320a3 100644 (file)
--- a/gbcore.cc
+++ b/gbcore.cc
@@ -18,6 +18,8 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type):
        IME(1),
        HALT(0),
        cycle_count(0),
+       cycles_until_video_update(0),
+       cycles_until_next_instruction(0),
        breakpoints(),
        last_breakpoint_id(0)
 {
@@ -33,6 +35,12 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type):
 void GameBoy::reset()
 {
        logger.info("GameBoy reset");
+       IME = 1;
+       HALT = 0;
+       cycle_count = 0;
+       cycles_until_video_update = 0;
+       cycles_until_next_instruction = 0;
+
        regs.PC = 0x0100;
        regs.AF = 0x01B0;
        regs.BC = 0x0013;
@@ -40,6 +48,11 @@ void GameBoy::reset()
        regs.HL = 0x014D;
        regs.SP = 0xFFFE;
 
+       for (int i=0; i<0xFFFF; i++)
+       {
+               memory.write(i, 0);
+       }
+
        memory.write(0xFF05, 0x00);   // TIMA
        memory.write(0xFF06, 0x00);   // TMA
        memory.write(0xFF07, 0x00);   // TAC
@@ -102,1083 +115,1235 @@ void GameBoy::disable_breakpoint(int id)
 
 GameBoy::run_status GameBoy::run_cycle()
 {
-       int opcode;
-       opcode = memory.read(regs.PC++);
-       
-       switch(opcode)
-       {
-               // LD n, nn
-               for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn)
+       cycle_count += CYCLE_STEP;
 
-               // LD r1,r2
-               for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg)
-               for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg)
-               for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg)
-               for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg)
-               for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg)
-               for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg)
-               for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg)
-               
-               // LD reg, (HL)
-               for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_)
-
-               // LD (HL), reg
-               for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg)
-               
-               case 0x36: // LD (HL), n
-                       memory.write(regs.HL, memory.read(regs.PC++));
-                       break;
-               
-               // LD A, mem
-               case 0x0A: // LD A, (BC)
-                       regs.A = memory.read(regs.BC);
-                       break;
-               case 0x1A: // LD A, (DE)
-                       regs.A = memory.read(regs.DE);
-                       break;
-               case 0xFA: // LD A, (nn)
-                       regs.A = memory.read(memory.read16(regs.PC));
-                       regs.PC+=2;
-                       break;
+       if (cycles_until_next_instruction > 0)
+       {
+               if (cycles_until_video_update <= 0)
+                       cycles_until_video_update = video.update();
                
-               // LD mem, A
-               case 0x02: // LD (BC), A
-                       memory.write(regs.BC, regs.A);
-                       break;
-               case 0x12: // LD (DE), A
-                       memory.write(regs.DE, regs.A);
-                       break;
-               case 0xEA: // LD (nn), A
-                       memory.write(memory.read16(regs.PC), regs.A);
-                       regs.PC+=2;
-                       break;
-
-               // LD A, (C)
-               case 0xF2:
-                       regs.A = memory.read(0xFF00 + regs.C);
-                       break;
-               // LD (C), A
-               case 0xE2:
-                       memory.write(0xFF00 + regs.C, regs.A);
-                       break;
-
-               // LD A, (HLD); LD A, (HL-); LDD A,(HL);
-               case 0x3A:
-                       regs.A = memory.read(regs.HL);
-                       --regs.HL;
-                       break;
-               // LD (HLD), A; LD (HL-), A; LDD (HL), A;
-               case 0x32:
-                       memory.write(regs.HL, regs.A);
-                       --regs.HL;
-                       break;
-               // LD A, (HLI); LD A, (HL+); LDI A, (HL);
-               case 0x2A:
-                       regs.A = memory.read(regs.HL);
-                       ++regs.HL;
-                       break;
-               // LD (HLI), A; LD (HL+), A; LDI (HL), A;
-               case 0x22:
-                       memory.write(regs.HL, regs.A);
-                       ++regs.HL;
-                       break;
-
-               // LDH (n), A
-               case 0xE0: {
-                       memory.high[memory.read(regs.PC++)] =  regs.A;
-                       break;
-               }
-               // LDH A, (n)
-               case 0xF0:
-                       regs.A = memory.high[memory.read(regs.PC++)];
-                       break;
-
-               // LD n, nn
-               case 0x01: // LD BC, nn
-                       regs.BC = memory.read16(regs.PC);
-                       regs.PC +=2;
-                       break;
-               case 0x11: // LD DE, nn
-                       regs.DE = memory.read16(regs.PC);
-                       regs.PC +=2;
-                       break;
-               case 0x21: // LD HL, nn
-                       regs.HL = memory.read16(regs.PC);
-                       regs.PC +=2;
-                       break;
-               case 0x31: // LD SP, nn
-                       regs.SP = memory.read16(regs.PC);
-                       regs.PC +=2;
-                       break;
+               cycles_until_video_update -= CYCLE_STEP;
+               cycles_until_next_instruction -= CYCLE_STEP;
                
-               // LD SP, HL
-               case 0xF9:
-                       regs.SP = regs.HL;
-                       break;
-
-               // LD HL, SP+n
-               // LDHL SP, n
-               case 0xF8: {
-                       s8 offset = memory.read(regs.PC++);
-                       int res = regs.SP + offset;
-                       
-                       // TODO: Verificar si los flags van asi
-                       set_flag_if (res > 0xFFFF, CARRY_FLAG);
-
-                       // TODO: hacer lo apropiado con el half-carry flag
-                       reset_flag(ADD_SUB_FLAG);
-                       reset_flag(ZERO_FLAG);
+               if (cycles_until_next_instruction > 0) return WAIT;
+               else return NORMAL;
+       }
 
-                       regs.HL = static_cast<u16>(res & 0xFFFF);
-                       break; 
+       // Check for interrupts before opcode fetching
+       u8 IE=memory.high[GBMemory::I_IE];
+       //logger.trace("IME=", int(IME), " IE=", int(IE));
+       if (IME && IE)
+       {
+               u8 IF = memory.high[GBMemory::I_IF];
+               //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");
                        }
-
-               // LD (nn), SP
-               case 0x08: {
-                       int addr = memory.read16(regs.PC);
-                       regs.PC += 2;
-                       memory.write(addr, regs.SP);
-                       break;
+                       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.high[GBMemory::I_IF] = IF;
+       }
 
-               // PUSH nn
-               PUSH(0xF5, A, flags)
-               PUSH(0xC5, B, C)
-               PUSH(0xD5, D, E)
-               PUSH(0xE5, H, L)
+       /*
+       for(BreakpointMap::iterator i=breakpoints.begin();
+                       i != breakpoints.end();
+                       i++)
+       {
+               if (i->second.addr == regs.PC && i->second.enabled)
+                       return BREAKPOINT;
+       }
+       */
+       
+       int opcode;
+       opcode = memory.read(regs.PC++);
 
-               // POP nn
-               POP(0xF1, A, flags)
-               POP(0xC1, B, C)
-               POP(0xD1, D, E)
-               POP(0xE1, H, L)
+       switch(opcode & 0x80)
+       {
+               case 0x00:
+               switch(opcode)
+               {
+                       // LD n, nn
+                       for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn)
+
+                       // LD r1,r2
+                       for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg)
+                       for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg)
+                       for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg)
+                       for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg)
+                       for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg)
+                       for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg)
+                       for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg)
+                       
+                       // LD reg, (HL)
+                       for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_)
 
-               // 8-bit ALU
-               // ADD A,reg
-               for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg)
-               
-               case 0x86: {// ADD A, (HL)
-                       int res = regs.A + memory.read(regs.HL);
-                       int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F);
-                       regs.A = static_cast<u8>(res);
+                       // LD (HL), reg
+                       for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg)
                        
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag_if (res > 0xFF,      CARRY_FLAG);
-                       set_flag_if (regs.A == 0,     ZERO_FLAG);
-                       set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
-                       break;
-                       }
-               case 0xC6: {//ADD A, #
-                       int inm = memory.read(regs.PC++);
-                       int res = regs.A + inm;
-                       int half_res = (regs.A & 0x0F) + (inm & 0x0F);
-                       regs.A = static_cast<u8>(res);
+                       case 0x36: // LD (HL), n
+                               memory.write(regs.HL, memory.read(regs.PC++));
+                               cycles_until_next_instruction = 12; 
+                               break;
                        
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag_if (res > 0xFF,      CARRY_FLAG);
-                       set_flag_if (regs.A == 0,     ZERO_FLAG);
-                       set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
-                       break;
-                       }
-
-               // ADC A, n
-               for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg)
-
-               case 0x8E: {// ADC A, (HL)
-                       int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       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<u8>(res);
+                       // LD A, mem
+                       case 0x0A: // LD A, (BC)
+                               regs.A = memory.read(regs.BC);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       case 0x1A: // LD A, (DE)
+                               regs.A = memory.read(regs.DE);
+                               cycles_until_next_instruction = 8; 
+                               break;
                        
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag_if (res > 0xFF,      CARRY_FLAG);
-                       set_flag_if (regs.A == 0,     ZERO_FLAG);
-                       set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
-                       break;
-                       }
-               case 0xCE: {//ADC A, #
-                       int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       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<u8>(res);
+                       // LD mem, A
+                       case 0x02: // LD (BC), A
+                               memory.write(regs.BC, regs.A);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       case 0x12: // LD (DE), A
+                               memory.write(regs.DE, regs.A);
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       // LD A, (HLD); LD A, (HL-); LDD A,(HL);
+                       case 0x3A:
+                               regs.A = memory.read(regs.HL);
+                               --regs.HL;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       // LD (HLD), A; LD (HL-), A; LDD (HL), A;
+                       case 0x32:
+                               memory.write(regs.HL, regs.A);
+                               --regs.HL;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       // LD A, (HLI); LD A, (HL+); LDI A, (HL);
+                       case 0x2A:
+                               regs.A = memory.read(regs.HL);
+                               ++regs.HL;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       // LD (HLI), A; LD (HL+), A; LDI (HL), A;
+                       case 0x22:
+                               memory.write(regs.HL, regs.A);
+                               ++regs.HL;
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       // LD n, nn
+                       case 0x01: // LD BC, nn
+                               regs.BC = memory.read16(regs.PC);
+                               regs.PC +=2;
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       case 0x11: // LD DE, nn
+                               regs.DE = memory.read16(regs.PC);
+                               regs.PC +=2;
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       case 0x21: // LD HL, nn
+                               regs.HL = memory.read16(regs.PC);
+                               regs.PC +=2;
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       case 0x31: // LD SP, nn
+                               regs.SP = memory.read16(regs.PC);
+                               regs.PC +=2;
+                               cycles_until_next_instruction = 12; 
+                               break;
                        
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag_if (res > 0xFF,      CARRY_FLAG);
-                       set_flag_if (regs.A == 0,     ZERO_FLAG);
-                       set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
-                       break;
-                       }
 
-               // SUB n
-               for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg)
+                       // LD (nn), SP
+                       case 0x08: {
+                               int addr = memory.read16(regs.PC);
+                               regs.PC += 2;
+                               memory.write(addr, regs.SP);
+                               cycles_until_next_instruction = 20; 
+                               break;
+                               }
 
-               case 0x96: {//SUB (HL)
-                       int res = regs.A - memory.read(regs.HL);
-                       int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
-                       regs.A = static_cast<u8>(res);
+                       // INC n
+                       for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg)
+
+                       case 0x34: {//INC (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.read(regs.HL) == 0, ZERO_FLAG); 
+                               set_flag_if (half_res > 0x0F,      HALF_CARRY_FLAG); 
+                               cycles_until_next_instruction = 12; 
+                               break; 
+                               }       
+
+                       // DEC n
+                       for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg)
+
+                       case 0x35: {//DEC (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.read(regs.HL) == 0, ZERO_FLAG); 
+                               set_flag_if (half_res < 0,         HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 12; 
+                               break; 
+                               }
 
-                       set_flag(ADD_SUB_FLAG);
-                       set_flag_if (res < 0,      CARRY_FLAG);
-                       set_flag_if (res == 0,     ZERO_FLAG);
-                       set_flag_if (half_res < 0, HALF_CARRY_FLAG);
-                       break;
-                       }
-               
-               case 0xD6: {//SUB #
-                       int inm = memory.read(regs.PC++);
-                       int res = regs.A - inm;
-                       int half_res = (regs.A & 0x0F) - (inm & 0x0F);
-                       regs.A = static_cast<u8>(res);
-
-                       set_flag(ADD_SUB_FLAG);
-                       set_flag_if (res < 0,      CARRY_FLAG);
-                       set_flag_if (res == 0,     ZERO_FLAG);
-                       set_flag_if (half_res < 0, HALF_CARRY_FLAG);
-                       break;
-                       }
+                       // 16-bit ALU
+                       // ADD HL, n
+                       for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16)
 
-               // SBC n
-               for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg)
-
-               case 0x9E: {//SBC (HL)
-                       int carry = (check_flag(CARRY_FLAG)? 1 : 0);
-                       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<u8>(res);
-
-                       set_flag(ADD_SUB_FLAG);
-                       set_flag_if (res < 0,      CARRY_FLAG);
-                       set_flag_if (res == 0,     ZERO_FLAG);
-                       set_flag_if (half_res < 0, HALF_CARRY_FLAG);
-                       break;
-                       }
+                       // INC nn
+                       for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16)
 
-               // There is no SBC inm
+                       // DEC nn
+                       for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16)
 
-               // AND n
-               for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg)
-
-               case 0xA6: //AND (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);
-                       reset_flag(CARRY_FLAG);
-                       break;
 
-               case 0xE6: //AND inm
-                       regs.A &= memory.read(regs.PC++);
-                       if (regs.A == 0) set_flag(ZERO_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag(HALF_CARRY_FLAG);
-                       reset_flag(CARRY_FLAG);
-                       break;
+                       // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA
+                       case 0x27: {
+                               u8 corr_factor = 0;
+                               if (regs.A > 0x99 || check_flag(CARRY_FLAG)) {
+                                       corr_factor = 0x60;
+                                       set_flag(CARRY_FLAG);
+                               } else {
+                                       reset_flag(CARRY_FLAG);
+                               }
 
-               // OR n
-               for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg)
-
-               case 0xB6: //OR (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);
-                       reset_flag(CARRY_FLAG);
-                       break;
+                               if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) {
+                                       corr_factor |= 0x06;
+                               }
 
-               case 0xF6: //OR inm
-                       regs.A |= memory.read(regs.PC++);
-                       if (regs.A == 0) set_flag(ZERO_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       reset_flag(HALF_CARRY_FLAG);
-                       reset_flag(CARRY_FLAG);
-                       break;
+                               if (!check_flag(ADD_SUB_FLAG)) {
+                                       regs.A += corr_factor;
+                               } else {
+                                       regs.A -= corr_factor;
+                               }
 
-               // XOR n
-               for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg)
-
-               case 0xAE: //XOR (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);
-                       reset_flag(CARRY_FLAG);
-                       break;
+                               set_flag_if(regs.A==0, ZERO_FLAG);
+                               reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P
+                               cycles_until_next_instruction = 4; 
+                               break;
+                       }
 
-               case 0xEE: //XOR inm
-                       regs.A ^= memory.read(regs.PC++);
-                       if (regs.A == 0) set_flag(ZERO_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       reset_flag(HALF_CARRY_FLAG);
-                       reset_flag(CARRY_FLAG);
-                       break;
-               
-               // CP n
-               for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg)
+                       // CPL
+                       case 0x2F:
+                               regs.A = ~regs.A;
+                               set_flag(HALF_CARRY_FLAG);
+                               set_flag(ADD_SUB_FLAG);
+                               cycles_until_next_instruction = 4; 
+                               break;
+
+                       // CCF
+                       case 0x3F:
+                               if (check_flag(CARRY_FLAG))
+                                       reset_flag(CARRY_FLAG);
+                               else
+                                       set_flag(CARRY_FLAG);
 
-               case 0xBE: {//CP (HL)
-                       int res = regs.A - memory.read(regs.HL);
-                       int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+                               reset_flag(HALF_CARRY_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               cycles_until_next_instruction = 4; 
+                               break;
 
-                       set_flag(ADD_SUB_FLAG);
-                       set_flag_if (res < 0,      CARRY_FLAG);
-                       set_flag_if (res == 0,     ZERO_FLAG);
-                       set_flag_if (half_res < 0, HALF_CARRY_FLAG);
-                       break;
+                       // SCF
+                       case 0x37:
+                               set_flag(CARRY_FLAG);
+                               reset_flag(HALF_CARRY_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               cycles_until_next_instruction = 4; 
+                               break;
+
+                       // NOP
+                       case 0x00:
+                               cycles_until_next_instruction = 4; 
+                               break;
+
+                       // HALT
+                       case 0x76:
+                               HALT = true;
+                               cycles_until_next_instruction = 4; 
+                               break;
+
+                       // STOP
+                       case 0x10: {
+                               int sub_opcode = memory.read(regs.PC++);
+                               if (sub_opcode == 0x00) {
+                                       HALT = true;
+                               } else {
+                                       logger.critical("Unknown sub-opcode after 0x10");
+                               }
+                               cycles_until_next_instruction = 4; 
+                               break;
                        }
-               
-               case 0xFE: {//CP #
-                       int inm = memory.read(regs.PC++);
-                       int res = regs.A - inm;
-                       int half_res = (regs.A & 0x0F) - (inm & 0x0F);
-
-                       set_flag(ADD_SUB_FLAG);
-                       set_flag_if (res < 0,      CARRY_FLAG);
-                       set_flag_if (res == 0,     ZERO_FLAG);
-                       set_flag_if (half_res < 0, HALF_CARRY_FLAG);
-                       break;
+                       
+                       // 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);
+                               cycles_until_next_instruction = 4; 
+                               break;
                        }
 
-               // INC n
-               for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg)
-
-               case 0x34: {//INC (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.read(regs.HL) == 0, ZERO_FLAG); 
-                       set_flag_if (half_res > 0x0F,      HALF_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);
+                               cycles_until_next_instruction = 4; 
+                               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);
+                               cycles_until_next_instruction = 4; 
+                               break;
+                       }
 
-               // DEC n
-               for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg)
-
-               case 0x35: {//DEC (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.read(regs.HL) == 0, ZERO_FLAG); 
-                       set_flag_if (half_res < 0,         HALF_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);
+                               cycles_until_next_instruction = 4; 
+                               break;
                        }
 
-               // 16-bit ALU
-               // ADD HL, n
-               for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16)
+                       
+                       // JR n
+                       case 0x18:
+                               // -1 because PC is now pointing past the opcode
+                               regs.PC += static_cast<s8>(memory.read(regs.PC++));
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       // JR cc, n
+                       case 0x20: { // JR NZ, n
+                               s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                               if (!check_flag(ZERO_FLAG)) 
+                                       regs.PC += offset;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       }
 
-               // ADD SP, #
-               case 0xE8: {
-                       // FIXME: No se que hacer con el half carry, en 4 o en 11?
-                       int n = static_cast<s8>(memory.read(regs.PC++));
-                       int res = regs.SP + n;
-                       regs.SP = static_cast<u8>(res);
-                       reset_flag(ZERO_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       set_flag_if(res > 0xFFFF, CARRY_FLAG);
-                       break;
-               }
+                       case 0x28: { // JR Z, n
+                               s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                               if (check_flag(ZERO_FLAG)) 
+                                       regs.PC += offset;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       }
 
-               // INC nn
-               for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16)
+                       case 0x30: { // JR NC, n
+                               s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                               if (!check_flag(CARRY_FLAG)) 
+                                       regs.PC += offset;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       }
 
-               // DEC nn
-               for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16)
+                       case 0x38: { // JR C, n
+                               s8 offset = static_cast<s8>(memory.read(regs.PC++));
+                               if (check_flag(CARRY_FLAG)) 
+                                       regs.PC += offset;
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       }
 
-               // Miscellaneous instructions
-               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)
-                               case 0x36: {
-                                       u8 tmp = memory.read(regs.HL);
-                                       tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4);
-                                       memory.write(regs.HL, tmp);
                
-                                       set_flag_if(tmp==0, ZERO_FLAG);
-                                       reset_flag(CARRY_FLAG);
-                                       reset_flag(HALF_CARRY_FLAG);
-                                       reset_flag(ADD_SUB_FLAG);
-                                       break;
-                               }
+                       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
+               break;
+               case 0x80:
+               switch(opcode)
+               {
+                       case 0xFA: // LD A, (nn)
+                               regs.A = memory.read(memory.read16(regs.PC));
+                               regs.PC+=2;
+                               cycles_until_next_instruction = 16; 
+                               break;
+                       case 0xEA: // LD (nn), A
+                               memory.write(memory.read16(regs.PC), regs.A);
+                               regs.PC+=2;
+                               cycles_until_next_instruction = 16; 
+                               break;
+
+                       // LD A, (C)
+                       case 0xF2:
+                               regs.A = memory.read(0xFF00 + regs.C);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       // LD (C), A
+                       case 0xE2:
+                               memory.write(0xFF00 + regs.C, regs.A);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       // LDH (n), A
+                       case 0xE0: {
+                               memory.high[memory.read(regs.PC++)] =  regs.A;
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       }
+                       // LDH A, (n)
+                       case 0xF0:
+                               regs.A = memory.high[memory.read(regs.PC++)];
+                               cycles_until_next_instruction = 12; 
+                               break;
+
+                       // LD SP, HL
+                       case 0xF9:
+                               regs.SP = regs.HL;
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       // LD HL, SP+n
+                       // LDHL SP, n
+                       case 0xF8: {
+                               s8 offset = memory.read(regs.PC++);
+                               int res = regs.SP + offset;
+                               
+                               // TODO: Verificar si los flags van asi
+                               set_flag_if (res > 0xFFFF, CARRY_FLAG);
 
-                               // RLC n
-                               for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg)
+                               // TODO: hacer lo apropiado con el half-carry flag
+                               reset_flag(ADD_SUB_FLAG);
+                               reset_flag(ZERO_FLAG);
 
-                               // 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;
+                               regs.HL = static_cast<u16>(res & 0xFFFF);
+                               cycles_until_next_instruction = 12; 
+                               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;
+                       // PUSH nn
+                       PUSH(0xF5, A, flags)
+                       PUSH(0xC5, B, C)
+                       PUSH(0xD5, D, E)
+                       PUSH(0xE5, H, L)
+
+                       // POP nn
+                       POP(0xF1, A, flags)
+                       POP(0xC1, B, C)
+                       POP(0xD1, D, E)
+                       POP(0xE1, H, L)
+
+                       // 8-bit ALU
+                       // ADD A,reg
+                       for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg)
+                       
+                       case 0x86: {// ADD A, (HL)
+                               int res = regs.A + memory.read(regs.HL);
+                               int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F);
+                               regs.A = static_cast<u8>(res);
+                               
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag_if (res > 0xFF,      CARRY_FLAG);
+                               set_flag_if (regs.A == 0,     ZERO_FLAG);
+                               set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               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;
+                       case 0xC6: {//ADD A, #
+                               int inm = memory.read(regs.PC++);
+                               int res = regs.A + inm;
+                               int half_res = (regs.A & 0x0F) + (inm & 0x0F);
+                               regs.A = static_cast<u8>(res);
+                               
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag_if (res > 0xFF,      CARRY_FLAG);
+                               set_flag_if (regs.A == 0,     ZERO_FLAG);
+                               set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
                                }
 
-                               // RR n (through carry)
-                               for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg)
+                       // ADC A, n
+                       for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg)
 
-                               // RR (HL) (through carry)
-                               case 0x1E: {
-                                       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(bit0, CARRY_FLAG);
-                                       set_flag_if(value == 0, ZERO_FLAG);
-                                       reset_flag(ADD_SUB_FLAG); 
-                                       reset_flag(HALF_CARRY_FLAG); 
-                                       break;
-                               }
+                       case 0x8E: {// ADC A, (HL)
+                               int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+                               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<u8>(res);
                                
-                               // SLA n
-                               for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg)
-
-                               // SLA (HL)
-                               case 0x26: {
-                                       u8 value = memory.read(regs.HL);
-                                       bool carry = (value & 0x80) != 0;
-                                       value <<= 1;
-                                       memory.write(regs.HL, value);
-                                       set_flag_if(value == 0, ZERO_FLAG);
-                                       reset_flag(ADD_SUB_FLAG);
-                                       reset_flag(HALF_CARRY_FLAG);
-                                       set_flag_if(carry, CARRY_FLAG);
-                                       break;
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag_if (res > 0xFF,      CARRY_FLAG);
+                               set_flag_if (regs.A == 0,     ZERO_FLAG);
+                               set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
                                }
+                       case 0xCE: {//ADC A, #
+                               int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+                               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<u8>(res);
                                
-                               // SRA n
-                               for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg)
-
-                               // SRA (HL)
-                               case 0x2E: {
-                                       u8 value = memory.read(regs.HL);
-                                       bool carry = (value & 0x01) != 0;
-                                       u8 MSB = value & 0x80;
-                                       value = (value >> 1) | MSB;
-                                       memory.write(regs.HL, value);
-                                       set_flag_if(value == 0, ZERO_FLAG);
-                                       reset_flag(ADD_SUB_FLAG);
-                                       reset_flag(HALF_CARRY_FLAG);
-                                       set_flag_if(carry, CARRY_FLAG);
-                                       break;
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag_if (res > 0xFF,      CARRY_FLAG);
+                               set_flag_if (regs.A == 0,     ZERO_FLAG);
+                               set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
                                }
 
-                               // SRL n
-                               for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg)
+                       // SUB n
+                       for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg)
 
-                               // SRL (HL)
-                               case 0x3E: {
-                                       u8 value = memory.read(regs.HL);
-                                       bool carry = (value & 0x01) != 0;
-                                       value >>= 1;
-                                       memory.write(regs.HL, value);
-                                       set_flag_if(value == 0, ZERO_FLAG);
-                                       reset_flag(ADD_SUB_FLAG);
-                                       reset_flag(HALF_CARRY_FLAG);
-                                       set_flag_if(carry, CARRY_FLAG);
-                                       break;
-                               }
+                       case 0x96: {//SUB (HL)
+                               int res = regs.A - memory.read(regs.HL);
+                               int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+                               regs.A = static_cast<u8>(res);
 
-                               default: {
-                                       int bit_op = sub_opcode >> 6;
-                                       int reg = sub_opcode & 7;
-                                       int b   = (sub_opcode >> 3) & 7;
-                                       bool res;
-                                       switch (bit_op)
-                                       {
-                                               case 1: // BIT
-                                                       switch(reg)
-                                                       {
-                                                               case 0:
-                                                                       res = check_bit(regs.B, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 1:
-                                                                       res = check_bit(regs.C, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 2:
-                                                                       res = check_bit(regs.D, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 3:
-                                                                       res = check_bit(regs.E, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 4:
-                                                                       res = check_bit(regs.H, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 5:
-                                                                       res = check_bit(regs.L, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 6:
-                                                                       res = check_bit(memory.read(regs.HL), b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                               case 7:
-                                                                       res = check_bit(regs.A, b);
-                                                                       set_flag_if(res == false, ZERO_FLAG);
-                                                                       reset_flag(ADD_SUB_FLAG);
-                                                                       set_flag(HALF_CARRY_FLAG);
-                                                                       break;
-                                                       }
-                                                       break;
-
-                                               case 2: // RES
-                                                       switch(reg)
-                                                       {
-                                                               case 0:
-                                                                       regs.B = reset_bit(regs.B, b);
-                                                                       break;
-                                                               case 1:
-                                                                       regs.C = reset_bit(regs.C, b);
-                                                                       break;
-                                                               case 2:
-                                                                       regs.D = reset_bit(regs.D, b);
-                                                                       break;
-                                                               case 3:
-                                                                       regs.E = reset_bit(regs.E, b);
-                                                                       break;
-                                                               case 4:
-                                                                       regs.H = reset_bit(regs.H, b);
-                                                                       break;
-                                                               case 5:
-                                                                       regs.L = reset_bit(regs.L, b);
-                                                                       break;
-                                                               case 6:
-                                                                       memory.write(regs.HL, reset_bit(memory.read(regs.HL), b));
-                                                                       break;
-                                                               case 7:
-                                                                       regs.A = reset_bit(regs.A, b);
-                                                                       break;
-                                                       }
-                                                       break;
-
-                                               case 3: // SET
-                                                       switch(reg)
-                                                       {
-                                                               case 0:
-                                                                       regs.B = set_bit(regs.B, b);
-                                                                       break;
-                                                               case 1:
-                                                                       regs.C = set_bit(regs.C, b);
-                                                                       break;
-                                                               case 2:
-                                                                       regs.D = set_bit(regs.D, b);
-                                                                       break;
-                                                               case 3:
-                                                                       regs.E = set_bit(regs.E, b);
-                                                                       break;
-                                                               case 4:
-                                                                       regs.H = set_bit(regs.H, b);
-                                                                       break;
-                                                               case 5:
-                                                                       regs.L = set_bit(regs.L, b);
-                                                                       break;
-                                                               case 6:
-                                                                       memory.write(regs.HL, set_bit(memory.read(regs.HL), b));
-                                                                       break;
-                                                               case 7:
-                                                                       regs.A = set_bit(regs.A, b);
-                                                                       break;
-                                                       }
-                                                       break;
-                                               
-                                               default:
-                                                       logger.critical("Unknown sub-opcode after 0xCB");
-                                                       break;
-                                       }
+                               set_flag(ADD_SUB_FLAG);
+                               set_flag_if (res < 0,      CARRY_FLAG);
+                               set_flag_if (res == 0,     ZERO_FLAG);
+                               set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                               }
+                       
+                       case 0xD6: {//SUB #
+                               int inm = memory.read(regs.PC++);
+                               int res = regs.A - inm;
+                               int half_res = (regs.A & 0x0F) - (inm & 0x0F);
+                               regs.A = static_cast<u8>(res);
+
+                               set_flag(ADD_SUB_FLAG);
+                               set_flag_if (res < 0,      CARRY_FLAG);
+                               set_flag_if (res == 0,     ZERO_FLAG);
+                               set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
                                }
-                                       
-                       }
-                       break;
-               }
-
-               // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA
-               case 0x27: {
-                       u8 corr_factor = 0;
-                       if (regs.A > 0x99 || check_flag(CARRY_FLAG)) {
-                               corr_factor = 0x60;
-                               set_flag(CARRY_FLAG);
-                       } else {
-                               reset_flag(CARRY_FLAG);
-                       }
-
-                       if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) {
-                               corr_factor |= 0x06;
-                       }
 
-                       if (!check_flag(ADD_SUB_FLAG)) {
-                               regs.A += corr_factor;
-                       } else {
-                               regs.A -= corr_factor;
-                       }
+                       // SBC n
+                       for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg)
+
+                       case 0x9E: {//SBC (HL)
+                               int carry = (check_flag(CARRY_FLAG)? 1 : 0);
+                               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<u8>(res);
+
+                               set_flag(ADD_SUB_FLAG);
+                               set_flag_if (res < 0,      CARRY_FLAG);
+                               set_flag_if (res == 0,     ZERO_FLAG);
+                               set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                               }
 
-                       set_flag_if(regs.A==0, ZERO_FLAG);
-                       reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P
-                       break;
-               }
+                       // There is no SBC inm
 
-               // CPL
-               case 0x2F:
-                       regs.A = ~regs.A;
-                       set_flag(HALF_CARRY_FLAG);
-                       set_flag(ADD_SUB_FLAG);
-                       break;
+                       // AND n
+                       for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg)
 
-               // CCF
-               case 0x3F:
-                       if (check_flag(CARRY_FLAG))
+                       case 0xA6: //AND (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);
                                reset_flag(CARRY_FLAG);
-                       else
-                               set_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xE6: //AND inm
+                               regs.A &= memory.read(regs.PC++);
+                               if (regs.A == 0) set_flag(ZERO_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag(HALF_CARRY_FLAG);
+                               reset_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
 
-                       reset_flag(HALF_CARRY_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       break;
+                       // OR n
+                       for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg)
 
-               // SCF
-               case 0x37:
-                       set_flag(CARRY_FLAG);
-                       reset_flag(HALF_CARRY_FLAG);
-                       reset_flag(ADD_SUB_FLAG);
-                       break;
+                       case 0xB6: //OR (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);
+                               reset_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xF6: //OR inm
+                               regs.A |= memory.read(regs.PC++);
+                               if (regs.A == 0) set_flag(ZERO_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               reset_flag(HALF_CARRY_FLAG);
+                               reset_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
 
-               // NOP
-               case 0x00:
-                       break;
+                       // XOR n
+                       for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg)
 
-               // HALT
-               case 0x76:
-                       HALT = true;
-                       break;
+                       case 0xAE: //XOR (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);
+                               reset_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xEE: //XOR inm
+                               regs.A ^= memory.read(regs.PC++);
+                               if (regs.A == 0) set_flag(ZERO_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               reset_flag(HALF_CARRY_FLAG);
+                               reset_flag(CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                       
+                       // CP n
+                       for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg)
+
+                       case 0xBE: {//CP (HL)
+                               int res = regs.A - memory.read(regs.HL);
+                               int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F);
+
+                               set_flag(ADD_SUB_FLAG);
+                               set_flag_if (res < 0,      CARRY_FLAG);
+                               set_flag_if (res == 0,     ZERO_FLAG);
+                               set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                               }
+                       
+                       case 0xFE: {//CP #
+                               int inm = memory.read(regs.PC++);
+                               int res = regs.A - inm;
+                               int half_res = (regs.A & 0x0F) - (inm & 0x0F);
+
+                               set_flag(ADD_SUB_FLAG);
+                               set_flag_if (res < 0,      CARRY_FLAG);
+                               set_flag_if (res == 0,     ZERO_FLAG);
+                               set_flag_if (half_res < 0, HALF_CARRY_FLAG);
+                               cycles_until_next_instruction = 8; 
+                               break;
+                               }
 
-               // STOP
-               case 0x10: {
-                       int sub_opcode = memory.read(regs.PC++);
-                       if (sub_opcode == 0x00) {
-                               HALT = true;
-                       } else {
-                               logger.critical("Unknown sub-opcode after 0x10");
+                       // ADD SP, #
+                       case 0xE8: {
+                               // FIXME: No se que hacer con el half carry, en 4 o en 11?
+                               int n = static_cast<s8>(memory.read(regs.PC++));
+                               int res = regs.SP + n;
+                               regs.SP = static_cast<u8>(res);
+                               reset_flag(ZERO_FLAG);
+                               reset_flag(ADD_SUB_FLAG);
+                               set_flag_if(res > 0xFFFF, CARRY_FLAG);
+                               cycles_until_next_instruction = 16; 
+                               break;
                        }
-                       break;
-               }
-               
-               // DI
-               case 0xF3:
-                       IME = 0;
-                       break;
-
-               // EI
-               case 0xFB:
-                       IME = 1;
-                       break;
-                          
-               // 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;
-               }
-
-               
-               // Jumps
-               // JP nn
-               case 0xC3:
-                       regs.PC = memory.read16(regs.PC);
-                       break;
-
-               // JP cc, nn
-               case 0xC2: { // JP NZ, nn
-                       u16 dst = memory.read16(regs.PC);
-                       if (!check_flag(ZERO_FLAG))
-                               regs.PC = dst;
-                       else
-                               regs.PC += 2; // if !cc, skip 2 dst bytes
-                       break;
-               }
+                       // Miscellaneous instructions
+                       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)
+                                       case 0x36: {
+                                               u8 tmp = memory.read(regs.HL);
+                                               tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4);
+                                               memory.write(regs.HL, tmp);
+                       
+                                               set_flag_if(tmp==0, ZERO_FLAG);
+                                               reset_flag(CARRY_FLAG);
+                                               reset_flag(HALF_CARRY_FLAG);
+                                               reset_flag(ADD_SUB_FLAG);
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               case 0xCA: { // JP Z, nn
-                       u16 dst = memory.read16(regs.PC);
-                       if (check_flag(ZERO_FLAG))
-                               regs.PC = dst;
-                       else
-                               regs.PC += 2; // if !cc, skip 2 dst bytes
-                       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); 
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               case 0xD2: { // JP NC, nn
-                       u16 dst = memory.read16(regs.PC);
-                       if (!check_flag(CARRY_FLAG))
-                               regs.PC = dst;
-                       else
-                               regs.PC += 2; // if !cc, skip 2 dst bytes
-                       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); 
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               case 0xDA: { // JP C, nn
-                       u16 dst = memory.read16(regs.PC);
-                       if (check_flag(CARRY_FLAG))
-                               regs.PC = dst;
-                       else
-                               regs.PC += 2; // if !cc, skip 2 dst bytes
-                       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); 
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               // JP (HL)
-               case 0xE9:
-                       regs.PC = regs.HL;
-                       break;
+                                       // RR n (through carry)
+                                       for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg)
+
+                                       // RR (HL) (through carry)
+                                       case 0x1E: {
+                                               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(bit0, CARRY_FLAG);
+                                               set_flag_if(value == 0, ZERO_FLAG);
+                                               reset_flag(ADD_SUB_FLAG); 
+                                               reset_flag(HALF_CARRY_FLAG); 
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
+                                       
+                                       // SLA n
+                                       for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg)
+
+                                       // SLA (HL)
+                                       case 0x26: {
+                                               u8 value = memory.read(regs.HL);
+                                               bool carry = (value & 0x80) != 0;
+                                               value <<= 1;
+                                               memory.write(regs.HL, value);
+                                               set_flag_if(value == 0, ZERO_FLAG);
+                                               reset_flag(ADD_SUB_FLAG);
+                                               reset_flag(HALF_CARRY_FLAG);
+                                               set_flag_if(carry, CARRY_FLAG);
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
+                                       
+                                       // SRA n
+                                       for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg)
+
+                                       // SRA (HL)
+                                       case 0x2E: {
+                                               u8 value = memory.read(regs.HL);
+                                               bool carry = (value & 0x01) != 0;
+                                               u8 MSB = value & 0x80;
+                                               value = (value >> 1) | MSB;
+                                               memory.write(regs.HL, value);
+                                               set_flag_if(value == 0, ZERO_FLAG);
+                                               reset_flag(ADD_SUB_FLAG);
+                                               reset_flag(HALF_CARRY_FLAG);
+                                               set_flag_if(carry, CARRY_FLAG);
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               // JR n
-               case 0x18:
-                       // -1 because PC is now pointing past the opcode
-                       regs.PC += static_cast<s8>(memory.read(regs.PC++));
-                       break;
+                                       // SRL n
+                                       for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg)
+
+                                       // SRL (HL)
+                                       case 0x3E: {
+                                               u8 value = memory.read(regs.HL);
+                                               bool carry = (value & 0x01) != 0;
+                                               value >>= 1;
+                                               memory.write(regs.HL, value);
+                                               set_flag_if(value == 0, ZERO_FLAG);
+                                               reset_flag(ADD_SUB_FLAG);
+                                               reset_flag(HALF_CARRY_FLAG);
+                                               set_flag_if(carry, CARRY_FLAG);
+                                               cycles_until_next_instruction = 16; 
+                                               break;
+                                       }
 
-               // JR cc, n
-               case 0x20: { // JR NZ, n
-                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
-                       if (!check_flag(ZERO_FLAG)) 
-                               regs.PC += offset;
-                       break;
-               }
+                                       default: {
+                                               int bit_op = sub_opcode >> 6;
+                                               int reg = sub_opcode & 7;
+                                               int b   = (sub_opcode >> 3) & 7;
+                                               bool res;
+                                               switch (bit_op)
+                                               {
+                                                       case 1: // BIT
+                                                               switch(reg)
+                                                               {
+                                                                       case 0:
+                                                                               res = check_bit(regs.B, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 1:
+                                                                               res = check_bit(regs.C, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 2:
+                                                                               res = check_bit(regs.D, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 3:
+                                                                               res = check_bit(regs.E, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 4:
+                                                                               res = check_bit(regs.H, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 5:
+                                                                               res = check_bit(regs.L, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 6:
+                                                                               res = check_bit(memory.read(regs.HL), b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 16; 
+                                                                               break;
+                                                                       case 7:
+                                                                               res = check_bit(regs.A, b);
+                                                                               set_flag_if(res == false, ZERO_FLAG);
+                                                                               reset_flag(ADD_SUB_FLAG);
+                                                                               set_flag(HALF_CARRY_FLAG);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                               }
+                                                               break;
+
+                                                       case 2: // RES
+                                                               switch(reg)
+                                                               {
+                                                                       case 0:
+                                                                               regs.B = reset_bit(regs.B, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 1:
+                                                                               regs.C = reset_bit(regs.C, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 2:
+                                                                               regs.D = reset_bit(regs.D, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 3:
+                                                                               regs.E = reset_bit(regs.E, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 4:
+                                                                               regs.H = reset_bit(regs.H, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 5:
+                                                                               regs.L = reset_bit(regs.L, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 6:
+                                                                               memory.write(regs.HL, reset_bit(memory.read(regs.HL), b));
+                                                                               cycles_until_next_instruction = 16; 
+                                                                               break;
+                                                                       case 7:
+                                                                               regs.A = reset_bit(regs.A, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                               }
+                                                               break;
+
+                                                       case 3: // SET
+                                                               switch(reg)
+                                                               {
+                                                                       case 0:
+                                                                               regs.B = set_bit(regs.B, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 1:
+                                                                               regs.C = set_bit(regs.C, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 2:
+                                                                               regs.D = set_bit(regs.D, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 3:
+                                                                               regs.E = set_bit(regs.E, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 4:
+                                                                               regs.H = set_bit(regs.H, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 5:
+                                                                               regs.L = set_bit(regs.L, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                                       case 6:
+                                                                               memory.write(regs.HL, set_bit(memory.read(regs.HL), b));
+                                                                               cycles_until_next_instruction = 16; 
+                                                                               break;
+                                                                       case 7:
+                                                                               regs.A = set_bit(regs.A, b);
+                                                                               cycles_until_next_instruction = 8; 
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       
+                                                       default:
+                                                               logger.critical("Unknown sub-opcode after 0xCB");
+                                                               break;
+                                               }
+                                       }
+                                               
+                               }
+                               break;
+                       }
+                       // DI
+                       case 0xF3:
+                               IME = 0;
+                               cycles_until_next_instruction = 4; 
+                               break;
+
+                       // EI
+                       case 0xFB:
+                               IME = 1;
+                               cycles_until_next_instruction = 4; 
+                               break;
+                                  
+                       // Jumps
+                       // JP nn
+                       case 0xC3:
+                               regs.PC = memory.read16(regs.PC);
+                               cycles_until_next_instruction = 12; 
+                               break;
+
+                       // JP cc, nn
+                       case 0xC2: { // JP NZ, nn
+                               u16 dst = memory.read16(regs.PC);
+                               if (!check_flag(ZERO_FLAG))
+                                       regs.PC = dst;
+                               else
+                                       regs.PC += 2; // if !cc, skip 2 dst bytes
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       }
 
-               case 0x28: { // JR Z, n
-                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
-                       if (check_flag(ZERO_FLAG)) 
-                               regs.PC += offset;
-                       break;
-               }
+                       case 0xCA: { // JP Z, nn
+                               u16 dst = memory.read16(regs.PC);
+                               if (check_flag(ZERO_FLAG))
+                                       regs.PC = dst;
+                               else
+                                       regs.PC += 2; // if !cc, skip 2 dst bytes
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       }
 
-               case 0x30: { // JR NC, n
-                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
-                       if (!check_flag(CARRY_FLAG)) 
-                               regs.PC += offset;
-                       break;
-               }
+                       case 0xD2: { // JP NC, nn
+                               u16 dst = memory.read16(regs.PC);
+                               if (!check_flag(CARRY_FLAG))
+                                       regs.PC = dst;
+                               else
+                                       regs.PC += 2; // if !cc, skip 2 dst bytes
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       }
 
-               case 0x38: { // JR C, n
-                       s8 offset = static_cast<s8>(memory.read(regs.PC++));
-                       if (check_flag(CARRY_FLAG)) 
-                               regs.PC += offset;
-                       break;
-               }
+                       case 0xDA: { // JP C, nn
+                               u16 dst = memory.read16(regs.PC);
+                               if (check_flag(CARRY_FLAG))
+                                       regs.PC = dst;
+                               else
+                                       regs.PC += 2; // if !cc, skip 2 dst bytes
+                               cycles_until_next_instruction = 12; 
+                               break;
+                       }
 
-               // Calls
-               // CALL nn
-               case 0xCD: {
-                       u16 addr = memory.read16(regs.PC);
-                       regs.PC += 2;
-                       do_call(addr);
-                       break;
-               }
+                       // JP (HL)
+                       case 0xE9:
+                               regs.PC = regs.HL;
+                               cycles_until_next_instruction = 4; 
+                               break;
 
-               // CALL cc, nn
-               case 0xC4: { // CALL NZ, nn
-                       if (!check_flag(ZERO_FLAG)) {
+                       // Calls
+                       // CALL nn
+                       case 0xCD: {
                                u16 addr = memory.read16(regs.PC);
                                regs.PC += 2;
                                do_call(addr);
-                       } else {
-                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                               cycles_until_next_instruction = 12; 
+                               break;
                        }
-                       break;
-               }
 
-               case 0xCC: { // CALL Z, nn
-                       if (check_flag(ZERO_FLAG)) {
-                               u16 addr = memory.read16(regs.PC);
-                               regs.PC += 2;
-                               do_call(addr);
-                       } else {
-                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       // CALL cc, nn
+                       case 0xC4: { // CALL NZ, nn
+                               if (!check_flag(ZERO_FLAG)) {
+                                       u16 addr = memory.read16(regs.PC);
+                                       regs.PC += 2;
+                                       do_call(addr);
+                               } else {
+                                       regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                               }
+                               cycles_until_next_instruction = 12; 
+                               break;
                        }
-                       break;
-               }
 
-               case 0xD4: { // CALL NC, nn
-                       if (!check_flag(CARRY_FLAG)) {
-                               u16 addr = memory.read16(regs.PC);
-                               regs.PC += 2;
-                               do_call(addr);
-                       } else {
-                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       case 0xCC: { // CALL Z, nn
+                               if (check_flag(ZERO_FLAG)) {
+                                       u16 addr = memory.read16(regs.PC);
+                                       regs.PC += 2;
+                                       do_call(addr);
+                               } else {
+                                       regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                               }
+                               cycles_until_next_instruction = 12; 
+                               break;
                        }
-                       break;
-               }
 
-               case 0xDC: { // CALL C, nn
-                       if (check_flag(CARRY_FLAG)) {
-                               u16 addr = memory.read16(regs.PC);
-                               regs.PC += 2;
-                               do_call(addr);
-                       } else {
-                               regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                       case 0xD4: { // CALL NC, nn
+                               if (!check_flag(CARRY_FLAG)) {
+                                       u16 addr = memory.read16(regs.PC);
+                                       regs.PC += 2;
+                                       do_call(addr);
+                               } else {
+                                       regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                               }
+                               cycles_until_next_instruction = 12; 
+                               break;
                        }
-                       break;
-               }
-
-               // 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.read16(regs.SP);
-                       regs.SP += 2;
-                       regs.PC = retaddr;
-                       break;
-               }
 
-               // RET cc
-               case 0xC0:  // RET NZ
-                       if (!check_flag(ZERO_FLAG)) { 
-                               u16 retaddr = memory.read16(regs.SP);
-                               regs.SP += 2;
-                               regs.PC = retaddr;
+                       case 0xDC: { // CALL C, nn
+                               if (check_flag(CARRY_FLAG)) {
+                                       u16 addr = memory.read16(regs.PC);
+                                       regs.PC += 2;
+                                       do_call(addr);
+                               } else {
+                                       regs.PC += 2; // if !cc, skip 2 (nn) bytes
+                               }
+                               cycles_until_next_instruction = 12; 
+                               break;
                        }
-                       break;
 
-               case 0xC8:  // RET Z
-                       if (check_flag(ZERO_FLAG)) { 
+                       // 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.read16(regs.SP);
                                regs.SP += 2;
                                regs.PC = retaddr;
+                               cycles_until_next_instruction = 8; 
+                               break;
                        }
-                       break;
 
-               case 0xD0:  // RET NC
-                       if (!check_flag(CARRY_FLAG)) { 
-                               u16 retaddr = memory.read16(regs.SP);
-                               regs.SP += 2;
-                               regs.PC = retaddr;
-                       }
-                       break;
+                       // RET cc
+                       case 0xC0:  // RET NZ
+                               if (!check_flag(ZERO_FLAG)) { 
+                                       u16 retaddr = memory.read16(regs.SP);
+                                       regs.SP += 2;
+                                       regs.PC = retaddr;
+                               }
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xC8:  // RET Z
+                               if (check_flag(ZERO_FLAG)) { 
+                                       u16 retaddr = memory.read16(regs.SP);
+                                       regs.SP += 2;
+                                       regs.PC = retaddr;
+                               }
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xD0:  // RET NC
+                               if (!check_flag(CARRY_FLAG)) { 
+                                       u16 retaddr = memory.read16(regs.SP);
+                                       regs.SP += 2;
+                                       regs.PC = retaddr;
+                               }
+                               cycles_until_next_instruction = 8; 
+                               break;
+
+                       case 0xD8:  // RET C
+                               if (check_flag(CARRY_FLAG)) { 
+                                       u16 retaddr = memory.read16(regs.SP);
+                                       regs.SP += 2;
+                                       regs.PC = retaddr;
+                               }
+                               cycles_until_next_instruction = 8; 
+                               break;
 
-               case 0xD8:  // RET C
-                       if (check_flag(CARRY_FLAG)) { 
+                       // RETI
+                       case 0xD9: {
+                               // RET && EI
                                u16 retaddr = memory.read16(regs.SP);
                                regs.SP += 2;
                                regs.PC = retaddr;
+                               IME=1;
+                               cycles_until_next_instruction = 8; 
+                               break;
                        }
-                       break;
-
-               // RETI
-               case 0xD9: {
-                       // RET && EI
-                       u16 retaddr = memory.read16(regs.SP);
-                       regs.SP += 2;
-                       regs.PC = retaddr;
-                       IME=1;
-                       break;
+                       
+                       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;
                }
+               break;
+       }
        
-               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
-
-       ++cycle_count;
+       if (cycles_until_video_update <= 0)
+               cycles_until_video_update = video.update();
        
-       video.update();
-
-       // Check for interrupts before opcode fetching
-       u8 IE=memory.high[GBMemory::I_IE];
-       //logger.trace("IME=", int(IME), " IE=", int(IE));
-       if (IME && IE)
-       {
-               u8 IF = memory.high[GBMemory::I_IF];
-               //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.high[GBMemory::I_IF] = IF;
-       }
-
-       /*
-       for(BreakpointMap::iterator i=breakpoints.begin();
-                       i != breakpoints.end();
-                       i++)
-       {
-               if (i->second.addr == regs.PC && i->second.enabled)
-                       return BREAKPOINT;
-       }
-       */
+       cycles_until_video_update -= CYCLE_STEP;
+       cycles_until_next_instruction -= CYCLE_STEP;
        
-       return NORMAL;
+       if (cycles_until_next_instruction > 0) return WAIT;
+       else return NORMAL;
 }
 
 GameBoy::run_status GameBoy::run() 
 {
+       static const int CYCLES_PER_INPUT_CHECK = 40000;
+       static int c=0;
        SDL_Event ev;
 
        run_status status=NORMAL;
-       while (status == NORMAL)
+       while (status == NORMAL || status == WAIT)
        {
-               while (video.poll_event(&ev))
+               ++c;
+               if (c==CYCLES_PER_INPUT_CHECK)
                {
-                       switch(ev.type)
+                       c=0;
+                       while (video.poll_event(&ev))
                        {
-                               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;
+                               switch(ev.type)
+                               {
+                                       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();
index 42bef041295c1c6143feb8a217e7cb39f8b6dc25..495fa41eac3f3da5bef835fa3f9d0ea3272a803b 100644 (file)
--- a/gbcore.h
+++ b/gbcore.h
@@ -70,6 +70,9 @@ class GameBoy
        u8 HALT; // Is the CPU halted waiting for an interrupt?
 
        u32 cycle_count;
+       u32 cycles_until_video_update;
+       u32 cycles_until_next_instruction;
+       static const u32 CYCLE_STEP = 4;
        
        inline void do_call(u16 addr)
        {
@@ -91,6 +94,7 @@ class GameBoy
                TRACEPOINT,
                PAUSED,
                QUIT,
+               WAIT,
        };
 
        // Constructors
index e872c6bc994c347ab19f3767dbca42efc5b6962e..c1d82d2e37ddc9cff5993db5f3d6bbf1d40aaab5 100644 (file)
--- a/opcodes.h
+++ b/opcodes.h
@@ -9,8 +9,8 @@
 #define for_each_register(opA, opB, opC, opD, opE, opH, opL, macro) \
        macro(opA, A) \
        macro(opB, B) \
-    macro(opC, C) \
-    macro(opD, D) \
+       macro(opC, C) \
+       macro(opD, D) \
        macro(opE, E) \
        macro(opH, H) \
        macro(opL, L)
 #define LD_reg_nn(opcode, reg) \
        case opcode: \
                regs.reg = memory.read(regs.PC++); \
+               cycles_until_next_instruction = 8; \
                break;
 
 #define LD_reg_reg(opcode, reg1, reg2) \
        case opcode: \
                regs.reg1 = regs.reg2; \
+               cycles_until_next_instruction = 4; \
                break;
 
 #define LD_A_reg(opcode, reg2) LD_reg_reg(opcode, A, reg2)
 #define LD_reg__HL_(opcode, reg) \
        case opcode: \
                regs.reg = memory.read(regs.HL); \
+               cycles_until_next_instruction = 8; \
                break;
 
 // LD (HL), reg
 #define LD__HL__reg(opcode, reg) \
        case opcode: \
                memory.write(regs.HL, regs.reg); \
+               cycles_until_next_instruction = 8; \
                break;
 
 #define PUSH(opcode, regH, regL) \
@@ -56,6 +60,7 @@
                memory.write(regs.SP-1, regs.regH); \
                memory.write(regs.SP-2, regs.regL); \
                regs.SP -= 2; \
+               cycles_until_next_instruction = 16; \
                break;
 
 #define POP(opcode, regH, regL) \
@@ -63,6 +68,7 @@
                regs.regL = memory.read(regs.SP); \
                regs.regH = memory.read(regs.SP+1); \
                regs.SP += 2; \
+               cycles_until_next_instruction = 12; \
                break;
 
 #define ADD_A_reg(opcode, reg) \
@@ -75,6 +81,7 @@
                set_flag_if (res > 0xFF,      CARRY_FLAG); \
                set_flag_if (regs.A == 0,     ZERO_FLAG);  \
                set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
@@ -89,6 +96,7 @@
                set_flag_if (res > 0xFF,      CARRY_FLAG); \
                set_flag_if (regs.A == 0,     ZERO_FLAG);  \
                set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                set_flag_if (res < 0,      CARRY_FLAG); \
                set_flag_if (res == 0,     ZERO_FLAG); \
                set_flag_if (half_res < 0, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                set_flag_if (res < 0,      CARRY_FLAG); \
                set_flag_if (res == 0,     ZERO_FLAG); \
                set_flag_if (half_res < 0, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                set_flag(HALF_CARRY_FLAG); \
                reset_flag(CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                reset_flag(CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                reset_flag(CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                set_flag_if (res < 0,      CARRY_FLAG); \
                set_flag_if (res == 0,     ZERO_FLAG); \
                set_flag_if (half_res < 0, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                set_flag_if (regs.reg == 0,   ZERO_FLAG); \
                set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                set_flag(ADD_SUB_FLAG); \
                set_flag_if (regs.reg == 0, ZERO_FLAG); \
                set_flag_if (half_res < 0, HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 4; \
                break; \
        }
 
                set_flag_if (res == 0,         ZERO_FLAG); \
                set_flag_if (half_res > 0xFFF, HALF_CARRY_FLAG); \
                set_flag_if (res > 0xFFFF,     CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
 #define INC_reg16(opcode, reg16) \
        case opcode: \
                ++regs.reg16; \
+               cycles_until_next_instruction = 8; \
                break;
 
 #define DEC_reg16(opcode, reg16) \
        case opcode: \
                --regs.reg16; \
+               cycles_until_next_instruction = 8; \
                break;
 
 #define SWAP_reg(opcode, reg) \
                reset_flag(CARRY_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                reset_flag(ADD_SUB_FLAG); \
+               cycles_until_next_instruction = 8; \
                break;
 
 #define RST(opcode, n) \
        case opcode: \
                do_call(n); \
+               cycles_until_next_instruction = 32; \
                break;
 
 
                set_flag_if(regs.reg == 0, ZERO_FLAG); \
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                set_flag_if(regs.reg == 0, ZERO_FLAG); \
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                set_flag_if(regs.reg == 0, ZERO_FLAG); \
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                set_flag_if(regs.reg == 0, ZERO_FLAG); \
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                set_flag_if(carry, CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                set_flag_if(carry, CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
                reset_flag(ADD_SUB_FLAG); \
                reset_flag(HALF_CARRY_FLAG); \
                set_flag_if(carry, CARRY_FLAG); \
+               cycles_until_next_instruction = 8; \
                break; \
        }
 
index e13056d7bd8f68e19f554ddce84df49c882e9f41..6dd0e9500dd1e1f0cfda1a9b55634bcffebfe8ab 100644 (file)
@@ -60,7 +60,8 @@ int main(int argc, char **argv)
                
                if (command == "step" || command == "s") 
                {
-                       gb.run_cycle();
+                       while(gb.run_cycle() == GameBoy::WAIT) {} // do nothing
+                       
                        cout << gb.status_string() << endl;
                }
                else if (command == "run" || command == "r" || command == "cont") 
@@ -69,20 +70,32 @@ int main(int argc, char **argv)
                        {
                                gb.reset();
                        }
-                       int status = gb.run();
-                       if (status == GameBoy::QUIT)
+                       if (arguments.size() == 0)
                        {
-                               break;
+                               int status = gb.run();
+                               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 (status == GameBoy::BREAKPOINT)
+                       else if (arguments.size() == 1)
                        {
-                               cout << "Breakpoint hit at " << gb.regs.PC << endl;
+                               int cycles = str2int(arguments[0]);
+
+                               for (u32 i=0; i<cycles/gb.CYCLE_STEP; i++)
+                                       gb.run_cycle();
+                               
                                cout << gb.status_string() << endl;
                        }
-                       else
-                       {
-                               cout << "run returned with status " << status << endl;
-                       }
                }
                else if (command == "quit" || command == "q")
                {
@@ -184,6 +197,10 @@ int main(int argc, char **argv)
                        else if (arguments[0] == "trace")
                                logger.set_log_level(Logger::TRACE);
                }
+               else if (command == "reset")
+               {
+                       gb.reset();
+               }
                else 
                {
                        cout << "Unknown command '" << command << "'" << endl;