// File: /workspace/github_cpp_makefile_star2_O3/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 0x3668
testb %al, %al
je 0x34eb
xorl %r14d, %r14d
cmpl $0x0, 0x5f6a(%rip)      # 0x9154
je 0x3208
movq 0x5fb5(%rip), %rsi      # 0x91a8
movsbl -0x29(%rbp), %edx
movl -0x30(%rbp), %ecx
leaq 0x2e03(%rip), %rdi      # 0x6004
xorl %eax, %eax
callq 0x2030
incq 0x5f99(%rip)            # 0x91a8
movzbl -0x29(%rbp), %eax
cmpl $0x65, %eax
je 0x34d3
cmpl $0x63, %eax
je 0x34bf
movslq -0x30(%rbp), %rsi
movq 0x20(%r14), %rax
movq (%rax,%rsi,8), %r12
testb $0x1, (%r12)
jne 0x33e4
movq %r14, %rdi
callq 0x42f6
testb %al, %al
je 0x3317
leaq -0x68(%rbp), %r13
movq %r13, %rdi
movq %rbx, %rsi
callq 0x3b38
movq -0x38(%rbp), %rdi
movq %r13, %rsi
callq 0x3882
movq %rax, %r13
movq -0x68(%rbp), %rdi
testq %rdi, %rdi
je 0x327f
movq -0x58(%rbp), %rsi
subq %rdi, %rsi
callq 0x2150
movslq 0x4(%r13), %rsi
cmpq $-0x1, %rsi
je 0x335d
movq (%rbx), %rax
movq (%rax,%rsi,8), %rax
incq 0x48(%rax)
cmpl $0x0, 0x5eb5(%rip)      # 0x9154
je 0x32be
movl 0x8(%r13), %edx
leaq 0x2d68(%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 0x335d
movl %ecx, %edx
andl $0xffffe03a, %edx       # imm = 0xFFFFE03A
movl %edx, (%rax)
testb $0x10, %cl
jne 0x3339
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, 0x5e48(%rip)      # 0x9154
leaq 0x2e71(%rip), %rdi      # 0x6184
jne 0x3358
jmp 0x335d
incq 0x38(%r14)
cmpl $0x0, 0x5e32(%rip)      # 0x9154
je 0x3488
leaq 0x2e4f(%rip), %rdi      # 0x617e
callq 0x21c0
jmp 0x3488
movslq 0x4(%r13), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %rax
incq 0x70(%rax)
cmpl $0x0, 0x5e05(%rip)      # 0x9154
leaq 0x2e4b(%rip), %rdi      # 0x61a1
je 0x335d
callq 0x21c0
movl (%r14), %eax
movl %eax, 0x4(%r13)
movl -0x30(%rbp), %eax
movl %eax, 0x8(%r13)
movl (%r12), %eax
testb $0x10, %al
jne 0x3391
testb $0x20, %al
jne 0x34a2
incq 0x78(%r14)
cmpl $0x0, 0x5dce(%rip)      # 0x9154
leaq 0x2dfc(%rip), %rdi      # 0x6189
jne 0x33a5
jmp 0x33aa
incq 0x60(%r14)
cmpl $0x0, 0x5db8(%rip)      # 0x9154
leaq 0x2df0(%rip), %rdi      # 0x6193
je 0x33aa
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, 0x5d84(%rip)      # 0x9154
je 0x33e4
movl (%r13), %esi
leaq 0x2c45(%rip), %rdi      # 0x6022
xorl %eax, %eax
callq 0x2030
movb -0x29(%rbp), %al
cmpb $0x77, %al
jne 0x3410
movb $0x77, %al
testb $0x8, (%r12)
je 0x3410
incq 0x40(%r14)
cmpl $0x0, 0x5d55(%rip)      # 0x9154
je 0x3410
leaq 0x2d90(%rip), %rdi      # 0x6198
callq 0x21c0
movb -0x29(%rbp), %al
movsbl %al, %esi
movq %r12, %rdi
callq 0x4780
cmpl $0x0, 0x5d46(%rip)      # 0x9168
je 0x3469
leaq -0x50(%rbp), %rdi
movq %rbx, %rsi
callq 0x3b38
movq -0x50(%rbp), %r12
movq -0x48(%rbp), %r13
cmpq %r13, %r12
je 0x3453
movq (%r12), %rdi
callq 0x4400
addq $0x8, %r12
cmpq %r13, %r12
jne 0x343d
movq -0x50(%rbp), %r12
testq %r12, %r12
je 0x347a
movq -0x40(%rbp), %rsi
subq %r12, %rsi
movq %r12, %rdi
callq 0x2150
jmp 0x347a
cmpl $0x0, 0x5cf4(%rip)      # 0x9164
je 0x347a
movq %r14, %rdi
callq 0x4400
cmpl $0x0, 0x5ceb(%rip)      # 0x916c
je 0x3488
callq 0x3555
movq %r15, %rdi
leaq -0x29(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0x3668
testb %al, %al
jne 0x31e3
jmp 0x34eb
incq 0x58(%r14)
cmpl $0x0, 0x5ca7(%rip)      # 0x9154
leaq 0x2cdb(%rip), %rdi      # 0x618f
jne 0x33a5
jmp 0x33aa
incq 0x5cea(%rip)            # 0x91b0
movslq -0x30(%rbp), %rax
movq (%rbx), %rcx
movq (%rcx,%rax,8), %r14
jmp 0x3488
incq 0x5cde(%rip)            # 0x91b8
movq %r14, %rdi
movq -0x38(%rbp), %rsi
callq 0x377c
xorl %r14d, %r14d
jmp 0x3488
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 0x351c
jmp 0x3527
movq %rax, %rbx
movq -0x50(%rbp), %rdi
leaq -0x40(%rbp), %rax
testq %rdi, %rdi
je 0x3527
movq (%rax), %rsi
subq %rdi, %rsi
callq 0x2150
movq %rbx, %rdi
callq 0x2230