// File: lukasz-wiecaszek[P]h264iframedecoder/picture_cabac.cpp
// Function: ymn::h264::picture_cabac::decode_coded_block_flag(ymn::h264::ctx_block_cat_e, int)
int picture_cabac::decode_coded_block_flag(const enum ctx_block_cat_e ctxBlockCat, int idx)
{
    /* Table 9-34 – Syntax elements and associated types of binarization, maxBinIdxCtx, and ctxIdxOffset
       Table 9-40 – Assignment of ctxIdxBlockCatOffset to ctxBlockCat for syntax elements coded_block_flag,
       significant_coeff_flag, last_significant_coeff_flag, and coeff_abs_level_minus1 */
    static const int base_ctx[CAT_NUM] =
    {
        85 + 0, 85 + 4, 85 + 8, 85 + 12, 85 + 16, // ctxBlockCat < 5
        1012,                                     // ctxBlockCat == 5
        460 + 0, 460 + 4, 460 + 8,                // 5 < ctxBlockCat < 9
        1012 + 4,                                 // ctxBlockCat == 9
        472 + 0, 472 + 4, 472 + 8,                // 9 < ctxBlockCat < 13
        1012 + 8                                  // ctxBlockCat == 13
    };

    int nza, nzb;
    int ctxIdxInc = 0;

    if (idx < 16 * CC_MAX) { /* ac */
        mb_cache& nzc_cache = m_context_variables.non_zero_count_cache[idx / 16];
        const int cache_idx = mb_cache_idx[idx % 16];

        nza = nzc_cache[cache_idx - 1];
        nzb = nzc_cache[cache_idx - 8];
    }
    else { /* dc */
        mb* curr_mb = m_context_variables.curr_mb;

        if (curr_mb->left)
            nza = curr_mb->left->non_zero_count[idx];
        else
            nza = MB_IS_INTRA(curr_mb->type);

        if (curr_mb->top)
            nzb = curr_mb->top->non_zero_count[idx];
        else
            nzb = MB_IS_INTRA(curr_mb->type);
    }

    if (nza > 0)
        ctxIdxInc += 1;

    if (nzb > 0)
        ctxIdxInc += 2;

    return m_cabac_decoder.decode_decision(base_ctx[ctxBlockCat] + ctxIdxInc);
}

// Assembly:
subq $0x48, %rsp
movq %rdi, 0x40(%rsp)
movl %esi, 0x3c(%rsp)
movl %edx, 0x38(%rsp)
movq 0x40(%rsp), %rax
movq %rax, 0x8(%rsp)
movl $0x0, 0x2c(%rsp)
cmpl $0x30, 0x38(%rsp)
jge 0x21296
movq 0x8(%rsp), %rax
addq $0x18, %rax
addq $0x68, %rax
movq %rax, (%rsp)
movl 0x38(%rsp), %eax
movl $0x10, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq (%rsp), %rax
movslq %ecx, %rcx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x20(%rsp)
movl 0x38(%rsp), %eax
movl $0x10, %ecx
cltd
idivl %ecx
movslq %edx, %rcx
leaq 0x7c6a(%rip), %rax      # 0x28ec0
movzbl (%rax,%rcx), %eax
movl %eax, 0x1c(%rsp)
movq 0x20(%rsp), %rdi
movl 0x1c(%rsp), %eax
subl $0x1, %eax
movslq %eax, %rsi
callq 0x22380
movzbl (%rax), %eax
movl %eax, 0x34(%rsp)
movq 0x20(%rsp), %rdi
movl 0x1c(%rsp), %eax
subl $0x8, %eax
movslq %eax, %rsi
callq 0x22380
movzbl (%rax), %eax
movl %eax, 0x30(%rsp)
jmp 0x2130e
movq 0x8(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
cmpq $0x0, 0x38(%rax)
je 0x212c9
movq 0x10(%rsp), %rax
movq 0x38(%rax), %rax
movslq 0x38(%rsp), %rcx
movzbl 0x78(%rax,%rcx), %eax
movl %eax, 0x34(%rsp)
jmp 0x212d8
movq 0x10(%rsp), %rax
movl 0x10(%rax), %eax
andl $0xf, %eax
movl %eax, 0x34(%rsp)
movq 0x10(%rsp), %rax
cmpq $0x0, 0x50(%rax)
je 0x212fd
movq 0x10(%rsp), %rax
movq 0x50(%rax), %rax
movslq 0x38(%rsp), %rcx
movzbl 0x78(%rax,%rcx), %eax
movl %eax, 0x30(%rsp)
jmp 0x2130c
movq 0x10(%rsp), %rax
movl 0x10(%rax), %eax
andl $0xf, %eax
movl %eax, 0x30(%rsp)
jmp 0x2130e
cmpl $0x0, 0x34(%rsp)
jle 0x21320
movl 0x2c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2c(%rsp)
cmpl $0x0, 0x30(%rsp)
jle 0x21332
movl 0x2c(%rsp), %eax
addl $0x2, %eax
movl %eax, 0x2c(%rsp)
movq 0x8(%rsp), %rdi
addq $0xdc0, %rdi            # imm = 0xDC0
movl 0x3c(%rsp), %eax
movl %eax, %ecx
leaq 0x7495(%rip), %rax      # 0x287e0
movl (%rax,%rcx,4), %esi
addl 0x2c(%rsp), %esi
callq 0x18cd0
addq $0x48, %rsp
retq
nopl (%rax)