// File: /workspace/github_cpp_makefile_star2_O3/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:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %rbx
movq 0x28(%rdi), %rax
cmpb $0x0, (%rax)
js 0x7cbc
xorl %eax, %eax
movl %eax, 0x20(%rbx)
movq 0x48(%rbx), %rcx
movb $0x0, (%rcx)
movl %eax, 0x84(%rbx)
movq 0x30(%rbx), %rax
andb $-0x4, (%rax)
movq 0x50(%rbx), %rax
movb (%rax), %al
movq 0x30(%rbx), %rcx
movq 0x48(%rbx), %rdx
cmpb (%rdx), %al
sete %al
movb (%rcx), %dl
andb $-0x5, %dl
shlb $0x2, %al
orb %dl, %al
movb %al, (%rcx)
cmpb $0x1, 0xb8(%rbx)
jne 0x7e77
movb $0x0, 0xb8(%rbx)
movq 0x88(%rbx), %r15
movq %rsp, %r14
xorl %r12d, %r12d
movq %r14, %rdi
xorl %edx, %edx
callq 0x7e84
movq (%r14), %rdi
movd (%rdi), %xmm0
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movdqu %xmm0, (%r15,%r12,4)
addq $0x4, %r12
cmpq $0x5a00, %r12           # imm = 0x5A00
jne 0x7c58
movq %rsp, %r14
movq 0x10(%r14), %rsi
subq %rdi, %rsi
callq 0x21c0
movq 0x8(%rbx), %rbx
xorl %r15d, %r15d
movq %r14, %rdi
xorl %edx, %edx
callq 0x7e84
movq (%r14), %rdi
movd (%rdi), %xmm0
pshufd $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movdqu %xmm0, (%rbx,%r15,4)
addq $0x4, %r15
cmpq $0x5a00, %r15           # imm = 0x5A00
jne 0x7c97
movq 0x10(%rsp), %rsi
subq %rdi, %rsi
callq 0x21c0
jmp 0x7e77
movb $0x1, 0xb8(%rbx)
movl 0x20(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x20(%rbx)
movzbl 0x80(%rbx), %ecx
cmpq $0x3, %rcx
ja 0x7dfc
leaq 0x1ea8(%rip), %rdx      # 0x9b8c
movslq (%rdx,%rcx,4), %rcx
addq %rdx, %rcx
jmpq *%rcx
cmpl $0x32, %eax
jl 0x7e15
addl $-0x32, %eax
movl %eax, 0x20(%rbx)
movq 0x48(%rbx), %rax
incb (%rax)
movq 0x48(%rbx), %rax
cmpb $-0x71, (%rax)
jbe 0x7de5
movb $0x1, 0x80(%rbx)
movq 0x30(%rbx), %rax
movb (%rax), %cl
andb $-0x4, %cl
incb %cl
movb %cl, (%rax)
movq 0x18(%rbx), %rax
movdqu 0x88(%rbx), %xmm0
movq 0x98(%rbx), %rcx
movq %rcx, 0x18(%rbx)
movups 0x8(%rbx), %xmm1
movdqu %xmm0, 0x8(%rbx)
movups %xmm1, 0x88(%rbx)
movq %rax, 0x98(%rbx)
movq (%rbx), %rdi
movl $0x1, %esi
callq 0x7010
jmp 0x7e15
cmpl $0x13, %eax
jl 0x7e15
addl $-0x13, %eax
jmp 0x7e04
cmpl $0x2a, %eax
jl 0x7e15
addl $-0x2a, %eax
movl %eax, 0x20(%rbx)
movb $0x0, 0x80(%rbx)
movq 0x30(%rbx), %rax
andb $-0x4, (%rax)
movq 0xa0(%rbx), %rdi
movl $0xa0, %edx
xorl %esi, %esi
callq 0x2120
movq %rbx, %rdi
callq 0x7f8e
movq %rbx, %rdi
callq 0x81d8
movq %rbx, %rdi
callq 0x83fa
jmp 0x7e15
cmpl $0x71, %eax
jl 0x7e15
addl $-0x71, %eax
movl %eax, 0x20(%rbx)
movq 0x48(%rbx), %rax
incb (%rax)
movq 0x48(%rbx), %rax
cmpb $-0x66, (%rax)
jb 0x7e15
movb $0x0, (%rax)
movl $0x0, 0x84(%rbx)
movb $0x2, 0x80(%rbx)
movq 0x30(%rbx), %rax
movb (%rax), %cl
andb $-0x4, %cl
orb $0x2, %cl
movb %cl, (%rax)
jmp 0x7e15
cmpl $0x12, %eax
jl 0x7e15
addl $-0x12, %eax
movl %eax, 0x20(%rbx)
movb $0x3, 0x80(%rbx)
movq 0x30(%rbx), %rax
orb $0x3, (%rax)
movq 0x50(%rbx), %rax
movb (%rax), %al
movq 0x48(%rbx), %rcx
cmpb (%rcx), %al
movq 0x30(%rbx), %rax
sete %cl
movb (%rax), %dl
andb $-0x5, %dl
shlb $0x2, %cl
orb %dl, %cl
movb %cl, (%rax)
movq 0x30(%rbx), %rax
movzbl (%rax), %eax
movl %eax, %ecx
notl %ecx
testb $0x44, %cl
je 0x7e5a
movb 0x80(%rbx), %cl
movl $0x8, %edx
shll %cl, %edx
cmpb $0x3, %cl
je 0x7e73
andl %eax, %edx
je 0x7e73
cmpb $0x0, 0x24(%rbx)
jne 0x7e77
movq (%rbx), %rdi
movl $0x2, %esi
callq 0x7010
movb $0x1, 0x24(%rbx)
jmp 0x7e77
movb $0x0, 0x24(%rbx)
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
nop