// File: khedoros[P]khednes/mapper_001_mmc1.cpp
// Function: mapper_001::put_pbyte(unsigned int, unsigned int, unsigned int)
void mapper_001::put_pbyte(const unsigned int cycle, const unsigned int val,const unsigned int addr) {
    //std::printf("MMC1: %04x = %02x (",addr,val);
    if(val < 128 && mmc1_reg.counter < 4) {
        if(mmc1_reg.counter == 0) {
            //std::cout<<std::endl<<std::endl<<"Initializing new MMC1 register write!"<<std::endl;
        }
        //std::printf("Set temp[%d] to %d\n",mmc1_reg_counter,((val&1)==1?1:0));
        if((val & 1) == 1) {
            mmc1_reg.temp[mmc1_reg.counter]=true;
        }
        else {
            mmc1_reg.temp[mmc1_reg.counter]=false;
        }
        ++(mmc1_reg.counter);
    } else if(val < 128 && mmc1_reg.counter == 4) {
        if(val & 1) {
            mmc1_reg.temp[mmc1_reg.counter]=true;
        }
        else {
            mmc1_reg.temp[mmc1_reg.counter]=false;
        }
        mmc1_reg.counter=0;
        //std::printf("MMC1: %04x = %02x\n",addr,tempval(mmc1_reg.temp));
        //std::cout<<"Setting addr "<<std::hex<<addr<<" to "<<tempval(mmc1_reg.temp)<<std::endl;
        if(addr >= 0x8000 && addr <= 0x9fff) {
            int mirror = mmc1_reg.reg0.mirror;
            int one_screen = mmc1_reg.reg0.obey_mirror;
            mmc1_reg.reg0.val = tempval(mmc1_reg.temp);
            if(mirror != mmc1_reg.reg0.mirror) {
                std::cout<<"Mirror mode changed to "<<!mirror<<"!"<<std::endl;
                if(mmc1_reg.reg0.mirror == 0) ppu_change(cycle, set_vert, 0);
                if(mmc1_reg.reg0.mirror == 1) ppu_change(cycle, set_horiz, 0);
            }
            if(one_screen != mmc1_reg.reg0.obey_mirror) {
                std::cout<<"One-screen mode changed!"<<std::endl;
                if(mmc1_reg.reg0.obey_mirror == 0) ppu_change(cycle, set_4_scr, 0);
                else if(mmc1_reg.reg0.mirror == 0) ppu_change(cycle, set_vert, 0);
                else if(mmc1_reg.reg0.mirror == 1) ppu_change(cycle, set_horiz, 0);
            }
            //std::cout<<"Mirror: "<<(mmc1_reg.reg0.mirror?'H':'V')<<" One-Screen: "<<(!mmc1_reg.reg0.obey_mirror);
            //std::cout<<" PRG Switch: "<<(mmc1_reg.reg0.high_low?'L':'H')<<" PRG Size: "<<(mmc1_reg.reg0.large_small_prg?'S':'L');
            //std::cout<<" CHR Size: "<<(mmc1_reg.reg0.large_small_chr?'S':'L')<<std::endl;
        } else if(addr >= 0xa000 && addr <= 0xbfff) {
            mmc1_reg.reg1.val = tempval(mmc1_reg.temp);
            if(mmc1_reg.reg0.large_small_chr) { //small chr
                cart->updated_crom = 3;
                int new_chr_lo_offset = mmc1_reg.reg1.val * 0x1000;
                int new_chr_hi_offset = mmc1_reg.reg2.val * 0x1000;
                ppu_change(cycle, lo_crom, new_chr_lo_offset);
                ppu_change(cycle, hi_crom, new_chr_hi_offset);
            } else {
                cart->updated_crom = 3;
                int new_chr_lo_offset = mmc1_reg.reg1.val * 0x2000;
                int new_chr_hi_offset = mmc1_reg.reg1.val * 0x2000 + 0x1000;
                ppu_change(cycle, lo_crom, new_chr_lo_offset);
                ppu_change(cycle, hi_crom, new_chr_hi_offset);
            }
            //std::cout<<"CHR ROM bank switching not properly implemented. Sry, dude!"<<std::endl;
        } else if(addr >= 0xc000 && addr <= 0xdfff) {
            mmc1_reg.reg2.val=tempval(mmc1_reg.temp);
            if(mmc1_reg.reg0.large_small_chr) { //small chr
                cart->updated_crom = 3;
                int new_chr_lo_offset = mmc1_reg.reg1.val * 0x1000;
                int new_chr_hi_offset = mmc1_reg.reg2.val * 0x1000;
                ppu_change(cycle, lo_crom, new_chr_lo_offset);
                ppu_change(cycle, hi_crom, new_chr_hi_offset);
            } else {
                cart->updated_crom = 3;
                int new_chr_lo_offset = mmc1_reg.reg1.val * 0x2000;
                int new_chr_hi_offset = mmc1_reg.reg1.val * 0x2000 + 0x1000;
                ppu_change(cycle, lo_crom, new_chr_lo_offset);
                ppu_change(cycle, hi_crom, new_chr_hi_offset);
            }
            //std::cout<<"CHR ROM bank switching not properly implemented. Sry, dude!"<<std::endl;
        } else if(addr >= 0xe000 && addr <= 0xffff) {
            mmc1_reg.reg3.val=tempval(mmc1_reg.temp);
            if(!mmc1_reg.reg0.large_small_prg) { //32KiB switching is "false" value
                int temp = mmc1_reg.reg3.val >>(1);
                prg_lo_offset=temp*0x8000;
                prg_hi_offset=temp*0x8000+PRG_PAGE_SIZE;
            } else if(mmc1_reg.reg0.high_low) { //Switch low PRG
                prg_lo_offset=mmc1_reg.reg3.val*16384;
                prg_hi_offset=(cart->prom_pages -1) * PRG_PAGE_SIZE;
            } else { //Switch high PRG
                prg_lo_offset=0;
                prg_hi_offset=mmc1_reg.reg3.val*16384;
            }
        }
    } else if(val>=128) {
        //std::printf("MMC1: %04x reset\n",addr);
        mmc1_reg.counter=0;
        if(addr>=0x8000&&addr<=0x9fff) {
            //mmc1_reg.reg0.val = 0;
            mmc1_reg.reg0.val |= 0x0C;
            //mmc1_reg.reg0.high_low = 1;
            //mmc1_reg.reg0.large_small_prg = 1;
            //std::cout<<"Clear reg 0"<<std::endl;
        } else if(addr>=0xa000&&addr<=0xbfff) {
            mmc1_reg.reg1.val = 0;
            //std::cout<<"Clear reg 1"<<std::endl;
        } else if(addr>=0xc000&&addr<=0xdfff) {
            mmc1_reg.reg2.val = 0;
            //std::cout<<"Clear reg 2"<<std::endl;
        } else if(addr>=0xe000&&addr<=0xffff) {
            mmc1_reg.reg3.val = 0;
            //std::cout<<"Clear reg 3"<<std::endl;
        }
    }
}

// Assembly:
subq $0x48, %rsp
movq %rdi, 0x40(%rsp)
movl %esi, 0x3c(%rsp)
movl %edx, 0x38(%rsp)
movl %ecx, 0x34(%rsp)
movq 0x40(%rsp), %rax
movq %rax, (%rsp)
cmpl $0x80, 0x38(%rsp)
jae 0x27116
movq (%rsp), %rax
cmpl $0x4, 0x38(%rax)
jae 0x27116
movq (%rsp), %rax
cmpl $0x0, 0x38(%rax)
jne 0x270de
jmp 0x270de
movl 0x38(%rsp), %eax
andl $0x1, %eax
cmpl $0x1, %eax
jne 0x270f8
movq (%rsp), %rax
movl 0x38(%rax), %ecx
movb $0x1, 0x3c(%rax,%rcx)
jmp 0x27104
movq (%rsp), %rax
movl 0x38(%rax), %ecx
movb $0x0, 0x3c(%rax,%rcx)
movq (%rsp), %rax
movl 0x38(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x38(%rax)
jmp 0x276fe
cmpl $0x80, 0x38(%rsp)
jae 0x27633
movq (%rsp), %rax
cmpl $0x4, 0x38(%rax)
jne 0x27633
movl 0x38(%rsp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x2714c
movq (%rsp), %rax
movl 0x38(%rax), %ecx
movb $0x1, 0x3c(%rax,%rcx)
jmp 0x27158
movq (%rsp), %rax
movl 0x38(%rax), %ecx
movb $0x0, 0x3c(%rax,%rcx)
movq (%rsp), %rax
movl $0x0, 0x38(%rax)
cmpl $0x8000, 0x34(%rsp)     # imm = 0x8000
jb 0x2732c
cmpl $0x9fff, 0x34(%rsp)     # imm = 0x9FFF
ja 0x2732c
movq (%rsp), %rdi
movb 0x28(%rdi), %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x30(%rsp)
movb 0x28(%rdi), %al
shrb %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x2c(%rsp)
movq %rdi, %rsi
addq $0x28, %rsi
addq $0x14, %rsi
callq 0x27710
movq (%rsp), %rcx
movb %al, %dl
movb 0x28(%rcx), %al
andb $0x1f, %dl
andb $-0x20, %al
orb %dl, %al
movb %al, 0x28(%rcx)
movl 0x30(%rsp), %eax
movb 0x28(%rcx), %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x2726c
movq 0xfdd4(%rip), %rdi      # 0x36fb0
leaq 0x63a9(%rip), %rsi      # 0x2d58c
callq 0x43c0
movq %rax, %rdi
cmpl $0x0, 0x30(%rsp)
setne %al
xorb $-0x1, %al
movzbl %al, %esi
andl $0x1, %esi
callq 0x46a0
movq %rax, %rdi
leaq 0x5f88(%rip), %rsi      # 0x2d192
callq 0x43c0
movq %rax, %rdi
movq 0xfd77(%rip), %rsi      # 0x36f90
callq 0x4400
movq (%rsp), %rax
movb 0x28(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x27244
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movq (%rdi), %rax
movl $0x3, %edx
xorl %ecx, %ecx
callq *0x50(%rax)
movq (%rsp), %rax
movb 0x28(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x2726a
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movq (%rdi), %rax
movl $0x2, %edx
xorl %ecx, %ecx
callq *0x50(%rax)
jmp 0x2726c
movq (%rsp), %rcx
movl 0x2c(%rsp), %eax
movb 0x28(%rcx), %cl
shrb %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x27327
movq 0xfd22(%rip), %rdi      # 0x36fb0
leaq 0x630f(%rip), %rsi      # 0x2d5a4
callq 0x43c0
movq %rax, %rdi
movq 0xfcec(%rip), %rsi      # 0x36f90
callq 0x4400
movq (%rsp), %rax
movb 0x28(%rax), %al
shrb %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x272d3
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movq (%rdi), %rax
movl $0x4, %edx
xorl %ecx, %ecx
callq *0x50(%rax)
jmp 0x27325
movq (%rsp), %rax
movb 0x28(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x272fb
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movq (%rdi), %rax
movl $0x3, %edx
xorl %ecx, %ecx
callq *0x50(%rax)
jmp 0x27323
movq (%rsp), %rax
movb 0x28(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x27321
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movq (%rdi), %rax
movl $0x2, %edx
xorl %ecx, %ecx
callq *0x50(%rax)
jmp 0x27323
jmp 0x27325
jmp 0x27327
jmp 0x2762e
cmpl $0xa000, 0x34(%rsp)     # imm = 0xA000
jb 0x2743c
cmpl $0xbfff, 0x34(%rsp)     # imm = 0xBFFF
ja 0x2743c
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x28, %rsi
addq $0x14, %rsi
callq 0x27710
movl %eax, %ecx
movq (%rsp), %rax
movb %cl, %dl
movb 0x2c(%rax), %cl
andb $0x1f, %dl
andb $-0x20, %cl
orb %dl, %cl
movb %cl, 0x2c(%rax)
movb 0x28(%rax), %al
shrb $0x4, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x273db
movq (%rsp), %rdi
movq 0x8(%rdi), %rax
movl $0x3, 0xa4(%rax)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xc, %eax
movl %eax, 0x28(%rsp)
movb 0x30(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xc, %eax
movl %eax, 0x24(%rsp)
movl 0x3c(%rsp), %esi
movl 0x28(%rsp), %ecx
movq (%rdi), %rax
xorl %edx, %edx
callq *0x50(%rax)
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movl 0x24(%rsp), %ecx
movq (%rdi), %rax
movl $0x1, %edx
callq *0x50(%rax)
jmp 0x27437
movq (%rsp), %rdi
movq 0x8(%rdi), %rax
movl $0x3, 0xa4(%rax)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xd, %eax
movl %eax, 0x20(%rsp)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xd, %eax
addl $0x1000, %eax           # imm = 0x1000
movl %eax, 0x1c(%rsp)
movl 0x3c(%rsp), %esi
movl 0x20(%rsp), %ecx
movq (%rdi), %rax
xorl %edx, %edx
callq *0x50(%rax)
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movl 0x1c(%rsp), %ecx
movq (%rdi), %rax
movl $0x1, %edx
callq *0x50(%rax)
jmp 0x2762c
cmpl $0xc000, 0x34(%rsp)     # imm = 0xC000
jb 0x2754c
cmpl $0xdfff, 0x34(%rsp)     # imm = 0xDFFF
ja 0x2754c
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x28, %rsi
addq $0x14, %rsi
callq 0x27710
movl %eax, %ecx
movq (%rsp), %rax
movb %cl, %dl
movb 0x30(%rax), %cl
andb $0x1f, %dl
andb $-0x20, %cl
orb %dl, %cl
movb %cl, 0x30(%rax)
movb 0x28(%rax), %al
shrb $0x4, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x274eb
movq (%rsp), %rdi
movq 0x8(%rdi), %rax
movl $0x3, 0xa4(%rax)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xc, %eax
movl %eax, 0x18(%rsp)
movb 0x30(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xc, %eax
movl %eax, 0x14(%rsp)
movl 0x3c(%rsp), %esi
movl 0x18(%rsp), %ecx
movq (%rdi), %rax
xorl %edx, %edx
callq *0x50(%rax)
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movl 0x14(%rsp), %ecx
movq (%rdi), %rax
movl $0x1, %edx
callq *0x50(%rax)
jmp 0x27547
movq (%rsp), %rdi
movq 0x8(%rdi), %rax
movl $0x3, 0xa4(%rax)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xd, %eax
movl %eax, 0x10(%rsp)
movb 0x2c(%rdi), %al
andb $0x1f, %al
movzbl %al, %eax
shll $0xd, %eax
addl $0x1000, %eax           # imm = 0x1000
movl %eax, 0xc(%rsp)
movl 0x3c(%rsp), %esi
movl 0x10(%rsp), %ecx
movq (%rdi), %rax
xorl %edx, %edx
callq *0x50(%rax)
movq (%rsp), %rdi
movl 0x3c(%rsp), %esi
movl 0xc(%rsp), %ecx
movq (%rdi), %rax
movl $0x1, %edx
callq *0x50(%rax)
jmp 0x2762a
cmpl $0xe000, 0x34(%rsp)     # imm = 0xE000
jb 0x27628
cmpl $0xffff, 0x34(%rsp)     # imm = 0xFFFF
ja 0x27628
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x28, %rsi
addq $0x14, %rsi
callq 0x27710
movl %eax, %ecx
movq (%rsp), %rax
movb %cl, %dl
movb 0x34(%rax), %cl
andb $0xf, %dl
andb $-0x10, %cl
orb %dl, %cl
movb %cl, 0x34(%rax)
movb 0x28(%rax), %al
shrb $0x3, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x275d1
movq (%rsp), %rax
movb 0x34(%rax), %cl
andb $0xf, %cl
movzbl %cl, %ecx
sarl %ecx
movl %ecx, 0x8(%rsp)
movl 0x8(%rsp), %ecx
shll $0xf, %ecx
movl %ecx, 0x44(%rax)
movl 0x8(%rsp), %ecx
shll $0xf, %ecx
addl $0x4000, %ecx           # imm = 0x4000
movl %ecx, 0x48(%rax)
jmp 0x27626
movq (%rsp), %rax
movb 0x28(%rax), %al
shrb $0x2, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x2760a
movq (%rsp), %rax
movb 0x34(%rax), %cl
andb $0xf, %cl
movzbl %cl, %ecx
shll $0xe, %ecx
movl %ecx, 0x44(%rax)
movq 0x8(%rax), %rcx
movl 0x78(%rcx), %ecx
subl $0x1, %ecx
shll $0xe, %ecx
movl %ecx, 0x48(%rax)
jmp 0x27624
movq (%rsp), %rax
movl $0x0, 0x44(%rax)
movb 0x34(%rax), %cl
andb $0xf, %cl
movzbl %cl, %ecx
shll $0xe, %ecx
movl %ecx, 0x48(%rax)
jmp 0x27626
jmp 0x27628
jmp 0x2762a
jmp 0x2762c
jmp 0x2762e
jmp 0x276fc
cmpl $0x80, 0x38(%rsp)
jb 0x276fa
movq (%rsp), %rax
movl $0x0, 0x38(%rax)
cmpl $0x8000, 0x34(%rsp)     # imm = 0x8000
jb 0x27682
cmpl $0x9fff, 0x34(%rsp)     # imm = 0x9FFF
ja 0x27682
movq (%rsp), %rax
movb 0x28(%rax), %cl
andb $0x1f, %cl
movzbl %cl, %ecx
orl $0xc, %ecx
movb %cl, %dl
movb 0x28(%rax), %cl
andb $0x1f, %dl
andb $-0x20, %cl
orb %dl, %cl
movb %cl, 0x28(%rax)
jmp 0x276f8
cmpl $0xa000, 0x34(%rsp)     # imm = 0xA000
jb 0x276a8
cmpl $0xbfff, 0x34(%rsp)     # imm = 0xBFFF
ja 0x276a8
movq (%rsp), %rax
movb 0x2c(%rax), %cl
andb $-0x20, %cl
orb $0x0, %cl
movb %cl, 0x2c(%rax)
jmp 0x276f6
cmpl $0xc000, 0x34(%rsp)     # imm = 0xC000
jb 0x276ce
cmpl $0xdfff, 0x34(%rsp)     # imm = 0xDFFF
ja 0x276ce
movq (%rsp), %rax
movb 0x30(%rax), %cl
andb $-0x20, %cl
orb $0x0, %cl
movb %cl, 0x30(%rax)
jmp 0x276f4
cmpl $0xe000, 0x34(%rsp)     # imm = 0xE000
jb 0x276f2
cmpl $0xffff, 0x34(%rsp)     # imm = 0xFFFF
ja 0x276f2
movq (%rsp), %rax
movb 0x34(%rax), %cl
andb $-0x10, %cl
orb $0x0, %cl
movb %cl, 0x34(%rax)
jmp 0x276f4
jmp 0x276f6
jmp 0x276f8
jmp 0x276fa
jmp 0x276fc
jmp 0x276fe
addq $0x48, %rsp
retq
nopw %cs:(%rax,%rax)