// File: /workspace/github_cpp_makefile_star2_O3/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 0x5105d
jne 0x51069
movq %rdi, %rbx
cmpq $0x0, 0x88(%rdi)
je 0x5105d
leaq 0x78(%rbx), %r14
movq (%r14), %r15
cmpq %r14, %r15
je 0x50fa7
movq 0x10(%r15), %rax
movl 0x8(%rax), %ecx
cmpl $0x2, %ecx
je 0x50f20
cmpl $0x1, %ecx
je 0x50f00
testl %ecx, %ecx
jne 0x50f45
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x50f5a
je 0x50f9e
cmpl $0x3, %ecx
jne 0x51088
movq 0xd8(%rbx), %rcx
jmp 0x50f27
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x50f4d
je 0x50f95
cmpl $0x3, %ecx
jne 0x510a7
movq 0xe0(%rbx), %rcx
jmp 0x50f27
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 0x3df04
movq (%r15), %r15
jmp 0x50ec2
movslq 0x18(%rax), %rcx
movq 0xb8(%rbx), %rdx
jmp 0x50f65
movslq 0x18(%rax), %rcx
movq 0xb0(%rbx), %rdx
movl 0x38(%rax), %esi
movl 0x3c(%rax), %eax
movq (%rdx,%rsi,8), %rdx
movq (%rdx,%rax,8), %rdi
cmpq $0x2710, %rcx           # imm = 0x2710
jne 0x50f85
addq $0x108, %rdi            # imm = 0x108
jmp 0x50f3c
movq %rcx, %rax
shlq $0x8, %rax
leaq (%rax,%rcx,8), %rax
addq %rax, %rdi
jmp 0x50f3c
movq 0xc8(%rbx), %rcx
jmp 0x50f27
movq 0xc0(%rbx), %rcx
jmp 0x50f27
cmpl $0x0, 0x44(%rbx)
je 0x5105d
xorl %r14d, %r14d
movq 0x38(%rbx), %rdi
movq (%rdi), %rax
movl %r14d, %esi
callq *0x28(%rax)
cmpl $0x1, %eax
jne 0x5104e
cmpl $0x0, 0x48(%rbx)
je 0x5104e
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 0x5101a
movq (%rbx), %rax
movq %rbx, %rdi
movq %r15, %rsi
callq *0x48(%rax)
testb %al, %al
jne 0x5101a
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 0x5104e
leal 0x1(%r12), %eax
cmpl 0x48(%rbx), %r12d
movl %eax, %r12d
jb 0x50fd6
incq %r14
movl 0x44(%rbx), %eax
cmpq %rax, %r14
jb 0x50fb4
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
movq 0x1df80(%rip), %rbx     # 0x6eff0
leaq 0x5531(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x980f(%rip), %rsi      # 0x5a895
jmp 0x510c4
movq 0x1df61(%rip), %rbx     # 0x6eff0
leaq 0x5512(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x96b9(%rip), %rsi      # 0x5a75e
jmp 0x510c4
movq 0x1df42(%rip), %rbx     # 0x6eff0
leaq 0x54f3(%rip), %rsi      # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x96d6(%rip), %rsi      # 0x5a79a
movq %rbx, %rdi
callq 0x7390
movq %rax, %rdi
callq 0x71c0
movq 0x1def5(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440