// File: /workspace/github_cpp_makefile_star2_O2/NishadSaraf[P]Championship-Simulator/src/ooo_cpu.cc
// Function: O3_CPU::fetch_instruction()
void O3_CPU::fetch_instruction()
{
    // TODO: can we model wrong path execusion?

    // add this request to ITLB
    uint32_t read_index = (ROB.last_read == (ROB.SIZE-1)) ? 0 : (ROB.last_read + 1);
    for (uint32_t i=0; i<FETCH_WIDTH; i++) {

        if (ROB.entry[read_index].ip == 0)
            break;

#ifdef SANITY_CHECK
        // sanity check
        if (ROB.entry[read_index].translated) {
            if (read_index == ROB.head)
                break;
            else {
                cout << "read_index: " << read_index << " ROB.head: " << ROB.head << " ROB.tail: " << ROB.tail << endl;
                assert(0);
            }
        }
#endif

        PACKET trace_packet;
        trace_packet.instruction = 1;
        trace_packet.tlb_access = 1;
        trace_packet.fill_level = FILL_L1;
        trace_packet.cpu = cpu;
        trace_packet.address = ROB.entry[read_index].ip >> LOG2_PAGE_SIZE;
        if (knob_cloudsuite)
            trace_packet.address = ((ROB.entry[read_index].ip >> LOG2_PAGE_SIZE) << 9) | ( 256 + ROB.entry[read_index].asid[0]);
        else
            trace_packet.address = ROB.entry[read_index].ip >> LOG2_PAGE_SIZE;
        trace_packet.full_addr = ROB.entry[read_index].ip;
        trace_packet.instr_id = ROB.entry[read_index].instr_id;
        trace_packet.rob_index = read_index;
        trace_packet.producer = 0; // TODO: check if this guy gets used or not
        trace_packet.ip = ROB.entry[read_index].ip;
        trace_packet.type = LOAD; 
        trace_packet.asid[0] = ROB.entry[read_index].asid[0];
        trace_packet.asid[1] = ROB.entry[read_index].asid[1];
        trace_packet.event_cycle = current_core_cycle[cpu];

        int rq_index = ITLB.add_rq(&trace_packet);

        if (rq_index == -2)
            break;
        else {
            /*
            if (rq_index >= 0) {
                uint32_t producer = ITLB.RQ.entry[rq_index].rob_index;
                ROB.entry[read_index].fetch_producer = producer;
                ROB.entry[read_index].is_consumer = 1;

                ROB.entry[producer].memory_instrs_depend_on_me[read_index] = 1;
                ROB.entry[producer].is_producer = 1; // producer for fetch
            }
            */

            ROB.last_read = read_index;
            read_index++;
            if (read_index == ROB.SIZE)
                read_index = 0;
        }
    }
    
    uint32_t fetch_index = (ROB.last_fetch == (ROB.SIZE-1)) ? 0 : (ROB.last_fetch + 1);

    for (uint32_t i=0; i<FETCH_WIDTH; i++) {

        // fetch is in-order so it should be break
        if ((ROB.entry[fetch_index].translated != COMPLETED) || (ROB.entry[fetch_index].event_cycle > current_core_cycle[cpu])) 
            break;

        // sanity check
        if (ROB.entry[fetch_index].fetched) {
            if (fetch_index == ROB.head)
                break;
            else {
                cout << "fetch_index: " << fetch_index << " ROB.head: " << ROB.head << " ROB.tail: " << ROB.tail << endl;
                assert(0);
            }
        }

        // add it to L1I
        PACKET fetch_packet;
        fetch_packet.instruction = 1;
        fetch_packet.fill_level = FILL_L1;
        fetch_packet.cpu = cpu;
        fetch_packet.address = ROB.entry[fetch_index].instruction_pa >> 6;
        fetch_packet.instruction_pa = ROB.entry[fetch_index].instruction_pa;
        fetch_packet.full_addr = ROB.entry[fetch_index].instruction_pa;
        fetch_packet.instr_id = ROB.entry[fetch_index].instr_id;
        fetch_packet.rob_index = fetch_index;
        fetch_packet.producer = 0;
        fetch_packet.ip = ROB.entry[fetch_index].ip;
        fetch_packet.type = LOAD; 
        fetch_packet.asid[0] = ROB.entry[fetch_index].asid[0];
        fetch_packet.asid[1] = ROB.entry[fetch_index].asid[1];
        fetch_packet.event_cycle = current_core_cycle[cpu];

        int rq_index = L1I.add_rq(&fetch_packet);

        if (rq_index == -2)
            break;
        else {
            /*
            if (rq_index >= 0) {
                uint32_t producer = L1I.RQ.entry[rq_index].rob_index;
                ROB.entry[fetch_index].fetch_producer = producer;
                ROB.entry[fetch_index].is_consumer = 1;

                ROB.entry[producer].memory_instrs_depend_on_me[fetch_index] = 1;
                ROB.entry[producer].is_producer = 1;
            }
            */

            ROB.entry[fetch_index].fetched = INFLIGHT;
            ROB.last_fetch = fetch_index;
            fetch_index++;
            if (fetch_index == ROB.SIZE)
                fetch_index = 0;
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x388, %rsp            # imm = 0x388
movq %rdi, %rbx
movl 0x950(%rdi), %eax
movl 0x964(%rdi), %ecx
leal -0x1(%rax), %edx
leal 0x1(%rcx), %ebp
xorl %esi, %esi
cmpl %edx, %ecx
cmovel %esi, %ebp
leaq 0x3690(%rdi), %r14
pushq $0x4
popq %r13
leaq 0x8(%rsp), %r15
subl $0x1, %r13d
jb 0xa72a
movq 0x9b8(%rbx), %rcx
movl %ebp, %edx
imulq $0x758, %rdx, %r12      # imm = 0x758
cmpq $0x0, 0x8(%rcx,%r12)
je 0xa72a
addq %r12, %rcx
cmpb $0x0, 0x4c(%rcx)
jne 0xa69a
movq %r15, %rdi
callq 0x53f4
movw $0x101, 0x8(%rsp)       # imm = 0x101
movl $0x1, 0x10(%rsp)
movl (%rbx), %eax
movl %eax, 0x338(%rsp)
movq 0x9b8(%rbx), %rcx
movq 0x8(%rcx,%r12), %rdx
movq %rdx, %rsi
shrq $0xc, %rsi
movq %rsi, 0x348(%rsp)
leaq 0xbd4f(%rip), %rdi      # 0x16335
cmpb $0x0, (%rdi)
je 0xa609
movq %rdx, %rsi
shrq $0x3, %rsi
andq $-0x200, %rsi           # imm = 0xFE00
movzbl 0x5b(%rcx,%r12), %edi
addq %rdi, %rsi
addq $0x100, %rsi            # imm = 0x100
movq %rsi, 0x348(%rsp)
movq %rdx, 0x350(%rsp)
movq (%rcx,%r12), %rsi
movq %rsi, 0x370(%rsp)
movl %ebp, 0x18(%rsp)
andl $0x0, 0x1c(%rsp)
movq %rdx, 0x378(%rsp)
movb $0x0, 0x337(%rsp)
movb 0x5b(%rcx,%r12), %dl
movb %dl, 0x335(%rsp)
movb 0x5c(%rcx,%r12), %cl
movb %cl, 0x336(%rsp)
leaq 0x72853(%rip), %rcx     # 0x7ceb0
movq (%rcx,%rax,8), %rax
movq %rax, 0x380(%rsp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x477a
cmpl $-0x2, %eax
je 0xa724
movl %ebp, 0x964(%rbx)
incl %ebp
movl 0x950(%rbx), %eax
cmpl %eax, %ebp
movl $0x0, %ecx
cmovel %ecx, %ebp
jmp 0xa571
cmpl 0x958(%rbx), %ebp
je 0xa72a
movq 0xb923(%rip), %rdi      # 0x15fd0
leaq 0x6600(%rip), %rsi      # 0x10cb4
callq 0x2230
movq %rax, %rdi
movl %ebp, %esi
callq 0x22a0
leaq 0x65f7(%rip), %rsi      # 0x10cc1
movq %rax, %rdi
callq 0x2230
movl 0x958(%rbx), %esi
movq %rax, %rdi
callq 0x22a0
leaq 0x65e6(%rip), %rsi      # 0x10ccd
movq %rax, %rdi
callq 0x2230
movl 0x95c(%rbx), %esi
movq %rax, %rdi
callq 0x22a0
movq %rax, %rdi
callq 0x2110
leaq 0x595b(%rip), %rdi      # 0x10067
leaq 0x64db(%rip), %rsi      # 0x10bee
leaq 0x65bf(%rip), %rcx      # 0x10cd9
movl $0x17b, %edx            # imm = 0x17B
callq 0x2160
movl 0x950(%rbx), %eax
movl 0x968(%rbx), %ecx
decl %eax
leal 0x1(%rcx), %edx
xorl %ebp, %ebp
cmpl %eax, %ecx
cmovnel %edx, %ebp
leaq 0x34188(%rbx), %r14
pushq $0x4
popq %r13
leaq 0x8(%rsp), %r15
subl $0x1, %r13d
jb 0xa86e
movq 0x9b8(%rbx), %rax
movl %ebp, %ecx
imulq $0x758, %rcx, %r12      # imm = 0x758
cmpb $0x2, 0x4c(%rax,%r12)
jne 0xa86e
addq %r12, %rax
movq 0x40(%rax), %rcx
movl (%rbx), %edx
leaq 0x7272e(%rip), %rsi     # 0x7ceb0
cmpq (%rsi,%rdx,8), %rcx
ja 0xa86e
cmpl $0x0, 0x64(%rax)
jne 0xa866
movq %r15, %rdi
callq 0x53f4
movb $0x1, 0x8(%rsp)
movl $0x1, 0x10(%rsp)
movl (%rbx), %eax
movl %eax, 0x338(%rsp)
movq 0x9b8(%rbx), %rcx
movq 0x588(%rcx,%r12), %rdx
movq %rdx, %rsi
shrq $0x6, %rsi
movq %rsi, 0x348(%rsp)
movq %rdx, 0x358(%rsp)
movq %rdx, 0x350(%rsp)
movl %ebp, 0x18(%rsp)
andl $0x0, 0x1c(%rsp)
movups (%rcx,%r12), %xmm0
movups %xmm0, 0x370(%rsp)
movb $0x0, 0x337(%rsp)
movb 0x5b(%rcx,%r12), %dl
movb %dl, 0x335(%rsp)
movb 0x5c(%rcx,%r12), %cl
movb %cl, 0x336(%rsp)
leaq 0x72691(%rip), %rcx     # 0x7ceb0
movq (%rcx,%rax,8), %rax
movq %rax, 0x380(%rsp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x477a
cmpl $-0x2, %eax
je 0xa86e
movq 0x9b8(%rbx), %rax
movl $0x1, 0x64(%rax,%r12)
movl %ebp, 0x968(%rbx)
incl %ebp
xorl %eax, %eax
cmpl 0x950(%rbx), %ebp
je 0xa85f
movl %ebp, %eax
movl %eax, %ebp
jmp 0xa74c
cmpl 0x958(%rbx), %ebp
jne 0xa880
addq $0x388, %rsp            # imm = 0x388
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0xb749(%rip), %rdi      # 0x15fd0
leaq 0x646c(%rip), %rsi      # 0x10cfa
callq 0x2230
movq %rax, %rdi
movl %ebp, %esi
callq 0x22a0
leaq 0x641d(%rip), %rsi      # 0x10cc1
movq %rax, %rdi
callq 0x2230
movl 0x958(%rbx), %esi
movq %rax, %rdi
callq 0x22a0
leaq 0x640c(%rip), %rsi      # 0x10ccd
movq %rax, %rdi
callq 0x2230
movl 0x95c(%rbx), %esi
movq %rax, %rdi
callq 0x22a0
movq %rax, %rdi
callq 0x2110
leaq 0x5781(%rip), %rdi      # 0x10067
leaq 0x6301(%rip), %rsi      # 0x10bee
leaq 0x63e5(%rip), %rcx      # 0x10cd9
movl $0x1b9, %edx            # imm = 0x1B9
callq 0x2160