// File: /workspace/github_cpp_makefile_star2_O2/NishadSaraf[P]Championship-Simulator/src/ooo_cpu.cc
// Function: O3_CPU::retire_rob()
void O3_CPU::retire_rob()
{
    for (uint32_t n=0; n<RETIRE_WIDTH; n++) {
        if (ROB.entry[ROB.head].ip == 0)
            return;

        // retire is in-order
        if (ROB.entry[ROB.head].executed != COMPLETED) { 
            DP ( if (warmup_complete[cpu]) {
            cout << "[ROB] " << __func__ << " instr_id: " << ROB.entry[ROB.head].instr_id << " head: " << ROB.head << " is not executed yet" << endl; });
            return;
        }

        // check store instruction
        uint32_t num_store = 0;
        for (uint32_t i=0; i<MAX_INSTR_DESTINATIONS; i++) {
            if (ROB.entry[ROB.head].destination_memory[i])
                num_store++;
        }

        if (num_store) {
            if ((L1D.WQ.occupancy + num_store) <= L1D.WQ.SIZE) {
                for (uint32_t i=0; i<MAX_INSTR_DESTINATIONS; i++) {
                    if (ROB.entry[ROB.head].destination_memory[i]) {

                        PACKET data_packet;
                        uint32_t sq_index = ROB.entry[ROB.head].sq_index[i];

                        // sq_index and rob_index are no longer available after retirement
                        // but we pass this information to avoid segmentation fault
                        data_packet.fill_level = FILL_L1;
                        data_packet.cpu = cpu;
                        data_packet.data_index = SQ.entry[sq_index].data_index;
                        data_packet.sq_index = sq_index;
                        data_packet.address = SQ.entry[sq_index].physical_address >> LOG2_BLOCK_SIZE;
                        data_packet.full_addr = SQ.entry[sq_index].physical_address;
                        data_packet.instr_id = SQ.entry[sq_index].instr_id;
                        data_packet.rob_index = SQ.entry[sq_index].rob_index;
                        data_packet.ip = SQ.entry[sq_index].ip;
                        data_packet.type = RFO;
                        data_packet.asid[0] = SQ.entry[sq_index].asid[0];
                        data_packet.asid[1] = SQ.entry[sq_index].asid[1];
                        data_packet.event_cycle = current_core_cycle[cpu];

                        L1D.add_wq(&data_packet);
                    }
                }
            }
            else {
                DP ( if (warmup_complete[cpu]) {
                cout << "[ROB] " << __func__ << " instr_id: " << ROB.entry[ROB.head].instr_id << " L1D WQ is full" << endl; });

                L1D.WQ.FULL++;
                L1D.STALL[RFO]++;

                return;
            }
        }

        // release SQ entries
        for (uint32_t i=0; i<MAX_INSTR_DESTINATIONS; i++) {
            if (ROB.entry[ROB.head].sq_index[i] != UINT32_MAX) {
                uint32_t sq_index = ROB.entry[ROB.head].sq_index[i];

                DP ( if (warmup_complete[cpu]) {
                cout << "[SQ] " << __func__ << " instr_id: " << ROB.entry[ROB.head].instr_id << " releases sq_index: " << sq_index;
                cout << hex << " address: " << (SQ.entry[sq_index].physical_address>>LOG2_BLOCK_SIZE);
                cout << " full_addr: " << SQ.entry[sq_index].physical_address << dec << endl; });

                LSQ_ENTRY empty_entry;
                memcpy (&SQ.entry[sq_index], &empty_entry, sizeof(LSQ_ENTRY));
                
                SQ.occupancy--;
                SQ.head++;
                if (SQ.head == SQ.SIZE)
                    SQ.head = 0;
            }
        }

        // release ROB entry
        DP ( if (warmup_complete[cpu]) {
        cout << "[ROB] " << __func__ << " instr_id: " << ROB.entry[ROB.head].instr_id << " is retired" << endl; });

        ooo_model_instr empty_entry;
        memcpy(&ROB.entry[ROB.head], &empty_entry, sizeof(ooo_model_instr));

        ROB.head++;
        if (ROB.head == ROB.SIZE)
            ROB.head = 0;
        ROB.occupancy--;
        completed_executions--;
        num_retired++;
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x768, %rsp            # imm = 0x768
movq %rdi, %rbx
leaq 0x44530(%rdi), %rax
movq %rax, 0x8(%rsp)
leaq 0x9533(%rip), %r13      # 0x16200
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
leaq 0x10(%rsp), %r15
xorl %r8d, %r8d
cmpl $0x4, %r8d
je 0xcf54
movq 0x9b8(%rbx), %rcx
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %rsi      # imm = 0x758
cmpq $0x0, 0x8(%rcx,%rsi)
je 0xcf54
leaq (%rcx,%rsi), %rax
cmpl $0x2, 0x78(%rax)
jne 0xcf54
movb (%r13), %al
movzbl %al, %edx
addq %rcx, %rsi
addq $0x5a8, %rsi            # imm = 0x5A8
xorl %edi, %edi
xorl %ecx, %ecx
cmpq %rdi, %rdx
je 0xcd39
cmpq $0x1, (%rsi,%rdi,8)
sbbl $-0x1, %ecx
incq %rdi
jmp 0xcd27
testl %ecx, %ecx
movl %r8d, 0x4(%rsp)
je 0xce66
addl 0x4b90c(%rbx), %ecx
cmpl 0x4b8f8(%rbx), %ecx
ja 0xcf46
xorl %r12d, %r12d
movzbl %al, %ecx
cmpq %rcx, %r12
jae 0xce66
movl 0x958(%rbx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq 0x9b8(%rbx), %rcx
cmpq $0x0, 0x5a8(%rcx,%r12,8)
je 0xce5e
movq %r15, %rdi
callq 0x53f4
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %rax      # imm = 0x758
addq 0x9b8(%rbx), %rax
movl 0x738(%rax,%r12,4), %eax
movl $0x1, 0x18(%rsp)
movl (%rbx), %ecx
movl %ecx, 0x340(%rsp)
movq 0xa28(%rbx), %rdx
imulq $0x140, %rax, %rsi      # imm = 0x140
movl 0x34(%rdx,%rsi), %edi
movl %edi, 0x344(%rsp)
movl %eax, 0x34c(%rsp)
movq 0x18(%rdx,%rsi), %rax
movq %rax, %rdi
shrq $0x6, %rdi
movq %rdi, 0x350(%rsp)
movq %rax, 0x358(%rsp)
movq (%rdx,%rsi), %rax
movq %rax, 0x378(%rsp)
movl 0x30(%rdx,%rsi), %eax
movl %eax, 0x20(%rsp)
movq 0x20(%rdx,%rsi), %rax
movq %rax, 0x380(%rsp)
movb $0x1, 0x33f(%rsp)
movb 0x3e(%rdx,%rsi), %al
movb %al, 0x33d(%rsp)
movb 0x3f(%rdx,%rsi), %al
movb %al, 0x33e(%rsp)
leaq 0x7006f(%rip), %rax     # 0x7ceb0
movq (%rax,%rcx,8), %rax
movq %rax, 0x388(%rsp)
movq 0x8(%rsp), %rdi
movq %r15, %rsi
callq 0x4b68
movb (%r13), %al
incq %r12
jmp 0xcd5b
xorl %r12d, %r12d
movzbl %al, %ecx
cmpq %rcx, %r12
jae 0xcee0
movl 0x958(%rbx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq 0x9b8(%rbx), %rcx
movl 0x738(%rcx,%r12,4), %r14d
cmpq %rbp, %r14
je 0xcedb
movq %r15, %rdi
callq 0xd644
imulq $0x140, %r14, %rdi      # imm = 0x140
addq 0xa28(%rbx), %rdi
movl $0x140, %edx            # imm = 0x140
movq %r15, %rsi
callq 0x21b0
decl 0xa1c(%rbx)
movl 0xa20(%rbx), %eax
incl %eax
cmpl 0xa18(%rbx), %eax
movl $0x0, %ecx
cmovel %ecx, %eax
movl %eax, 0xa20(%rbx)
movb (%r13), %al
incq %r12
jmp 0xce69
movq %r15, %rdi
callq 0xd550
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %rdi      # imm = 0x758
addq 0x9b8(%rbx), %rdi
movl $0x758, %edx            # imm = 0x758
movq %r15, %rsi
callq 0x21b0
movl 0x958(%rbx), %eax
incl %eax
cmpl 0x950(%rbx), %eax
movl $0x0, %ecx
cmovel %ecx, %eax
movl %eax, 0x958(%rbx)
decl 0x960(%rbx)
decq 0x8b8(%rbx)
incq 0x918(%rbx)
movl 0x4(%rsp), %r8d
incl %r8d
jmp 0xccda
incq 0x4b968(%rbx)
incq 0x4b860(%rbx)
addq $0x768, %rsp            # imm = 0x768
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq