// File: /workspace/github_cpp_makefile_star2_O1/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 $0x48, %rsp
movq %rdx, %rbx
movq %rsi, -0x38(%rbp)
movq %rdi, %r15
leaq -0x29(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0x3604
testb %al, %al
je 0x3496
xorl %r14d, %r14d
cmpl $0x0, 0x5fb4(%rip)      # 0x9154
je 0x31be
movq 0x5fff(%rip), %rsi      # 0x91a8
movsbl -0x29(%rbp), %edx
movl -0x30(%rbp), %ecx
leaq 0x2e4d(%rip), %rdi      # 0x6004
xorl %eax, %eax
callq 0x2030
incq 0x5fe3(%rip)            # 0x91a8
movzbl -0x29(%rbp), %eax
cmpl $0x65, %eax
je 0x347e
cmpl $0x63, %eax
je 0x346a
movslq -0x30(%rbp), %rsi
movq 0x20(%r14), %rax
movq (%rax,%rsi,8), %r12
testb $0x1, (%r12)
jne 0x339a
movq %r14, %rdi
callq 0x4282
testb %al, %al
je 0x32cd
leaq -0x68(%rbp), %r13
movq %r13, %rdi
movq %rbx, %rsi
callq 0x3ad4
movq -0x38(%rbp), %rdi
movq %r13, %rsi
callq 0x381e
movq %rax, %r13
movq -0x68(%rbp), %rdi
testq %rdi, %rdi
je 0x3235
movq -0x58(%rbp), %rsi
subq %rdi, %rsi
callq 0x2150
movslq 0x4(%r13), %rsi
cmpq $-0x1, %rsi
je 0x3313
movq (%rbx), %rax
movq (%rax,%rsi,8), %rax
incq 0x48(%rax)
cmpl $0x0, 0x5eff(%rip)      # 0x9154
je 0x3269
movl 0x8(%r13), %edx
leaq 0x2db2(%rip), %rdi      # 0x6014
xorl %eax, %eax
callq 0x2030
movslq 0x4(%r13), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %rax
movslq 0x8(%r13), %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 0x3313
movl %ecx, %edx
andl $0xffffe03a, %edx       # imm = 0xFFFFE03A
movl %edx, (%rax)
testb $0x10, %cl
jne 0x32ef
andl $0xffffe00a, %ecx       # imm = 0xFFFFE00A
orl $0x20, %ecx
movl %ecx, (%rax)
movslq 0x4(%r13), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %rax
incq 0x68(%rax)
cmpl $0x0, 0x5e92(%rip)      # 0x9154
leaq 0x2ebb(%rip), %rdi      # 0x6184
jne 0x330e
jmp 0x3313
incq 0x38(%r14)
cmpl $0x0, 0x5e7c(%rip)      # 0x9154
je 0x3433
leaq 0x2e99(%rip), %rdi      # 0x617e
callq 0x21c0
jmp 0x3433
movslq 0x4(%r13), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %rax
incq 0x70(%rax)
cmpl $0x0, 0x5e4f(%rip)      # 0x9154
leaq 0x2e95(%rip), %rdi      # 0x61a1
je 0x3313
callq 0x21c0
movl (%r14), %eax
movl %eax, 0x4(%r13)
movl -0x30(%rbp), %eax
movl %eax, 0x8(%r13)
movl (%r12), %eax
testb $0x10, %al
jne 0x3347
testb $0x20, %al
jne 0x344d
incq 0x78(%r14)
cmpl $0x0, 0x5e18(%rip)      # 0x9154
leaq 0x2e46(%rip), %rdi      # 0x6189
jne 0x335b
jmp 0x3360
incq 0x60(%r14)
cmpl $0x0, 0x5e02(%rip)      # 0x9154
leaq 0x2e3a(%rip), %rdi      # 0x6193
je 0x3360
callq 0x21c0
incq 0x50(%r14)
movl (%r13), %eax
andl $0x7f, %eax
shll $0x6, %eax
movl (%r12), %ecx
movl $0xffffe03f, %edx       # imm = 0xFFFFE03F
andl %edx, %ecx
orl %eax, %ecx
movl %ecx, (%r12)
cmpl $0x0, 0x5dce(%rip)      # 0x9154
je 0x339a
movl (%r13), %esi
leaq 0x2c8f(%rip), %rdi      # 0x6022
xorl %eax, %eax
callq 0x2030
cmpb $0x77, -0x29(%rbp)
jne 0x33c0
testb $0x8, (%r12)
je 0x33c0
incq 0x40(%r14)
cmpl $0x0, 0x5da2(%rip)      # 0x9154
je 0x33c0
leaq 0x2ddd(%rip), %rdi      # 0x6198
callq 0x21c0
movsbl -0x29(%rbp), %esi
movq %r12, %rdi
callq 0x4708
cmpl $0x0, 0x5d95(%rip)      # 0x9168
je 0x3414
leaq -0x50(%rbp), %rdi
movq %rbx, %rsi
callq 0x3ad4
movq -0x50(%rbp), %r12
movq -0x48(%rbp), %r13
cmpq %r13, %r12
je 0x33fd
movq (%r12), %rdi
callq 0x4390
addq $0x8, %r12
jmp 0x33e9
movq -0x50(%rbp), %rdi
testq %rdi, %rdi
je 0x3425
movq -0x40(%rbp), %rsi
subq %rdi, %rsi
callq 0x2150
jmp 0x3425
cmpl $0x0, 0x5d49(%rip)      # 0x9164
je 0x3425
movq %r14, %rdi
callq 0x4390
cmpl $0x0, 0x5d40(%rip)      # 0x916c
je 0x3433
callq 0x3500
movq %r15, %rdi
leaq -0x29(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0x3604
testb %al, %al
jne 0x3199
jmp 0x3496
incq 0x58(%r14)
cmpl $0x0, 0x5cfc(%rip)      # 0x9154
leaq 0x2d30(%rip), %rdi      # 0x618f
jne 0x335b
jmp 0x3360
incq 0x5d3f(%rip)            # 0x91b0
movslq -0x30(%rbp), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %r14
jmp 0x3433
incq 0x5d33(%rip)            # 0x91b8
movq %r14, %rdi
movq -0x38(%rbp), %rsi
callq 0x3718
xorl %r14d, %r14d
jmp 0x3433
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
movq -0x68(%rbp), %rdi
testq %rdi, %rdi
leaq -0x58(%rbp), %rax
jne 0x34c7
jmp 0x34d2
movq %rax, %rbx
movq -0x50(%rbp), %rdi
leaq -0x40(%rbp), %rax
testq %rdi, %rdi
je 0x34d2
movq (%rax), %rsi
subq %rdi, %rsi
callq 0x2150
movq %rbx, %rdi
callq 0x2230