// File: CMU-SAFARI[P]MQSim/src/ssd/Data_Cache_Manager_Flash_Advanced.cpp
// Function: SSD_Components::Data_Cache_Manager_Flash_Advanced::handle_transaction_serviced_signal_from_PHY(SSD_Components::NVM_Transaction_Flash*)
void Data_Cache_Manager_Flash_Advanced::handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction)
	{
		//First check if the transaction source is a user request or the cache itself
		if (transaction->Source != Transaction_Source_Type::USERIO && transaction->Source != Transaction_Source_Type::CACHE) {
			return;
		}

		if (transaction->Source == Transaction_Source_Type::USERIO) {
			_my_instance->broadcast_user_memory_transaction_serviced_signal(transaction);
		}

		/* This is an update read (a read that is generated for a write request that partially updates page data).
		*  An update read transaction is issued in Address Mapping Unit, but is consumed in data cache manager.*/
		if (transaction->Type == Transaction_Type::READ) {
			if (((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite != NULL) {
				((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->RelatedRead = NULL;
				return;
			}

			switch (Data_Cache_Manager_Flash_Advanced::caching_mode_per_input_stream[transaction->Stream_id])
			{
				case Caching_Mode::TURNED_OFF:
				case Caching_Mode::WRITE_CACHE:
					transaction->UserIORequest->Transaction_list.remove(transaction);
					if (_my_instance->is_user_request_finished(transaction->UserIORequest)) {
						_my_instance->broadcast_user_request_serviced_signal(transaction->UserIORequest);
					}
					break;
				case Caching_Mode::READ_CACHE:
				case Caching_Mode::WRITE_READ_CACHE:
				{					
					if (((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Exists(transaction->Stream_id, transaction->LPA)) {
						/*MQSim should get rid of writting stale data to the cache.
						* This situation may result from out-of-order transaction execution*/
						Data_Cache_Slot_Type slot = ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Get_slot(transaction->Stream_id, transaction->LPA);
						sim_time_type timestamp = slot.Timestamp;
						NVM::memory_content_type content = slot.Content;
						if (((NVM_Transaction_Flash_RD*)transaction)->DataTimeStamp > timestamp) {
							timestamp = ((NVM_Transaction_Flash_RD*)transaction)->DataTimeStamp;
							content = ((NVM_Transaction_Flash_RD*)transaction)->Content;
						}

						((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Update_data(transaction->Stream_id, transaction->LPA, content,
							timestamp, ((NVM_Transaction_Flash_RD*)transaction)->read_sectors_bitmap | slot.State_bitmap_of_existing_sectors);
					} else  {
						if (!((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Check_free_slot_availability()) {
							std::list<NVM_Transaction*>* evicted_cache_slots = new std::list<NVM_Transaction*>;
							Data_Cache_Slot_Type evicted_slot = ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Evict_one_slot_lru();
							if (evicted_slot.Status == Cache_Slot_Status::DIRTY_NO_FLASH_WRITEBACK) {
								Memory_Transfer_Info* transfer_info = new Memory_Transfer_Info;
								transfer_info->Size_in_bytes = count_sector_no_from_status_bitmap(evicted_slot.State_bitmap_of_existing_sectors) * SECTOR_SIZE_IN_BYTE;
								evicted_cache_slots->push_back(new NVM_Transaction_Flash_WR(Transaction_Source_Type::USERIO,
									transaction->Stream_id, transfer_info->Size_in_bytes, evicted_slot.LPA, NULL, IO_Flow_Priority_Class::UNDEFINED, evicted_slot.Content,
									evicted_slot.State_bitmap_of_existing_sectors, evicted_slot.Timestamp));
								transfer_info->Related_request = evicted_cache_slots;
								transfer_info->next_event_type = Data_Cache_Simulation_Event_Type::MEMORY_READ_FOR_CACHE_EVICTION_FINISHED;
								transfer_info->Stream_id = transaction->Stream_id;
								unsigned int cache_eviction_read_size_in_sectors = count_sector_no_from_status_bitmap(evicted_slot.State_bitmap_of_existing_sectors);
								int sharing_id = transaction->Stream_id;
								if (((Data_Cache_Manager_Flash_Advanced*)_my_instance)->shared_dram_request_queue) {
									sharing_id = 0;
								}
								((Data_Cache_Manager_Flash_Advanced*)_my_instance)->back_pressure_buffer_depth[sharing_id] += cache_eviction_read_size_in_sectors;
								((Data_Cache_Manager_Flash_Advanced*)_my_instance)->service_dram_access_request(transfer_info);
							}
						}
						((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Insert_read_data(transaction->Stream_id, transaction->LPA,
							((NVM_Transaction_Flash_RD*)transaction)->Content, ((NVM_Transaction_Flash_RD*)transaction)->DataTimeStamp, ((NVM_Transaction_Flash_RD*)transaction)->read_sectors_bitmap);

						Memory_Transfer_Info* transfer_info = new Memory_Transfer_Info;
						transfer_info->Size_in_bytes = count_sector_no_from_status_bitmap(((NVM_Transaction_Flash_RD*)transaction)->read_sectors_bitmap) * SECTOR_SIZE_IN_BYTE;
						transfer_info->next_event_type = Data_Cache_Simulation_Event_Type::MEMORY_WRITE_FOR_CACHE_FINISHED;
						transfer_info->Stream_id = transaction->Stream_id;
						((Data_Cache_Manager_Flash_Advanced*)_my_instance)->service_dram_access_request(transfer_info);
					}

					transaction->UserIORequest->Transaction_list.remove(transaction);
					if (_my_instance->is_user_request_finished(transaction->UserIORequest)) {
						_my_instance->broadcast_user_request_serviced_signal(transaction->UserIORequest);
					}
					break;
				}
			}
		} else {//This is a write request
			switch (Data_Cache_Manager_Flash_Advanced::caching_mode_per_input_stream[transaction->Stream_id])
			{
				case Caching_Mode::TURNED_OFF:
				case Caching_Mode::READ_CACHE:
					transaction->UserIORequest->Transaction_list.remove(transaction);
					if (_my_instance->is_user_request_finished(transaction->UserIORequest)) {
						_my_instance->broadcast_user_request_serviced_signal(transaction->UserIORequest);
					}
					break;
				case Caching_Mode::WRITE_CACHE:
				case Caching_Mode::WRITE_READ_CACHE:
				{
					int sharing_id = transaction->Stream_id;
					if (((Data_Cache_Manager_Flash_Advanced*)_my_instance)->shared_dram_request_queue) {
						sharing_id = 0;
					}
					((Data_Cache_Manager_Flash_Advanced*)_my_instance)->back_pressure_buffer_depth[sharing_id] -= transaction->Data_and_metadata_size_in_byte / SECTOR_SIZE_IN_BYTE + (transaction->Data_and_metadata_size_in_byte % SECTOR_SIZE_IN_BYTE == 0 ? 0 : 1);

					if (((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Exists(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA)) {
						Data_Cache_Slot_Type slot = ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Get_slot(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA);
						sim_time_type timestamp = slot.Timestamp;
						NVM::memory_content_type content = slot.Content;
						if (((NVM_Transaction_Flash_WR*)transaction)->DataTimeStamp >= timestamp) {
							((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Remove_slot(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA);
						}
					}
					
					auto user_request = ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[sharing_id].begin();
					while (user_request != ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[sharing_id].end())
					{
						((Data_Cache_Manager_Flash_Advanced*)_my_instance)->write_to_destage_buffer(*user_request);
						if ((*user_request)->Transaction_list.size() == 0) {
							((Data_Cache_Manager_Flash_Advanced*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[sharing_id].erase(user_request++);
						} else {
							user_request++;
						}
						//The traffic load on the backend is high and the waiting requests cannot be serviced
						if (((Data_Cache_Manager_Flash_Advanced*)_my_instance)->back_pressure_buffer_depth[sharing_id] > ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->back_pressure_buffer_max_depth) {
							break;
						}
					}

					/*if (_my_instance->back_pressure_buffer_depth[sharing_id] < _my_instance->back_pressure_buffer_max_depth)//The traffic load on the backend is low and the waiting requests can be serviced
					{
						std::list<NVM_Transaction*>* evicted_cache_slots = new std::list<NVM_Transaction*>;
						while (!((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Empty())
						{
							DataCacheSlotType evicted_slot = ((Data_Cache_Manager_Flash_Advanced*)_my_instance)->per_stream_cache[transaction->Stream_id]->Evict_one_dirty_slot();
							if (evicted_slot.Status != CacheSlotStatus::EMPTY)
							{
								evicted_cache_slots->push_back(new NVM_Transaction_Flash_WR(Transaction_Source_Type::CACHE,
									transaction->Stream_id, count_sector_no_from_status_bitmap(evicted_slot.State_bitmap_of_existing_sectors) * SECTOR_SIZE_IN_BYTE,
									evicted_slot.LPA, NULL, IO_Flow_Priority_Class::UNDEFINED, evicted_slot.Content, evicted_slot.State_bitmap_of_existing_sectors, evicted_slot.Timestamp));
								_my_instance->back_pressure_buffer_depth[sharing_id] += count_sector_no_from_status_bitmap(evicted_slot.State_bitmap_of_existing_sectors);
								cache_eviction_read_size_in_sectors += count_sector_no_from_status_bitmap(evicted_slot.State_bitmap_of_existing_sectors);
							}
							else break;
							if (_my_instance->back_pressure_buffer_depth[sharing_id] >= _my_instance->back_pressure_buffer_max_depth)
								break;
						}
						
						if (cache_eviction_read_size_in_sectors > 0)
						{
							Memory_Transfer_Info* read_transfer_info = new Memory_Transfer_Info;
							read_transfer_info->Size_in_bytes = cache_eviction_read_size_in_sectors * SECTOR_SIZE_IN_BYTE;
							read_transfer_info->Related_request = evicted_cache_slots;
							read_transfer_info->next_event_type = Data_Cache_Simulation_Event_Type::MEMORY_READ_FOR_CACHE_EVICTION_FINISHED;
							read_transfer_info->Stream_id = transaction->Stream_id;
							((Data_Cache_Manager_Flash_Advanced*)_my_instance)->service_dram_access_request(read_transfer_info);
						}
					}*/

					break;
				}
			}
		}
	}

// Assembly:
subq $0x198, %rsp            # imm = 0x198
movq %rdi, 0x190(%rsp)
movq 0x190(%rsp), %rax
cmpl $0x0, 0x4(%rax)
je 0x6a150
movq 0x190(%rsp), %rax
cmpl $0x1, 0x4(%rax)
je 0x6a150
jmp 0x6aadd
movq 0x190(%rsp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x6a175
leaq 0x7057b(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rsi
callq 0x67ca0
movq 0x190(%rsp), %rax
cmpl $0x0, 0x8(%rax)
jne 0x6a746
movq 0x190(%rsp), %rax
cmpq $0x0, 0x88(%rax)
je 0x6a1b8
movq 0x190(%rsp), %rax
movq 0x88(%rax), %rax
movq $0x0, 0x88(%rax)
jmp 0x6aadd
leaq 0x70529(%rip), %rax     # 0xda6e8
movq (%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x54(%rsp)
testl %eax, %eax
je 0x6a1f6
jmp 0x6a1da
movl 0x54(%rsp), %eax
decl %eax
subl $0x2, %eax
jb 0x6a264
jmp 0x6a1e7
movl 0x54(%rsp), %eax
subl $0x3, %eax
jne 0x6a741
jmp 0x6a1f6
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x40, %rdi
movq 0x190(%rsp), %rax
movq %rax, 0x188(%rsp)
leaq 0x188(%rsp), %rsi
callq 0x6c2c0
leaq 0x704b6(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x6c3c0
testb $0x1, %al
jne 0x6a244
jmp 0x6a25f
leaq 0x70495(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x67bf0
jmp 0x6a741
leaq 0x70475(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rdx
movzwl %ax, %esi
callq 0x64390
testb $0x1, %al
jne 0x6a2ac
jmp 0x6a3c5
leaq 0x7042d(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rsi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rcx
leaq 0x158(%rsp), %rdi
movzwl %ax, %edx
callq 0x644c0
movq 0x170(%rsp), %rax
movq %rax, 0x150(%rsp)
movq 0x168(%rsp), %rax
movq %rax, 0x148(%rsp)
movq 0x190(%rsp), %rax
movq 0x98(%rax), %rax
cmpq 0x150(%rsp), %rax
jbe 0x6a35a
movq 0x190(%rsp), %rax
movq 0x98(%rax), %rax
movq %rax, 0x150(%rsp)
movq 0x190(%rsp), %rax
movq 0x80(%rax), %rax
movq %rax, 0x148(%rsp)
leaq 0x7037f(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rdx
movq 0x148(%rsp), %rcx
movq 0x150(%rsp), %r8
movq 0x190(%rsp), %rsi
movq 0x90(%rsi), %r9
orq 0x158(%rsp), %r9
movzwl %ax, %esi
callq 0x64e60
jmp 0x6a6d6
leaq 0x70314(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
callq 0x64610
testb $0x1, %al
jne 0x6a5f8
movl $0x18, %edi
callq 0x8450
movq %rax, %rdi
movq %rdi, 0x48(%rsp)
callq 0x6c250
movq 0x48(%rsp), %rax
movq %rax, 0x140(%rsp)
leaq 0x702c3(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rsi
leaq 0x110(%rsp), %rdi
callq 0x64830
cmpl $0x2, 0x130(%rsp)
jne 0x6a5f6
movl $0x18, %edi
callq 0x8450
movq %rax, 0x108(%rsp)
movq 0x110(%rsp), %rdi
callq 0x5a170
movl %eax, %ecx
shll $0x9, %ecx
movq 0x108(%rsp), %rax
movl %ecx, (%rax)
movq 0x140(%rsp), %rax
movq %rax, 0x38(%rsp)
movl $0xb0, %edi
callq 0x8450
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x40(%rsp)
movq 0x190(%rsp), %rax
movzwl (%rax), %edx
movq 0x108(%rsp), %rax
movl (%rax), %ecx
movq 0x110(%rsp), %r9
movq 0x118(%rsp), %r8
movq 0x120(%rsp), %rsi
movq 0x128(%rsp), %r10
movq %rsp, %rax
movq %r10, 0x18(%rax)
movq %r9, 0x10(%rax)
movq %rsi, 0x8(%rax)
movl $0x2710, (%rax)         # imm = 0x2710
xorl %esi, %esi
movl %esi, %r9d
callq 0x963f0
jmp 0x6a4f7
movq 0x38(%rsp), %rdi
movq 0x40(%rsp), %rax
movq %rax, 0x100(%rsp)
leaq 0x100(%rsp), %rsi
callq 0x6c260
movq 0x140(%rsp), %rcx
movq 0x108(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x108(%rsp), %rax
movl $0x0, 0x10(%rax)
movq 0x190(%rsp), %rax
movw (%rax), %cx
movq 0x108(%rsp), %rax
movw %cx, 0x14(%rax)
movq 0x110(%rsp), %rdi
callq 0x5a170
movl %eax, 0xf0(%rsp)
movq 0x190(%rsp), %rax
movzwl (%rax), %eax
movl %eax, 0xec(%rsp)
leaq 0x70163(%rip), %rax     # 0xda6e0
movq (%rax), %rax
testb $0x1, 0xe0(%rax)
je 0x6a5b9
movl $0x0, 0xec(%rsp)
jmp 0x6a5b9
movq 0x40(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xf8(%rsp)
movl %eax, 0xf4(%rsp)
callq 0x8410
jmp 0x6aae5
movl 0xf0(%rsp), %edx
leaq 0x70119(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xf0(%rax), %rax
movslq 0xec(%rsp), %rcx
addl (%rax,%rcx,4), %edx
movl %edx, (%rax,%rcx,4)
leaq 0x700fa(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x108(%rsp), %rsi
callq 0x6b220
jmp 0x6a5f8
leaq 0x700e1(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rdx
movq 0x190(%rsp), %rcx
movq 0x80(%rcx), %rcx
movq 0x190(%rsp), %rsi
movq 0x98(%rsi), %r8
movq 0x190(%rsp), %rsi
movq 0x90(%rsi), %r9
movzwl %ax, %esi
callq 0x649a0
movl $0x18, %edi
callq 0x8450
movq %rax, 0xe0(%rsp)
movq 0x190(%rsp), %rax
movq 0x90(%rax), %rdi
callq 0x5a170
movl %eax, %ecx
shll $0x9, %ecx
movq 0xe0(%rsp), %rax
movl %ecx, (%rax)
movq 0xe0(%rsp), %rax
movl $0x1, 0x10(%rax)
movq 0x190(%rsp), %rax
movw (%rax), %cx
movq 0xe0(%rsp), %rax
movw %cx, 0x14(%rax)
leaq 0x7001a(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0xe0(%rsp), %rsi
callq 0x6b220
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x40, %rdi
movq 0x190(%rsp), %rax
movq %rax, 0xd8(%rsp)
leaq 0xd8(%rsp), %rsi
callq 0x6c2c0
leaq 0x6ffd6(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x6c3c0
testb $0x1, %al
jne 0x6a724
jmp 0x6a73f
leaq 0x6ffb5(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x67bf0
jmp 0x6a741
jmp 0x6aadd
leaq 0x6ff9b(%rip), %rax     # 0xda6e8
movq (%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movl (%rax,%rcx,4), %eax
movq %rax, 0x30(%rsp)
subq $0x3, %rax
ja 0x6aadb
movq 0x30(%rsp), %rax
leaq 0x42a8f(%rip), %rcx     # 0xad208
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x40, %rdi
movq 0x190(%rsp), %rax
movq %rax, 0xd0(%rsp)
leaq 0xd0(%rsp), %rsi
callq 0x6c2c0
leaq 0x6ff2a(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x6c3c0
testb $0x1, %al
jne 0x6a7d0
jmp 0x6a7eb
leaq 0x6ff09(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x67bf0
jmp 0x6aadb
movq 0x190(%rsp), %rax
movzwl (%rax), %eax
movl %eax, 0xcc(%rsp)
leaq 0x6fed7(%rip), %rax     # 0xda6e0
movq (%rax), %rax
testb $0x1, 0xe0(%rax)
je 0x6a820
movl $0x0, 0xcc(%rsp)
movq 0x190(%rsp), %rax
movl 0x50(%rax), %esi
shrl $0x9, %esi
movq 0x190(%rsp), %rax
movl 0x50(%rax), %edx
andl $0x1ff, %edx            # imm = 0x1FF
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, %edx
cmovel %ecx, %eax
addl %eax, %esi
leaq 0x6fe8b(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xf0(%rax), %rax
movslq 0xcc(%rsp), %rcx
movl (%rax,%rcx,4), %edx
subl %esi, %edx
movl %edx, (%rax,%rcx,4)
leaq 0x6fe6a(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rdx
movzwl %ax, %esi
callq 0x64390
testb $0x1, %al
jne 0x6a8b7
jmp 0x6a978
leaq 0x6fe22(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rsi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rcx
leaq 0x98(%rsp), %rdi
movzwl %ax, %edx
callq 0x644c0
movq 0xb0(%rsp), %rax
movq %rax, 0x90(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x88(%rsp)
movq 0x190(%rsp), %rax
movq 0xa0(%rax), %rax
cmpq 0x90(%rsp), %rax
jb 0x6a976
leaq 0x6fda2(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rax
movq 0x190(%rsp), %rcx
movzwl (%rcx), %ecx
movq (%rax,%rcx,8), %rdi
movq 0x190(%rsp), %rax
movw (%rax), %ax
movq 0x190(%rsp), %rcx
movq 0x58(%rcx), %rdx
movzwl %ax, %esi
callq 0x65060
jmp 0x6a978
leaq 0x6fd61(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd8(%rax), %rdi
movslq 0xcc(%rsp), %rax
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x6bfd0
movq %rax, 0x80(%rsp)
leaq 0x6fd34(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd8(%rax), %rdi
movslq 0xcc(%rsp), %rax
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x6c000
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x6c030
testb $0x1, %al
jne 0x6a9ea
jmp 0x6aad9
leaq 0x6fcef(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq %rax, 0x28(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x6c050
movq 0x28(%rsp), %rdi
movq (%rax), %rsi
callq 0x6b320
leaq 0x80(%rsp), %rdi
callq 0x6c050
movq (%rax), %rdi
addq $0x40, %rdi
callq 0x59910
cmpq $0x0, %rax
jne 0x6aa90
leaq 0x6fca7(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd8(%rax), %rax
movslq 0xcc(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x20(%rsp)
leaq 0x80(%rsp), %rdi
xorl %esi, %esi
callq 0x6c460
movq %rax, 0x68(%rsp)
leaq 0x70(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x6c490
movq 0x20(%rsp), %rdi
movq 0x70(%rsp), %rsi
callq 0x6c410
movq %rax, 0x60(%rsp)
jmp 0x6aaa4
leaq 0x80(%rsp), %rdi
xorl %esi, %esi
callq 0x6c460
movq %rax, 0x58(%rsp)
leaq 0x6fc35(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xf0(%rax), %rax
movslq 0xcc(%rsp), %rcx
movl (%rax,%rcx,4), %eax
leaq 0x6fc19(%rip), %rcx     # 0xda6e0
movq (%rcx), %rcx
cmpl 0xe8(%rcx), %eax
jbe 0x6aad4
jmp 0x6aad9
jmp 0x6a9a5
jmp 0x6aadb
jmp 0x6aadd
addq $0x198, %rsp            # imm = 0x198
retq
movq 0xf8(%rsp), %rdi
callq 0x8770
nopw %cs:(%rax,%rax)