// File: nicoeps[P]NicoGB/src/ppu.cpp
// Function: PPU::update()
void PPU::update() {
    if ((lcdc & 0x80) == 0) {
        totalCycles = 0;
        ly = 0;
        windowCounter = 0;
        stat = (stat & 0xFC) | 0x00;
        stat = (lyc == ly) ? (stat | 0x4) : (stat & ~0x4);
        if (clear) {
            clear = false;
            std::fill_n(writebuffer.begin(), 160*144, getPalette(0)[0]);
            std::fill_n(framebuffer.begin(), 160*144, getPalette(0)[0]);
        }
        return;
    }
    clear = true;

    totalCycles++;

    switch (mode) {
        case 2: // OAM Search
            if (totalCycles >= 20) {
                totalCycles -= 20;
                mode = 3;
                stat = (stat & 0xFC) | 0x03;
            }
            break;

        case 3: // Pixel Transfer
            if (totalCycles >= 43) {
                totalCycles -= 43;
                mode = 0;
                stat = (stat & 0xFC) | 0x00;
                std::fill_n(line.begin(), 160, 0);
                drawBackground();
                drawWindow();
                drawSprites();
            }
            break;

        case 0: // H-Blank
            if (totalCycles >= 51) {
                totalCycles -= 51;
                ++ly;
                if (ly < 144) {
                    mode = 2;
                    stat = (stat & 0xFC) | 0x02;
                } else {
                    mode = 1;
                    stat = (stat & 0xFC) | 0x01;
                    framebuffer.swap(writebuffer);
                    memory.interrupt(0x1);
                }
            }
            break;

        case 1: // V-Blank
            if (totalCycles >= 114) {
                totalCycles -= 114;
                ++ly;
                if (ly > 153) {
                    ly = 0;
                    windowCounter = 0;
                    mode = 2;
                    stat = (stat & 0xFC) | 0x02;
                }
            }
            break;

        default: // Glitched OAM Search
            if (totalCycles >= 19) {
                totalCycles -= 19;
                mode = 3;
                stat = (stat & 0xFC) | 0x03;
            }
            break;
    }

    stat = (lyc == ly) ? (stat | 0x4) : (stat & ~0x4);
    if (((stat & 0x4) && (stat & 0x40))
    || (((stat >> (mode + 3)) & 1) && mode != 0x3)) {
        if (interrupt == false) {
            memory.interrupt(0x2);
            interrupt = true;
        }
    } else {
        interrupt = false;
    }
}

// Assembly:
subq $0xd8, %rsp
movq %rdi, 0xd0(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x28(%rax), %rax
movzbl (%rax), %eax
andl $0x80, %eax
cmpl $0x0, %eax
jne 0x10b10
movq 0x50(%rsp), %rcx
movl $0x0, 0x20(%rcx)
movq 0x48(%rcx), %rax
movb $0x0, (%rax)
movl $0x0, 0x84(%rcx)
movq 0x30(%rcx), %rax
movzbl (%rax), %eax
andl $0xfc, %eax
orl $0x0, %eax
movb %al, %dl
movq 0x30(%rcx), %rax
movb %dl, (%rax)
movq 0x50(%rcx), %rax
movzbl (%rax), %eax
movq 0x48(%rcx), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jne 0x1099c
movq 0x50(%rsp), %rax
movq 0x30(%rax), %rax
movzbl (%rax), %eax
orl $0x4, %eax
movl %eax, 0x4c(%rsp)
jmp 0x109af
movq 0x50(%rsp), %rax
movq 0x30(%rax), %rax
movzbl (%rax), %eax
andl $-0x5, %eax
movl %eax, 0x4c(%rsp)
movq 0x50(%rsp), %rax
movl 0x4c(%rsp), %ecx
movb %cl, %dl
movq 0x30(%rax), %rcx
movb %dl, (%rcx)
testb $0x1, 0xb8(%rax)
je 0x10b0b
movq 0x50(%rsp), %rdi
movb $0x0, 0xb8(%rdi)
addq $0x88, %rdi
callq 0x13440
movq 0x50(%rsp), %rsi
movq %rax, 0xc8(%rsp)
leaq 0xb0(%rsp), %rdi
movq %rdi, 0x38(%rsp)
xorl %edx, %edx
movl %edx, 0x34(%rsp)
callq 0x10e60
movl 0x34(%rsp), %eax
movq 0x38(%rsp), %rdi
movl %eax, %esi
callq 0x134d0
movq %rax, %rdx
movq 0xc8(%rsp), %rdi
movl $0x5a00, %esi           # imm = 0x5A00
callq 0x13470
movq %rax, 0x40(%rsp)
jmp 0x10a36
movq 0x40(%rsp), %rax
movq %rax, 0x98(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0xd450
movq 0x50(%rsp), %rdi
addq $0x8, %rdi
callq 0x13440
movq 0x50(%rsp), %rsi
movq %rax, 0x90(%rsp)
leaq 0x78(%rsp), %rdi
movq %rdi, 0x20(%rsp)
xorl %edx, %edx
movl %edx, 0x1c(%rsp)
callq 0x10e60
movl 0x1c(%rsp), %eax
movq 0x20(%rsp), %rdi
movl %eax, %esi
callq 0x134d0
movq %rax, %rdx
movq 0x90(%rsp), %rdi
movl $0x5a00, %esi           # imm = 0x5A00
callq 0x13470
movq %rax, 0x28(%rsp)
jmp 0x10aac
movq 0x28(%rsp), %rax
movq %rax, 0x70(%rsp)
leaq 0x78(%rsp), %rdi
callq 0xd450
jmp 0x10b0b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xa8(%rsp)
movl %eax, 0xa4(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0xd450
jmp 0x10e44
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xa8(%rsp)
movl %eax, 0xa4(%rsp)
leaq 0x78(%rsp), %rdi
callq 0xd450
jmp 0x10e44
jmp 0x10e3c
movq 0x50(%rsp), %rax
movb $0x1, 0xb8(%rax)
movl 0x20(%rax), %ecx
incl %ecx
movl %ecx, 0x20(%rax)
movzbl 0x80(%rax), %eax
movq %rax, 0x10(%rsp)
subq $0x3, %rax
ja 0x10d28
movq 0x10(%rsp), %rax
leaq 0x5f4e(%rip), %rcx      # 0x16a94
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x50(%rsp), %rax
cmpl $0x14, 0x20(%rax)
jl 0x10b85
movq 0x50(%rsp), %rax
movl 0x20(%rax), %ecx
subl $0x14, %ecx
movl %ecx, 0x20(%rax)
movb $0x3, 0x80(%rax)
movq 0x30(%rax), %rcx
movzbl (%rcx), %ecx
andl $0xfc, %ecx
orl $0x3, %ecx
movq 0x30(%rax), %rax
movb %cl, (%rax)
jmp 0x10d60
movq 0x50(%rsp), %rax
cmpl $0x2b, 0x20(%rax)
jl 0x10c11
movq 0x50(%rsp), %rdi
movl 0x20(%rdi), %eax
subl $0x2b, %eax
movl %eax, 0x20(%rdi)
movb $0x0, 0x80(%rdi)
movq 0x30(%rdi), %rax
movzbl (%rax), %eax
andl $0xfc, %eax
orl $0x0, %eax
movb %al, %cl
movq 0x30(%rdi), %rax
movb %cl, (%rax)
addq $0xa0, %rdi
callq 0x4170
movq %rax, 0x68(%rsp)
movl $0x0, 0x64(%rsp)
movq 0x68(%rsp), %rdi
movl $0xa0, %esi
leaq 0x64(%rsp), %rdx
callq 0x4110
movq 0x50(%rsp), %rdi
movq %rax, 0x58(%rsp)
callq 0x11140
movq 0x50(%rsp), %rdi
callq 0x11600
movq 0x50(%rsp), %rdi
callq 0x119d0
jmp 0x10d60
movq 0x50(%rsp), %rax
cmpl $0x33, 0x20(%rax)
jl 0x10cba
movq 0x50(%rsp), %rax
movl 0x20(%rax), %ecx
subl $0x33, %ecx
movl %ecx, 0x20(%rax)
movq 0x48(%rax), %rcx
movb (%rcx), %dl
addb $0x1, %dl
movb %dl, (%rcx)
movq 0x48(%rax), %rax
movzbl (%rax), %eax
cmpl $0x90, %eax
jge 0x10c70
movq 0x50(%rsp), %rax
movb $0x2, 0x80(%rax)
movq 0x30(%rax), %rcx
movzbl (%rcx), %ecx
andl $0xfc, %ecx
orl $0x2, %ecx
movq 0x30(%rax), %rax
movb %cl, (%rax)
jmp 0x10cb8
movq 0x50(%rsp), %rsi
movb $0x1, 0x80(%rsi)
movq 0x30(%rsi), %rax
movzbl (%rax), %eax
andl $0xfc, %eax
orl $0x1, %eax
movb %al, %cl
movq 0x30(%rsi), %rax
movb %cl, (%rax)
movq %rsi, %rdi
addq $0x8, %rdi
addq $0x88, %rsi
callq 0x134f0
movq 0x50(%rsp), %rax
movq (%rax), %rdi
movl $0x1, %esi
callq 0xef30
jmp 0x10cba
jmp 0x10d60
movq 0x50(%rsp), %rax
cmpl $0x72, 0x20(%rax)
jl 0x10d26
movq 0x50(%rsp), %rax
movl 0x20(%rax), %ecx
subl $0x72, %ecx
movl %ecx, 0x20(%rax)
movq 0x48(%rax), %rcx
movb (%rcx), %dl
addb $0x1, %dl
movb %dl, (%rcx)
movq 0x48(%rax), %rax
movzbl (%rax), %eax
cmpl $0x99, %eax
jle 0x10d24
movq 0x50(%rsp), %rax
movq 0x48(%rax), %rcx
movb $0x0, (%rcx)
movl $0x0, 0x84(%rax)
movb $0x2, 0x80(%rax)
movq 0x30(%rax), %rcx
movzbl (%rcx), %ecx
andl $0xfc, %ecx
orl $0x2, %ecx
movq 0x30(%rax), %rax
movb %cl, (%rax)
jmp 0x10d26
jmp 0x10d60
movq 0x50(%rsp), %rax
cmpl $0x13, 0x20(%rax)
jl 0x10d5e
movq 0x50(%rsp), %rax
movl 0x20(%rax), %ecx
subl $0x13, %ecx
movl %ecx, 0x20(%rax)
movb $0x3, 0x80(%rax)
movq 0x30(%rax), %rcx
movzbl (%rcx), %ecx
andl $0xfc, %ecx
orl $0x3, %ecx
movq 0x30(%rax), %rax
movb %cl, (%rax)
jmp 0x10d60
movq 0x50(%rsp), %rcx
movq 0x50(%rcx), %rax
movzbl (%rax), %eax
movq 0x48(%rcx), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jne 0x10d8c
movq 0x50(%rsp), %rax
movq 0x30(%rax), %rax
movzbl (%rax), %eax
orl $0x4, %eax
movl %eax, 0xc(%rsp)
jmp 0x10d9f
movq 0x50(%rsp), %rax
movq 0x30(%rax), %rax
movzbl (%rax), %eax
andl $-0x5, %eax
movl %eax, 0xc(%rsp)
movq 0x50(%rsp), %rax
movl 0xc(%rsp), %ecx
movb %cl, %dl
movq 0x30(%rax), %rcx
movb %dl, (%rcx)
movq 0x30(%rax), %rax
movzbl (%rax), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x10dd3
movq 0x50(%rsp), %rax
movq 0x30(%rax), %rax
movzbl (%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
jne 0x10e04
movq 0x50(%rsp), %rcx
movq 0x30(%rcx), %rax
movzbl (%rax), %eax
movzbl 0x80(%rcx), %ecx
addl $0x3, %ecx
sarl %cl, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x10e33
movq 0x50(%rsp), %rax
movzbl 0x80(%rax), %eax
cmpl $0x3, %eax
je 0x10e33
movq 0x50(%rsp), %rax
movb 0x24(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x10e31
movq 0x50(%rsp), %rax
movq (%rax), %rdi
movl $0x2, %esi
callq 0xef30
movq 0x50(%rsp), %rax
movb $0x1, 0x24(%rax)
jmp 0x10e3c
movq 0x50(%rsp), %rax
movb $0x0, 0x24(%rax)
addq $0xd8, %rsp
retq
movq 0xa8(%rsp), %rdi
callq 0x33d0
nopw %cs:(%rax,%rax)