// File: 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:
subq $0x138, %rsp            # imm = 0x138
movq %rdi, 0x130(%rsp)
movq 0x130(%rsp), %rax
movq %rax, 0x100(%rsp)
movl 0xa8(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0xa8(%rax)
cmpl $0x0, 0xa8(%rax)
jle 0xa260c
jmp 0xa2f27
movq 0x100(%rsp), %rax
cmpl $0x0, 0xa8(%rax)
jge 0xa2668
movq 0x379cc(%rip), %rdi     # 0xd9ff0
leaq 0x82bd(%rip), %rsi      # 0xaa8e8
callq 0x8440
movq 0x379b9(%rip), %rdi     # 0xd9ff0
leaq 0xc463(%rip), %rsi      # 0xaeaa1
callq 0x8440
movq %rax, %rdi
movq 0x3790b(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x37977(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
movq 0x100(%rsp), %rdi
addq $0x78, %rdi
callq 0x91c80
cmpq $0x0, %rax
jne 0xa2684
jmp 0xa2f27
movq 0x100(%rsp), %rdi
addq $0x78, %rdi
callq 0x7ff20
movq %rax, 0x128(%rsp)
movq 0x100(%rsp), %rdi
addq $0x78, %rdi
callq 0x5d430
movq %rax, 0x120(%rsp)
leaq 0x128(%rsp), %rdi
leaq 0x120(%rsp), %rsi
callq 0x80030
testb $0x1, %al
jne 0xa26d4
jmp 0xa2dc0
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq (%rax), %rax
movl 0x8(%rax), %eax
movl %eax, 0xfc(%rsp)
testl %eax, %eax
je 0xa271b
jmp 0xa26f4
movl 0xfc(%rsp), %eax
subl $0x1, %eax
je 0xa2a44
jmp 0xa2706
movl 0xfc(%rsp), %eax
subl $0x2, %eax
je 0xa2d22
jmp 0xa2da0
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq (%rax), %rax
movl 0x4(%rax), %eax
movl %eax, 0xf8(%rsp)
subl $0x2, %eax
jb 0xa2763
jmp 0xa273c
movl 0xf8(%rsp), %eax
subl $0x2, %eax
je 0xa2964
jmp 0xa274e
movl 0xf8(%rsp), %eax
subl $0x3, %eax
je 0xa28d1
jmp 0xa29f4
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq (%rax), %rax
cmpl $0x2710, 0x18(%rax)     # imm = 0x2710
je 0xa283e
movq 0x100(%rsp), %rax
movq 0xb0(%rax), %rax
movq %rax, 0xd8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xd8(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0xe0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xe0(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0xe8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xe8(%rsp), %rax
movq (%rcx), %rcx
movslq 0x18(%rcx), %rcx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0xf0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0xf0(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa28cc
movq 0x100(%rsp), %rax
movq 0xb0(%rax), %rax
movq %rax, 0xc0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xc0(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0xc8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xc8(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
movq (%rax,%rcx,8), %rax
addq $0x108, %rax            # imm = 0x108
movq %rax, 0xd0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0xd0(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2a3f
movq 0x100(%rsp), %rax
movq 0xd8(%rax), %rax
movq %rax, 0xa8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xa8(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0xb0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0xb0(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0xb8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0xb8(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2a3f
movq 0x100(%rsp), %rax
movq 0xc0(%rax), %rax
movq %rax, 0x90(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x90(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x98(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x98(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0xa0(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0xa0(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2a3f
movq 0x375f5(%rip), %rdi     # 0xd9ff0
leaq 0x7ee6(%rip), %rsi      # 0xaa8e8
callq 0x8440
movq 0x375e2(%rip), %rdi     # 0xd9ff0
leaq 0xbf82(%rip), %rsi      # 0xae997
callq 0x8440
movq %rax, %rdi
movq 0x37534(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x375a0(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
jmp 0xa2da2
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq (%rax), %rax
movl 0x4(%rax), %eax
movl %eax, 0x8c(%rsp)
subl $0x2, %eax
jb 0xa2a8c
jmp 0xa2a65
movl 0x8c(%rsp), %eax
subl $0x2, %eax
je 0xa2c54
jmp 0xa2a77
movl 0x8c(%rsp), %eax
subl $0x3, %eax
je 0xa2bd3
jmp 0xa2cd2
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq (%rax), %rax
cmpl $0x2710, 0x18(%rax)     # imm = 0x2710
je 0xa2b52
movq 0x100(%rsp), %rax
movq 0xb8(%rax), %rax
movq %rax, 0x68(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x70(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x70(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x78(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x78(%rsp), %rax
movq (%rcx), %rcx
movslq 0x18(%rcx), %rcx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0x80(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0x80(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2bce
movq 0x100(%rsp), %rax
movq 0xb8(%rax), %rax
movq %rax, 0x50(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x50(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x58(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x58(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
movq (%rax,%rcx,8), %rax
addq $0x108, %rax            # imm = 0x108
movq %rax, 0x60(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0x60(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2d1d
movq 0x100(%rsp), %rax
movq 0xe0(%rax), %rax
movq %rax, 0x38(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x38(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x40(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x40(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0x48(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0x48(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2d1d
movq 0x100(%rsp), %rax
movq 0xc8(%rax), %rax
movq %rax, 0x20(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x20(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x28(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x28(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0x30(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0x30(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2d1d
movq 0x37317(%rip), %rdi     # 0xd9ff0
leaq 0x7c08(%rip), %rsi      # 0xaa8e8
callq 0x8440
movq 0x37304(%rip), %rdi     # 0xd9ff0
leaq 0xbce0(%rip), %rsi      # 0xae9d3
callq 0x8440
movq %rax, %rdi
movq 0x37256(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x372c2(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
jmp 0xa2da2
movq 0x100(%rsp), %rax
movq 0xd0(%rax), %rax
movq %rax, 0x8(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x8(%rsp), %rax
movq (%rcx), %rcx
movl 0x38(%rcx), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x10(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq %rax, %rcx
movq 0x10(%rsp), %rax
movq (%rcx), %rcx
movl 0x3c(%rcx), %ecx
imulq $0x108, %rcx, %rcx      # imm = 0x108
addq %rcx, %rax
movq %rax, 0x18(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7fda0
movq 0x18(%rsp), %rdi
movq %rax, %rsi
callq 0x7ef00
jmp 0xa2da2
jmp 0xa2da2
jmp 0xa2da4
leaq 0x128(%rsp), %rdi
xorl %esi, %esi
callq 0x91c50
movq %rax, 0x118(%rsp)
jmp 0xa269d
movl $0x0, 0x114(%rsp)
movq 0x100(%rsp), %rcx
movl 0x114(%rsp), %eax
cmpl 0x44(%rcx), %eax
jae 0xa2f27
movq 0x100(%rsp), %rax
movq 0x38(%rax), %rdi
movl 0x114(%rsp), %esi
movq (%rdi), %rax
callq *0x28(%rax)
cmpl $0x1, %eax
jne 0xa2f0f
movl $0x0, 0x110(%rsp)
movq 0x100(%rsp), %rcx
movl 0x110(%rsp), %eax
cmpl 0x48(%rcx), %eax
jae 0xa2f0d
movq 0x100(%rsp), %rax
movq 0x38(%rax), %rdi
movl 0x114(%rsp), %esi
movq 0x70(%rax), %rax
movl 0x114(%rsp), %ecx
movl (%rax,%rcx,4), %edx
movq (%rdi), %rax
callq *0x30(%rax)
movq 0x100(%rsp), %rdi
movq %rax, 0x108(%rsp)
movq 0x108(%rsp), %rsi
movq (%rdi), %rax
callq *0x40(%rax)
testb $0x1, %al
jne 0xa2ea3
movq 0x100(%rsp), %rdi
movq 0x108(%rsp), %rsi
movq (%rdi), %rax
callq *0x48(%rax)
testb $0x1, %al
jne 0xa2ea1
movq 0x100(%rsp), %rdi
movq 0x108(%rsp), %rsi
movq (%rdi), %rax
callq *0x50(%rax)
jmp 0xa2ea3
movq 0x100(%rsp), %rcx
movq 0x70(%rcx), %rax
movl 0x114(%rsp), %edx
movl (%rax,%rdx,4), %eax
addl $0x1, %eax
xorl %edx, %edx
divl 0x48(%rcx)
movq 0x100(%rsp), %rax
movl %edx, %esi
movq 0x70(%rax), %rcx
movl 0x114(%rsp), %edx
movl %esi, (%rcx,%rdx,4)
movq 0x38(%rax), %rdi
movq 0x108(%rsp), %rax
movl 0x2c(%rax), %esi
movq (%rdi), %rax
callq *0x28(%rax)
cmpl $0x1, %eax
je 0xa2ef5
jmp 0xa2f0d
jmp 0xa2ef7
movl 0x110(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x110(%rsp)
jmp 0xa2e10
jmp 0xa2f0f
jmp 0xa2f11
movl 0x114(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x114(%rsp)
jmp 0xa2dcb
addq $0x138, %rsp            # imm = 0x138
retq
nop