// File: khedoros[P]khednes/apu.cpp
// Function: apu::reg_dequeue()
void apu::reg_dequeue() {
    if(writes.size() > 0) {
        int addr = writes.front().second.first - 0x4000;
        int chan = addr / 4;
        int reg = addr % 4;
        if(addr == 0x10) reg = 0x10;
        if(addr == 0x11) reg = 0x11;
        if(addr == 0x12) reg = 0x12;
        if(addr == 0x13) reg = 0x13;
        if(addr == 0x15) reg = 0x15;
        if(addr == 0x17) reg = 0x17;
        int val = writes.front().second.second;
        if(reg < 4 && addr > 0x10) writes.pop_front();
        switch(reg) {
            case 0:
                if(chan != TRI) {
                    vol_reg a;
                    a.val = val;
                    vol[chan] = a.vol;
                    enable_decay[chan] = !a.disable_decay;
                    loop_decay[chan] = a.loop_decay;
                    decay_count[chan] = a.vol;
                    //cout<<"Chan: "<<chan<<" Enable decay: "<<enable_decay[chan]<<" loop: "<<a.loop_decay<<" rate: "<<a.vol<<endl;
                    decay_vol_lvl[chan] = 15;
                    if(chan != NOISE) {
                        duty_cycle[chan] = a.duty_cycle;
                    }
                }
                else {
                    lin_ctr_reg a;
                    a.val = val;
                    linear_cntr = a.count;
                    enable_linear_cntr = a.length_disable;
                }
                break;
            case 1: {
                sweep_reg a;
                a.val = val;
                sweep_enable[chan] = a.enable;
                sweep_shift[chan] = a.shift;
                sweep_rate[chan] = a.rate;
                sweep_count[chan] = a.rate + 1;
                sweep_dir[chan] = a.dir;
                }
                break;
            case 2:
                if(chan != NOISE) {
                    freq_len_reg a;
                    a.freq = wavelength_count_reset[chan];
                    a.low = val;
                    wavelength_count_reset[chan] = a.freq;
                }
                else {
                    freq_len_reg a;
                    a.low = val;
                    wavelength_count_reset[chan] = noise_freq(a);
                    wavelength_count[chan] = noise_freq(a);
                    duty_cycle[chan] = a.noise_type;
                }
                break;
            case 3: 
                if(chan != NOISE) {
                    freq_len_reg a;
                    a.freq = wavelength_count_reset[chan];
                    a.high = val;
                    wavelength_count_reset[chan] = a.freq;
                    wavelength_count[chan] = a.freq;
                    length[chan] = play_length(a);
                }
                else {
                    freq_len_reg a;
                    a.high = val;
                    length[chan] = play_length(a);
                    if(chan == SQ1 || chan == SQ2 || chan == NOISE)
                        decay_vol_lvl[chan] = 15;
                }
                break;
            case 0x10:
                //cout<<"0x4010: Mode: "<<hex<<((val&0xC0)>>(6))<<" Speed: "<<(val&0x0F)<<endl;
                dmc_loop = ((val&0x40) > 0);
                dmc_gen_irq = ((val >= 0x80) && !dmc_loop);
                dmc_freq = dmc_freq_table[val&0x0f]/8;
                dmc_freq_cnt = dmc_freq;
                //cout<<"0x4010: Loop: "<<dmc_loop<<" gen_irq: "<<dmc_gen_irq<<" freq: "<<dmc_freq<<endl;
                if(dmc_gen_irq) cerr<<"DMC can't generate an IRQ, so this game may not work right."<<endl;
                break;
            case 0x11:
                //cout<<"0x4011: PCM/counter val: "<<hex<<val<<endl;
                dmc_pcm_data = (val&0x7f); //The data's just 7 bits
                break;
            case 0x12:
                //cout<<"0x4012: DMC load address: "<<hex<<(((int(val))<<(6))|0xc000)<<endl;
                dmc_addr = (((int(val))<<(6))|0xc000);
                dmc_addr_reset = dmc_addr;
                dmc_bit = 0;
                dmc_cur_byte = memi->read(dmc_addr);
                break;
            case 0x13:
                //cout<<"0x4013: DMC length val: "<<hex<<((int(val))<<(4))<<endl;
                dmc_length = ((int(val))<<(4));
                if(!dmc_length) enabled[DMC] = false;
                break;
            case 0x15: {
                //cout<<"Set 0x15 to "<<val<<endl;
                status_reg a;
                a.val = val;
                enabled[SQ1] = a.sq1_on;
                enabled[SQ2] = a.sq2_on;
                enabled[TRI] = a.tri_on;
                enabled[NOISE] = a.noise_on;
                enabled[DMC] = a.dmc_on;
                //if(enabled[DMC]) cout<<"0x4015 DMC enabled"<<endl;
                //else           cout<<"0x4015 DMC disabled"<<endl;
                pin1_enabled = a.sq1_on + a.sq2_on;
                pin2_enabled = a.tri_on + a.noise_on + a.dmc_on;
                }
                break;
            case 0x17: {
                frame_counter_reg a;
                a.val = val;
                if(a.counter_mode) {
                    clock_quarter();
                    clock_full();
                    framecounter_reset = 111846;
                }
                else {
                    framecounter_reset = 89490;
                }
                enable_irq = !a.irq_disable;
                //cout<<"0x4017: IRQ enable: "<<enable_irq<<endl;
                counter_mode = a.counter_mode;
                framecounter_pos = 0;
                }
                break;
            default:
                cout<<"Not implemented"<<endl;
                break;
        }
        writes.pop_front();
    }
}

// Assembly:
subq $0x68, %rsp
movq %rdi, 0x60(%rsp)
movq 0x60(%rsp), %rdi
movq %rdi, 0x10(%rsp)
addq $0x50, %rdi
callq 0x24930
cmpq $0x0, %rax
jbe 0x24112
movq 0x10(%rsp), %rdi
addq $0x50, %rdi
callq 0x24960
movl 0x8(%rax), %eax
subl $0x4000, %eax           # imm = 0x4000
movl %eax, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
movl %eax, 0x58(%rsp)
movl 0x5c(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
movl %edx, 0x54(%rsp)
cmpl $0x10, 0x5c(%rsp)
jne 0x239df
movl $0x10, 0x54(%rsp)
cmpl $0x11, 0x5c(%rsp)
jne 0x239ee
movl $0x11, 0x54(%rsp)
cmpl $0x12, 0x5c(%rsp)
jne 0x239fd
movl $0x12, 0x54(%rsp)
cmpl $0x13, 0x5c(%rsp)
jne 0x23a0c
movl $0x13, 0x54(%rsp)
cmpl $0x15, 0x5c(%rsp)
jne 0x23a1b
movl $0x15, 0x54(%rsp)
cmpl $0x17, 0x5c(%rsp)
jne 0x23a2a
movl $0x17, 0x54(%rsp)
movq 0x10(%rsp), %rdi
addq $0x50, %rdi
callq 0x24960
movl 0xc(%rax), %eax
movl %eax, 0x50(%rsp)
cmpl $0x4, 0x54(%rsp)
jge 0x23a5b
cmpl $0x10, 0x5c(%rsp)
jle 0x23a5b
movq 0x10(%rsp), %rdi
addq $0x50, %rdi
callq 0x24a10
movl 0x54(%rsp), %eax
movq %rax, 0x8(%rsp)
subq $0x17, %rax
ja 0x240e2
movq 0x8(%rsp), %rax
leaq 0x92f6(%rip), %rcx      # 0x2cd70
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpl $0x2, 0x58(%rsp)
je 0x23b42
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
movb %cl, 0x4c(%rsp)
movb 0x4c(%rsp), %cl
andb $0xf, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0xbc(%rax,%rcx,4)
movb 0x4c(%rsp), %cl
shrb $0x4, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %dl
xorb $-0x1, %dl
movslq 0x58(%rsp), %rcx
andb $0x1, %dl
movb %dl, 0xe4(%rax,%rcx)
movb 0x4c(%rsp), %cl
shrb $0x5, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %dl
movslq 0x58(%rsp), %rcx
andb $0x1, %dl
movb %dl, 0xe9(%rax,%rcx)
movb 0x4c(%rsp), %cl
andb $0xf, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0xd0(%rax,%rcx,4)
movslq 0x58(%rsp), %rcx
movl $0xf, 0xf0(%rax,%rcx,4)
cmpl $0x3, 0x58(%rsp)
je 0x23b40
movq 0x10(%rsp), %rax
movb 0x4c(%rsp), %cl
shrb $0x6, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x104(%rax,%rcx,4)
jmp 0x23b78
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
movb %cl, 0x48(%rsp)
movb 0x48(%rsp), %cl
andb $0x7f, %cl
movzbl %cl, %ecx
movl %ecx, 0x118(%rax)
movb 0x48(%rsp), %cl
shrb $0x7, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0x11c(%rax)
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
movb %cl, 0x44(%rsp)
movb 0x44(%rsp), %cl
shrb $0x7, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %dl
movslq 0x58(%rsp), %rcx
andb $0x1, %dl
movb %dl, 0x11d(%rax,%rcx)
movb 0x44(%rsp), %cl
andb $0x7, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x124(%rax,%rcx,4)
movb 0x44(%rsp), %cl
shrb $0x4, %cl
andb $0x7, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x14c(%rax,%rcx,4)
movb 0x44(%rsp), %cl
shrb $0x4, %cl
andb $0x7, %cl
movzbl %cl, %edx
addl $0x1, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x160(%rax,%rcx,4)
movb 0x44(%rsp), %cl
shrb $0x3, %cl
andb $0x1, %cl
movzbl %cl, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x138(%rax,%rcx,4)
jmp 0x24104
cmpl $0x3, 0x58(%rsp)
je 0x23c80
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl 0x188(%rax,%rcx,4), %ecx
movw %cx, %dx
movw 0x40(%rsp), %cx
andw $0x7ff, %dx             # imm = 0x7FF
andw $0xf800, %cx            # imm = 0xF800
orw %dx, %cx
movw %cx, 0x40(%rsp)
movl 0x50(%rsp), %ecx
movw %cx, %dx
movw 0x40(%rsp), %cx
andw $0xff, %dx
andw $0xff00, %cx            # imm = 0xFF00
orw %dx, %cx
movw %cx, 0x40(%rsp)
movw 0x40(%rsp), %cx
andw $0x7ff, %cx             # imm = 0x7FF
movzwl %cx, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x188(%rax,%rcx,4)
jmp 0x23d01
movl 0x50(%rsp), %eax
movw %ax, %cx
movw 0x3c(%rsp), %ax
andw $0xff, %cx
andw $0xff00, %ax            # imm = 0xFF00
orw %cx, %ax
movw %ax, 0x3c(%rsp)
movl 0x3c(%rsp), %eax
movl %eax, 0x38(%rsp)
movl 0x38(%rsp), %edi
callq 0x24480
movl %eax, %edx
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl %edx, 0x188(%rax,%rcx,4)
movl 0x3c(%rsp), %eax
movl %eax, 0x34(%rsp)
movl 0x34(%rsp), %edi
callq 0x24480
movl %eax, %edx
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl %edx, 0x19c(%rax,%rcx,4)
movw 0x3c(%rsp), %cx
shrw $0x7, %cx
andw $0x1, %cx
movzwl %cx, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x104(%rax,%rcx,4)
jmp 0x24104
cmpl $0x3, 0x58(%rsp)
je 0x23db6
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl 0x188(%rax,%rcx,4), %ecx
movw %cx, %dx
movw 0x30(%rsp), %cx
andw $0x7ff, %dx             # imm = 0x7FF
andw $0xf800, %cx            # imm = 0xF800
orw %dx, %cx
movw %cx, 0x30(%rsp)
movl 0x50(%rsp), %ecx
movw %cx, %dx
movw 0x30(%rsp), %cx
andw $0xff, %dx
shlw $0x8, %dx
andw $0xff, %cx
orw %dx, %cx
movw %cx, 0x30(%rsp)
movw 0x30(%rsp), %cx
andw $0x7ff, %cx             # imm = 0x7FF
movzwl %cx, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x188(%rax,%rcx,4)
movw 0x30(%rsp), %cx
andw $0x7ff, %cx             # imm = 0x7FF
movzwl %cx, %edx
movslq 0x58(%rsp), %rcx
movl %edx, 0x19c(%rax,%rcx,4)
movl 0x30(%rsp), %eax
movl %eax, 0x2c(%rsp)
movl 0x2c(%rsp), %edi
callq 0x244a0
movl %eax, %edx
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl %edx, 0x174(%rax,%rcx,4)
jmp 0x23e27
movl 0x50(%rsp), %eax
movw %ax, %cx
movw 0x28(%rsp), %ax
andw $0xff, %cx
shlw $0x8, %cx
andw $0xff, %ax
orw %cx, %ax
movw %ax, 0x28(%rsp)
movl 0x28(%rsp), %eax
movl %eax, 0x24(%rsp)
movl 0x24(%rsp), %edi
callq 0x244a0
movl %eax, %edx
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl %edx, 0x174(%rax,%rcx,4)
cmpl $0x0, 0x58(%rsp)
je 0x23e10
cmpl $0x1, 0x58(%rsp)
je 0x23e10
cmpl $0x3, 0x58(%rsp)
jne 0x23e25
movq 0x10(%rsp), %rax
movslq 0x58(%rsp), %rcx
movl $0xf, 0xf0(%rax,%rcx,4)
jmp 0x23e27
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
andl $0x40, %ecx
cmpl $0x0, %ecx
setg %cl
andb $0x1, %cl
movb %cl, 0x235(%rax)
xorl %eax, %eax
cmpl $0x80, 0x50(%rsp)
movb %al, 0x7(%rsp)
jl 0x23e68
movq 0x10(%rsp), %rax
movb 0x235(%rax), %al
xorb $-0x1, %al
movb %al, 0x7(%rsp)
movq 0x10(%rsp), %rax
movb 0x7(%rsp), %cl
andb $0x1, %cl
movb %cl, 0x234(%rax)
movl 0x50(%rsp), %ecx
andl $0xf, %ecx
movslq %ecx, %rcx
movl 0x1e0(%rax,%rcx,4), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq 0x10(%rsp), %rax
movl %ecx, 0x230(%rax)
movl 0x230(%rax), %ecx
movl %ecx, 0x22c(%rax)
testb $0x1, 0x234(%rax)
je 0x23ed7
movq 0x13134(%rip), %rdi     # 0x36ff0
leaq 0x91a5(%rip), %rsi      # 0x2d068
callq 0x43c0
movq %rax, %rdi
movq 0x130be(%rip), %rsi     # 0x36f90
callq 0x4400
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
andl $0x7f, %ecx
movl %ecx, 0x220(%rax)
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
shll $0x6, %ecx
orl $0xc000, %ecx           # imm = 0xC000
movl %ecx, 0x224(%rax)
movl 0x224(%rax), %ecx
movl %ecx, 0x228(%rax)
movl $0x0, 0x23c(%rax)
movq 0x30(%rax), %rdi
movl 0x224(%rax), %esi
callq 0x14460
movl %eax, %ecx
movq 0x10(%rsp), %rax
movl %ecx, 0x240(%rax)
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
shll $0x4, %ecx
movl %ecx, 0x238(%rax)
cmpl $0x0, 0x238(%rax)
jne 0x23f69
movq 0x10(%rsp), %rax
movb $0x0, 0xb8(%rax)
jmp 0x24104
movq 0x10(%rsp), %rax
movl 0x50(%rsp), %ecx
movb %cl, 0x20(%rsp)
movb 0x20(%rsp), %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0xb4(%rax)
movb 0x20(%rsp), %cl
shrb %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0xb5(%rax)
movb 0x20(%rsp), %cl
shrb $0x2, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0xb6(%rax)
movb 0x20(%rsp), %cl
shrb $0x3, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0xb7(%rax)
movb 0x20(%rsp), %cl
shrb $0x4, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0xb8(%rax)
movb 0x20(%rsp), %cl
andb $0x1, %cl
movzbl %cl, %ecx
movb 0x20(%rsp), %dl
shrb %dl
andb $0x1, %dl
movzbl %dl, %edx
addl %edx, %ecx
movl %ecx, 0x1c4(%rax)
movb 0x20(%rsp), %cl
shrb $0x2, %cl
andb $0x1, %cl
movzbl %cl, %ecx
movb 0x20(%rsp), %dl
shrb $0x3, %dl
andb $0x1, %dl
movzbl %dl, %edx
addl %edx, %ecx
movb 0x20(%rsp), %dl
shrb $0x4, %dl
andb $0x1, %dl
movzbl %dl, %edx
addl %edx, %ecx
movl %ecx, 0x1c8(%rax)
jmp 0x24104
movl 0x50(%rsp), %eax
movb %al, 0x1c(%rsp)
movb 0x1c(%rsp), %al
shrb $0x7, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x24093
movq 0x10(%rsp), %rdi
callq 0x23000
movq 0x10(%rsp), %rdi
callq 0x233b0
movq 0x10(%rsp), %rax
movl $0x1b4e6, 0x1d4(%rax)   # imm = 0x1B4E6
jmp 0x240a2
movq 0x10(%rsp), %rax
movl $0x15d92, 0x1d4(%rax)   # imm = 0x15D92
movq 0x10(%rsp), %rax
movb 0x1c(%rsp), %cl
shrb $0x6, %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl $0x0, %ecx
setne %cl
xorb $-0x1, %cl
andb $0x1, %cl
movb %cl, 0x1d8(%rax)
movb 0x1c(%rsp), %cl
shrb $0x7, %cl
movzbl %cl, %ecx
movl %ecx, 0x1dc(%rax)
movl $0x0, 0x1d0(%rax)
jmp 0x24104
movq 0x12ec7(%rip), %rdi     # 0x36fb0
leaq 0x8fb4(%rip), %rsi      # 0x2d0a4
callq 0x43c0
movq %rax, %rdi
movq 0x12e91(%rip), %rsi     # 0x36f90
callq 0x4400
movq 0x10(%rsp), %rdi
addq $0x50, %rdi
callq 0x24a10
addq $0x68, %rsp
retq
nopw (%rax,%rax)