// File: NishadSaraf[P]Championship-Simulator/src/cache.cc
// Function: CACHE::add_pq(PACKET*)
int CACHE::add_pq(PACKET *packet)
{
    // check for the latest wirtebacks in the write queue
    int wq_index = WQ.check_queue(packet);
    if (wq_index != -1) {
        
        // check fill level
        if (packet->fill_level < fill_level) {

            packet->data = WQ.entry[wq_index].data;
            if (packet->instruction) 
                upper_level_icache[packet->cpu]->return_data(packet);
            else // data
                upper_level_dcache[packet->cpu]->return_data(packet);
        }

        HIT[packet->type]++;
        ACCESS[packet->type]++;

        WQ.FORWARD++;
        PQ.ACCESS++;

        return -1;
    }

    // check for duplicates in the PQ
    int index = PQ.check_queue(packet);
    if (index != -1) {
        if (packet->fill_level < PQ.entry[index].fill_level)
            PQ.entry[index].fill_level = packet->fill_level;

        PQ.MERGED++;
        PQ.ACCESS++;

        return index; // merged index
    }

    // check occupancy
    if (PQ.occupancy == PQ_SIZE) {
        PQ.FULL++;

        DP ( if (warmup_complete[packet->cpu]) {
        cout << "[" << NAME << "] cannot process add_pq since it is full" << endl; });
        return -2; // cannot handle this request
    }

    // if there is no duplicate, add it to PQ
    index = PQ.tail;

#ifdef SANITY_CHECK
    if (PQ.entry[index].address != 0) {
        cerr << "[" << NAME << "_ERROR] " << __func__ << " is not empty index: " << index;
        cerr << " address: " << hex << PQ.entry[index].address;
        cerr << " full_addr: " << PQ.entry[index].full_addr << dec << endl;
        assert(0);
    }
#endif

    memcpy(&PQ.entry[index], packet, sizeof(PACKET));

    // ADD LATENCY
    if (PQ.entry[index].event_cycle < current_core_cycle[packet->cpu])
        PQ.entry[index].event_cycle = current_core_cycle[packet->cpu] + LATENCY;
    else
        PQ.entry[index].event_cycle += LATENCY;

    PQ.occupancy++;
    PQ.tail++;
    if (PQ.tail >= PQ.SIZE)
        PQ.tail = 0;

    DP ( if (warmup_complete[PQ.entry[index].cpu]) {
    cout << "[" << NAME << "_PQ] " <<  __func__ << " instr_id: " << PQ.entry[index].instr_id << " address: " << hex << PQ.entry[index].address;
    cout << " full_addr: " << PQ.entry[index].full_addr << dec;
    cout << " type: " << +PQ.entry[index].type << " head: " << PQ.head << " tail: " << PQ.tail << " occupancy: " << PQ.occupancy;
    cout << " event: " << PQ.entry[index].event_cycle << " current: " << current_core_cycle[PQ.entry[index].cpu] << endl; });

    if (packet->address == 0)
        assert(0);

    PQ.TO_CACHE++;
    PQ.ACCESS++;

    return -1;
}

// Assembly:
subq $0x28, %rsp
movq %rdi, 0x18(%rsp)
movq %rsi, 0x10(%rsp)
movq 0x18(%rsp), %rdi
movq %rdi, (%rsp)
addq $0x73a8, %rdi           # imm = 0x73A8
movq 0x10(%rsp), %rsi
callq 0x14da0
movl %eax, 0xc(%rsp)
cmpl $-0x1, 0xc(%rsp)
je 0x8f89
movq (%rsp), %rcx
movq 0x10(%rsp), %rax
movl 0x8(%rax), %eax
cmpl 0x7398(%rcx), %eax
jge 0x8f14
movq (%rsp), %rax
movq 0x7440(%rax), %rax
movslq 0xc(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x360(%rax), %rcx
movq 0x10(%rsp), %rax
movq %rcx, 0x360(%rax)
movq 0x10(%rsp), %rax
cmpb $0x0, (%rax)
je 0x8ef3
movq (%rsp), %rax
movq 0x10(%rsp), %rcx
movl 0x330(%rcx), %ecx
movq 0x8(%rax,%rcx,8), %rdi
movq 0x10(%rsp), %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x8f12
movq (%rsp), %rax
movq 0x10(%rsp), %rcx
movl 0x330(%rcx), %ecx
movq 0x10(%rax,%rcx,8), %rdi
movq 0x10(%rsp), %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x8f14
movq (%rsp), %rax
movq 0x10(%rsp), %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72c8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72c8(%rax,%rcx,8)
movq 0x10(%rsp), %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72a8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72a8(%rax,%rcx,8)
movq 0x7410(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x7410(%rax)
movq 0xad48(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad48(%rax)
movl $0xffffffff, 0x24(%rsp) # imm = 0xFFFFFFFF
jmp 0x932a
movq (%rsp), %rdi
addq $0xace8, %rdi           # imm = 0xACE8
movq 0x10(%rsp), %rsi
callq 0x14da0
movl %eax, 0x8(%rsp)
cmpl $-0x1, 0x8(%rsp)
je 0x902e
movq (%rsp), %rcx
movq 0x10(%rsp), %rax
movl 0x8(%rax), %eax
movq 0xad80(%rcx), %rcx
movslq 0x8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
cmpl 0x8(%rcx), %eax
jge 0x8ff9
movq (%rsp), %rax
movq 0x10(%rsp), %rcx
movl 0x8(%rcx), %ecx
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movl %ecx, 0x8(%rax)
movq (%rsp), %rax
movq 0xad58(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad58(%rax)
movq 0xad48(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad48(%rax)
movl 0x8(%rsp), %eax
movl %eax, 0x24(%rsp)
jmp 0x932a
movq (%rsp), %rcx
movl 0xad1c(%rcx), %eax
cmpl 0x7384(%rcx), %eax
jne 0x9063
movq (%rsp), %rax
movq 0xad78(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad78(%rax)
movl $0xfffffffe, 0x24(%rsp) # imm = 0xFFFFFFFE
jmp 0x932a
movq (%rsp), %rax
movl 0xad18(%rax), %ecx
movl %ecx, 0x8(%rsp)
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
cmpq $0x0, 0x340(%rax)
je 0x91b8
movq 0x1ff54(%rip), %rdi     # 0x28ff0
leaq 0x19f8a(%rip), %rsi     # 0x2302d
callq 0x3220
movq (%rsp), %rsi
movq %rax, %rdi
addq $0x7350, %rsi           # imm = 0x7350
callq 0x31c0
movq %rax, %rdi
leaq 0x1ab20(%rip), %rsi     # 0x23be5
callq 0x3220
movq %rax, %rdi
leaq 0x1a13d(%rip), %rsi     # 0x23211
callq 0x3220
movq %rax, %rdi
leaq 0x1a0ed(%rip), %rsi     # 0x231d0
callq 0x3220
movq %rax, %rdi
movl 0x8(%rsp), %esi
callq 0x33b0
movq 0x1fef5(%rip), %rdi     # 0x28ff0
leaq 0x1a01e(%rip), %rsi     # 0x23120
callq 0x3220
movq %rax, %rdi
leaq 0x79f(%rip), %rsi       # 0x98b0
callq 0x30d0
movq %rax, %rdi
movq (%rsp), %rax
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x340(%rax), %rsi
callq 0x3080
movq 0x1feaa(%rip), %rdi     # 0x28ff0
leaq 0x19fde(%rip), %rsi     # 0x2312b
callq 0x3220
movq %rax, %rdi
movq (%rsp), %rax
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x348(%rax), %rsi
callq 0x3080
movq %rax, %rdi
leaq 0x74b(%rip), %rsi       # 0x98d0
callq 0x30d0
movq %rax, %rdi
movq 0x1fe24(%rip), %rsi     # 0x28fb8
callq 0x3250
leaq 0x19e64(%rip), %rdi     # 0x23004
leaq 0x19e5f(%rip), %rsi     # 0x23006
movl $0x4c9, %edx            # imm = 0x4C9
leaq 0x1a065(%rip), %rcx     # 0x23218
callq 0x3160
movq (%rsp), %rax
movq 0xad80(%rax), %rdi
movslq 0x8(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rdi
movq 0x10(%rsp), %rsi
movl $0x380, %edx            # imm = 0x380
callq 0x31a0
movq (%rsp), %rax
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x378(%rax), %rax
movq 0x10(%rsp), %rcx
movl 0x330(%rcx), %ecx
movl %ecx, %edx
leaq 0x86caa(%rip), %rcx     # 0x8fec0
cmpq (%rcx,%rdx,8), %rax
jae 0x9260
movq (%rsp), %rax
movq 0x10(%rsp), %rcx
movl 0x330(%rcx), %ecx
movl %ecx, %edx
leaq 0x86c8c(%rip), %rcx     # 0x8fec0
movq (%rcx,%rdx,8), %rcx
movl 0x738c(%rax), %edx
addq %rdx, %rcx
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x378(%rax)
jmp 0x928e
movq (%rsp), %rax
movl 0x738c(%rax), %ecx
movq 0xad80(%rax), %rax
movslq 0x8(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
addq 0x378(%rax), %rcx
movq %rcx, 0x378(%rax)
movq (%rsp), %rcx
movl 0xad1c(%rcx), %eax
addl $0x1, %eax
movl %eax, 0xad1c(%rcx)
movl 0xad18(%rcx), %eax
addl $0x1, %eax
movl %eax, 0xad18(%rcx)
movl 0xad18(%rcx), %eax
cmpl 0xad08(%rcx), %eax
jb 0x92cc
movq (%rsp), %rax
movl $0x0, 0xad18(%rax)
movq 0x10(%rsp), %rax
cmpq $0x0, 0x340(%rax)
jne 0x92fa
leaq 0x19d22(%rip), %rdi     # 0x23004
leaq 0x19d1d(%rip), %rsi     # 0x23006
movl $0x4e1, %edx            # imm = 0x4E1
leaq 0x19f23(%rip), %rcx     # 0x23218
callq 0x3160
movq (%rsp), %rax
movq 0xad60(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad60(%rax)
movq 0xad48(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0xad48(%rax)
movl $0xffffffff, 0x24(%rsp) # imm = 0xFFFFFFFF
movl 0x24(%rsp), %eax
addq $0x28, %rsp
retq
nopw %cs:(%rax,%rax)