// File: /workspace/github_cpp_makefile_star2_O1/khedoros[P]khednes/ppu3.cpp
// Function: ppu::reg_write(unsigned int, unsigned char, unsigned int)
void ppu::reg_write(const unsigned int addr,const unsigned char val, const unsigned int cycle) {
    //cout<<"!! "<<phases[phase(cycle)]<<" Write address: 0x"<<hex<<addr<<" Value: 0x"<<int(val)<<dec<<" Cycle: "<<cycle<<endl;
    ppu_phase curphase = phase(cycle);
    if(curphase == RENDER) ++s.writes_during_render;
    switch(addr) {
        case 0x2000:
        {
            int bg_table = control0.bg_table;
            int spr_table = control0.sprite_table;
            control0.reg = val;
            vram_ptr_reset.fields.page_y = (control0.base_addr & 2)/2;
            vram_ptr_reset.fields.page_x = (control0.base_addr & 1);

            int xscroll = (control0.base_addr%2) * 32 + vram_ptr_reset.fields.tile_x;
            int yscroll = (control0.base_addr/2) * 30 + vram_ptr_reset.fields.tile_y;
            if(curphase != RENDER && curphase != POST_RENDER) { //keeps track of where the screen will start
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y);
                cart.ppu_change(cycle, BG_CHANGE_ADDR, control0.bg_table);
                cart.ppu_change(cycle, SPR_CHANGE_ADDR, control0.sprite_table);
                //if(control0.bg_table != bg_table) cout<<"Changed the bg table (to "<<control0.bg_table<<"), cycle: "<<cycle<<endl;
                //if(control0.sprite_table != spr_table) cout<<"Changed the sprite table (to "<<control0.sprite_table<<"), cycle: "<<cycle<<endl;
            } else { //keeps track of when (during rendering) the reset shifts, but only worry about the X reset
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y, cycle%CLK_PER_LINE, cycle/CLK_PER_LINE);
                if(control0.bg_table != bg_table) {
                    //cout<<"Changed the bg table mid-frame! (to "<<control0.bg_table<<"), cycle: "<<cycle<<endl;
                    cart.ppu_change(cycle, BG_CHANGE_ADDR, 1 - control0.bg_table);
                }
                if(control0.sprite_table != spr_table) {
                    //cout<<"Changed the sprite table mid-frame! (to "<<control0.sprite_table<<"), cycle: "<<cycle<<endl;
                    cart.ppu_change(cycle, SPR_CHANGE_ADDR, 1 - control0.sprite_table);
                }
            }
        }
            break;
        case 0x2001:
            /*
            cout<<"Wrote "<<hex<<val<<dec<<" to 2001 (Color disabled: "<<control1.bits.color_disabled
                <<" show left bg: "<<control1.bits.show_left_bg<<" show left sprites: "<<control1.bits.show_left_sprites
                <<" show bg: "<<control1.bits.show_bg<<" show sprites: "<<control1.bits.show_sprites<<endl;
            */
            control1.reg = val;
            break;
        case 0x2003:
            spraddr = val;
            break;
        case 0x2004:
            if(spraddr/4 == 0) recalc_s0 = true;
            recalc_overflow = true;
            sprites[spraddr/4].val[spraddr%4] = val;
            spraddr++;
            break;
        case 0x2005:
            if(!scroll_latch) {
                vram_ptr_reset.fields.tile_x = (val & 0xf8)>>(3) ;
                fine_x = (val & 0x7);
                //cout<<"Set X reset to ("<<(control0.base_addr&1)*256+vram_ptr_reset.fields.tile_x*8+fine_x<<", "
                //    <<(control0.base_addr&2)*120+vram_ptr_reset.fields.tile_y*8+vram_ptr_reset.fields.fine_y<<") at cycle "
                //    <<cycle<<" ("<<cycle/CLK_PER_LINE<<", "<<cycle%CLK_PER_LINE<<") ("<<phases[curphase]<<")"<<endl;
            }
            else {
                vram_ptr_reset.fields.tile_y = (val & 0xf8)>>(3);
                vram_ptr_reset.fields.fine_y = (val & 0x7);
                //cout<<"Set Y reset to ("<<(control0.base_addr&1)*256+vram_ptr_reset.fields.tile_x*8+fine_x<<", "
                //    <<(control0.base_addr&2)*120+vram_ptr_reset.fields.tile_y*8+vram_ptr_reset.fields.fine_y<<") at cycle "
                //    <<cycle<<" ("<<cycle/CLK_PER_LINE<<", "<<cycle%CLK_PER_LINE<<") ("<<phases[curphase]<<")"<<endl;
            }
            if(curphase != RENDER) { //keeps track of where the screen will start
                int xscroll = (control0.base_addr%2) * 32 + vram_ptr_reset.fields.tile_x;
                int yscroll = (control0.base_addr/2) * 30 + vram_ptr_reset.fields.tile_y;
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y);
            }
            else if(curphase == RENDER) { //keeps track of when (during rendering) the reset shifts, but only worry about the X reset
                int xscroll = (control0.base_addr%2) * 32 + vram_ptr_reset.fields.tile_x;
                int yscroll = (control0.base_addr/2) * 30 + vram_ptr_reset.fields.tile_y;
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y, cycle%CLK_PER_LINE, cycle/CLK_PER_LINE);
            }
            scroll_latch = !scroll_latch;
            break;
        case 0x2006:
            if(!scroll_latch) {
                vram_ptr_reset.bytes.high = val;
                vram_ptr_reset.bytes.pad = 0;
            }
            else {
                vram_ptr_reset.bytes.low = val;
                vram_ptr = vram_ptr_reset;
            }

            if(curphase != RENDER) { //keep track of where the screen starts
                int xscroll = (control0.base_addr%2) * 32 + vram_ptr_reset.fields.tile_x;
                int yscroll = (control0.base_addr/2) * 30 + vram_ptr_reset.fields.tile_y;
                //cout<<"2006: set scroll to ("<<yscroll<<", "<<xscroll<<")"<<endl;
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y);
            }
            else if(curphase == RENDER) {
                int xscroll = (control0.base_addr%2) * 32 + vram_ptr_reset.fields.tile_x;
                int yscroll = (control0.base_addr/2) * 30 + vram_ptr_reset.fields.tile_y;
                set_scroll(xscroll*8+fine_x, yscroll*8+vram_ptr_reset.fields.fine_y, cycle%CLK_PER_LINE, cycle/CLK_PER_LINE);
            }
            scroll_latch = !scroll_latch;
            break;
        case 0x2007:
            //cout<<"0x2007 (0x"<<hex<<vram_ptr.pointer<<dec<<"): "<<hex<<int(val)<<dec<<"(";
            if(vram_ptr.pointer < 0x2000) {
                //cout<<"Writing to Pattern Table)"<<endl;
                bool wrote = cart.put_cbyte(val, vram_ptr.pointer);
                if(wrote) {
                    int table = (vram_ptr.pointer < 0x1000)?0:1;
                    int tile = (vram_ptr.pointer & 0xfff) / 16;
                    for(int palnum = 0; palnum < 8; ++palnum) {
                        unget_Surface(table, tile, palnum);
                    }
                }
            }
            else {
                unsigned int ptr = vram_ptr.pointer;
                if(ptr >= 0x3000 && ptr < 0x3F00) ptr -= 0x1000;
                if(ptr < 0x23C0) {
                    //cout<<"Writing to Name Table 0)"<<endl;
                    nt[0][ptr - 0x2000] = val;
                }
                else if(ptr < 0x2400) {
                    //cout<<"Writing to Attribute Table 0)"<<endl;
                    at[0][ptr - 0x23C0] = val;
                }
                else if(ptr < 0x27C0) {
                    //cout<<"Writing to Name Table 1)"<<endl;
                    nt[1][ptr - 0x2400] = val;
                }
                else if(ptr < 0x2800) {
                    //cout<<"Writing to Attribute Table 1)"<<endl;
                    at[1][ptr - 0x27C0] = val;
                }
                else if(ptr < 0x2BC0) {
                    //cout<<"Writing to Name Table 2)"<<endl;
                    nt[2][ptr - 0x2800] = val;
                }
                else if(ptr < 0x2C00) {
                    //cout<<"Writing to Attribute Table 2)"<<endl;
                    at[2][ptr - 0x2BC0] = val;
                }
                else if(ptr < 0x2FC0) {
                    //cout<<"Writing to Name Table 3)"<<endl;
                    nt[3][ptr - 0x2C00] = val;
                }
                else if(ptr < 0x3000) {
                    //cout<<"Writing to Attribute Table 3)"<<endl;
                    at[3][ptr - 0x2FC0] = val;
                }
                else {
                    ptr &= 0x1f;
                    if(ptr < 0x10) {
                        //cout<<"Writing to Background Palette)"<<endl;
                    }
                    else {
                        //cout<<"Writing to Sprite Palette)"<<endl;
                    }
                    int oldval = *(pal[ptr]);
                    if(val != oldval) {
                        *(pal[ptr]) = (val&0x3f);
                        //cout<<hex<<"Palette value "<<ptr<<" changed, clearing palette "<<(ptr>>(2))<<" tiles"<<endl;
                        for(int table = 0; table < 2; ++table) {
                            for(int tile = 0; tile < 256; ++tile) {
                                unget_Surface(table, tile, ptr>>(2));
                            }
                        }
                    }
                }
            }
            vram_ptr.pointer++;
            if(control0.v_inc_down) vram_ptr.pointer +=31;
            break;
        default:
            cout<<"Writing to register 0x"<<hex<<addr<<" isn't handled."<<dec<<endl;
        break;
    }
    ++s.writes;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
pushq %rax
movl %ecx, %ebp
movl %esi, %r14d
movq %rdi, %rbx
testb $0x18, 0x21854(%rdi)
je 0xe259
movl $0x1, %eax
cmpl $0x1aa4, %ebp           # imm = 0x1AA4
jb 0xe25e
movl 0x2185c(%rbx), %ecx
andl $0x1, %ecx
movl %ecx, %esi
xorl $0x1bf9, %esi           # imm = 0x1BF9
movl $0x2, %eax
cmpl %ebp, %esi
ja 0xe25e
movl %ecx, %esi
xorl $0x15ba9, %esi          # imm = 0x15BA9
movl $0x3, %eax
cmpl %ebp, %esi
ja 0xe25e
movl $0x15cfe, %esi          # imm = 0x15CFE
subl %ecx, %esi
xorl %eax, %eax
cmpl %ebp, %esi
seta %al
shll $0x2, %eax
jmp 0xe25e
movl $0x5, %eax
cmpl $0x3, %eax
jne 0xe269
incl 0x1c4(%rbx)
leal -0x2000(%r14), %ecx
cmpl $0x7, %ecx
ja 0xe358
leaq 0x72c0(%rip), %rsi      # 0x15540
movslq (%rsi,%rcx,4), %rcx
addq %rsi, %rcx
jmpq *%rcx
movb 0x21850(%rbx), %r14b
movb %dl, 0x21850(%rbx)
movl %edx, %esi
shrb %sil
movzwl 0x6d8(%rbx), %ecx
andb $0x1, %sil
movzbl %sil, %esi
shll $0xb, %esi
movl %ecx, %edi
andl $0xf3ff, %edi           # imm = 0xF3FF
orl %esi, %edi
movl %edx, %esi
andb $0x1, %sil
movzbl %sil, %esi
shll $0xa, %esi
orl %edi, %esi
movw %si, 0x6d8(%rbx)
movl %edx, %esi
andb $0x3, %sil
movzbl %sil, %edi
movl %edi, %r8d
shll $0x5, %r8d
andl $0x20, %r8d
movl %ecx, %esi
andl $0x1f, %esi
orl %r8d, %esi
addl $-0x5, %eax
cmpl $-0x3, %eax
ja 0xe516
shrl %edi
leal (%rdi,%rdi), %eax
shll $0x5, %edi
subl %eax, %edi
movl %ecx, %eax
shrl $0x5, %eax
andl $0x1f, %eax
addl %edi, %eax
movzbl 0x6e0(%rbx), %edi
andl $0x7, %edi
leal (%rdi,%rsi,8), %esi
shrl $0xc, %ecx
andl $0x7, %ecx
leal (%rcx,%rax,8), %eax
movl %esi, 0x1e8(%rbx)
movl %eax, 0x1ec(%rbx)
movq (%rbx), %rdi
shrb $0x4, %dl
andb $0x1, %dl
movzbl %dl, %ecx
movl %ebp, %esi
movl $0x20004, %edx          # imm = 0x20004
callq 0xa17e
movq (%rbx), %rdi
movl 0x21850(%rbx), %ecx
shrl $0x3, %ecx
andl $0x1, %ecx
jmp 0xe59c
movq 0xdc51(%rip), %r15      # 0x1bfb0
leaq 0x72b2(%rip), %rsi      # 0x15618
movl $0x16, %edx
movq %r15, %rdi
callq 0x4410
movq (%r15), %rax
movq -0x18(%rax), %rax
movl 0x18(%r15,%rax), %ecx
andl $-0x4b, %ecx
orl $0x8, %ecx
movl %ecx, 0x18(%r15,%rax)
movl %r14d, %esi
movq %r15, %rdi
callq 0x4280
movq %rax, %r14
leaq 0x7290(%rip), %rsi      # 0x1562f
movl $0xf, %edx
movq %rax, %rdi
callq 0x4410
movq (%r14), %rax
movq -0x18(%rax), %rcx
movl 0x18(%r14,%rcx), %edx
andl $-0x4b, %edx
orl $0x2, %edx
movl %edx, 0x18(%r14,%rcx)
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x4390
movsbl %al, %esi
movq %r14, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4290
jmp 0xe6ae
cmpb $0x0, 0x6e2(%rbx)
je 0xe508
movb %dl, 0x6d8(%rbx)
movl 0x6d8(%rbx), %ecx
movl %ecx, 0x6dc(%rbx)
jmp 0xe608
movb %dl, 0x21854(%rbx)
jmp 0xe6ae
movzwl 0x6dc(%rbx), %eax
andl $0x3fff, %eax           # imm = 0x3FFF
cmpl $0x1fff, %eax           # imm = 0x1FFF
ja 0xe5ad
movq (%rbx), %rdi
movzbl %dl, %esi
movl %eax, %edx
callq 0xa168
testb %al, %al
je 0xe76b
movzwl 0x6dc(%rbx), %eax
xorl %ebp, %ebp
testl $0x3000, %eax           # imm = 0x3000
setne %bpl
shrl $0x4, %eax
movzbl %al, %r14d
xorl %r15d, %r15d
movq %rbx, %rdi
movl %ebp, %esi
movl %r14d, %edx
movl %r15d, %ecx
callq 0xdf26
incl %r15d
cmpl $0x8, %r15d
jne 0xe463
jmp 0xe76b
movb %dl, 0x308(%rbx)
jmp 0xe6ae
movzbl 0x308(%rbx), %eax
cmpl $0x3, %eax
ja 0xe49f
movb $0x1, 0x6d5(%rbx)
movb $0x1, 0x6d4(%rbx)
movl %eax, %ecx
andl $-0x4, %ecx
addq %rbx, %rcx
movl %eax, %esi
andl $0x3, %esi
movb %dl, 0x208(%rsi,%rcx)
incb %al
movb %al, 0x308(%rbx)
jmp 0xe6ae
movl %edx, %ecx
shrb $0x3, %cl
movzbl %cl, %esi
movzwl 0x6d8(%rbx), %ecx
andb $0x7, %dl
cmpb $0x0, 0x6e2(%rbx)
je 0xe5e8
movzwl %si, %esi
shll $0x5, %esi
andl $0xffff8c1f, %ecx       # imm = 0xFFFF8C1F
orl %esi, %ecx
movzbl %dl, %edx
shll $0xc, %edx
orl %ecx, %edx
movw %dx, 0x6d8(%rbx)
jmp 0xe608
andb $0x3f, %dl
movb %dl, 0x6d9(%rbx)
jmp 0xe608
movl %r14d, %r15d
shrb $0x3, %r15b
andb $0x1, %r15b
movzbl 0x6e0(%rbx), %eax
andl $0x7, %eax
leal (%rax,%rsi,8), %esi
movl %ebp, %eax
movl $0x80601807, %ecx       # imm = 0x80601807
imulq %rax, %rcx
shrq $0x20, %rcx
movl %ebp, %r8d
subl %ecx, %r8d
shrl %r8d
addl %ecx, %r8d
shrl $0x8, %r8d
movq %rbx, %rdi
callq 0xec40
movl 0x21850(%rbx), %ecx
shrl $0x4, %ecx
andl $0x1, %ecx
movzbl %r14b, %eax
btl $0x4, %eax
movl %ecx, %eax
sbbb $0x0, %al
je 0xe581
movq (%rbx), %rdi
xorl $0x1, %ecx
movl %ebp, %esi
movl $0x20004, %edx          # imm = 0x20004
callq 0xa17e
movl 0x21850(%rbx), %ecx
shrl $0x3, %ecx
andl $0x1, %ecx
cmpb %r15b, %cl
je 0xe6ae
movq (%rbx), %rdi
xorl $0x1, %ecx
movl %ebp, %esi
movl $0x20003, %edx          # imm = 0x20003
callq 0xa17e
jmp 0xe6ae
movzwl %ax, %ecx
addl $0xffffd000, %ecx       # imm = 0xFFFFD000
movzwl %cx, %ecx
leal -0x1000(%rax), %r14d
cmpl $0xf00, %ecx            # imm = 0xF00
cmovael %eax, %r14d
cmpl $0x23c0, %r14d          # imm = 0x23C0
jae 0xe6bf
movq $-0x2000, %rax          # imm = 0xE000
movl $0x16f0, %ecx           # imm = 0x16F0
jmp 0xe761
andl $-0x20, %ecx
movzwl %si, %esi
orl %ecx, %esi
movw %si, 0x6d8(%rbx)
movb 0x6e0(%rbx), %cl
andb $-0x8, %cl
orb %dl, %cl
movb %cl, 0x6e0(%rbx)
movzbl 0x21850(%rbx), %ecx
cmpl $0x3, %eax
jne 0xe658
shll $0x5, %ecx
andl $0x20, %ecx
movzwl 0x6d8(%rbx), %eax
andl $0x1f, %eax
orl %ecx, %eax
movzbl 0x6e0(%rbx), %ecx
andl $0x7, %ecx
leal (%rcx,%rax,8), %esi
movl %ebp, %eax
movl $0x80601807, %ecx       # imm = 0x80601807
imulq %rax, %rcx
shrq $0x20, %rcx
subl %ecx, %ebp
shrl %ebp
addl %ecx, %ebp
shrl $0x8, %ebp
movq %rbx, %rdi
movl %ebp, %r8d
callq 0xec40
jmp 0xe6a7
movl %ecx, %edx
andl $0x2, %edx
shll $0x5, %ecx
andl $0x20, %ecx
movzwl 0x6d8(%rbx), %eax
movl %eax, %esi
andl $0x1f, %esi
orl %ecx, %esi
shrl %edx
leal (%rdx,%rdx), %ecx
shll $0x5, %edx
subl %ecx, %edx
movl %eax, %ecx
shrl $0x5, %ecx
andl $0x1f, %ecx
addl %edx, %ecx
movzbl 0x6e0(%rbx), %edx
andl $0x7, %edx
leal (%rdx,%rsi,8), %edx
shrl $0xc, %eax
andl $0x7, %eax
leal (%rax,%rcx,8), %eax
movl %edx, 0x1e8(%rbx)
movl %eax, 0x1ec(%rbx)
xorb $0x1, 0x6e2(%rbx)
incl 0x1cc(%rbx)
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
cmpl $0x2400, %r14d          # imm = 0x2400
jae 0xe6d9
movq $-0x23c0, %rax          # imm = 0xDC40
movl $0x1710, %ecx           # imm = 0x1710
jmp 0xe761
cmpl $0x27c0, %r14d          # imm = 0x27C0
jae 0xe6f0
movq $-0x2400, %rax          # imm = 0xDC00
movl $0x16f8, %ecx           # imm = 0x16F8
jmp 0xe761
cmpl $0x2800, %r14d          # imm = 0x2800
jae 0xe707
movq $-0x27c0, %rax          # imm = 0xD840
movl $0x1718, %ecx           # imm = 0x1718
jmp 0xe761
cmpl $0x2bc0, %r14d          # imm = 0x2BC0
jae 0xe71e
movq $-0x2800, %rax          # imm = 0xD800
movl $0x1700, %ecx           # imm = 0x1700
jmp 0xe761
cmpl $0x2c00, %r14d          # imm = 0x2C00
jae 0xe735
movq $-0x2bc0, %rax          # imm = 0xD440
movl $0x1720, %ecx           # imm = 0x1720
jmp 0xe761
cmpl $0x2fc0, %r14d          # imm = 0x2FC0
jae 0xe74c
movq $-0x2c00, %rax          # imm = 0xD400
movl $0x1708, %ecx           # imm = 0x1708
jmp 0xe761
cmpl $0x3000, %r14d          # imm = 0x3000
jae 0xe7af
movq $-0x2fc0, %rax          # imm = 0xD040
movl $0x1728, %ecx           # imm = 0x1728
movl %r14d, %esi
addq (%rbx,%rcx), %rsi
movb %dl, (%rax,%rsi)
movzwl 0x6dc(%rbx), %eax
leal 0x1(%rax), %edx
andl $0x3fff, %edx           # imm = 0x3FFF
movl %eax, %ecx
andl $0xc000, %ecx           # imm = 0xC000
orl %ecx, %edx
movw %dx, 0x6dc(%rbx)
testb $0x4, 0x21850(%rbx)
je 0xe6ae
addl $0x20, %eax
andl $0x3fff, %eax           # imm = 0x3FFF
orl %eax, %ecx
movw %cx, 0x6dc(%rbx)
jmp 0xe6ae
andl $0x1f, %r14d
movq 0x1750(%rbx,%r14,8), %rax
cmpb %dl, (%rax)
je 0xe76b
andb $0x3f, %dl
movb %dl, (%rax)
shrl $0x2, %r14d
xorl %r15d, %r15d
xorl %ebp, %ebp
movq %rbx, %rdi
movl %r15d, %esi
movl %ebp, %edx
movl %r14d, %ecx
callq 0xdf26
incl %ebp
cmpl $0x100, %ebp            # imm = 0x100
jne 0xe7cd
leal 0x1(%r15), %eax
testl %r15d, %r15d
movl %eax, %r15d
je 0xe7cb
jmp 0xe76b