// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rdx, %r14
movq %rsi, -0x40(%rbp)
movq %rdi, -0x48(%rbp)
leaq -0x60(%rbp), %r12
xorl %r15d, %r15d
movq %r12, -0x38(%rbp)
movq -0x48(%rbp), %rdi
leaq -0x29(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0x31f2
testb %al, %al
je 0x30a1
cmpl $0x0, 0x5397(%rip)      # 0x8174
je 0x2dfb
movq 0x53e2(%rip), %rsi      # 0x81c8
movsbl -0x29(%rbp), %edx
movl -0x30(%rbp), %ecx
leaq 0x2210(%rip), %rdi      # 0x5004
xorl %eax, %eax
callq 0x2030
incq 0x53c6(%rip)            # 0x81c8
movzbl -0x29(%rbp), %eax
cmpl $0x65, %eax
je 0x3086
cmpl $0x63, %eax
je 0x306f
movslq -0x30(%rbp), %rsi
movq 0x20(%r15), %rax
movq (%rax,%rsi,8), %r13
testb $0x1, (%r13)
jne 0x2fc9
movq %r15, %rdi
callq 0x3f6c
testb %al, %al
je 0x2f02
movq %r14, %rsi
leaq -0x60(%rbp), %r14
movq %r14, %rdi
movq %rsi, %r12
callq 0x3598
movq -0x40(%rbp), %rdi
movq %r14, %rsi
callq 0x33a4
movq %rax, %rbx
movq %r14, %rdi
callq 0x382a
movslq 0x4(%rbx), %rsi
cmpq $-0x1, %rsi
movq %r12, %r14
je 0x2f48
movq (%r14), %rax
movq (%rax,%rsi,8), %rax
incq 0x48(%rax)
cmpl $0x0, 0x52e9(%rip)      # 0x8174
je 0x2ea9
movl 0x8(%rbx), %edx
leaq 0x217d(%rip), %rdi      # 0x5014
xorl %eax, %eax
callq 0x2030
movslq 0x4(%rbx), %rax
movq (%r14), %rcx
movq (%rcx,%rax,8), %rax
movslq 0x8(%rbx), %rcx
movq 0x20(%rax), %rax
movq (%rax,%rcx,8), %rax
movl (%rax), %ecx
movl %ecx, %edx
andl $-0x2, %edx
movl %edx, (%rax)
testb $0x4, %cl
je 0x2f48
movl %ecx, %edx
andl $0xffffe03a, %edx       # imm = 0xFFFFE03A
movl %edx, (%rax)
testb $0x10, %cl
jne 0x2f24
andl $0xffffe00a, %ecx       # imm = 0xFFFFE00A
orl $0x20, %ecx
movl %ecx, (%rax)
movslq 0x4(%rbx), %rax
movq (%r14), %rcx
movq (%rcx,%rax,8), %rax
incq 0x68(%rax)
cmpl $0x0, 0x527d(%rip)      # 0x8174
leaq 0x2286(%rip), %rdi      # 0x5184
jne 0x2f43
jmp 0x2f48
incq 0x38(%r15)
cmpl $0x0, 0x5267(%rip)      # 0x8174
je 0x2dbd
leaq 0x2264(%rip), %rdi      # 0x517e
callq 0x2200
jmp 0x2dbd
movslq 0x4(%rbx), %rax
movq (%r14), %rcx
movq (%rcx,%rax,8), %rax
incq 0x70(%rax)
cmpl $0x0, 0x523a(%rip)      # 0x8174
leaq 0x2260(%rip), %rdi      # 0x51a1
je 0x2f48
callq 0x2200
movl (%r15), %eax
movl %eax, 0x4(%rbx)
movl -0x30(%rbp), %eax
movl %eax, 0x8(%rbx)
movl (%r13), %eax
testb $0x10, %al
jne 0x2f7a
testb $0x20, %al
jne 0x3052
incq 0x78(%r15)
cmpl $0x0, 0x5205(%rip)      # 0x8174
leaq 0x2213(%rip), %rdi      # 0x5189
jne 0x2f8e
jmp 0x2f93
incq 0x60(%r15)
cmpl $0x0, 0x51ef(%rip)      # 0x8174
leaq 0x2207(%rip), %rdi      # 0x5193
je 0x2f93
callq 0x2200
incq 0x50(%r15)
movl (%rbx), %eax
andl $0x7f, %eax
shll $0x6, %eax
movl (%r13), %ecx
movl $0xffffe03f, %edx       # imm = 0xFFFFE03F
andl %edx, %ecx
orl %eax, %ecx
movl %ecx, (%r13)
cmpl $0x0, 0x51bd(%rip)      # 0x8174
je 0x2fc9
movl (%rbx), %esi
leaq 0x2060(%rip), %rdi      # 0x5022
xorl %eax, %eax
callq 0x2030
movb -0x29(%rbp), %al
cmpb $0x77, %al
jne 0x2ff5
movb $0x77, %al
testb $0x8, (%r13)
je 0x2ff5
incq 0x40(%r15)
cmpl $0x0, 0x5190(%rip)      # 0x8174
je 0x2ff5
leaq 0x21ab(%rip), %rdi      # 0x5198
callq 0x2200
movb -0x29(%rbp), %al
movsbl %al, %esi
movq %r13, %rdi
callq 0x44c2
cmpl $0x0, 0x5181(%rip)      # 0x8188
je 0x302a
leaq -0x78(%rbp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x3598
movq %r12, %rdi
callq 0x30cd
movq %r12, %rdi
callq 0x382a
jmp 0x303b
cmpl $0x0, 0x5153(%rip)      # 0x8184
je 0x303b
movq %r15, %rdi
callq 0x4072
cmpl $0x0, 0x514a(%rip)      # 0x818c
je 0x2dbd
callq 0x30f3
jmp 0x2dbd
incq 0x58(%r15)
cmpl $0x0, 0x5117(%rip)      # 0x8174
leaq 0x212b(%rip), %rdi      # 0x518f
jne 0x2f8e
jmp 0x2f93
incq 0x515a(%rip)            # 0x81d0
movslq -0x30(%rbp), %rax
movq (%r14), %rcx
movq (%rcx,%rax,8), %r15
jmp 0x2dbd
incq 0x514b(%rip)            # 0x81d8
movq %r15, %rdi
movq -0x40(%rbp), %rsi
callq 0x32bb
xorl %r15d, %r15d
jmp 0x2dbd
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
jmp 0x30bc
movq %rax, %rbx
movq %r12, -0x38(%rbp)
movq -0x38(%rbp), %rdi
callq 0x382a
movq %rbx, %rdi
callq 0x2270