// File: /workspace/github_cpp_makefile_star2_O1/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 0x18(%rsp), %r13
xorl %ebp, %ebp
leaq 0xa470(%rip), %r15      # 0x1a210
xorl %esi, %esi
movq 0x9b8(%rbx), %rax
movl 0x958(%rbx), %ecx
imulq $0x758, %rcx, %rdx      # imm = 0x758
cmpq $0x0, 0x8(%rax,%rdx)
je 0x100be
leaq (%rax,%rdx), %rcx
cmpl $0x2, 0x78(%rcx)
jne 0x100be
movl %esi, 0x4(%rsp)
movzbl (%r15), %ecx
testq %rcx, %rcx
je 0xfdfd
addq %rax, %rdx
addq $0x5a8, %rdx            # imm = 0x5A8
xorl %esi, %esi
xorl %eax, %eax
cmpq $0x1, (%rdx,%rsi,8)
sbbl $-0x1, %eax
incq %rsi
cmpq %rsi, %rcx
jne 0xfdeb
jmp 0xfdff
xorl %eax, %eax
testl %eax, %eax
je 0xff83
addl 0x4b90c(%rbx), %eax
cmpl 0x4b8f8(%rbx), %eax
ja 0x100b0
cmpb $0x0, (%r15)
je 0xff83
xorl %r14d, %r14d
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %r12      # imm = 0x758
addq 0x9b8(%rbx), %r12
cmpq $0x0, 0x5a8(%r12,%r14,8)
je 0xff73
movl %ebp, 0x13(%rsp)
movl %ebp, 0x10(%rsp)
movl $0xffff00, 0x33c(%rsp) # imm = 0xFFFF00
pcmpeqd %xmm0, %xmm0
movdqu %xmm0, (%r13)
movl $0x314, %edx            # imm = 0x314
leaq 0x28(%rsp), %rdi
xorl %esi, %esi
callq 0x3130
movl $0x1, %ecx
movl %ecx, 0x340(%rsp)
pxor %xmm0, %xmm0
movdqu %xmm0, 0x32c(%r13)
movdqu %xmm0, 0x33c(%r13)
movl %ebp, 0x34c(%r13)
movdqu %xmm0, 0x358(%r13)
movq $0x0, 0x368(%r13)
movq $-0x1, 0x388(%rsp)
movl 0x738(%r12,%r14,4), %eax
movl %ecx, 0x18(%rsp)
movl (%rbx), %ecx
movl %ecx, 0x340(%rsp)
movq 0xa28(%rbx), %rdx
leaq (%rax,%rax,4), %rsi
shlq $0x6, %rsi
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 0x70f68(%rip), %rax     # 0x80ec0
movq (%rax,%rcx,8), %rax
movq %rax, 0x388(%rsp)
movq 0x8(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x5e82
incq %r14
movzbl (%r15), %eax
cmpq %rax, %r14
jb 0xfe26
cmpb $0x0, (%r15)
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
je 0x10046
xorl %r14d, %r14d
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %rax      # imm = 0x758
addq 0x9b8(%rbx), %rax
movl 0x738(%rax,%r14,4), %eax
cmpq %r12, %rax
je 0x10036
movq 0xa28(%rbx), %rcx
leaq (%rax,%rax,4), %rax
shlq $0x6, %rax
leaq (%rcx,%rax), %rdi
addq $0x40, %rdi
movq %rbp, -0x40(%rdi)
movq $-0x1, -0x38(%rdi)
pxor %xmm0, %xmm0
movdqu %xmm0, -0x30(%rdi)
movdqu %xmm0, -0x20(%rdi)
movq %rbp, -0x10(%rdi)
movabsq $-0xffff00000001, %rax  # imm = 0xFFFF0000FFFFFFFF
movq %rax, -0x8(%rdi)
movl $0x100, %edx            # imm = 0x100
xorl %esi, %esi
callq 0x3130
movq 0xa1c(%rbx), %xmm0
paddd 0x4c0a(%rip), %xmm0     # 0x14c20
movq %xmm0, 0xa1c(%rbx)
pshufd $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
movd %xmm0, %eax
cmpl 0xa18(%rbx), %eax
cmovel %ebp, %eax
movl %eax, 0xa20(%rbx)
incq %r14
movzbl (%r15), %eax
cmpq %rax, %r14
jb 0xff96
leaq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0x1077a
movl 0x958(%rbx), %eax
imulq $0x758, %rax, %rdi      # imm = 0x758
addq 0x9b8(%rbx), %rdi
movl $0x758, %edx            # imm = 0x758
movq %r14, %rsi
callq 0x31c0
movl 0x958(%rbx), %eax
incl %eax
cmpl 0x950(%rbx), %eax
cmovel %ebp, %eax
movl %eax, 0x958(%rbx)
decl 0x960(%rbx)
decq 0x8b8(%rbx)
incq 0x918(%rbx)
movl 0x4(%rsp), %esi
incl %esi
cmpl $0x4, %esi
jne 0xfda2
jmp 0x100be
incq 0x4b968(%rbx)
incq 0x4b860(%rbx)
addq $0x768, %rsp            # imm = 0x768
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq