// File: eva23511[P]OS-Virtual-Memory-Management/main.cpp
// Function: Simulation(std::basic_ifstream<char, std::char_traits<char>>&, Pager*, std::vector<Process*, std::allocator<Process*>>)
void Simulation(ifstream &input_file, Pager * pager, vector<Process *> processes) {
    char operation;
    int vpage;
    Process * curr_process = nullptr;
    
    while (GetNextInstruction(input_file, operation, vpage)) {
        
        if (O_option) {
            printf("%ld: ==> %c %d\n", inst_count, operation, vpage);
        }
        inst_count++;
        
        // handle special case of “c”: context switch to process #<procid>
        if (operation == 'c') {
            ctx_switches++;
            curr_process = processes[vpage];
            continue;
        }
        
        // handle special case of “e”: exit current process
        if (operation == 'e') {
            process_exits++;
            ExitProcess(curr_process, pager);
            curr_process = nullptr;
            continue;
        }
        
        Pte * curr_pte = curr_process->page_table[vpage];
        
        // the page is not present, raise a page fault exception
        if (!curr_pte->present) {
            
            // the vpage can't be accessed, i.e. it is not part of one of the VMAs
            if (!curr_process->InVmas(vpage)) {
                curr_process->segv_count++;
                if (O_option) {
                    printf(" SEGV\n");
                }
                continue;
            }
            
            // Select a frame to replace
            Frame * curr_frame = GetFrame(pager, processes);
            
            // curr_frame is not free currently
            if (curr_frame->pid != -1) {
                
                // Unmap its current user (UNMAP)
                processes[curr_frame->pid]->unmap_count++;
                if (O_option) {
                    printf(" UNMAP %d:%d\n", curr_frame->pid, curr_frame->vpage);
                }
                Pte * pre_ptd = processes[curr_frame->pid]->page_table[curr_frame->vpage];
                pre_ptd->present = 0;
                
                // Save frame to disk (OUT / FOUT)
                if (pre_ptd->modified) {
                    pre_ptd->modified = 0;
                    pre_ptd->physical_frame = 0;
                    
                    if (pre_ptd->file_mapped) {
                        processes[curr_frame->pid]->fout_count++;
                        if (O_option) {
                            printf(" FOUT\n");
                        }
                    } else {
                        pre_ptd->pagedout = 1;
                        processes[curr_frame->pid]->out_count++;
                        if (O_option) {
                            printf(" OUT\n");
                        }
                    }
                }
            }
            
            // Fill frame with proper content of current instruction’s address space (IN, FIN,ZERO)
            curr_frame->pid = curr_process->pid;
            curr_frame->vpage = vpage;
            
            if (curr_pte->file_mapped) {
                curr_process->fin_count++;
                if (O_option) {
                    printf(" FIN\n");
                }
            } else if (curr_pte->pagedout) {
                curr_process->in_count++;
                if (O_option) {
                    printf(" IN\n");
                }
            } else {
                curr_process->zero_count++;
                if (O_option) {
                    printf(" ZERO\n");
                }
            }
            
            // Map its new user (MAP)
            curr_process->map_count++;
            curr_pte->physical_frame = curr_frame->idx;
            if (O_option) {
                printf(" MAP %d\n", curr_frame->idx);
            }
        }
        
        // check write protection: page is considered referenced but not modified
        if (operation == 'w' && curr_pte->write_protect) {
            curr_process->segprot_count++;
            if (O_option) {
                printf(" SEGPROT\n");
            }
        }
        
        // updating the R/M PTE bits
        curr_pte->UpdatePte(operation); // update_pte(read/modify) bits based on operations
        
        if (y_option) {
            PrintPagetable(processes);
        } else if (x_option) {
            curr_process->PrintPagetable();
        }
        
        if (f_option) {
            PrintFrameTable();
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdx, -0x88(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq $0x0, -0x28(%rbp)
movq -0x8(%rbp), %rdi
leaq -0x19(%rbp), %rsi
leaq -0x20(%rbp), %rdx
callq 0x4ba0
testb $0x1, %al
jne 0x44c0
jmp 0x4961
cmpl $0x0, 0x10d1d(%rip)     # 0x151e4
je 0x44e5
movq 0x10d68(%rip), %rsi     # 0x15238
movsbl -0x19(%rbp), %edx
movl -0x20(%rbp), %ecx
leaq 0x9bf6(%rip), %rdi      # 0xe0d4
movb $0x0, %al
callq 0x3030
movq 0x10d4c(%rip), %rax     # 0x15238
addq $0x1, %rax
movq %rax, 0x10d41(%rip)     # 0x15238
movsbl -0x19(%rbp), %eax
cmpl $0x63, %eax
jne 0x452e
movq -0x88(%rbp), %rdi
movq 0x10d32(%rip), %rax     # 0x15240
addq $0x1, %rax
movq %rax, 0x10d27(%rip)     # 0x15240
movslq -0x20(%rbp), %rsi
callq 0x5410
movq (%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0x44a6
movsbl -0x19(%rbp), %eax
cmpl $0x65, %eax
jne 0x4563
movq 0x10d0a(%rip), %rax     # 0x15248
addq $0x1, %rax
movq %rax, 0x10cff(%rip)     # 0x15248
movq -0x28(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x4cf0
movq $0x0, -0x28(%rbp)
jmp 0x44a6
movq -0x28(%rbp), %rdi
addq $0x20, %rdi
movslq -0x20(%rbp), %rsi
callq 0x5430
movq (%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movl (%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x489a
movq -0x28(%rbp), %rdi
movl -0x20(%rbp), %esi
callq 0x90b0
testb $0x1, %al
jne 0x45c9
movq -0x28(%rbp), %rax
movq 0x38(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x38(%rax)
cmpl $0x0, 0x10c30(%rip)     # 0x151e4
je 0x45c4
leaq 0x9b27(%rip), %rdi      # 0xe0e4
movb $0x0, %al
callq 0x3030
jmp 0x44a6
movq -0x88(%rbp), %rsi
movq -0x10(%rbp), %rax
movq %rax, -0xa0(%rbp)
leaq -0x50(%rbp), %rdi
movq %rdi, -0x98(%rbp)
callq 0x52c0
movq -0xa0(%rbp), %rdi
movq -0x98(%rbp), %rsi
callq 0x4e70
movq %rax, -0x90(%rbp)
jmp 0x4607
leaq -0x50(%rbp), %rdi
callq 0x53b0
movq -0x90(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
cmpl $-0x1, 0x4(%rax)
je 0x4799
movq -0x88(%rbp), %rdi
movq -0x38(%rbp), %rax
movslq 0x4(%rax), %rsi
callq 0x5410
movq (%rax), %rax
movq 0x48(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x48(%rax)
cmpl $0x0, 0x10b91(%rip)     # 0x151e4
je 0x468d
movq -0x38(%rbp), %rax
movl 0x4(%rax), %esi
movq -0x38(%rbp), %rax
movl 0x8(%rax), %edx
leaq 0x9a81(%rip), %rdi      # 0xe0eb
movb $0x0, %al
callq 0x3030
jmp 0x468d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x53b0
jmp 0x496a
movq -0x88(%rbp), %rdi
movq -0x38(%rbp), %rax
movslq 0x4(%rax), %rsi
callq 0x5410
movq (%rax), %rdi
addq $0x20, %rdi
movq -0x38(%rbp), %rax
movslq 0x8(%rax), %rsi
callq 0x5430
movq (%rax), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movl (%rax), %ecx
andl $-0x2, %ecx
orl $0x0, %ecx
movl %ecx, (%rax)
movq -0x68(%rbp), %rax
movl (%rax), %eax
shrl $0x2, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x4797
movq -0x68(%rbp), %rax
movl (%rax), %ecx
andl $-0x5, %ecx
orl $0x0, %ecx
movl %ecx, (%rax)
movq -0x68(%rbp), %rax
movl (%rax), %ecx
andl $0xffffe03f, %ecx       # imm = 0xFFFFE03F
orl $0x0, %ecx
movl %ecx, (%rax)
movq -0x68(%rbp), %rax
movl (%rax), %eax
shrl $0x4, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x474b
movq -0x88(%rbp), %rdi
movq -0x38(%rbp), %rax
movslq 0x4(%rax), %rsi
callq 0x5410
movq (%rax), %rax
movq 0x70(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x70(%rax)
cmpl $0x0, 0x10aab(%rip)     # 0x151e4
je 0x4749
leaq 0x99b7(%rip), %rdi      # 0xe0f9
movb $0x0, %al
callq 0x3030
jmp 0x4795
movq -0x88(%rbp), %rdi
movq -0x68(%rbp), %rax
movl (%rax), %ecx
andl $-0x21, %ecx
orl $0x20, %ecx
movl %ecx, (%rax)
movq -0x38(%rbp), %rax
movslq 0x4(%rax), %rsi
callq 0x5410
movq (%rax), %rax
movq 0x68(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x68(%rax)
cmpl $0x0, 0x10a61(%rip)     # 0x151e4
je 0x4793
leaq 0x9974(%rip), %rdi      # 0xe100
movb $0x0, %al
callq 0x3030
jmp 0x4795
jmp 0x4797
jmp 0x4799
movq -0x28(%rbp), %rax
movl (%rax), %ecx
movq -0x38(%rbp), %rax
movl %ecx, 0x4(%rax)
movl -0x20(%rbp), %ecx
movq -0x38(%rbp), %rax
movl %ecx, 0x8(%rax)
movq -0x30(%rbp), %rax
movl (%rax), %eax
shrl $0x4, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x47ea
movq -0x28(%rbp), %rax
movq 0x60(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x60(%rax)
cmpl $0x0, 0x10a0c(%rip)     # 0x151e4
je 0x47e8
leaq 0x9925(%rip), %rdi      # 0xe106
movb $0x0, %al
callq 0x3030
jmp 0x484f
movq -0x30(%rbp), %rax
movl (%rax), %eax
shrl $0x5, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x4824
movq -0x28(%rbp), %rax
movq 0x58(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x58(%rax)
cmpl $0x0, 0x109d2(%rip)     # 0x151e4
je 0x4822
leaq 0x98f1(%rip), %rdi      # 0xe10c
movb $0x0, %al
callq 0x3030
jmp 0x484d
movq -0x28(%rbp), %rax
movq 0x78(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x78(%rax)
cmpl $0x0, 0x109a9(%rip)     # 0x151e4
je 0x484b
leaq 0x98cd(%rip), %rdi      # 0xe111
movb $0x0, %al
callq 0x3030
jmp 0x484d
jmp 0x484f
movq -0x28(%rbp), %rax
movq 0x50(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x50(%rax)
movq -0x38(%rbp), %rax
movl (%rax), %edx
movq -0x30(%rbp), %rax
movl (%rax), %ecx
andl $0x7f, %edx
shll $0x6, %edx
andl $0xffffe03f, %ecx       # imm = 0xFFFFE03F
orl %edx, %ecx
movl %ecx, (%rax)
cmpl $0x0, 0x10962(%rip)     # 0x151e4
je 0x4898
movq -0x38(%rbp), %rax
movl (%rax), %esi
leaq 0x9887(%rip), %rdi      # 0xe118
movb $0x0, %al
callq 0x3030
jmp 0x489a
movsbl -0x19(%rbp), %eax
cmpl $0x77, %eax
jne 0x48dd
movq -0x30(%rbp), %rax
movl (%rax), %eax
shrl $0x3, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x48dd
movq -0x28(%rbp), %rax
movq 0x40(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x40(%rax)
cmpl $0x0, 0x10919(%rip)     # 0x151e4
je 0x48db
leaq 0x984d(%rip), %rdi      # 0xe121
movb $0x0, %al
callq 0x3030
jmp 0x48dd
movq -0x30(%rbp), %rdi
movsbl -0x19(%rbp), %esi
callq 0xa950
cmpl $0x0, 0x10907(%rip)     # 0x151f8
je 0x493a
movq -0x88(%rbp), %rsi
leaq -0x80(%rbp), %rdi
movq %rdi, -0xa8(%rbp)
callq 0x52c0
movq -0xa8(%rbp), %rdi
callq 0x4980
jmp 0x4918
leaq -0x80(%rbp), %rdi
callq 0x53b0
jmp 0x494e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0x80(%rbp), %rdi
callq 0x53b0
jmp 0x496a
cmpl $0x0, 0x108b3(%rip)     # 0x151f4
je 0x494c
movq -0x28(%rbp), %rdi
callq 0x9290
jmp 0x494e
cmpl $0x0, 0x108a7(%rip)     # 0x151fc
je 0x495c
callq 0x49f0
jmp 0x44a6
addq $0xb0, %rsp
popq %rbp
retq
movq -0x58(%rbp), %rdi
callq 0x3320
nopw %cs:(%rax,%rax)