// File: /workspace/github_cpp_makefile_star2_O3/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 0x111b3
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %rbx
cmpl $0x0, 0x238(%rdi)
je 0x111a5
movl 0x240(%rbx), %eax
xorl %ebp, %ebp
xorl %r14d, %r14d
xorl %r15d, %r15d
movl 0x23c(%rbx), %ecx
movl $0x1, %esi
shll %cl, %esi
movl 0x22c(%rbx), %edx
xorl %edi, %edi
testl %eax, %esi
setg %dil
leal -0x2(,%rdi,4), %r13d
movl $0x28, %esi
subl %r15d, %esi
cmpl %esi, %edx
movl %esi, %r12d
cmovll %edx, %r12d
imull %r12d, %r13d
addl 0x220(%rbx), %r13d
movl %r13d, 0x220(%rbx)
movl $0x0, %edi
js 0x110fd
movl $0x7f, %edi
cmpl $0x80, %r13d
jb 0x11106
movl %edi, 0x220(%rbx)
movl %edi, %r13d
movl %edx, %edi
subl %r12d, %edi
movl %edi, 0x22c(%rbx)
cmpl %esi, %edx
jg 0x11185
movl 0x230(%rbx), %edx
leal 0x1(%rcx), %esi
addl $0x8, %ecx
testl %esi, %esi
cmovnsl %esi, %ecx
movl %edx, 0x22c(%rbx)
andl $-0x8, %ecx
subl %ecx, %esi
movl %esi, 0x23c(%rbx)
jne 0x11185
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 0x11176
movb 0x235(%rbx), %cl
movl %eax, 0x224(%rbx)
cmpb $0x1, %cl
jne 0x111b4
movl $0x0, 0x23c(%rbx)
movl %eax, %esi
movq 0x30(%rbx), %rdi
callq 0xa836
movl %eax, 0x240(%rbx)
addl %r13d, %ebp
addl %r12d, %r15d
incl %r14d
cmpl $0x27, %r15d
jle 0x110a2
movl %ebp, %eax
xorl %edx, %edx
divl %r14d
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 0x111a5
nop