// File: NishadSaraf[P]Championship-Simulator/src/dram_controller.cc
// Function: MEMORY_CONTROLLER::add_rq(PACKET*)
int MEMORY_CONTROLLER::add_rq(PACKET *packet)
{
    // simply return read requests with dummy response before the warmup
    if (all_warmup_complete < NUM_CPUS) {
        if (packet->instruction) 
            upper_level_icache[packet->cpu]->return_data(packet);
        else // data
            upper_level_dcache[packet->cpu]->return_data(packet);

        return -1;
    }

    // check for the latest wirtebacks in the write queue
    //int wq_index = WQ.check_queue(packet);
    int wq_index = check_dram_queue(&WQ, packet);
    if (wq_index != -1) {
        
        // no need to 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);
        //}

        DP ( if (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 << endl; });

        ACCESS[1]++;
        HIT[1]++;

        WQ.FORWARD++;
        RQ.ACCESS++;
        //assert(0);

        return -1;
    }

    // check for duplicates in the read queue
    //int index = RQ.check_queue(packet);
    int index = check_dram_queue(&RQ, packet);
    if (index != -1)
        return index; // merged index

    // search for the empty index
    for (index=0; index<DRAM_RQ_SIZE; index++) {
        if (RQ.entry[index].address == 0) {
            
            memcpy(&RQ.entry[index], packet, sizeof(PACKET));
            RQ.occupancy++;

#ifdef DEBUG_PRINT
            uint32_t channel = dram_get_channel(packet->address),
                     rank = dram_get_rank(packet->address),
                     bank = dram_get_bank(packet->address),
                     row = dram_get_row(packet->address),
                     column = dram_get_column(packet->address); 
#endif

            DP ( if(warmup_complete[packet->cpu]) {
            cout << "[" << NAME << "_RQ] " <<  __func__ << " instr_id: " << packet->instr_id << " address: " << hex << packet->address;
            cout << " full_addr: " << packet->full_addr << dec << " ch: " << channel;
            cout << " rank: " << rank << " bank: " << bank << " row: " << row << " col: " << column;
            cout << " occupancy: " << RQ.occupancy << " current: " << current_core_cycle[packet->cpu] << " event: " << packet->event_cycle << endl; });

            break;
        }
    }

    update_schedule_cycle(&RQ);

    return -1;
}

// Assembly:
subq $0x28, %rsp
movq %rdi, 0x18(%rsp)
movq %rsi, 0x10(%rsp)
movq 0x18(%rsp), %rax
movq %rax, (%rsp)
leaq 0x14a95(%rip), %rax     # 0x29343
movzbl (%rax), %eax
cmpl $0x1, %eax
jge 0x1490d
movq 0x10(%rsp), %rax
cmpb $0x0, (%rax)
je 0x148e1
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 0x14900
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)
movl $0xffffffff, 0x24(%rsp) # imm = 0xFFFFFFFF
jmp 0x14acf
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x8258, %rsi           # imm = 0x8258
movq 0x10(%rsp), %rdx
callq 0x14ae0
movl %eax, 0xc(%rsp)
cmpl $-0x1, 0xc(%rsp)
je 0x14a04
movq (%rsp), %rax
movq 0x82f0(%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 0x1498c
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 0x149ab
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)
movq (%rsp), %rax
movq 0x72b0(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x72b0(%rax)
movq 0x72d0(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x72d0(%rax)
movq 0x82c0(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x82c0(%rax)
movq 0x9f58(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x9f58(%rax)
movl $0xffffffff, 0x24(%rsp) # imm = 0xFFFFFFFF
jmp 0x14acf
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x9ef8, %rsi           # imm = 0x9EF8
movq 0x10(%rsp), %rdx
callq 0x14ae0
movl %eax, 0x8(%rsp)
cmpl $-0x1, 0x8(%rsp)
je 0x14a34
movl 0x8(%rsp), %eax
movl %eax, 0x24(%rsp)
jmp 0x14acf
movl $0x0, 0x8(%rsp)
cmpl $0x30, 0x8(%rsp)
jge 0x14ab4
movq (%rsp), %rax
movq 0x9f90(%rax), %rax
movslq 0x8(%rsp), %rcx
imulq $0x380, %rcx, %rcx      # imm = 0x380
addq %rcx, %rax
cmpq $0x0, 0x340(%rax)
jne 0x14aa5
movq (%rsp), %rax
movq 0x9f90(%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
movl 0x9f2c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x9f2c(%rax)
jmp 0x14ab4
jmp 0x14aa7
movl 0x8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x8(%rsp)
jmp 0x14a3c
movq (%rsp), %rdi
movq %rdi, %rsi
addq $0x9ef8, %rsi           # imm = 0x9EF8
callq 0x13530
movl $0xffffffff, 0x24(%rsp) # imm = 0xFFFFFFFF
movl 0x24(%rsp), %eax
addq $0x28, %rsp
retq
nopl (%rax,%rax)