// File: NishadSaraf[P]Championship-Simulator/src/cache.cc
// Function: CACHE::handle_writeback()
void CACHE::handle_writeback()
{
    // handle write
    uint32_t writeback_cpu = WQ.entry[WQ.head].cpu;
    if (writeback_cpu == NUM_CPUS)
        return;

    // handle the oldest entry
    if ((WQ.entry[WQ.head].event_cycle <= current_core_cycle[writeback_cpu]) && (WQ.occupancy > 0)) {
        int index = WQ.head;

        // access cache
        uint32_t set = get_set(WQ.entry[index].address);
        int way = check_hit(&WQ.entry[index]);
        
        if (way >= 0) { // writeback hit (or RFO hit for L1D)

            if (cache_type == IS_LLC) {
                llc_update_replacement_state(writeback_cpu, set, way, block[set][way].full_addr, WQ.entry[index].ip, 0, WQ.entry[index].type, 1);

            }
            else
                update_replacement_state(writeback_cpu, set, way, block[set][way].full_addr, WQ.entry[index].ip, 0, WQ.entry[index].type, 1);

            // COLLECT STATS
            sim_hit[writeback_cpu][WQ.entry[index].type]++;
            sim_access[writeback_cpu][WQ.entry[index].type]++;

            // mark dirty
            block[set][way].dirty = 1;

            if (cache_type == IS_ITLB)
                WQ.entry[index].instruction_pa = block[set][way].data;
            else if (cache_type == IS_DTLB)
                WQ.entry[index].data_pa = block[set][way].data;
            else if (cache_type == IS_STLB)
                WQ.entry[index].data = block[set][way].data;

            // check fill level
            if (WQ.entry[index].fill_level < fill_level) {

                if (WQ.entry[index].instruction) 
                    upper_level_icache[writeback_cpu]->return_data(&WQ.entry[index]);
                else // data
                    upper_level_dcache[writeback_cpu]->return_data(&WQ.entry[index]);
            }

            HIT[WQ.entry[index].type]++;
            ACCESS[WQ.entry[index].type]++;

            // remove this entry from WQ
            WQ.remove_queue(&WQ.entry[index]);
        }
        else { // writeback miss (or RFO miss for L1D)
            
            DP ( if (warmup_complete[writeback_cpu]) {
            cout << "[" << NAME << "] " << __func__ << " type: " << +WQ.entry[index].type << " miss";
            cout << " instr_id: " << WQ.entry[index].instr_id << " address: " << hex << WQ.entry[index].address;
            cout << " full_addr: " << WQ.entry[index].full_addr << dec;
            cout << " cycle: " << WQ.entry[index].event_cycle << endl; });

            if (cache_type == IS_L1D) { // RFO miss

                // check mshr
                uint8_t miss_handled = 1;
                int mshr_index = check_mshr(&WQ.entry[index]);

                if ((mshr_index == -1) && (MSHR.occupancy < MSHR_SIZE)) { // this is a new miss

                    // add it to mshr (RFO miss)
                    add_mshr(&WQ.entry[index]);

                    // add it to the next level's read queue
                    //if (lower_level) // L1D always has a lower level cache
                        lower_level->add_rq(&WQ.entry[index]);
                }
                else {
                    if ((mshr_index == -1) && (MSHR.occupancy == MSHR_SIZE)) { // not enough MSHR resource
                        
                        // cannot handle miss request until one of MSHRs is available
                        miss_handled = 0;
                        STALL[WQ.entry[index].type]++;
                    }
                    else if (mshr_index != -1) { // already in-flight miss

                        // update fill_level
                        if (WQ.entry[index].fill_level < MSHR.entry[mshr_index].fill_level)
                            MSHR.entry[mshr_index].fill_level = WQ.entry[index].fill_level;

                        // update request
                        if (MSHR.entry[mshr_index].type == PREFETCH) {
                            uint8_t  prior_returned = MSHR.entry[mshr_index].returned;
                            uint64_t prior_event_cycle = MSHR.entry[mshr_index].event_cycle;
                            memcpy(&MSHR.entry[mshr_index], &WQ.entry[index], sizeof(PACKET));

                            // in case request is already returned, we should keep event_cycle and retunred variables
                            MSHR.entry[mshr_index].returned = prior_returned;
                            MSHR.entry[mshr_index].event_cycle = prior_event_cycle;
                        }

                        MSHR_MERGED[WQ.entry[index].type]++;

                        DP ( if (warmup_complete[writeback_cpu]) {
                        cout << "[" << NAME << "] " << __func__ << " mshr merged";
                        cout << " instr_id: " << WQ.entry[index].instr_id << " prior_id: " << MSHR.entry[mshr_index].instr_id; 
                        cout << " address: " << hex << WQ.entry[index].address;
                        cout << " full_addr: " << WQ.entry[index].full_addr << dec;
                        cout << " cycle: " << WQ.entry[index].event_cycle << endl; });
                    }
                    else { // WE SHOULD NOT REACH HERE
                        cerr << "[" << NAME << "] MSHR errors" << endl;
                        assert(0);
                    }
                }

                if (miss_handled) {

                    MISS[WQ.entry[index].type]++;
                    ACCESS[WQ.entry[index].type]++;

                    // remove this entry from WQ
                    WQ.remove_queue(&WQ.entry[index]);
                }

            }
            else {
                // find victim
                uint32_t set = get_set(WQ.entry[index].address), way;
                if (cache_type == IS_LLC) {
                    way = llc_find_victim(writeback_cpu, WQ.entry[index].instr_id, set, block[set], WQ.entry[index].ip, WQ.entry[index].full_addr, WQ.entry[index].type);
                }
                else
                    way = find_victim(writeback_cpu, WQ.entry[index].instr_id, set, block[set], WQ.entry[index].ip, WQ.entry[index].full_addr, WQ.entry[index].type);

#ifdef LLC_BYPASS
                if ((cache_type == IS_LLC) && (way == LLC_WAY)) {
                    cerr << "LLC bypassing for writebacks is not allowed!" << endl;
                    assert(0);
                }
#endif

                uint8_t  do_fill = 1;

                // is this dirty?
                if (block[set][way].dirty) {

                    // check if the lower level WQ has enough room to keep this writeback request
                    if (lower_level) { 
                        if (lower_level->get_occupancy(2) == lower_level->get_size(2)) {

                            // lower level WQ is full, cannot replace this victim
                            do_fill = 0;
                            lower_level->increment_WQ_FULL();
                            STALL[WQ.entry[index].type]++;

                            DP ( if (warmup_complete[writeback_cpu]) {
                            cout << "[" << NAME << "] " << __func__ << "do_fill: " << +do_fill;
                            cout << " lower level wq is full!" << " fill_addr: " << hex << WQ.entry[index].address;
                            cout << " victim_addr: " << block[set][way].tag << dec << endl; });
                        }
                        else { 
                            PACKET writeback_packet;

                            writeback_packet.fill_level = fill_level << 1;
                            writeback_packet.cpu = writeback_cpu;
                            writeback_packet.address = block[set][way].address;
                            writeback_packet.full_addr = block[set][way].full_addr;
                            writeback_packet.data = block[set][way].data;
                            writeback_packet.instr_id = WQ.entry[index].instr_id;
                            writeback_packet.ip = 0;
                            writeback_packet.type = WRITEBACK;
                            writeback_packet.event_cycle = current_core_cycle[writeback_cpu];

                            lower_level->add_wq(&writeback_packet);
                        }
                    }
#ifdef SANITY_CHECK
                    else {
                        // sanity check
                        if (cache_type != IS_STLB)
                            assert(0);
                    }
#endif
                }

                if (do_fill) {
                    // update prefetcher
                    if (cache_type == IS_L1D)
                        l1d_prefetcher_cache_fill(WQ.entry[index].full_addr, set, way, 0, block[set][way].full_addr);
                    else if (cache_type == IS_L2C)
                        l2c_prefetcher_cache_fill(WQ.entry[index].full_addr, set, way, 0, block[set][way].full_addr);

                    // update replacement policy
                    if (cache_type == IS_LLC) {
                        llc_update_replacement_state(writeback_cpu, set, way, WQ.entry[index].full_addr, WQ.entry[index].ip, block[set][way].full_addr, WQ.entry[index].type, 0);

                    }
                    else
                        update_replacement_state(writeback_cpu, set, way, WQ.entry[index].full_addr, WQ.entry[index].ip, block[set][way].full_addr, WQ.entry[index].type, 0);

                    // COLLECT STATS
                    sim_miss[writeback_cpu][WQ.entry[index].type]++;
                    sim_access[writeback_cpu][WQ.entry[index].type]++;

                    fill_cache(set, way, &WQ.entry[index]);

                    // mark dirty
                    block[set][way].dirty = 1; 

                    // check fill level
                    if (WQ.entry[index].fill_level < fill_level) {

                        if (WQ.entry[index].instruction) 
                            upper_level_icache[writeback_cpu]->return_data(&WQ.entry[index]);
                        else // data
                            upper_level_dcache[writeback_cpu]->return_data(&WQ.entry[index]);
                    }

                    MISS[WQ.entry[index].type]++;
                    ACCESS[WQ.entry[index].type]++;

                    // remove this entry from WQ
                    WQ.remove_queue(&WQ.entry[index]);
                }
            }
        }
    }
}

// Assembly:
subq $0x3e8, %rsp            # imm = 0x3E8
movq %rdi, 0x3e0(%rsp)
movq 0x3e0(%rsp), %rcx
movq %rcx, 0x20(%rsp)
movq 0x7440(%rcx), %rax
movl 0x73d4(%rcx), %ecx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movl 0x330(%rax), %eax
movl %eax, 0x3dc(%rsp)
cmpl $0x1, 0x3dc(%rsp)
jne 0x4f2f
jmp 0x613d
movq 0x20(%rsp), %rcx
movq 0x7440(%rcx), %rax
movl 0x73d4(%rcx), %ecx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x378(%rax), %rax
movl 0x3dc(%rsp), %ecx
movl %ecx, %edx
leaq 0x8af5e(%rip), %rcx     # 0x8fec0
cmpq (%rcx,%rdx,8), %rax
ja 0x613d
movq 0x20(%rsp), %rax
cmpl $0x0, 0x73dc(%rax)
jbe 0x613d
movq 0x20(%rsp), %rdi
movl 0x73d4(%rdi), %eax
movl %eax, 0x3d8(%rsp)
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x340(%rax), %rsi
callq 0x49b0
movq 0x20(%rsp), %rdi
movl %eax, 0x3d4(%rsp)
movq 0x7440(%rdi), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x6150
movl %eax, 0x3d0(%rsp)
cmpl $0x0, 0x3d0(%rsp)
jl 0x545d
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x6, %eax
jne 0x50aa
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movl 0x3d4(%rsp), %edx
movl 0x3d0(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3d4(%rsp), %r8d
movq (%rax,%r8,8), %rax
movslq 0x3d0(%rsp), %r8
imulq $0x50, %r8, %r8
addq %r8, %rax
movq 0x20(%rax), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r10
imulq $0x380, %r10, %r10      # imm = 0x380
addq %r10, %rax
movzbl 0x32f(%rax), %eax
xorl %r10d, %r10d
movq $0x0, (%rsp)
movl %eax, 0x8(%rsp)
movl $0x1, 0x10(%rsp)
callq 0x22750
jmp 0x5146
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movl 0x3d4(%rsp), %edx
movl 0x3d0(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3d4(%rsp), %r8d
movq (%rax,%r8,8), %rax
movslq 0x3d0(%rsp), %r8
imulq $0x50, %r8, %r8
addq %r8, %rax
movq 0x20(%rax), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r10
imulq $0x380, %r10, %r10      # imm = 0x380
addq %r10, %rax
movzbl 0x32f(%rax), %eax
xorl %r10d, %r10d
movq $0x0, (%rsp)
movl %eax, 0x8(%rsp)
movl $0x1, 0x10(%rsp)
callq 0x22510
movq 0x20(%rsp), %rax
movq %rax, %rcx
addq $0x10308, %rcx          # imm = 0x10308
movl 0x3dc(%rsp), %edx
shlq $0x5, %rdx
addq %rdx, %rcx
movq 0x7440(%rax), %rdx
movslq 0x3d8(%rsp), %rsi
imulq $0x380, %rsi, %rsi      # imm = 0x380
addq %rsi, %rdx
movzbl 0x32f(%rdx), %edx
movq (%rcx,%rdx,8), %rsi
addq $0x1, %rsi
movq %rsi, (%rcx,%rdx,8)
movq %rax, %rcx
addq $0x102e8, %rcx          # imm = 0x102E8
movl 0x3dc(%rsp), %edx
shlq $0x5, %rdx
addq %rdx, %rcx
movq 0x7440(%rax), %rdx
movslq 0x3d8(%rsp), %rsi
imulq $0x380, %rsi, %rsi      # imm = 0x380
addq %rsi, %rdx
movzbl 0x32f(%rdx), %edx
movq (%rcx,%rdx,8), %rsi
addq $0x1, %rsi
movq %rsi, (%rcx,%rdx,8)
movq 0x7390(%rax), %rcx
movl 0x3d4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movslq 0x3d0(%rsp), %rdx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movb $0x1, 0x2(%rcx)
movzbl 0x73a4(%rax), %eax
cmpl $0x0, %eax
jne 0x5253
movq 0x20(%rsp), %rax
movq 0x7390(%rax), %rcx
movl 0x3d4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movslq 0x3d0(%rsp), %rdx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x30(%rcx), %rcx
movq 0x7440(%rax), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x350(%rax)
jmp 0x530f
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x1, %eax
jne 0x52b0
movq 0x20(%rsp), %rax
movq 0x7390(%rax), %rcx
movl 0x3d4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movslq 0x3d0(%rsp), %rdx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x30(%rcx), %rcx
movq 0x7440(%rax), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x358(%rax)
jmp 0x530d
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x2, %eax
jne 0x530b
movq 0x20(%rsp), %rax
movq 0x7390(%rax), %rcx
movl 0x3d4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movslq 0x3d0(%rsp), %rdx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x30(%rcx), %rcx
movq 0x7440(%rax), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x360(%rax)
jmp 0x530d
jmp 0x530f
movq 0x20(%rsp), %rcx
movq 0x7440(%rcx), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movl 0x8(%rax), %eax
cmpl 0x7398(%rcx), %eax
jge 0x53c3
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
cmpb $0x0, (%rax)
je 0x5391
movq 0x20(%rsp), %rax
movl 0x3dc(%rsp), %ecx
movq 0x8(%rax,%rcx,8), %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x53c1
movq 0x20(%rsp), %rax
movl 0x3dc(%rsp), %ecx
movq 0x10(%rax,%rcx,8), %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x53c3
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72c8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72c8(%rax,%rcx,8)
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72a8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72a8(%rax,%rcx,8)
movq %rax, %rdi
addq $0x73a8, %rdi           # imm = 0x73A8
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x150e0
jmp 0x613b
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x4, %eax
jne 0x5858
movq 0x20(%rsp), %rdi
movb $0x1, 0x3cf(%rsp)
movq 0x7440(%rdi), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x6370
movl %eax, 0x3c8(%rsp)
cmpl $-0x1, 0x3c8(%rsp)
jne 0x5510
movq 0x20(%rsp), %rcx
movl 0xc9bc(%rcx), %eax
cmpl 0x7388(%rcx), %eax
jae 0x5510
movq 0x20(%rsp), %rdi
movq 0x7440(%rdi), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x6400
movq 0x20(%rsp), %rax
movq 0x18(%rax), %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movq (%rdi), %rax
callq *(%rax)
jmp 0x57b0
cmpl $-0x1, 0x3c8(%rsp)
jne 0x5573
movq 0x20(%rsp), %rcx
movl 0xc9bc(%rcx), %eax
cmpl 0x7388(%rcx), %eax
jne 0x5573
movq 0x20(%rsp), %rax
movb $0x0, 0x3cf(%rsp)
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x7328(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x7328(%rax,%rcx,8)
jmp 0x57ae
cmpl $-0x1, 0x3c8(%rsp)
je 0x5748
movq 0x20(%rsp), %rcx
movq 0x7440(%rcx), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movl 0x8(%rax), %eax
movq 0xca20(%rcx), %rcx
movslq 0x3c8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
cmpl 0x8(%rcx), %eax
jge 0x55fd
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movl 0x8(%rcx), %ecx
movq 0xca20(%rax), %rax
movslq 0x3c8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movl %ecx, 0x8(%rax)
movq 0x20(%rsp), %rax
movq 0xca20(%rax), %rax
movslq 0x3c8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movzbl 0x32f(%rax), %eax
cmpl $0x2, %eax
jne 0x570d
movq 0x20(%rsp), %rax
movq 0xca20(%rax), %rcx
movslq 0x3c8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movb 0x32c(%rcx), %cl
movb %cl, 0x3c7(%rsp)
movq 0xca20(%rax), %rcx
movslq 0x3c8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movq 0x378(%rcx), %rcx
movq %rcx, 0x3b8(%rsp)
movq 0xca20(%rax), %rdi
movslq 0x3c8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movl $0x380, %edx            # imm = 0x380
callq 0x31a0
movq 0x20(%rsp), %rax
movb 0x3c7(%rsp), %dl
movq 0xca20(%rax), %rcx
movslq 0x3c8(%rsp), %rsi
imulq $0x380, %rsi, %rsi      # imm = 0x380
addq %rsi, %rcx
movb %dl, 0x32c(%rcx)
movq 0x3b8(%rsp), %rcx
movq 0xca20(%rax), %rax
movslq 0x3c8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x378(%rax)
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x7308(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x7308(%rax,%rcx,8)
jmp 0x57ac
movq 0x238a1(%rip), %rdi     # 0x28ff0
leaq 0x1d8d7(%rip), %rsi     # 0x2302d
callq 0x3220
movq 0x20(%rsp), %rsi
movq %rax, %rdi
addq $0x7350, %rsi           # imm = 0x7350
callq 0x31c0
movq %rax, %rdi
leaq 0x1d8b6(%rip), %rsi     # 0x2302f
callq 0x3220
movq %rax, %rdi
movq 0x23830(%rip), %rsi     # 0x28fb8
callq 0x3250
leaq 0x1d870(%rip), %rdi     # 0x23004
leaq 0x1d86b(%rip), %rsi     # 0x23006
movl $0x11a, %edx            # imm = 0x11A
leaq 0x1d896(%rip), %rcx     # 0x2303d
callq 0x3160
jmp 0x57ae
jmp 0x57b0
cmpb $0x0, 0x3cf(%rsp)
je 0x5853
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72e8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72e8(%rax,%rcx,8)
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72a8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72a8(%rax,%rcx,8)
movq %rax, %rdi
addq $0x73a8, %rdi           # imm = 0x73A8
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x150e0
jmp 0x6139
movq 0x20(%rsp), %rdi
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x340(%rax), %rsi
callq 0x49b0
movl %eax, %ecx
movq 0x20(%rsp), %rax
movl %ecx, 0x3b4(%rsp)
movzbl 0x73a4(%rax), %eax
cmpl $0x6, %eax
jne 0x595f
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x368(%rax), %rdx
movl 0x3b4(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r8d
movq (%rax,%r8,8), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r10
imulq $0x380, %r10, %r10      # imm = 0x380
addq %r10, %rax
movq 0x348(%rax), %r10
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r11
imulq $0x380, %r11, %r11      # imm = 0x380
addq %r11, %rax
movzbl 0x32f(%rax), %eax
movq %r10, (%rsp)
movl %eax, 0x8(%rsp)
callq 0x226f0
movl %eax, 0x3b0(%rsp)
jmp 0x5a19
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x368(%rax), %rdx
movl 0x3b4(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r8d
movq (%rax,%r8,8), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r10
imulq $0x380, %r10, %r10      # imm = 0x380
addq %r10, %rax
movq 0x348(%rax), %r10
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r11
imulq $0x380, %r11, %r11      # imm = 0x380
addq %r11, %rax
movzbl 0x32f(%rax), %eax
movq %r10, (%rsp)
movl %eax, 0x8(%rsp)
callq 0x22300
movl %eax, 0x3b0(%rsp)
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x6, %eax
jne 0x5a75
cmpl $0x10, 0x3b0(%rsp)
jne 0x5a75
movq 0x235b5(%rip), %rdi     # 0x28ff0
leaq 0x1d61a(%rip), %rsi     # 0x2305c
callq 0x3220
movq %rax, %rdi
movq 0x23567(%rip), %rsi     # 0x28fb8
callq 0x3250
leaq 0x1d5a7(%rip), %rdi     # 0x23004
leaq 0x1d5a2(%rip), %rsi     # 0x23006
movl $0x134, %edx            # imm = 0x134
leaq 0x1d5cd(%rip), %rcx     # 0x2303d
callq 0x3160
movq 0x20(%rsp), %rax
movb $0x1, 0x3af(%rsp)
movq 0x7390(%rax), %rax
movl 0x3b4(%rsp), %ecx
movq (%rax,%rcx,8), %rax
movl 0x3b0(%rsp), %ecx
imulq $0x50, %rcx, %rcx
addq %rcx, %rax
cmpb $0x0, 0x2(%rax)
je 0x5c93
movq 0x20(%rsp), %rax
cmpq $0x0, 0x18(%rax)
je 0x5c5f
movq 0x20(%rsp), %rax
movq 0x18(%rax), %rdi
movq (%rdi), %rax
movl $0x2, %esi
callq *0x30(%rax)
movl %eax, %ecx
movq 0x20(%rsp), %rax
movl %ecx, 0x1c(%rsp)
movq 0x18(%rax), %rdi
movq (%rdi), %rax
movl $0x2, %esi
callq *0x38(%rax)
movl %eax, %ecx
movl 0x1c(%rsp), %eax
cmpl %ecx, %eax
jne 0x5b49
movq 0x20(%rsp), %rax
movb $0x0, 0x3af(%rsp)
movq 0x18(%rax), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x7328(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x7328(%rax,%rcx,8)
jmp 0x5c5d
leaq 0x28(%rsp), %rdi
callq 0x9750
movq 0x20(%rsp), %rax
movl 0x7398(%rax), %ecx
shll %ecx
movl %ecx, 0x30(%rsp)
movl 0x3dc(%rsp), %ecx
movl %ecx, 0x358(%rsp)
movq 0x7390(%rax), %rcx
movl 0x3b4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movl 0x3b0(%rsp), %edx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x18(%rcx), %rcx
movq %rcx, 0x368(%rsp)
movq 0x7390(%rax), %rcx
movl 0x3b4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movl 0x3b0(%rsp), %edx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x20(%rcx), %rcx
movq %rcx, 0x370(%rsp)
movq 0x7390(%rax), %rcx
movl 0x3b4(%rsp), %edx
movq (%rcx,%rdx,8), %rcx
movl 0x3b0(%rsp), %edx
imulq $0x50, %rdx, %rdx
addq %rdx, %rcx
movq 0x30(%rcx), %rcx
movq %rcx, 0x388(%rsp)
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movq 0x368(%rcx), %rcx
movq %rcx, 0x390(%rsp)
movq $0x0, 0x398(%rsp)
movb $0x3, 0x357(%rsp)
movl 0x3dc(%rsp), %ecx
movl %ecx, %edx
leaq 0x8a27e(%rip), %rcx     # 0x8fec0
movq (%rcx,%rdx,8), %rcx
movq %rcx, 0x3a0(%rsp)
movq 0x18(%rax), %rdi
movq (%rdi), %rax
leaq 0x28(%rsp), %rsi
callq *0x8(%rax)
jmp 0x5c91
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x2, %eax
je 0x5c8f
leaq 0x1d38d(%rip), %rdi     # 0x23004
leaq 0x1d388(%rip), %rsi     # 0x23006
movl $0x15f, %edx            # imm = 0x15F
leaq 0x1d3b3(%rip), %rcx     # 0x2303d
callq 0x3160
jmp 0x5c91
jmp 0x5c93
cmpb $0x0, 0x3af(%rsp)
je 0x6137
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x4, %eax
jne 0x5d15
movq 0x20(%rsp), %rdi
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x348(%rax), %rsi
movl 0x3b4(%rsp), %edx
movl 0x3b0(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r8d
movq (%rax,%r8,8), %rax
movl 0x3b0(%rsp), %r8d
imulq $0x50, %r8, %r8
addq %r8, %rax
movq 0x20(%rax), %r9
xorl %r8d, %r8d
callq 0x229a0
jmp 0x5d89
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x5, %eax
jne 0x5d87
movq 0x20(%rsp), %rdi
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x348(%rax), %rsi
movl 0x3b4(%rsp), %edx
movl 0x3b0(%rsp), %ecx
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r8d
movq (%rax,%r8,8), %rax
movl 0x3b0(%rsp), %r8d
imulq $0x50, %r8, %r8
addq %r8, %rax
movq 0x20(%rax), %r9
xorl %r8d, %r8d
callq 0x22940
jmp 0x5d89
movq 0x20(%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x6, %eax
jne 0x5e5b
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movl 0x3b4(%rsp), %edx
movl 0x3b0(%rsp), %ecx
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r8
imulq $0x380, %r8, %r8        # imm = 0x380
addq %r8, %rax
movq 0x348(%rax), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r10d
movq (%rax,%r10,8), %rax
movl 0x3b0(%rsp), %r10d
imulq $0x50, %r10, %r10
addq %r10, %rax
movq 0x20(%rax), %r10
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r11
imulq $0x380, %r11, %r11      # imm = 0x380
addq %r11, %rax
movzbl 0x32f(%rax), %eax
xorl %r11d, %r11d
movq %r10, (%rsp)
movl %eax, 0x8(%rsp)
movl $0x0, 0x10(%rsp)
callq 0x22750
jmp 0x5f13
movq 0x20(%rsp), %rdi
movl 0x3dc(%rsp), %esi
movl 0x3b4(%rsp), %edx
movl 0x3b0(%rsp), %ecx
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r8
imulq $0x380, %r8, %r8        # imm = 0x380
addq %r8, %rax
movq 0x348(%rax), %r8
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r9
imulq $0x380, %r9, %r9        # imm = 0x380
addq %r9, %rax
movq 0x370(%rax), %r9
movq 0x7390(%rdi), %rax
movl 0x3b4(%rsp), %r10d
movq (%rax,%r10,8), %rax
movl 0x3b0(%rsp), %r10d
imulq $0x50, %r10, %r10
addq %r10, %rax
movq 0x20(%rax), %r10
movq 0x7440(%rdi), %rax
movslq 0x3d8(%rsp), %r11
imulq $0x380, %r11, %r11      # imm = 0x380
addq %r11, %rax
movzbl 0x32f(%rax), %eax
xorl %r11d, %r11d
movq %r10, (%rsp)
movl %eax, 0x8(%rsp)
movl $0x0, 0x10(%rsp)
callq 0x22510
movq 0x20(%rsp), %rdi
movq %rdi, %rax
addq $0x10328, %rax          # imm = 0x10328
movl 0x3dc(%rsp), %ecx
shlq $0x5, %rcx
addq %rcx, %rax
movq 0x7440(%rdi), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq (%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, (%rax,%rcx,8)
movq %rdi, %rax
addq $0x102e8, %rax          # imm = 0x102E8
movl 0x3dc(%rsp), %ecx
shlq $0x5, %rcx
addq %rcx, %rax
movq 0x7440(%rdi), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq (%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, (%rax,%rcx,8)
movl 0x3b4(%rsp), %esi
movl 0x3b0(%rsp), %edx
movq 0x7440(%rdi), %rcx
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rcx
callq 0x4b00
movq 0x20(%rsp), %rcx
movq 0x7390(%rcx), %rax
movl 0x3b4(%rsp), %edx
movq (%rax,%rdx,8), %rax
movl 0x3b0(%rsp), %edx
imulq $0x50, %rdx, %rdx
addq %rdx, %rax
movb $0x1, 0x2(%rax)
movq 0x7440(%rcx), %rax
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movl 0x8(%rax), %eax
cmpl 0x7398(%rcx), %eax
jge 0x60a2
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rax
movslq 0x3d8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
cmpb $0x0, (%rax)
je 0x6070
movq 0x20(%rsp), %rax
movl 0x3dc(%rsp), %ecx
movq 0x8(%rax,%rcx,8), %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x60a0
movq 0x20(%rsp), %rax
movl 0x3dc(%rsp), %ecx
movq 0x10(%rax,%rcx,8), %rdi
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x60a2
movq 0x20(%rsp), %rax
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72e8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72e8(%rax,%rcx,8)
movq 0x7440(%rax), %rcx
movslq 0x3d8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72a8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72a8(%rax,%rcx,8)
movq %rax, %rdi
addq $0x73a8, %rdi           # imm = 0x73A8
movq 0x7440(%rax), %rsi
movslq 0x3d8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rsi
callq 0x150e0
jmp 0x6139
jmp 0x613b
jmp 0x613d
addq $0x3e8, %rsp            # imm = 0x3E8
retq
nopw %cs:(%rax,%rax)