// File: /workspace/github_cpp_makefile_star2_O1/CMU-SAFARI[P]MQSim/src/ssd/TSU_Priority_OutOfOrder.cpp
// Function: SSD_Components::TSU_Priority_OutOfOrder::Schedule()
void TSU_Priority_OutOfOrder::Schedule()
{
    opened_scheduling_reqs--;
    if (opened_scheduling_reqs > 0)
    {
        return;
    }

    if (opened_scheduling_reqs < 0)
    {
        PRINT_ERROR("TSU_Priority_OutOfOrder: Illegal status!");
    }

    if (transaction_receive_slots.size() == 0)
    {
        return;
    }

    for (std::list<NVM_Transaction_Flash *>::iterator it = transaction_receive_slots.begin();
         it != transaction_receive_slots.end();
         it++)
    {
        switch ((*it)->Type)
        {
        case Transaction_Type::READ:
            switch ((*it)->Source)
            {
            case Transaction_Source_Type::CACHE:
            case Transaction_Source_Type::USERIO:
                if ((*it)->Priority_class != IO_Flow_Priority_Class::UNDEFINED)
                {
                    UserReadTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID][static_cast<int>((*it)->Priority_class)].push_back((*it));
                }
                else
                {
                    UserReadTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID][IO_Flow_Priority_Class::HIGH].push_back((*it));
                }
                break;
            case Transaction_Source_Type::MAPPING:
                MappingReadTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID].push_back((*it));
                break;
            case Transaction_Source_Type::GC_WL:
                GCReadTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID].push_back((*it));
                break;
            default:
                PRINT_ERROR("TSU_OutOfOrder: unknown source type for a read transaction!")
            }
            break;
        case Transaction_Type::WRITE:
            switch ((*it)->Source)
            {
            case Transaction_Source_Type::CACHE:
            case Transaction_Source_Type::USERIO:
                if ((*it)->Priority_class != IO_Flow_Priority_Class::UNDEFINED)
                {
                    UserWriteTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID][static_cast<int>((*it)->Priority_class)].push_back((*it));
                }
                else
                {
                    UserWriteTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID][IO_Flow_Priority_Class::HIGH].push_back((*it));
                }
                break;
            case Transaction_Source_Type::MAPPING:
                MappingWriteTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID].push_back((*it));
                break;
            case Transaction_Source_Type::GC_WL:
                GCWriteTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID].push_back((*it));
                break;
            default:
                PRINT_ERROR("TSU_OutOfOrder: unknown source type for a write transaction!")
            }
            break;
        case Transaction_Type::ERASE:
            GCEraseTRQueue[(*it)->Address.ChannelID][(*it)->Address.ChipID].push_back((*it));
            break;
        default:
            break;
        }
    }

    for (flash_channel_ID_type channelID = 0; channelID < channel_count; channelID++)
    {
        if (_NVMController->Get_channel_status(channelID) == BusChannelStatus::IDLE)
        {
            for (unsigned int i = 0; i < chip_no_per_channel; i++)
            {
                NVM::FlashMemory::Flash_Chip *chip = _NVMController->Get_chip(channelID, Round_robin_turn_of_channel[channelID]);
                //The TSU does not check if the chip is idle or not since it is possible to suspend a busy chip and issue a new command
                if (!service_read_transaction(chip))
                {
                    if (!service_write_transaction(chip))
                    {
                        service_erase_transaction(chip);
                    }
                }
                Round_robin_turn_of_channel[channelID] = (flash_chip_ID_type)(Round_robin_turn_of_channel[channelID] + 1) % chip_no_per_channel;
                if (_NVMController->Get_channel_status(chip->ChannelID) != BusChannelStatus::IDLE)
                {
                    break;
                }
            }
        }
    }
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
movl 0xa8(%rdi), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0xa8(%rdi)
cmpl $0x1, %eax
jg 0x51ab5
jne 0x51ac1
movq %rdi, %rbx
cmpq $0x0, 0x88(%rdi)
je 0x51ab5
leaq 0x78(%rbx), %r14
movq (%r14), %r15
cmpq %r14, %r15
je 0x519ff
movl $0x108, %r12d           # imm = 0x108
movq 0x10(%r15), %rax
movl 0x8(%rax), %ecx
cmpl $0x2, %ecx
je 0x51946
cmpl $0x1, %ecx
je 0x51926
testl %ecx, %ecx
jne 0x5196b
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x51998
je 0x519f3
cmpl $0x3, %ecx
jne 0x51ae0
movq 0xd8(%rbx), %rcx
jmp 0x5194d
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x5197c
je 0x519c8
cmpl $0x3, %ecx
jne 0x51aff
movq 0xe0(%rbx), %rcx
jmp 0x5194d
movq 0xd0(%rbx), %rcx
movl 0x38(%rax), %edx
movl 0x3c(%rax), %eax
movq %rax, %rsi
shlq $0x8, %rsi
leaq (%rsi,%rax,8), %rdi
addq (%rcx,%rdx,8), %rdi
leaq 0x10(%r15), %rsi
callq 0x3e954
movq (%r15), %r15
cmpq %r14, %r15
jne 0x518ed
jmp 0x519ff
movslq 0x18(%rax), %rcx
movl 0x38(%rax), %edx
movl 0x3c(%rax), %eax
cmpq $0x2710, %rcx           # imm = 0x2710
jne 0x519bf
movq 0xb8(%rbx), %rcx
jmp 0x519b2
movslq 0x18(%rax), %rcx
movl 0x38(%rax), %edx
movl 0x3c(%rax), %eax
cmpq $0x2710, %rcx           # imm = 0x2710
jne 0x519d4
movq 0xb0(%rbx), %rcx
movq (%rcx,%rdx,8), %rcx
movq (%rcx,%rax,8), %rdi
addq %r12, %rdi
jmp 0x51962
movq 0xb8(%rbx), %rsi
jmp 0x519db
movq 0xc8(%rbx), %rcx
jmp 0x5194d
movq 0xb0(%rbx), %rsi
movq (%rsi,%rdx,8), %rdx
movq %rcx, %rsi
shlq $0x8, %rsi
leaq (%rsi,%rcx,8), %rdi
addq (%rdx,%rax,8), %rdi
jmp 0x51962
movq 0xc0(%rbx), %rcx
jmp 0x5194d
cmpl $0x0, 0x44(%rbx)
je 0x51ab5
xorl %r14d, %r14d
movq 0x38(%rbx), %rdi
movq (%rdi), %rax
movl %r14d, %esi
callq *0x28(%rax)
cmpl $0x1, %eax
jne 0x51aa6
cmpl $0x0, 0x48(%rbx)
je 0x51aa6
movl $0x1, %r12d
movq 0x38(%rbx), %rdi
movq 0x70(%rbx), %rax
movl (%rax,%r14,4), %edx
movq (%rdi), %rax
movl %r14d, %esi
callq *0x30(%rax)
movq %rax, %r15
movq (%rbx), %rax
movq %rbx, %rdi
movq %r15, %rsi
callq *0x40(%rax)
testb %al, %al
jne 0x51a72
movq (%rbx), %rax
movq %rbx, %rdi
movq %r15, %rsi
callq *0x48(%rax)
testb %al, %al
jne 0x51a72
movq (%rbx), %rax
movq %rbx, %rdi
movq %r15, %rsi
callq *0x50(%rax)
movq 0x70(%rbx), %rcx
movl (%rcx,%r14,4), %eax
incl %eax
xorl %edx, %edx
divl 0x48(%rbx)
movl %edx, (%rcx,%r14,4)
movq 0x38(%rbx), %rdi
movl 0x2c(%r15), %esi
movq (%rdi), %rax
callq *0x28(%rax)
cmpl $0x1, %eax
jne 0x51aa6
leal 0x1(%r12), %eax
cmpl 0x48(%rbx), %r12d
movl %eax, %r12d
jb 0x51a2e
incq %r14
movl 0x44(%rbx), %eax
cmpq %rax, %r14
jb 0x51a0c
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
movq 0x1d528(%rip), %rbx     # 0x6eff0
leaq 0x4ad9(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x8d6b(%rip), %rsi      # 0x5a849
jmp 0x51b1c
movq 0x1d509(%rip), %rbx     # 0x6eff0
leaq 0x4aba(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x8c61(%rip), %rsi      # 0x5a75e
jmp 0x51b1c
movq 0x1d4ea(%rip), %rbx     # 0x6eff0
leaq 0x4a9b(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x8c7e(%rip), %rsi      # 0x5a79a
movq %rbx, %rdi
callq 0x7390
movq %rax, %rdi
callq 0x71c0
movq 0x1d49d(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440