// File: 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:
subq $0xc48, %rsp            # imm = 0xC48
movq %rdi, 0xc40(%rsp)
movq 0xc40(%rsp), %rax
movq %rax, (%rsp)
movl $0x0, 0xc3c(%rsp)
cmpl $0x4, 0xc3c(%rsp)
jae 0x1b80c
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
cmpq $0x0, 0x8(%rax)
jne 0x1b32b
jmp 0x1b80c
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
cmpl $0x2, 0x78(%rax)
je 0x1b351
jmp 0x1b80c
movl $0x0, 0xc38(%rsp)
movl $0x0, 0xc34(%rsp)
movl 0xc34(%rsp), %eax
leaq 0xde9b(%rip), %rcx      # 0x29210
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jae 0x1b3cf
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
movl 0xc34(%rsp), %ecx
cmpq $0x0, 0x5a8(%rax,%rcx,8)
je 0x1b3ba
movl 0xc38(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc38(%rsp)
jmp 0x1b3bc
movl 0xc34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc34(%rsp)
jmp 0x1b367
cmpl $0x0, 0xc38(%rsp)
je 0x1b645
movq (%rsp), %rcx
movl 0x4b90c(%rcx), %eax
addl 0xc38(%rsp), %eax
cmpl 0x4b8f8(%rcx), %eax
ja 0x1b616
movl $0x0, 0xc30(%rsp)
movl 0xc30(%rsp), %eax
leaq 0xddfd(%rip), %rcx      # 0x29210
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jae 0x1b614
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
movl 0xc30(%rsp), %ecx
cmpq $0x0, 0x5a8(%rax,%rcx,8)
je 0x1b5fc
leaq 0x8b0(%rsp), %rdi
callq 0x9750
movq (%rsp), %rdi
movq 0x9b8(%rdi), %rax
movl 0x958(%rdi), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
movl 0xc30(%rsp), %ecx
movl 0x738(%rax,%rcx,4), %eax
movl %eax, 0x8ac(%rsp)
movl $0x1, 0x8b8(%rsp)
movl (%rdi), %eax
movl %eax, 0xbe0(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movl 0x34(%rax), %eax
movl %eax, 0xbe4(%rsp)
movl 0x8ac(%rsp), %eax
movl %eax, 0xbec(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movq 0x18(%rax), %rax
shrq $0x6, %rax
movq %rax, 0xbf0(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movq 0x18(%rax), %rax
movq %rax, 0xbf8(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movq (%rax), %rax
movq %rax, 0xc18(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movl 0x30(%rax), %eax
movl %eax, 0x8c0(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movq 0x20(%rax), %rax
movq %rax, 0xc20(%rsp)
movb $0x1, 0xbdf(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movb 0x3e(%rax), %al
movb %al, 0xbdd(%rsp)
movq 0xa28(%rdi), %rax
movl 0x8ac(%rsp), %ecx
imulq $0x140, %rcx, %rcx      # imm = 0x140
addq %rcx, %rax
movb 0x3f(%rax), %al
movb %al, 0xbde(%rsp)
movl (%rdi), %eax
movl %eax, %ecx
leaq 0x748e4(%rip), %rax     # 0x8fec0
movq (%rax,%rcx,8), %rax
movq %rax, 0xc28(%rsp)
addq $0x44530, %rdi          # imm = 0x44530
leaq 0x8b0(%rsp), %rsi
callq 0x8870
jmp 0x1b5fe
movl 0xc30(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc30(%rsp)
jmp 0x1b405
jmp 0x1b643
movq (%rsp), %rax
movq 0x4b968(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x4b968(%rax)
movq 0x4b860(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x4b860(%rax)
jmp 0x1b80c
jmp 0x1b645
movl $0x0, 0x8a8(%rsp)
movl 0x8a8(%rsp), %eax
leaq 0xdbb2(%rip), %rcx      # 0x29210
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jae 0x1b75c
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
movl 0x8a8(%rsp), %ecx
cmpl $-0x1, 0x738(%rax,%rcx,4)
je 0x1b744
movq (%rsp), %rcx
movq 0x9b8(%rcx), %rax
movl 0x958(%rcx), %ecx
imulq $0x758, %rcx, %rcx      # imm = 0x758
addq %rcx, %rax
movl 0x8a8(%rsp), %ecx
movl 0x738(%rax,%rcx,4), %eax
movl %eax, 0x8a4(%rsp)
leaq 0x760(%rsp), %rdi
callq 0x1c670
movq (%rsp), %rax
movq 0xa28(%rax), %rdi
movl 0x8a4(%rsp), %eax
imulq $0x140, %rax, %rax      # imm = 0x140
addq %rax, %rdi
leaq 0x760(%rsp), %rsi
movl $0x140, %edx            # imm = 0x140
callq 0x31a0
movq (%rsp), %rcx
movl 0xa1c(%rcx), %eax
addl $-0x1, %eax
movl %eax, 0xa1c(%rcx)
movl 0xa20(%rcx), %eax
addl $0x1, %eax
movl %eax, 0xa20(%rcx)
movl 0xa20(%rcx), %eax
cmpl 0xa18(%rcx), %eax
jne 0x1b742
movq (%rsp), %rax
movl $0x0, 0xa20(%rax)
jmp 0x1b744
jmp 0x1b746
movl 0x8a8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x8a8(%rsp)
jmp 0x1b650
leaq 0x8(%rsp), %rdi
callq 0x1c430
movq (%rsp), %rax
movq 0x9b8(%rax), %rdi
movl 0x958(%rax), %eax
imulq $0x758, %rax, %rax      # imm = 0x758
addq %rax, %rdi
leaq 0x8(%rsp), %rsi
movl $0x758, %edx            # imm = 0x758
callq 0x31a0
movq (%rsp), %rcx
movl 0x958(%rcx), %eax
addl $0x1, %eax
movl %eax, 0x958(%rcx)
movl 0x958(%rcx), %eax
cmpl 0x950(%rcx), %eax
jne 0x1b7bf
movq (%rsp), %rax
movl $0x0, 0x958(%rax)
movq (%rsp), %rax
movl 0x960(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x960(%rax)
movq 0x8b8(%rax), %rcx
addq $-0x1, %rcx
movq %rcx, 0x8b8(%rax)
movq 0x918(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x918(%rax)
movl 0xc3c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc3c(%rsp)
jmp 0x1b2f6
addq $0xc48, %rsp            # imm = 0xC48
retq
nopw %cs:(%rax,%rax)
nop