// File: /workspace/github_c_makefile_star2_O0/juliuswwj[P]emch55x/core.c
// Function: timer_tick
static void timer_tick(struct em8051 *aCPU)
{
    int increment;
    int v;

    // TODO: External int 0 flag

    if ((aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_0 | TMODMASK_M1_0)) == (TMODMASK_M0_0 | TMODMASK_M1_0))
    {
        // timer/counter 0 in mode 3

        increment = 0;
        
        // Check if we're run enabled
        // TODO: also run if GATE is one and INT is one (external interrupt)
        if (!(aCPU->mSFR[REG_TMOD] & TMODMASK_GATE_0) && 
            (aCPU->mSFR[REG_TCON] & TCONMASK_TR0))
        {
            // check timer / counter mode
            if (aCPU->mSFR[REG_TMOD] & TMODMASK_CT_0)
            {
                // counter op;
                // counter works if T0 pin was 1 and is now 0 (P3.4 on AT89C2051)
                increment = 0; // TODO
            }
            else
            {
                increment = 1;
            }
        }
        if (increment)
        {
            v = aCPU->mSFR[REG_TL0];
            v++;
            aCPU->mSFR[REG_TL0] = v & 0xff;
            if (v > 0xff)
            {
                // TL0 overflowed
                aCPU->mSFR[REG_TCON] |= TCONMASK_TF0;
            }
        }

        increment = 0;
        
        // Check if we're run enabled
        // TODO: also run if GATE is one and INT is one (external interrupt)
        if (!(aCPU->mSFR[REG_TMOD] & TMODMASK_GATE_1) && 
            (aCPU->mSFR[REG_TCON] & TCONMASK_TR1))
        {
            // check timer / counter mode
            if (aCPU->mSFR[REG_TMOD] & TMODMASK_CT_1)
            {
                // counter op;
                // counter works if T1 pin was 1 and is now 0
                increment = 0; // TODO
            }
            else
            {
                increment = 1;
            }
        }

        if (increment)
        {
            v = aCPU->mSFR[REG_TH0];
            v++;
            aCPU->mSFR[REG_TH0] = v & 0xff;
            if (v > 0xff)
            {
                // TH0 overflowed
                aCPU->mSFR[REG_TCON] |= TCONMASK_TF1;
            }
        }

    }

    {   // Timer/counter 0
        
        increment = 0;
        
        // Check if we're run enabled
        // TODO: also run if GATE is one and INT is one (external interrupt)
        if (!(aCPU->mSFR[REG_TMOD] & TMODMASK_GATE_0) && 
            (aCPU->mSFR[REG_TCON] & TCONMASK_TR0))
        {
            // check timer / counter mode
            if (aCPU->mSFR[REG_TMOD] & TMODMASK_CT_0)
            {
                // counter op;
                // counter works if T0 pin was 1 and is now 0 (P3.4 on AT89C2051)
                increment = 0; // TODO
            }
            else
            {
                increment = 1;
            }
        }
        
        if (increment)
        {
            switch (aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_0 | TMODMASK_M1_0))
            {
            case 0: // 13-bit timer
                v = aCPU->mSFR[REG_TL0] & 0x1f; // lower 5 bits of TL0
                v++;
                aCPU->mSFR[REG_TL0] = (aCPU->mSFR[REG_TL0] & ~0x1f) | (v & 0x1f);
                if (v > 0x1f)
                {
                    // TL0 overflowed
                    v = aCPU->mSFR[REG_TH0];
                    v++;
                    aCPU->mSFR[REG_TH0] = v & 0xff;
                    if (v > 0xff)
                    {
                        // TH0 overflowed; set bit
                        aCPU->mSFR[REG_TCON] |= TCONMASK_TF0;
                    }
                }
                break;
            case TMODMASK_M0_0: // 16-bit timer/counter
                v = aCPU->mSFR[REG_TL0];
                v++;
                aCPU->mSFR[REG_TL0] = v & 0xff;
                if (v > 0xff)
                {
                    // TL0 overflowed
                    v = aCPU->mSFR[REG_TH0];
                    v++;
                    aCPU->mSFR[REG_TH0] = v & 0xff;
                    if (v > 0xff)
                    {
                        // TH0 overflowed; set bit
                        aCPU->mSFR[REG_TCON] |= TCONMASK_TF0;
                    }
                }
                break;
            case TMODMASK_M1_0: // 8-bit auto-reload timer
                v = aCPU->mSFR[REG_TL0];
                v++;
                aCPU->mSFR[REG_TL0] = v & 0xff;
                if (v > 0xff)
                {
                    // TL0 overflowed; reload
                    aCPU->mSFR[REG_TL0] = aCPU->mSFR[REG_TH0];
                    aCPU->mSFR[REG_TCON] |= TCONMASK_TF0;
                }
                break;
            default: // two 8-bit timers
                // TODO
                break;
            }
        }
    }

    // TODO: External int 1 

    {   // Timer/counter 1 
        
        increment = 0;

        if (!(aCPU->mSFR[REG_TMOD] & TMODMASK_GATE_1) && 
            (aCPU->mSFR[REG_TCON] & TCONMASK_TR1))
        {
            if (aCPU->mSFR[REG_TMOD] & TMODMASK_CT_1)
            {
                // counter op;
                // counter works if T1 pin was 1 and is now 0
                increment = 0; // TODO
            }
            else
            {
                increment = 1;
            }
        }

        if (increment)
        {
            switch (aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_1 | TMODMASK_M1_1))
            {
            case 0: // 13-bit timer
                v = aCPU->mSFR[REG_TL1] & 0x1f; // lower 5 bits of TL0
                v++;
                aCPU->mSFR[REG_TL1] = (aCPU->mSFR[REG_TL1] & ~0x1f) | (v & 0x1f);
                if (v > 0x1f)
                {
                    // TL1 overflowed
                    v = aCPU->mSFR[REG_TH1];
                    v++;
                    aCPU->mSFR[REG_TH1] = v & 0xff;
                    if (v > 0xff)
                    {
                        // TH1 overflowed; set bit
                        // Only update TF1 if timer 0 is not in "mode 3"
                        if (!(aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_0 | TMODMASK_M1_0)))
                            aCPU->mSFR[REG_TCON] |= TCONMASK_TF1;
                    }
                }
                break;
            case TMODMASK_M0_1: // 16-bit timer/counter
                v = aCPU->mSFR[REG_TL1];
                v++;
                aCPU->mSFR[REG_TL1] = v & 0xff;
                if (v > 0xff)
                {
                    // TL1 overflowed
                    v = aCPU->mSFR[REG_TH1];
                    v++;
                    aCPU->mSFR[REG_TH1] = v & 0xff;
                    if (v > 0xff)
                    {
                        // TH1 overflowed; set bit
                        // Only update TF1 if timer 0 is not in "mode 3"
                        if (!(aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_0 | TMODMASK_M1_0)))
                            aCPU->mSFR[REG_TCON] |= TCONMASK_TF1;
                    }
                }
                break;
            case TMODMASK_M1_1: // 8-bit auto-reload timer
                v = aCPU->mSFR[REG_TL1];
                v++;
                aCPU->mSFR[REG_TL1] = v & 0xff;
                if (v > 0xff)
                {
                    // TL0 overflowed; reload
                    aCPU->mSFR[REG_TL1] = aCPU->mSFR[REG_TH1];
                    // Only update TF1 if timer 0 is not in "mode 3"
                    if (!(aCPU->mSFR[REG_TMOD] & (TMODMASK_M0_0 | TMODMASK_M1_0)))
                        aCPU->mSFR[REG_TCON] |= TCONMASK_TF1;
                }
                break;
            default: // disabled
                break;
            }
        }
    }

    // TODO: serial port, timer2, other stuff
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x3, %eax
cmpl $0x3, %eax
jne 0x6b91
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x8, %eax
cmpl $0x0, %eax
jne 0x6a95
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x6a95
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x6a8c
movl $0x0, -0xc(%rbp)
jmp 0x6a93
movl $0x1, -0xc(%rbp)
jmp 0x6a95
cmpl $0x0, -0xc(%rbp)
je 0x6ae5
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xa(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xa(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6ae3
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x20, %ecx
movb %cl, 0x8(%rax)
jmp 0x6ae5
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x80, %eax
cmpl $0x0, %eax
jne 0x6b3c
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
je 0x6b3c
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
je 0x6b33
movl $0x0, -0xc(%rbp)
jmp 0x6b3a
movl $0x1, -0xc(%rbp)
jmp 0x6b3c
cmpl $0x0, -0xc(%rbp)
je 0x6b8f
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xc(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xc(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6b8d
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x80, %ecx
movb %cl, 0x8(%rax)
jmp 0x6b8f
jmp 0x6b91
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x8, %eax
cmpl $0x0, %eax
jne 0x6be6
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x6be6
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x6bdd
movl $0x0, -0xc(%rbp)
jmp 0x6be4
movl $0x1, -0xc(%rbp)
jmp 0x6be6
cmpl $0x0, -0xc(%rbp)
je 0x6d9f
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x3, %eax
movl %eax, -0x14(%rbp)
je 0x6c25
jmp 0x6c06
movl -0x14(%rbp), %eax
subl $0x1, %eax
je 0x6cb9
jmp 0x6c14
movl -0x14(%rbp), %eax
subl $0x2, %eax
je 0x6d3b
jmp 0x6d9b
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xa(%rax), %eax
andl $0x1f, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xa(%rax), %eax
andl $-0x20, %eax
movl -0x10(%rbp), %ecx
andl $0x1f, %ecx
orl %ecx, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xa(%rax)
cmpl $0x1f, -0x10(%rbp)
jle 0x6cb4
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xc(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xc(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6cb2
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x20, %ecx
movb %cl, 0x8(%rax)
jmp 0x6cb4
jmp 0x6d9d
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xa(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xa(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6d39
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xc(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xc(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6d37
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x20, %ecx
movb %cl, 0x8(%rax)
jmp 0x6d39
jmp 0x6d9d
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xa(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xa(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6d99
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb 0xc(%rax), %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xa(%rax)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x20, %ecx
movb %cl, 0x8(%rax)
jmp 0x6d9d
jmp 0x6d9d
jmp 0x6d9f
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x80, %eax
cmpl $0x0, %eax
jne 0x6df6
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
je 0x6df6
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
je 0x6ded
movl $0x0, -0xc(%rbp)
jmp 0x6df4
movl $0x1, -0xc(%rbp)
jmp 0x6df6
cmpl $0x0, -0xc(%rbp)
je 0x6ffa
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x30, %eax
movl %eax, -0x18(%rbp)
je 0x6e35
jmp 0x6e16
movl -0x18(%rbp), %eax
subl $0x10, %eax
je 0x6ee2
jmp 0x6e24
movl -0x18(%rbp), %eax
subl $0x20, %eax
je 0x6f7d
jmp 0x6ff6
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xb(%rax), %eax
andl $0x1f, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xb(%rax), %eax
andl $-0x20, %eax
movl -0x10(%rbp), %ecx
andl $0x1f, %ecx
orl %ecx, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xb(%rax)
cmpl $0x1f, -0x10(%rbp)
jle 0x6edd
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xd(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xd(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6edb
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x3, %eax
cmpl $0x0, %eax
jne 0x6ed9
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x80, %ecx
movb %cl, 0x8(%rax)
jmp 0x6edb
jmp 0x6edd
jmp 0x6ff8
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xb(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xb(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6f7b
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xd(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xd(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6f79
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x3, %eax
cmpl $0x0, %eax
jne 0x6f77
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x80, %ecx
movb %cl, 0x8(%rax)
jmp 0x6f79
jmp 0x6f7b
jmp 0x6ff8
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0xb(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xb(%rax)
cmpl $0xff, -0x10(%rbp)
jle 0x6ff4
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb 0xd(%rax), %cl
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movb %cl, 0xb(%rax)
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x9(%rax), %eax
andl $0x3, %eax
cmpl $0x0, %eax
jne 0x6ff2
movq -0x8(%rbp), %rax
movq 0x30(%rax), %rax
movzbl 0x8(%rax), %ecx
orl $0x80, %ecx
movb %cl, 0x8(%rax)
jmp 0x6ff4
jmp 0x6ff8
jmp 0x6ff8
jmp 0x6ffa
popq %rbp
retq
nopl (%rax)