// File: /workspace/github_cpp_makefile_star2_O2/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:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
movq %rsi, %r14
movq %rdi, %rbx
addq $0x73a8, %rdi           # imm = 0x73A8
callq 0x9b10
cmpl $-0x1, %eax
je 0x4853
movl 0x8(%r14), %ecx
cmpl 0x7398(%rbx), %ecx
jge 0x47ea
movq 0x7440(%rbx), %rcx
cltq
imulq $0x380, %rax, %rax      # imm = 0x380
movq 0x360(%rcx,%rax), %rax
movq %rax, 0x360(%r14)
xorl %eax, %eax
cmpb $0x0, (%r14)
sete %al
movl 0x330(%r14), %ecx
leaq (%rbx,%rax,8), %rax
movq 0x8(%rax,%rcx,8), %rdi
movq (%rdi), %rax
movq %r14, %rsi
callq *0x18(%rax)
movzbl 0x73a4(%rbx), %eax
cmpq $0x4, %rax
ja 0x482e
leaq 0xb82e(%rip), %rcx      # 0x1002c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpb $0x2, 0x32f(%r14)
je 0x482e
movl 0xe65c(%rbx), %eax
cmpl 0xe648(%rbx), %eax
jae 0x482e
leaq 0xe628(%rbx), %rdi
movq %r14, %rsi
callq 0x9c5e
movzbl 0x32f(%r14), %eax
incq 0x72c8(%rbx,%rax,8)
incq 0x72a8(%rbx,%rax,8)
pushq $-0x1
popq %rax
movl $0x7410, %ecx           # imm = 0x7410
jmp 0x49d8
leaq 0x9048(%rbx), %rdi
movq %r14, %rsi
callq 0x9b10
cmpl $-0x1, %eax
je 0x48a1
cmpb $0x0, (%r14)
je 0x48bc
movl 0x10(%r14), %ecx
movslq %eax, %rdx
imulq $0x380, %rdx, %rdx      # imm = 0x380
movq 0x90e0(%rbx), %rsi
addq %rdx, %rsi
movb $0x1, %dil
movb %dil, 0x29(%rcx,%rsi)
movq 0x90e0(%rbx), %rcx
movb %dil, 0x329(%rcx,%rdx)
jmp 0x49d3
movl 0x907c(%rbx), %eax
cmpl 0x7380(%rbx), %eax
jne 0x4904
pushq $-0x2
popq %rax
movl $0x90d8, %ecx           # imm = 0x90D8
jmp 0x49e1
cmpb $0x1, 0x32f(%r14)
movq 0x90e0(%rbx), %rcx
movslq %eax, %rdx
jne 0x49a8
movl 0x33c(%r14), %esi
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movb $0x1, %dil
movb %dil, 0x229(%rsi,%rcx)
movq 0x90e0(%rbx), %rcx
movb %dil, 0x32b(%rcx,%rdx)
jmp 0x49d3
movslq 0x9078(%rbx), %r15
movq 0x90e0(%rbx), %rdi
imulq $0x380, %r15, %r12      # imm = 0x380
cmpq $0x0, 0x340(%rdi,%r12)
jne 0x4a4e
addq %r12, %rdi
movl $0x380, %edx            # imm = 0x380
movq %r14, %rsi
callq 0x21b0
movq 0x90e0(%rbx), %rax
movq 0x378(%rax,%r12), %rcx
movl 0x330(%r14), %edx
leaq 0x7855b(%rip), %rsi     # 0x7ceb0
movq (%rsi,%rdx,8), %rdx
movl 0x738c(%rbx), %esi
cmpq %rdx, %rcx
cmovaq %rcx, %rdx
addq %rsi, %rdx
movq %rdx, 0x378(%rax,%r12)
incl 0x907c(%rbx)
movl 0x9078(%rbx), %eax
incl %eax
xorl %ecx, %ecx
cmpl 0x9068(%rbx), %eax
cmovbl %eax, %ecx
movl %ecx, 0x9078(%rbx)
cmpq $0x0, 0x340(%r14)
je 0x4b48
pushq $-0x1
popq %rax
movl $0x90c0, %ecx           # imm = 0x90C0
jmp 0x49d8
movl 0x338(%r14), %esi
imulq $0x380, %rdx, %rdx      # imm = 0x380
addq %rdx, %rcx
movb $0x1, %dil
movb %dil, 0x129(%rsi,%rcx)
movq 0x90e0(%rbx), %rcx
movb %dil, 0x32a(%rcx,%rdx)
movl $0x90b8, %ecx           # imm = 0x90B8
incq (%rbx,%rcx)
movl $0x90a8, %ecx           # imm = 0x90A8
incq (%rbx,%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
leaq 0xb66f(%rip), %rdi      # 0x10067
leaq 0xb66a(%rip), %rsi      # 0x10069
leaq 0xb802(%rip), %rcx      # 0x10208
movl $0x3b6, %edx            # imm = 0x3B6
callq 0x2160
leaq 0xb650(%rip), %rdi      # 0x10067
leaq 0xb64b(%rip), %rsi      # 0x10069
leaq 0xb7e3(%rip), %rcx      # 0x10208
movl $0x3b4, %edx            # imm = 0x3B4
callq 0x2160
leaq 0xb631(%rip), %rdi      # 0x10067
leaq 0xb62c(%rip), %rsi      # 0x10069
leaq 0xb7c4(%rip), %rcx      # 0x10208
movl $0x3b2, %edx            # imm = 0x3B2
callq 0x2160
movq 0x1159b(%rip), %r14     # 0x15ff0
leaq 0xb634(%rip), %rsi      # 0x10090
movq %r14, %rdi
callq 0x2230
leaq 0x7350(%rbx), %rsi
movq %rax, %rdi
callq 0x21d0
leaq 0xc1a4(%rip), %rsi      # 0x10c1e
movq %rax, %rdi
callq 0x2230
leaq 0xb7a3(%rip), %rsi      # 0x1022c
movq %rax, %rdi
callq 0x2230
leaq 0xb79b(%rip), %rsi      # 0x10233
movq %rax, %rdi
callq 0x2230
movq %rax, %rdi
movl %r15d, %esi
callq 0x2390
leaq 0xb6d1(%rip), %rsi      # 0x10183
movq %r14, %rdi
callq 0x2230
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
movl 0x18(%rax,%rcx), %edx
andl $-0x4b, %edx
orl $0x8, %edx
movl %edx, 0x18(%rax,%rcx)
movq 0x90e0(%rbx), %rcx
movq 0x340(%rcx,%r12), %rsi
movq %rax, %rdi
callq 0x2080
leaq 0xb6a1(%rip), %rsi      # 0x1018e
movq %r14, %rdi
callq 0x2230
movq 0x90e0(%rbx), %rcx
movq 0x348(%rcx,%r12), %rsi
movq %rax, %rdi
callq 0x2080
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
movl 0x18(%rax,%rcx), %edx
andl $-0x4b, %edx
orl $0x2, %edx
movl %edx, 0x18(%rax,%rcx)
movq %rax, %rdi
callq 0x2110
leaq 0xb537(%rip), %rdi      # 0x10067
leaq 0xb532(%rip), %rsi      # 0x10069
leaq 0xb6ca(%rip), %rcx      # 0x10208
movl $0x402, %edx            # imm = 0x402
callq 0x2160
leaq 0xb518(%rip), %rdi      # 0x10067
leaq 0xb513(%rip), %rsi      # 0x10069
leaq 0xb6ab(%rip), %rcx      # 0x10208
movl $0x41a, %edx            # imm = 0x41A
callq 0x2160
nop