static void runop_main(uint8_t op)
{
    int b67 = op >> 6;

    switch(op) {
        /* 8-bit load group except ld r,r/ld r,imm/ld r,(hl)/ld (hl),r in default */
    case 0x36:
        op_store_mem_imm8(regs.g.rr.hl, fetch_byte());
        break;
    case 0x0a:
        op_load_reg8_mem(R_A, regs.g.rr.bc);
        break;
    case 0x1a:
        op_load_reg8_mem(R_A, regs.g.rr.de);
        break;
    case 0x3a:
        op_load_reg8_mem(R_A, fetch_imm16());
        break;
    case 0x02:
        op_store_mem_reg8(regs.g.rr.bc, R_A);
        break;
    case 0x12:
        op_store_mem_reg8(regs.g.rr.de, R_A);
        break;
    case 0x32:
        op_store_mem_reg8(fetch_imm16(), R_A);
        break;

        /* 16-bit load group */
    case 0x01:
    case 0x11:
    case 0x21:
    case 0x31:
        op_load_reg16_imm16(OP_RR(op), fetch_imm16());
        break;
    case 0x2a:
        op_load_reg16_imm16(RR_HL, fetch_imm16());
        break;
    case 0x22:
        op_store_mem_reg16(fetch_imm16(), RR_HL);
        break;
    case 0xf9:
        op_load_reg16_reg16(RR_SP, RR_HL);
        break;
    case 0xc5:
    case 0xd5:
    case 0xe0:
    case 0xf5:
        op_push_reg16(RRSET2 | OP_RR(op));
        break;
    case 0xc1:
    case 0xd1:
    case 0xe1:
    case 0xf1:
        op_pop_reg16(RRSET2 | OP_RR(op));
        break;

        /* exchange, block transfer, block search groups */
    case 0xeb:
        SWAP_RR(regs.g.rr.de, regs.g.rr.hl);
        break;
    case 0x08:
        SWAP_RR(regs.g.rr.af, regs.shadow.rr.af);
        break;
    case 0xd9:
        SWAP_RR(regs.g.rr.bc, regs.shadow.rr.bc);
        SWAP_RR(regs.g.rr.de, regs.shadow.rr.de);
        SWAP_RR(regs.g.rr.hl, regs.shadow.rr.hl);
        break;
    case 0xe3:
        op_exch_mem_reg16(regs.g.rr.sp, RR_HL);
        break;

        /* general purpose arithmetic and cpu control groups */
    case 0x27:
        break;  /* TODO implement DAA */
    case 0x2f:  /* cpl a */
        regs.g.r.a = ~regs.g.r.a;
        regs.g.r.f |= FLAGS_H | FLAGS_N;
        break;
    case 0x3f:  /* ccf */
        regs.g.r.f ^= FLAGS_C;
        break;
    case 0x37:  /* scf */
        regs.g.r.f |= FLAGS_C;
    case 0x00:  /* nop */
        break;
    case 0x76:  /* halt */
        halt = 1;
        break;
    case 0xf3:  /* di */
        regs.iff = 0;
        break;
    case 0xfb:  /* ei */
        regs.iff = 1;
        break;

        /* 16-bit arithmetic group */
    case 0x09:
    case 0x19:
    case 0x29:
    case 0x39:
        op_add_reg16_reg16(RR_HL, OP_RR(op));
        break;
    case 0x03:
    case 0x13:
    case 0x23:
    case 0x33:
        op_incdec_reg16(OP_RR(op), 1);
        break;
    case 0x0b:
    case 0x1b:
    case 0x2b:
    case 0x3b:
        op_incdec_reg16(OP_RR(op), -1);
        break;

        /* rotate and shift group */
    case 0x07:  /* rlca */
        op_rl_reg8(R_A, 8);
        break;
    case 0x17:  /* rla */
        op_rl_reg8(R_A, 9);
        break;
    case 0x0f:  /* rrca */
        op_rr_reg8(R_A, 8);
        break;
    case 0x1f:  /* rra */
        op_rr_reg8(R_A, 9);
        break;

        /* jump group */
    case 0xc3:  /* jp imm16 */
        regs.g.rr.pc = fetch_imm16();
        break;
    case 0xc2:
    case 0xd2:
    case 0xe2:
    case 0xf2:
    case 0xca:
    case 0xda:
    case 0xea:
    case 0xfa:
        if(cond(OPCOND(op))) {
            regs.g.rr.pc = fetch_imm16();
        }
        break;


    default:
        switch(b67) {
        case 0:
            if(SRC_R(op) == 6) {
                op_load_reg8_imm8(DEST_R(op), fetch_byte());
            } else if(SRC_R(op) == 4 || SRC_R(op) == 5) {
                int adj = (op & 1) ? -1 : 1;
                if(DEST_R(op) != 6) {
                    op_incdec_reg8(DEST_R(op), adj);
                } else {
                    op_incdec_mem(regs.g.rr.hl, adj);
                }
            }
            break;

        case 1:
            if(DEST_R(op) != 6 && SRC_R(op) != 6) {
                op_load_reg8_reg8(DEST_R(op), SRC_R(op));
            } else {
                if(SRC_R(op) == 6) {
                    op_load_reg8_mem(DEST_R(op), regs.g.rr.hl);
                } else if(DEST_R(op) == 6) {
                    op_store_mem_reg8(regs.g.rr.hl, SRC_R(op));
                }
            }
            break;

        case 2:
            if(SRC_R(op) != 6) {
                op_alu_reg8(ALUOP(op), SRC_R(op));
            }
            break;

        case 3:
            if(SRC_R(op) == 6) {
                op_alu_imm8(ALUOP(op), fetch_byte());
            }
            break;

        default:
            break;
        }

        break;  /* treat any unknown opcodes as nops */
    }
}