// File: 0x6D70[P]chip8_emu/src/cpu.cpp
// Function: Cpu::run(SDL_Renderer*)
void Cpu::run(SDL_Renderer *renderer) {

    bool isFinished = false;
    bool update_video = false;
    uint64_t instruction_count = 0;

    SDL_Event event;

    // variable for keyboard
    bool keys[0x10] = {false};
    

    while (!isFinished) {
        instruction_count++;

        uint16_t opcode = this->mem_read_u16(this->state.pc);
        this->state.pc += 2;

        //  uncomment for single stepping
        // std::cout << "0x" << std::hex << opcode;
        // getchar();

        uint8_t opcode_n3 = opcode & 0xf;
        uint8_t opcode_n2 = (opcode >> 4) & 0xf;
        uint8_t opcode_n1 = (opcode >> 8) & 0xf;
        uint8_t opcode_n0 = (opcode >> 12) & 0xf;

        switch (opcode_n0) {
            case 0x0: {
                if (opcode == 0x00e0) {
                    // cls
                    update_video = true;
                    for (int y = 0; y < VIDEO_HEIGHT; y++) {
                        for (int x = 0; x < VIDEO_WIDTH; x++) {
                            this->state.video[x][y] = false;
                        }
                    }
                } else if (opcode == 0x00ee) {
                    // ret
                    this->state.pc = this->state.call_stack.top();
                    this->state.call_stack.pop();
                } else {
                    // sys addr
                    // this instruction is ignored
                    // http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0nnn
                }
                break;
            }
            case 0x1: {
                // JP addr
                this->state.pc = opcode & 0xfff;
                break;
            }
            case 0x2: {
                // CALL addr
                this->state.call_stack.push(this->state.pc);
                this->state.pc = opcode & 0xfff;
                break;
            }
            case 0x3: {
                // SE Vx, byte
                if (this->state.regs[opcode_n1] == (uint8_t)(opcode & 0xff)) {
                    // skip instruction
                    this->state.pc += 2;
                }
                break;
            }
            case 0x4: {
                // SNE Vx, byte
                if (this->state.regs[opcode_n1] != (uint8_t)(opcode & 0xff)) {
                    // skip instruction
                    this->state.pc += 2;
                }
                break;
            }
            case 0x5: {
                // SE Vx, Vy
                if (this->state.regs[opcode_n1] == this->state.regs[opcode_n2]) {
                    // skip instruction
                    this->state.pc += 2;
                }
                break;
            }
            case 0x6: {
                // ld vx,byte
                this->state.regs[opcode_n1] = (uint8_t)(opcode & 0xff);
                break;
            }
            case 0x7: {
                // ADD Vx, byte
                this->state.regs[opcode_n1] += (opcode & 0xff);
                break;
            }
            case 0x8: {
                // logical and arithmetic instruction
                switch (opcode_n3) {
                    case 0x0: {
                        this->state.regs[opcode_n1] = this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x1: {
                        this->state.regs[opcode_n1] |= this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x2: {
                        this->state.regs[opcode_n1] &= this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x3: {
                        this->state.regs[opcode_n1] ^= this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x4: {
                        // check overflow
                        if ((uint16_t)this->state.regs[opcode_n1] + (uint16_t)this->state.regs[opcode_n2] > 0xff) {
                            this->state.regs[0xf] = 1;
                        } else {
                            this->state.regs[0xf] = 0;
                        }

                        this->state.regs[opcode_n1] += this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x5: {
                        if (this->state.regs[opcode_n1] > this->state.regs[opcode_n2]) {
                            this->state.regs[0xf] = 1;
                        } else {
                            this->state.regs[0xf] = 0;
                        }

                        this->state.regs[opcode_n1] -= this->state.regs[opcode_n2];
                        break;
                    }
                    case 0x6: {
                        this->state.regs[opcode_n1] = this->state.regs[opcode_n2];
                        // shift right

                        this->state.regs[0xf] = this->state.regs[opcode_n1] & 1;
                        this->state.regs[opcode_n1] >>= 1;

                        break;
                    }
                    case 0x7: {
                        if (this->state.regs[opcode_n2] > this->state.regs[opcode_n1]) {
                            this->state.regs[0xf] = 1;
                        } else {
                            this->state.regs[0xf] = 0;
                        }
                        
                        this->state.regs[opcode_n1] = this->state.regs[opcode_n2] - this->state.regs[opcode_n1];
                        break;
                    }
                    case 0xe: {
                        this->state.regs[opcode_n1] = this->state.regs[opcode_n2];
                        // shift left

                        this->state.regs[0xf] = (this->state.regs[opcode_n1] >> 7) & 1;
                        this->state.regs[opcode_n1] <<= 1;

                        break;
                    }
                }
                break;
            }
            case 0x9: {
                // SNE Vx, Vy
                if (this->state.regs[opcode_n1] != this->state.regs[opcode_n2]) {
                    // skip instruction
                    this->state.pc += 2;
                }
                break;
            }
            case 0xa: {
                // ld l, addr
                this->state.l = opcode & 0xfff;
                break;
            }
            case 0xb: {
                // Bnnn - JP V0, addr
                this->state.pc = (opcode & 0xfff) + this->state.regs[0x0];
                break;
            }
            case 0xc: {
                // Cxkk - RND Vx, byte
                this->state.regs[opcode_n1] = (uint8_t)(rand() & (opcode & 0xff));
                break;
            }
            case 0xd: {
                // DXYN
                uint8_t x_base = this->state.regs[opcode_n1] % 64;
                uint8_t y_base = this->state.regs[opcode_n2] % 32;
                this->state.regs[0xf] = 0;
                update_video = true;

                for (int n = 0; n < opcode_n3; n++) {
                    uint8_t pixels = this->state.ram[this->state.l + n];

                    for (int x = 0; x < 8; x++) {
                        if (pixels & (0x80 >> x)) {
                            // current bit is one

                            if (this->state.video[x_base + x][y_base + n]) {
                                this->state.regs[0xf] = 1;
                                // flip bit
                                this->state.video[x_base + x][y_base + n] = false;
                            } else {
                                this->state.video[x_base + x][y_base + n] = true;
                            }
                        }
                    }

                }

                break;
            }
            case 0xe: {
                switch (opcode & 0xff) {
                    case 0x9e: {
                        // Ex9E - SKP Vx
                        uint8_t index = this->state.regs[opcode_n1] & 0xf;
                        if (keys[index])
                            this->state.pc += 2;
                        break;
                    }
                    case 0xa1: {
                        // ExA1 - SKNP Vx
                        uint8_t index = this->state.regs[opcode_n1] & 0xf;
                        if (!keys[index])
                            this->state.pc += 2;
                        break;
                    }
                }
                break;
            }
            case 0xf: {

                switch (opcode & 0xff) { 
                    case 0x7: {
                        // LD Vx, DT
                        this->state.regs[opcode_n1] = this->state.delay_timer;
                        break;
                    }
                    case 0xa: {
                        // LD Vx, K
                        // wait until key is pressed
                        // when the key is pressed, put it into Vx

                        if (isKeyPressed(keys)) {
                            for (int i = 0; i < 0x10; i++) {
                                if (keys[i]) {
                                    this->state.regs[opcode_n1] = i;
                                }
                            }
                        } else {
                            // decrement pc to hit this instruction again
                            this->state.pc -= 2;
                        }
                        break;
                    }
                    case 0x15: {
                        // LD DT, Vx
                        this->state.delay_timer = this->state.regs[opcode_n1];
                        break;
                    }
                    case 0x18: {
                        // LD ST, Vx
                        this->state.sound_timer = this->state.regs[opcode_n1];
                        break;
                    }
                    case 0x1e: {
                        // ADD I, Vx
                        this->state.l += this->state.regs[opcode_n1];

                        if (this->state.l > 0xfff) {
                            this->state.regs[0xf] = 1;
                        } else {
                            this->state.regs[0xf] = 0;
                        }

                        this->state.l &= 0xfff;
                        break;
                    }
                    case 0x29: {
                        // LD F, Vx
                        this->state.l = 0x50 + (opcode & 0xff) * 5;
                        break;
                    }
                    case 0x33: {
                        // Fx33 - LD B, Vx
                        // Binary-coded decimal conversion

                        this->state.ram[this->state.l + 0] = this->state.regs[opcode_n1] / 100;
                        this->state.ram[this->state.l + 1] = (this->state.regs[opcode_n1] / 10) % 10;
                        this->state.ram[this->state.l + 2] = this->state.regs[opcode_n1] % 10;

                        break;
                    }
                    case 0x55: {
                        // LD [I], Vx

                        for (int i = 0; i <= opcode_n1; i++) {
                            this->state.ram[this->state.l + i] = this->state.regs[i];
                        }

                        break;
                    }
                    case 0x65: {
                        // LD Vx, [I]

                        for (int i = 0; i <= opcode_n1; i++) {
                            this->state.regs[i] = this->state.ram[this->state.l + i];
                        }

                        break;
                    }
                }
                break;
            }
            default:
                std::cout << "missing instruction 0x" << std::hex << (int)opcode_n0 << std::endl;
                isFinished = true;
        }

        // update timers

        if (instruction_count % 10  == 0) {
            // ownly decrease every 10 instructions which should be a rate of about ~60 times a second

            if (this->state.delay_timer > 0)
                this->state.delay_timer--;
            if (this->state.sound_timer > 0)
                this->state.sound_timer--;
        }

        if (update_video || instruction_count % 0x100 == 0) {
            // video array has changed => update window

            SDL_RenderClear(renderer);

            for (int y = 0; y < VIDEO_HEIGHT; y++) {
                for (int x = 0; x < VIDEO_WIDTH; x++) {
                    if (this->state.video[x][y]) {
                        // white
                        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                    } else {
                        // black
                        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
                    }

                    SDL_Rect rect;
                    rect.h = VIDEO_MULTI;
                    rect.w = VIDEO_MULTI;
                    rect.x = x * VIDEO_MULTI;
                    rect.y = y * VIDEO_MULTI;

                    SDL_RenderFillRect(renderer, &rect);
                }
            }

            SDL_RenderPresent(renderer);

            update_video = false;
        }

        while(SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    isFinished = true;
                    break;
                case SDL_KEYDOWN: {
                    uint8_t index = keysym_to_index(event.key.keysym);

                    if (index < 0x10) {
                        keys[index] = true;
                    }
                    
                    break;
                }
                case SDL_KEYUP: {
                    uint8_t index = keysym_to_index(event.key.keysym);

                    if (index < 0x10) {
                        keys[index] = false;
                    }

                    break;
                }
            }
        }

        SDL_Delay(1);
    }

    std::cout << "Exited after 0x" << std::hex << (long)instruction_count << " instructions\n";
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x110, %rsp            # imm = 0x110
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xe8(%rbp)
movb $0x0, -0x11(%rbp)
movb $0x0, -0x12(%rbp)
movq $0x0, -0x20(%rbp)
leaq -0x70(%rbp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x2140
movb -0x11(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x287c
jmp 0x36f6
movq -0xe8(%rbp), %rdi
movq -0x20(%rbp), %rax
incq %rax
movq %rax, -0x20(%rbp)
movzwl 0x1860(%rdi), %esi
callq 0x2550
movw %ax, %cx
movq -0xe8(%rbp), %rax
movw %cx, -0x72(%rbp)
movw 0x1860(%rax), %cx
addw $0x2, %cx
movw %cx, 0x1860(%rax)
movb -0x72(%rbp), %al
andb $0xf, %al
movb %al, -0x73(%rbp)
movb -0x72(%rbp), %al
shrb $0x4, %al
movb %al, -0x74(%rbp)
movb -0x71(%rbp), %al
andb $0xf, %al
movb %al, -0x75(%rbp)
movzwl -0x72(%rbp), %eax
shrl $0xc, %eax
movb %al, -0x76(%rbp)
movzbl -0x76(%rbp), %eax
movq %rax, -0xf0(%rbp)
subq $0xf, %rax
ja 0x343a
movq -0xf0(%rbp), %rax
leaq 0x3838(%rip), %rcx      # 0x6138
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movzwl -0x72(%rbp), %eax
cmpl $0xe0, %eax
jne 0x296c
movb $0x1, -0x12(%rbp)
movl $0x0, -0x7c(%rbp)
cmpl $0x20, -0x7c(%rbp)
jge 0x296a
movl $0x0, -0x80(%rbp)
cmpl $0x40, -0x80(%rbp)
jge 0x295d
movq -0xe8(%rbp), %rax
addq $0x1010, %rax           # imm = 0x1010
movslq -0x80(%rbp), %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movslq -0x7c(%rbp), %rcx
movb $0x0, (%rax,%rcx)
movl -0x80(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
jmp 0x292c
jmp 0x295f
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x291f
jmp 0x29ad
movzwl -0x72(%rbp), %eax
cmpl $0xee, %eax
jne 0x29a9
movq -0xe8(%rbp), %rdi
addq $0x1810, %rdi           # imm = 0x1810
callq 0x3880
movq -0xe8(%rbp), %rdi
movw (%rax), %ax
movw %ax, 0x1860(%rdi)
addq $0x1810, %rdi           # imm = 0x1810
callq 0x38a0
jmp 0x29ab
jmp 0x29ab
jmp 0x29ad
jmp 0x347b
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xfff, %ecx            # imm = 0xFFF
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rsi
movq %rsi, %rdi
addq $0x1810, %rdi           # imm = 0x1810
addq $0x1860, %rsi           # imm = 0x1860
callq 0x38c0
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xfff, %ecx            # imm = 0xFFF
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movzwl -0x72(%rbp), %ecx
andl $0xff, %ecx
movzbl %cl, %ecx
cmpl %ecx, %eax
jne 0x2a45
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movzwl -0x72(%rbp), %ecx
andl $0xff, %ecx
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x2a86
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rcx
movzbl -0x75(%rbp), %eax
movzbl 0x1000(%rcx,%rax), %eax
movzbl -0x74(%rbp), %edx
movzbl 0x1000(%rcx,%rdx), %ecx
cmpl %ecx, %eax
jne 0x2ac6
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xff, %ecx
movb %cl, %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %esi
andl $0xff, %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
addl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x347b
movzbl -0x73(%rbp), %eax
movq %rax, -0xf8(%rbp)
subq $0xe, %rax
ja 0x2ddc
movq -0xf8(%rbp), %rax
leaq 0x363c(%rip), %rcx      # 0x6178
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movb 0x1000(%rax,%rcx), %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
orl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
andl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
xorl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rcx
movzbl -0x75(%rbp), %eax
movzbl 0x1000(%rcx,%rax), %eax
movzwl %ax, %eax
movzbl -0x74(%rbp), %edx
movzbl 0x1000(%rcx,%rdx), %ecx
movzwl %cx, %ecx
addl %ecx, %eax
cmpl $0xff, %eax
jle 0x2c2c
movq -0xe8(%rbp), %rax
movb $0x1, 0x100f(%rax)
jmp 0x2c3a
movq -0xe8(%rbp), %rax
movb $0x0, 0x100f(%rax)
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
addl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rcx
movzbl -0x75(%rbp), %eax
movzbl 0x1000(%rcx,%rax), %eax
movzbl -0x74(%rbp), %edx
movzbl 0x1000(%rcx,%rdx), %ecx
cmpl %ecx, %eax
jle 0x2c9a
movq -0xe8(%rbp), %rax
movb $0x1, 0x100f(%rax)
jmp 0x2ca8
movq -0xe8(%rbp), %rax
movb $0x0, 0x100f(%rax)
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %esi
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
subl %esi, %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movb 0x1000(%rax,%rcx), %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %ecx
andl $0x1, %ecx
movb %cl, 0x100f(%rax)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
sarl %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rcx
movzbl -0x74(%rbp), %eax
movzbl 0x1000(%rcx,%rax), %eax
movzbl -0x75(%rbp), %edx
movzbl 0x1000(%rcx,%rdx), %ecx
cmpl %ecx, %eax
jle 0x2d54
movq -0xe8(%rbp), %rax
movb $0x1, 0x100f(%rax)
jmp 0x2d62
movq -0xe8(%rbp), %rax
movb $0x0, 0x100f(%rax)
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %ecx
movzbl -0x75(%rbp), %edx
movzbl 0x1000(%rax,%rdx), %edx
subl %edx, %ecx
movb %cl, %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x2ddc
movq -0xe8(%rbp), %rax
movzbl -0x74(%rbp), %ecx
movb 0x1000(%rax,%rcx), %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %ecx
sarl $0x7, %ecx
andl $0x1, %ecx
movb %cl, 0x100f(%rax)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
shll %edx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x347b
movq -0xe8(%rbp), %rcx
movzbl -0x75(%rbp), %eax
movzbl 0x1000(%rcx,%rax), %eax
movzbl -0x74(%rbp), %edx
movzbl 0x1000(%rcx,%rdx), %ecx
cmpl %ecx, %eax
je 0x2e1c
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xfff, %ecx            # imm = 0xFFF
movw %cx, 0x1862(%rax)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xfff, %ecx            # imm = 0xFFF
movzbl 0x1000(%rax), %edx
addl %edx, %ecx
movw %cx, 0x1860(%rax)
jmp 0x347b
callq 0x20a0
movl %eax, %ecx
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %edx
andl $0xff, %edx
andl %edx, %ecx
movb %cl, %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x347b
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movl $0x40, %ecx
cltd
idivl %ecx
movq -0xe8(%rbp), %rax
movb %dl, %cl
movb %cl, -0x81(%rbp)
movzbl -0x74(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movl $0x20, %ecx
cltd
idivl %ecx
movq -0xe8(%rbp), %rax
movb %dl, %cl
movb %cl, -0x82(%rbp)
movb $0x0, 0x100f(%rax)
movb $0x1, -0x12(%rbp)
movl $0x0, -0x88(%rbp)
movl -0x88(%rbp), %eax
movzbl -0x73(%rbp), %ecx
cmpl %ecx, %eax
jge 0x303d
movq -0xe8(%rbp), %rax
movzwl 0x1862(%rax), %ecx
addl -0x88(%rbp), %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %al
movb %al, -0x89(%rbp)
movl $0x0, -0x90(%rbp)
cmpl $0x8, -0x90(%rbp)
jge 0x3027
movzbl -0x89(%rbp), %eax
movl -0x90(%rbp), %ecx
movl $0x80, %edx
sarl %cl, %edx
movl %edx, %ecx
andl %ecx, %eax
cmpl $0x0, %eax
je 0x3011
movq -0xe8(%rbp), %rax
addq $0x1010, %rax           # imm = 0x1010
movzbl -0x81(%rbp), %ecx
addl -0x90(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movzbl -0x82(%rbp), %ecx
addl -0x88(%rbp), %ecx
movslq %ecx, %rcx
testb $0x1, (%rax,%rcx)
je 0x2fd7
movq -0xe8(%rbp), %rax
movb $0x1, 0x100f(%rax)
addq $0x1010, %rax           # imm = 0x1010
movzbl -0x81(%rbp), %ecx
addl -0x90(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movzbl -0x82(%rbp), %ecx
addl -0x88(%rbp), %ecx
movslq %ecx, %rcx
movb $0x0, (%rax,%rcx)
jmp 0x300f
movq -0xe8(%rbp), %rax
addq $0x1010, %rax           # imm = 0x1010
movzbl -0x81(%rbp), %ecx
addl -0x90(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movzbl -0x82(%rbp), %ecx
addl -0x88(%rbp), %ecx
movslq %ecx, %rcx
movb $0x1, (%rax,%rcx)
jmp 0x3011
jmp 0x3013
movl -0x90(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x90(%rbp)
jmp 0x2f2e
jmp 0x3029
movl -0x88(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x88(%rbp)
jmp 0x2ef2
jmp 0x347b
movzbl -0x72(%rbp), %eax
movl %eax, -0xfc(%rbp)
subl $0x9e, %eax
je 0x3067
jmp 0x3055
movl -0xfc(%rbp), %eax
subl $0xa1, %eax
je 0x30ab
jmp 0x30ef
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
andl $0xf, %eax
movb %al, -0x91(%rbp)
movzbl -0x91(%rbp), %eax
testb $0x1, -0x70(%rbp,%rax)
je 0x30a9
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x30ef
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
andl $0xf, %eax
movb %al, -0x92(%rbp)
movzbl -0x92(%rbp), %eax
testb $0x1, -0x70(%rbp,%rax)
jne 0x30ed
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
addl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x30ef
jmp 0x347b
movzbl -0x72(%rbp), %eax
movl %eax, -0x100(%rbp)
subl $0x7, %eax
je 0x3194
jmp 0x3109
movl -0x100(%rbp), %eax
subl $0xa, %eax
je 0x31b1
jmp 0x311a
movl -0x100(%rbp), %eax
subl $0x15, %eax
je 0x322d
jmp 0x312b
movl -0x100(%rbp), %eax
subl $0x18, %eax
je 0x324a
jmp 0x313c
movl -0x100(%rbp), %eax
subl $0x1e, %eax
je 0x3267
jmp 0x314d
movl -0x100(%rbp), %eax
subl $0x29, %eax
je 0x32d6
jmp 0x315e
movl -0x100(%rbp), %eax
subl $0x33, %eax
je 0x32f9
jmp 0x316f
movl -0x100(%rbp), %eax
subl $0x55, %eax
je 0x3392
jmp 0x3180
movl -0x100(%rbp), %eax
subl $0x65, %eax
je 0x33e5
jmp 0x3438
movq -0xe8(%rbp), %rax
movb 0x1864(%rax), %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x3438
leaq -0x70(%rbp), %rdi
callq 0x27e0
testb $0x1, %al
jne 0x31c0
jmp 0x3210
movl $0x0, -0x98(%rbp)
cmpl $0x10, -0x98(%rbp)
jge 0x320e
movslq -0x98(%rbp), %rax
testb $0x1, -0x70(%rbp,%rax)
je 0x31fb
movq -0xe8(%rbp), %rax
movl -0x98(%rbp), %ecx
movb %cl, %dl
movzbl -0x75(%rbp), %ecx
movb %dl, 0x1000(%rax,%rcx)
jmp 0x31fd
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
jmp 0x31ca
jmp 0x3228
movq -0xe8(%rbp), %rax
movzwl 0x1860(%rax), %ecx
subl $0x2, %ecx
movw %cx, 0x1860(%rax)
jmp 0x3438
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movb 0x1000(%rax,%rcx), %cl
movb %cl, 0x1864(%rax)
jmp 0x3438
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movb 0x1000(%rax,%rcx), %cl
movb %cl, 0x1865(%rax)
jmp 0x3438
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %edx
movzwl 0x1862(%rax), %ecx
addl %edx, %ecx
movw %cx, 0x1862(%rax)
movzwl 0x1862(%rax), %eax
cmpl $0xfff, %eax            # imm = 0xFFF
jle 0x32a8
movq -0xe8(%rbp), %rax
movb $0x1, 0x100f(%rax)
jmp 0x32b6
movq -0xe8(%rbp), %rax
movb $0x0, 0x100f(%rax)
movq -0xe8(%rbp), %rax
movzwl 0x1862(%rax), %ecx
andl $0xfff, %ecx            # imm = 0xFFF
movw %cx, 0x1862(%rax)
jmp 0x3438
movq -0xe8(%rbp), %rax
movzwl -0x72(%rbp), %ecx
andl $0xff, %ecx
imull $0x5, %ecx, %ecx
addl $0x50, %ecx
movw %cx, 0x1862(%rax)
jmp 0x3438
movq -0xe8(%rbp), %rax
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movl $0x64, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq -0xe8(%rbp), %rax
movb %cl, %dl
movzwl 0x1862(%rax), %ecx
addl $0x0, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movl $0xa, %ecx
cltd
idivl %ecx
movl $0xa, %ecx
cltd
idivl %ecx
movq -0xe8(%rbp), %rax
movzwl 0x1862(%rax), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movzbl -0x75(%rbp), %ecx
movzbl 0x1000(%rax,%rcx), %eax
movl $0xa, %ecx
cltd
idivl %ecx
movq -0xe8(%rbp), %rax
movzwl 0x1862(%rax), %ecx
addl $0x2, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
jmp 0x3438
movl $0x0, -0x9c(%rbp)
movl -0x9c(%rbp), %eax
movzbl -0x75(%rbp), %ecx
cmpl %ecx, %eax
jg 0x33e3
movq -0xe8(%rbp), %rax
movslq -0x9c(%rbp), %rcx
movb 0x1000(%rax,%rcx), %dl
movzwl 0x1862(%rax), %ecx
addl -0x9c(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x9c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x9c(%rbp)
jmp 0x339c
jmp 0x3438
movl $0x0, -0xa0(%rbp)
movl -0xa0(%rbp), %eax
movzbl -0x75(%rbp), %ecx
cmpl %ecx, %eax
jg 0x3436
movq -0xe8(%rbp), %rax
movzwl 0x1862(%rax), %ecx
addl -0xa0(%rbp), %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %dl
movslq -0xa0(%rbp), %rcx
movb %dl, 0x1000(%rax,%rcx)
movl -0xa0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa0(%rbp)
jmp 0x33ef
jmp 0x3438
jmp 0x347b
movq 0x5b97(%rip), %rdi      # 0x8fd8
leaq 0x2dcb(%rip), %rsi      # 0x6213
callq 0x21f0
movq %rax, %rdi
leaq 0x499(%rip), %rsi       # 0x38f0
callq 0x20c0
movq %rax, %rdi
movzbl -0x76(%rbp), %esi
callq 0x22e0
movq %rax, %rdi
movq 0x5b56(%rip), %rsi      # 0x8fc8
callq 0x2230
movb $0x1, -0x11(%rbp)
movq -0x20(%rbp), %rax
movl $0xa, %ecx
xorl %edx, %edx
divq %rcx
cmpq $0x0, %rdx
jne 0x34e3
movq -0xe8(%rbp), %rax
movzbl 0x1864(%rax), %eax
cmpl $0x0, %eax
jle 0x34b8
movq -0xe8(%rbp), %rax
movb 0x1864(%rax), %cl
addb $-0x1, %cl
movb %cl, 0x1864(%rax)
movq -0xe8(%rbp), %rax
movzbl 0x1865(%rax), %eax
cmpl $0x0, %eax
jle 0x34e1
movq -0xe8(%rbp), %rax
movb 0x1865(%rax), %cl
addb $-0x1, %cl
movb %cl, 0x1865(%rax)
jmp 0x34e3
testb $0x1, -0x12(%rbp)
jne 0x34fd
movq -0x20(%rbp), %rax
andq $0xff, %rax
cmpq $0x0, %rax
jne 0x3600
movq -0x10(%rbp), %rdi
callq 0x21e0
movl $0x0, -0xa4(%rbp)
cmpl $0x20, -0xa4(%rbp)
jge 0x35f3
movl $0x0, -0xa8(%rbp)
cmpl $0x40, -0xa8(%rbp)
jge 0x35dd
movq -0xe8(%rbp), %rax
addq $0x1010, %rax           # imm = 0x1010
movslq -0xa8(%rbp), %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movslq -0xa4(%rbp), %rcx
testb $0x1, (%rax,%rcx)
je 0x3576
movq -0x10(%rbp), %rdi
movl $0xff, %r8d
movl %r8d, %esi
movl %r8d, %edx
movl %r8d, %ecx
callq 0x2270
jmp 0x358b
movq -0x10(%rbp), %rdi
xorl %ecx, %ecx
movl $0xff, %r8d
movl %ecx, %esi
movl %ecx, %edx
callq 0x2270
movl $0x14, -0xac(%rbp)
movl $0x14, -0xb0(%rbp)
imull $0x14, -0xa8(%rbp), %eax
movl %eax, -0xb8(%rbp)
imull $0x14, -0xa4(%rbp), %eax
movl %eax, -0xb4(%rbp)
movq -0x10(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x2120
movl -0xa8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa8(%rbp)
jmp 0x3527
jmp 0x35df
movl -0xa4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa4(%rbp)
jmp 0x3510
movq -0x10(%rbp), %rdi
callq 0x2070
movb $0x0, -0x12(%rbp)
jmp 0x3602
leaq -0x58(%rbp), %rdi
callq 0x2150
cmpl $0x0, %eax
je 0x36e7
movl -0x58(%rbp), %eax
movl %eax, -0x104(%rbp)
subl $0x100, %eax            # imm = 0x100
je 0x3647
jmp 0x3626
movl -0x104(%rbp), %eax
subl $0x300, %eax            # imm = 0x300
je 0x3650
jmp 0x3635
movl -0x104(%rbp), %eax
subl $0x301, %eax            # imm = 0x301
je 0x3699
jmp 0x36e2
movb $0x1, -0x11(%rbp)
jmp 0x36e2
movq -0x48(%rbp), %rax
movq %rax, -0xcc(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0xc4(%rbp)
movq -0xcc(%rbp), %rdi
movq -0xc4(%rbp), %rsi
callq 0x2740
movb %al, -0xb9(%rbp)
movzbl -0xb9(%rbp), %eax
cmpl $0x10, %eax
jge 0x3697
movzbl -0xb9(%rbp), %eax
movb $0x1, -0x70(%rbp,%rax)
jmp 0x36e2
movq -0x48(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xe0(%rbp), %rdi
movq -0xd8(%rbp), %rsi
callq 0x2740
movb %al, -0xcd(%rbp)
movzbl -0xcd(%rbp), %eax
cmpl $0x10, %eax
jge 0x36e0
movzbl -0xcd(%rbp), %eax
movb $0x0, -0x70(%rbp,%rax)
jmp 0x36e2
jmp 0x3602
movl $0x1, %edi
callq 0x2170
jmp 0x286e
movq 0x58db(%rip), %rdi      # 0x8fd8
leaq 0x2b26(%rip), %rsi      # 0x622a
callq 0x21f0
movq %rax, %rdi
leaq 0x1dd(%rip), %rsi       # 0x38f0
callq 0x20c0
movq %rax, %rdi
movq -0x20(%rbp), %rsi
callq 0x2310
movq %rax, %rdi
leaq 0x2b0c(%rip), %rsi      # 0x623a
callq 0x21f0
addq $0x110, %rsp            # imm = 0x110
popq %rbp
retq
nopl (%rax)