// File: NishadSaraf[P]Championship-Simulator/src/cache.cc
// Function: CACHE::add_rq(PACKET*)
int CACHE::add_rq(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);
        }

#ifdef SANITY_CHECK
        if (cache_type == IS_ITLB)
            assert(0);
        else if (cache_type == IS_DTLB)
            assert(0);
        else if (cache_type == IS_L1I)
            assert(0);
#endif
        // update processed packets
        if ((cache_type == IS_L1D) && (packet->type != PREFETCH)) {
            if (PROCESSED.occupancy < PROCESSED.SIZE)
                PROCESSED.add_queue(packet);

            DP ( if (warmup_complete[packet->cpu]) {
            cout << "[" << NAME << "_RQ] " << __func__ << " instr_id: " << packet->instr_id << " found recent writebacks";
            cout << hex << " read: " << packet->address << " writeback: " << WQ.entry[wq_index].address << dec;
            cout << " index: " << MAX_READ << " rob_signal: " << packet->rob_signal << endl; });
        }

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

        WQ.FORWARD++;
        RQ.ACCESS++;

        return -1;
    }

    // check for duplicates in the read queue
    int index = RQ.check_queue(packet);
    if (index != -1) {
        
        if (packet->instruction) {
            uint32_t rob_index = packet->rob_index;
            RQ.entry[index].rob_index_depend_on_me[rob_index] = 1;
            RQ.entry[index].instr_merged = 1;

            DP (if (warmup_complete[packet->cpu]) {
            cout << "[INSTR_MERGED] " << __func__ << " cpu: " << packet->cpu << " instr_id: " << RQ.entry[index].instr_id;
            cout << " merged rob_index: " << rob_index << " instr_id: " << packet->instr_id << endl; });
        }
        else 
        {
            // mark merged consumer
            if (packet->type == RFO) {

                uint32_t sq_index = packet->sq_index;
                RQ.entry[index].sq_index_depend_on_me[sq_index] = 1;
                RQ.entry[index].store_merged = 1;
            }
            else {
                uint32_t lq_index = packet->lq_index; 
                RQ.entry[index].lq_index_depend_on_me[lq_index] = 1;
                RQ.entry[index].load_merged = 1;

                DP (if (warmup_complete[packet->cpu]) {
                cout << "[DATA_MERGED] " << __func__ << " cpu: " << packet->cpu << " instr_id: " << RQ.entry[index].instr_id;
                cout << " merged rob_index: " << packet->rob_index << " instr_id: " << packet->instr_id << " lq_index: " << packet->lq_index << endl; });
            }
        }

        RQ.MERGED++;
        RQ.ACCESS++;

        return index; // merged index
    }

    // check occupancy
    if (RQ.occupancy == RQ_SIZE) {
        RQ.FULL++;

        return -2; // cannot handle this request
    }

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

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

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

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

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

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

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

    RQ.TO_CACHE++;
    RQ.ACCESS++;

    return -1;
}

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x28(%rsp)
movq %rsi, 0x20(%rsp)
movq 0x28(%rsp), %rdi
movq %rdi, (%rsp)
addq $0x73a8, %rdi           # imm = 0x73A8
movq 0x20(%rsp), %rsi
callq 0x14da0
movl %eax, 0x1c(%rsp)
cmpl $-0x1, 0x1c(%rsp)
je 0x83f4
movq (%rsp), %rcx
movq 0x20(%rsp), %rax
movl 0x8(%rax), %eax
cmpl 0x7398(%rcx), %eax
jge 0x82a4
movq (%rsp), %rax
movq 0x7440(%rax), %rax
movslq 0x1c(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x360(%rax), %rcx
movq 0x20(%rsp), %rax
movq %rcx, 0x360(%rax)
movq 0x20(%rsp), %rax
cmpb $0x0, (%rax)
je 0x8283
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x330(%rcx), %ecx
movq 0x8(%rax,%rcx,8), %rdi
movq 0x20(%rsp), %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x82a2
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x330(%rcx), %ecx
movq 0x10(%rax,%rcx,8), %rdi
movq 0x20(%rsp), %rsi
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x82a4
movq (%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x0, %eax
jne 0x82d3
leaq 0x1ad49(%rip), %rdi     # 0x23004
leaq 0x1ad44(%rip), %rsi     # 0x23006
movl $0x3b2, %edx            # imm = 0x3B2
leaq 0x1aed7(%rip), %rcx     # 0x231a5
callq 0x3160
movq (%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x1, %eax
jne 0x8302
leaq 0x1ad1a(%rip), %rdi     # 0x23004
leaq 0x1ad15(%rip), %rsi     # 0x23006
movl $0x3b4, %edx            # imm = 0x3B4
leaq 0x1aea8(%rip), %rcx     # 0x231a5
callq 0x3160
movq (%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x3, %eax
jne 0x8331
leaq 0x1aceb(%rip), %rdi     # 0x23004
leaq 0x1ace6(%rip), %rsi     # 0x23006
movl $0x3b6, %edx            # imm = 0x3B6
leaq 0x1ae79(%rip), %rcx     # 0x231a5
callq 0x3160
jmp 0x8333
jmp 0x8335
movq (%rsp), %rax
movzbl 0x73a4(%rax), %eax
cmpl $0x4, %eax
jne 0x837f
movq 0x20(%rsp), %rax
movzbl 0x32f(%rax), %eax
cmpl $0x2, %eax
je 0x837f
movq (%rsp), %rcx
movl 0xe65c(%rcx), %eax
cmpl 0xe648(%rcx), %eax
jae 0x837d
movq (%rsp), %rdi
addq $0xe628, %rdi           # imm = 0xE628
movq 0x20(%rsp), %rsi
callq 0x15040
jmp 0x837f
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movzbl 0x32f(%rcx), %ecx
movq 0x72c8(%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, 0x72c8(%rax,%rcx,8)
movq 0x20(%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 0x90a8(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90a8(%rax)
movl $0xffffffff, 0x34(%rsp) # imm = 0xFFFFFFFF
jmp 0x885d
movq (%rsp), %rdi
addq $0x9048, %rdi           # imm = 0x9048
movq 0x20(%rsp), %rsi
callq 0x14da0
movl %eax, 0x18(%rsp)
cmpl $-0x1, 0x18(%rsp)
je 0x8561
movq 0x20(%rsp), %rax
cmpb $0x0, (%rax)
je 0x8473
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x10(%rcx), %ecx
movl %ecx, 0x14(%rsp)
movq 0x90e0(%rax), %rcx
movslq 0x18(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movl 0x14(%rsp), %edx
movb $0x1, 0x29(%rcx,%rdx)
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movb $0x1, 0x329(%rax)
jmp 0x852c
movq 0x20(%rsp), %rax
movzbl 0x32f(%rax), %eax
cmpl $0x1, %eax
jne 0x84d8
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x33c(%rcx), %ecx
movl %ecx, 0x10(%rsp)
movq 0x90e0(%rax), %rcx
movslq 0x18(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movl 0x10(%rsp), %edx
movb $0x1, 0x229(%rcx,%rdx)
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movb $0x1, 0x32b(%rax)
jmp 0x852a
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x338(%rcx), %ecx
movl %ecx, 0xc(%rsp)
movq 0x90e0(%rax), %rcx
movslq 0x18(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movl 0xc(%rsp), %edx
movb $0x1, 0x129(%rcx,%rdx)
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movb $0x1, 0x32a(%rax)
jmp 0x852c
movq (%rsp), %rax
movq 0x90b8(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90b8(%rax)
movq 0x90a8(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90a8(%rax)
movl 0x18(%rsp), %eax
movl %eax, 0x34(%rsp)
jmp 0x885d
movq (%rsp), %rcx
movl 0x907c(%rcx), %eax
cmpl 0x7380(%rcx), %eax
jne 0x8596
movq (%rsp), %rax
movq 0x90d8(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90d8(%rax)
movl $0xfffffffe, 0x34(%rsp) # imm = 0xFFFFFFFE
jmp 0x885d
movq (%rsp), %rax
movl 0x9078(%rax), %ecx
movl %ecx, 0x18(%rsp)
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
cmpq $0x0, 0x340(%rax)
je 0x86eb
movq 0x20a21(%rip), %rdi     # 0x28ff0
leaq 0x1aa57(%rip), %rsi     # 0x2302d
callq 0x3220
movq (%rsp), %rsi
movq %rax, %rdi
addq $0x7350, %rsi           # imm = 0x7350
callq 0x31c0
movq %rax, %rdi
leaq 0x1b5ed(%rip), %rsi     # 0x23be5
callq 0x3220
movq %rax, %rdi
leaq 0x1abc2(%rip), %rsi     # 0x231c9
callq 0x3220
movq %rax, %rdi
leaq 0x1abba(%rip), %rsi     # 0x231d0
callq 0x3220
movq %rax, %rdi
movl 0x18(%rsp), %esi
callq 0x33b0
movq 0x209c2(%rip), %rdi     # 0x28ff0
leaq 0x1aaeb(%rip), %rsi     # 0x23120
callq 0x3220
movq %rax, %rdi
leaq 0x126c(%rip), %rsi      # 0x98b0
callq 0x30d0
movq %rax, %rdi
movq (%rsp), %rax
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x340(%rax), %rsi
callq 0x3080
movq 0x20977(%rip), %rdi     # 0x28ff0
leaq 0x1aaab(%rip), %rsi     # 0x2312b
callq 0x3220
movq %rax, %rdi
movq (%rsp), %rax
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x348(%rax), %rsi
callq 0x3080
movq %rax, %rdi
leaq 0x1218(%rip), %rsi      # 0x98d0
callq 0x30d0
movq %rax, %rdi
movq 0x208f1(%rip), %rsi     # 0x28fb8
callq 0x3250
leaq 0x1a931(%rip), %rdi     # 0x23004
leaq 0x1a92c(%rip), %rsi     # 0x23006
movl $0x402, %edx            # imm = 0x402
leaq 0x1aabf(%rip), %rcx     # 0x231a5
callq 0x3160
movq (%rsp), %rax
movq 0x90e0(%rax), %rdi
movslq 0x18(%rsp), %rax
imulq $0x380, %rax, %rax      # imm = 0x380
addq %rax, %rdi
movq 0x20(%rsp), %rsi
movl $0x380, %edx            # imm = 0x380
callq 0x31a0
movq (%rsp), %rax
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
movq 0x378(%rax), %rax
movq 0x20(%rsp), %rcx
movl 0x330(%rcx), %ecx
movl %ecx, %edx
leaq 0x87777(%rip), %rcx     # 0x8fec0
cmpq (%rcx,%rdx,8), %rax
jae 0x8793
movq (%rsp), %rax
movq 0x20(%rsp), %rcx
movl 0x330(%rcx), %ecx
movl %ecx, %edx
leaq 0x87759(%rip), %rcx     # 0x8fec0
movq (%rcx,%rdx,8), %rcx
movl 0x738c(%rax), %edx
addq %rdx, %rcx
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
movq %rcx, 0x378(%rax)
jmp 0x87c1
movq (%rsp), %rax
movl 0x738c(%rax), %ecx
movq 0x90e0(%rax), %rax
movslq 0x18(%rsp), %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rax
addq 0x378(%rax), %rcx
movq %rcx, 0x378(%rax)
movq (%rsp), %rcx
movl 0x907c(%rcx), %eax
addl $0x1, %eax
movl %eax, 0x907c(%rcx)
movl 0x9078(%rcx), %eax
addl $0x1, %eax
movl %eax, 0x9078(%rcx)
movl 0x9078(%rcx), %eax
cmpl 0x9068(%rcx), %eax
jb 0x87ff
movq (%rsp), %rax
movl $0x0, 0x9078(%rax)
movq 0x20(%rsp), %rax
cmpq $0x0, 0x340(%rax)
jne 0x882d
leaq 0x1a7ef(%rip), %rdi     # 0x23004
leaq 0x1a7ea(%rip), %rsi     # 0x23006
movl $0x41a, %edx            # imm = 0x41A
leaq 0x1a97d(%rip), %rcx     # 0x231a5
callq 0x3160
movq (%rsp), %rax
movq 0x90c0(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90c0(%rax)
movq 0x90a8(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x90a8(%rax)
movl $0xffffffff, 0x34(%rsp) # imm = 0xFFFFFFFF
movl 0x34(%rsp), %eax
addq $0x38, %rsp
retq
nopw %cs:(%rax,%rax)