// File: /workspace/github_cpp_makefile_star2_O2/khedoros[P]khednes/apu.cpp
// Function: apu::clock_every()
void apu::clock_every() {
    if(!enabled[DMC]||!dmc_length) {
        //cout<<"returning"<<endl;
        return;
    }

    //CLK_PER_FRAME is the *pixel clock* which runs 3x faster than the CPU clock, which is where the *3 comes from.
    const int clocks_per_sample = int(double(CLK_PER_FRAME) / double(SAMPLES_PER_FRAME * 3));
    int accum = 0;       //Generating either 1 or 2 samples, so this is where I'm collecting them
    int samples = 0;     //Number of samples generated, so that I can divide accum by the right number

    //"clock" represents a CPU clock. The goal is to generate samples faster than incrementing/decrementing the PCM value by 1 at a time
    for(int clock = 0; clock < clocks_per_sample;) {
        samples++;
        int sign = ((dmc_cur_byte & (1<<(dmc_bit))) > 0)?2:-2;

        //Either run up to the wavelength count, or the number of CPU cycles we need to simulate, whichever is less
        //If we still need to simulate more cycles, that'll happen in the next loop iteration.
        int increment = (dmc_freq_cnt > (clocks_per_sample - clock)) ? (clocks_per_sample - clock) : dmc_freq_cnt;
        dmc_pcm_data += (increment*sign);

        //The PCM data doesn't wrap like an X86 register, it "saturates" to stay in the range [0,127]
        if(dmc_pcm_data < 0) dmc_pcm_data = 0;
        else if(dmc_pcm_data > 127) dmc_pcm_data = 127;

        accum +=dmc_pcm_data;

        dmc_freq_cnt-=increment;
        clock += increment;

        //Clock the DMC registers if we're at the end of the wavelength counter
        if(!dmc_freq_cnt) {
            dmc_freq_cnt = dmc_freq;
            dmc_bit++;
            dmc_bit%=8;
            if(!dmc_bit) {
                //TODO: Fix so that it ends when the length runs out, but also wraps around to 0x8000 if it doesn't
                dmc_addr++;
                if(dmc_addr==dmc_addr_reset+dmc_length && !dmc_loop) {
                    dmc_addr = dmc_addr_reset;
                    enabled[DMC] = false;
                    return;
                }
                else if (dmc_addr==dmc_addr_reset+dmc_length) {
                    dmc_addr = dmc_addr_reset;
                    dmc_bit = 0;
                    dmc_freq_cnt = dmc_freq;
                }
                //Grab the next byte both if we're not done going through samples and if we're done, but looping.
                dmc_cur_byte = memi->read(dmc_addr);
            }
        }
    }
    dmc_pcm_data = accum/samples;
    //cout<<"Final data: "<<dmc_pcm_data<<endl;
}

// Assembly:
cmpb $0x1, 0xb8(%rdi)
jne 0xf23b
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
cmpl $0x0, 0x238(%rdi)
je 0xf22d
xorl %r14d, %r14d
pushq $0x1
popq %rdi
pushq $0x28
popq %r8
pushq $0x8
popq %r10
pushq $0x7f
popq %r11
xorl %r13d, %r13d
xorl %ebp, %ebp
cmpl $0x27, %r14d
jg 0xf220
movl 0x23c(%rbx), %ecx
movl %edi, %edx
shll %cl, %edx
movl 0x22c(%rbx), %eax
xorl %esi, %esi
testl %edx, 0x240(%rbx)
setg %sil
leal -0x2(,%rsi,4), %r12d
movl %r8d, %edx
subl %r14d, %edx
cmpl %edx, %eax
movl %edx, %r15d
cmovll %eax, %r15d
imull %r15d, %r12d
addl 0x220(%rbx), %r12d
movl %r12d, 0x220(%rbx)
js 0xf182
movl %r11d, %esi
cmpl $0x80, %r12d
jae 0xf184
jmp 0xf18d
xorl %esi, %esi
movl %esi, 0x220(%rbx)
movl %esi, %r12d
movl %eax, %esi
subl %r15d, %esi
movl %esi, 0x22c(%rbx)
cmpl %edx, %eax
jg 0xf212
movl 0x230(%rbx), %eax
movl %eax, 0x22c(%rbx)
incl %ecx
movl %ecx, %eax
cltd
idivl %r10d
movl %edx, 0x23c(%rbx)
testl %edx, %edx
jne 0xf212
movl 0x224(%rbx), %esi
movl 0x228(%rbx), %eax
incl %esi
movl %esi, 0x224(%rbx)
movl 0x238(%rbx), %ecx
addl %eax, %ecx
cmpl %ecx, %esi
jne 0xf1f4
movb 0x235(%rbx), %cl
movl %eax, 0x224(%rbx)
cmpb $0x1, %cl
jne 0xf23c
andl $0x0, 0x23c(%rbx)
movl %eax, %esi
movq 0x30(%rbx), %rdi
callq 0x96dc
pushq $0x7f
popq %r11
pushq $0x8
popq %r10
pushq $0x28
popq %r8
pushq $0x1
popq %rdi
movl %eax, 0x240(%rbx)
addl %r12d, %ebp
addl %r15d, %r14d
incl %r13d
jmp 0xf123
movl %ebp, %eax
xorl %edx, %edx
divl %r13d
movl %eax, 0x220(%rbx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movb $0x0, 0xb8(%rbx)
jmp 0xf22d
nop