// File: /workspace/github_cpp_makefile_star2_O2/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 %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
movl 0xa8(%rdi), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0xa8(%rdi)
cmpl $0x1, %eax
jg 0x3f4d4
jne 0x3f51b
movq %rdi, %rbx
cmpq $0x0, 0x88(%rdi)
je 0x3f4d4
leaq 0x78(%rbx), %r14
movq %r14, %r15
movq (%r15), %r15
cmpq %r14, %r15
je 0x3f432
movq 0x10(%r15), %rax
movl 0x8(%rax), %ecx
cmpl $0x2, %ecx
je 0x3f3b9
cmpl $0x1, %ecx
je 0x3f39d
testl %ecx, %ecx
jne 0x3f35c
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x3f3e9
je 0x3f429
cmpl $0x3, %ecx
jne 0x3f4dd
movq 0xd8(%rbx), %rcx
jmp 0x3f3c0
movl 0x4(%rax), %ecx
cmpl $0x2, %ecx
jb 0x3f3dc
je 0x3f420
cmpl $0x3, %ecx
jne 0x3f4fc
movq 0xe0(%rbx), %rcx
jmp 0x3f3c0
movq 0xd0(%rbx), %rcx
movl 0x38(%rax), %edx
movl 0x3c(%rax), %eax
imulq $0x108, %rax, %rdi      # imm = 0x108
addq (%rcx,%rdx,8), %rdi
leaq 0x10(%r15), %rsi
callq 0x3240c
jmp 0x3f35c
movslq 0x18(%rax), %rcx
movq 0xb8(%rbx), %rdx
jmp 0x3f3f4
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 0x3f414
addq $0x108, %rdi            # imm = 0x108
jmp 0x3f3d1
imulq $0x108, %rcx, %rax      # imm = 0x108
addq %rax, %rdi
jmp 0x3f3d1
movq 0xc8(%rbx), %rcx
jmp 0x3f3c0
movq 0xc0(%rbx), %rcx
jmp 0x3f3c0
xorl %r14d, %r14d
pushq $-0x1
popq %rbp
movl 0x44(%rbx), %eax
cmpq %rax, %r14
jae 0x3f4d4
movq 0x38(%rbx), %rdi
movq (%rdi), %rax
movl %r14d, %esi
callq *0x28(%rax)
cmpl $0x1, %eax
jne 0x3f4cc
movl %ebp, %r12d
incl %r12d
cmpl 0x48(%rbx), %r12d
jae 0x3f4cc
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 0x3f4a6
movq (%rbx), %rax
movq %rbx, %rdi
movq %r15, %rsi
callq *0x48(%rax)
testb %al, %al
jne 0x3f4a6
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
je 0x3f459
incq %r14
jmp 0x3f438
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
movq 0x22b0c(%rip), %rbx     # 0x61ff0
leaq 0x509d(%rip), %rsi      # 0x44588
movq %rbx, %rdi
callq 0x7360
leaq 0x9135(%rip), %rsi      # 0x4862f
jmp 0x3f538
movq 0x22aed(%rip), %rbx     # 0x61ff0
leaq 0x507e(%rip), %rsi      # 0x44588
movq %rbx, %rdi
callq 0x7360
leaq 0x9152(%rip), %rsi      # 0x4866b
jmp 0x3f538
movq 0x22ace(%rip), %rbx     # 0x61ff0
leaq 0x505f(%rip), %rsi      # 0x44588
movq %rbx, %rdi
callq 0x7360
leaq 0x91e1(%rip), %rsi      # 0x48719
movq %rbx, %rdi
callq 0x7360
movq %rax, %rdi
callq 0x71a0
movq 0x22a81(%rip), %rdi     # 0x61fd0
callq 0x73d0
pushq $0x1
popq %rdi
callq 0x73e0