// File: /workspace/github_cpp_makefile_star2_O2/gibsjose[P]VirtualMemorySimulation/Memory.cpp
// Function: Memory::Reference(Process&, unsigned short)
void Memory::Reference(Process & process, uint16_t page) {

    //Check to see if the process already has an entry in it's page table
    if(process.GetPageTable().EntryExists(page)) {
        //Get frame number
        uint16_t frame = process.GetPageTable().GetEntry(page).frame;

        //Check to see if it is already in RAM or if it is in the free frame list
        if(InRAM(frame)) {
            //...nothing to do...
            std::cout << Color::Green("*") << " Process " << process.GetName() << " (page " << page << " --> frame " << frame << ") already in RAM" << std::endl;
            return;
        }

        else if(InFreeFrameList(frame)) {
            std::cout << "Frame " << frame << " in free frame list" << std::endl;
            return;
        }

        //Bad... if the entry exists it should always either be in the free frame list or in RAM
        else {
            std::cerr << "Frame " << frame << ": something bad has happened..." << std::endl;
            return;
        }
    }

    //Process does NOT have an entry for this page: PAGE FAULT
    else {
        std::cout << Color::Red("! [PAGE FAULT]") << " for process " << process.GetName() << " page " << page;
        process.PageFault();

        //Add an entry
        PageTableEntry entry;

        //Check if there are any free frames
        if(AreFreeFrames()) {
            entry.frame = GetFreeFrame();
            entry.ref = true;
            entry.dirty = false;

            process.GetPageTable().AddEntry(page, entry);

            //Move the frame from the available set to RAM
            AvailableToRAM(entry.frame);

            LRUEntry lruEntry;
            lruEntry.process = &process;
            lruEntry.page = page;
            lruEntry.frame = entry.frame;

            //Push the process, page, and frame to the LRU deque
            lru.push_front(lruEntry);

            std::cout << ": Assigned " << Color::Green("free") << " frame " << entry.frame << std::endl;
        }

        //No free frames!
        //Must implement LRU to select a victim...
        else {
            std::cout << std::endl;
            std::cout << Color::Cyan("- [COLLISION]") << " LRU Replacement Needed for process " << process.GetName() << " page " << page;

            //Find a victim, remove it's entry from the page table (set entry.valid = false)
            entry.frame = SelectVictim();
            entry.ref = true;
            entry.dirty = false;

            std::cout << ": Assigned " << Color::Cyan("victim") << " frame " << entry.frame << std::endl;

            process.GetPageTable().AddEntry(page, entry);

            LRUEntry lruEntry;
            lruEntry.process = &process;
            lruEntry.page = page;
            lruEntry.frame = entry.frame;

            //Push back onto the LRU
            lru.push_front(lruEntry);
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movl %edx, %ebx
movq %rsi, %r14
movq %rdi, %r15
leaq 0x28(%rsi), %r12
movq %r12, %rdi
movl %edx, %esi
callq 0x6142
movzwl %bx, %ebx
testb %al, %al
je 0x520b
movq %r12, %rdi
movl %ebx, %esi
callq 0x61c0
movzwl (%rax), %ebp
movq %r15, %rdi
movl %ebp, %esi
callq 0x5608
testb %al, %al
je 0x5386
leaq 0x204b(%rip), %rsi      # 0x71a7
leaq 0xb8(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x30d4
leaq 0x8(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x321c
movq 0x6e41(%rip), %rdi      # 0xbfc8
leaq 0x8(%rsp), %rsi
callq 0x21c0
leaq 0x2011(%rip), %rsi      # 0x71a9
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movq %r14, %rsi
callq 0x21c0
leaq 0x2001(%rip), %rsi      # 0x71b3
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movl %ebx, %esi
callq 0x2300
leaq 0x1ff0(%rip), %rsi      # 0x71bb
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movl %ebp, %esi
callq 0x2300
leaq 0x1fe3(%rip), %rsi      # 0x71c7
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20f0
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0xb8(%rsp), %rdi
jmp 0x537c
leaq 0x2001(%rip), %rsi      # 0x7213
leaq 0x98(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x30d4
leaq 0x8(%rsp), %rdi
leaq 0x98(%rsp), %rsi
callq 0x5790
movq 0x6d8b(%rip), %rdi      # 0xbfc8
leaq 0x8(%rsp), %rsi
callq 0x21c0
leaq 0x2011(%rip), %rsi      # 0x725f
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movq %r14, %rsi
callq 0x21c0
leaq 0x1fba(%rip), %rsi      # 0x7222
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movl %ebx, %esi
callq 0x2300
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x98(%rsp), %rdi
callq 0x20e0
movq %r14, %rdi
callq 0x5e36
andl $0x0, (%rsp)
movb $0x1, 0x4(%rsp)
cmpq $0x0, 0x58(%r15)
je 0x53c1
movq %r15, %rdi
callq 0x564a
movq %rsp, %r13
movw %ax, (%r13)
movw $0x1, 0x2(%r13)
movq %r12, %rdi
movl %ebx, %esi
movq %r13, %rdx
callq 0x6180
movzwl (%r13), %esi
movq %r15, %rdi
callq 0x56ec
leaq 0x28(%rsp), %rsi
movq %r14, (%rsi)
movw %bx, 0x8(%rsi)
movzwl (%r13), %eax
movw %ax, 0xa(%rsi)
addq $0x90, %r15
movq %r15, %rdi
callq 0x5816
movq 0x6cbf(%rip), %rdi      # 0xbfc8
leaq 0x1f19(%rip), %rsi      # 0x7229
callq 0x21d0
movq %rax, %rbx
leaq 0x1f16(%rip), %rsi      # 0x7235
leaq 0x78(%rsp), %rdi
leaq 0x7(%rsp), %rdx
callq 0x30d4
leaq 0x8(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0x321c
leaq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x21c0
leaq 0x1e6e(%rip), %rsi      # 0x71bf
movq %rax, %rdi
callq 0x21d0
movzwl (%rsp), %esi
movq %rax, %rdi
callq 0x2300
movq %rax, %rdi
callq 0x20f0
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x78(%rsp), %rdi
callq 0x20e0
jmp 0x5515
movq %r15, %rdi
movl %ebp, %esi
callq 0x5622
testb %al, %al
je 0x5527
movq 0x6c29(%rip), %rdi      # 0xbfc8
leaq 0x1e32(%rip), %rsi      # 0x71d8
callq 0x21d0
movq %rax, %rdi
movl %ebp, %esi
callq 0x2300
leaq 0x1e23(%rip), %rsi      # 0x71df
jmp 0x554b
movq 0x6c00(%rip), %rdi      # 0xbfc8
callq 0x20f0
leaq 0x1e66(%rip), %rsi      # 0x723a
leaq 0x58(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x30d4
leaq 0x8(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x5832
movq 0x6bcf(%rip), %rdi      # 0xbfc8
leaq 0x8(%rsp), %rsi
callq 0x21c0
leaq 0x1e3e(%rip), %rsi      # 0x7248
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movq %r14, %rsi
callq 0x21c0
leaq 0x1dfe(%rip), %rsi      # 0x7222
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
movl %ebx, %esi
callq 0x2300
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x58(%rsp), %rdi
callq 0x20e0
movq %r15, %rdi
callq 0x573c
movw %ax, (%rsp)
movw $0x1, 0x2(%rsp)
movq 0x6b64(%rip), %rdi      # 0xbfc8
leaq 0x1dbe(%rip), %rsi      # 0x7229
callq 0x21d0
movq %rax, %r13
leaq 0x1df3(%rip), %rsi      # 0x726d
leaq 0x38(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x30d4
leaq 0x8(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x5832
leaq 0x8(%rsp), %rsi
movq %r13, %rdi
callq 0x21c0
leaq 0x1d13(%rip), %rsi      # 0x71bf
movq %rax, %rdi
callq 0x21d0
movzwl (%rsp), %esi
movq %rax, %rdi
callq 0x2300
movq %rax, %rdi
callq 0x20f0
leaq 0x8(%rsp), %r13
movq %r13, %rdi
callq 0x20e0
leaq 0x38(%rsp), %rdi
callq 0x20e0
movq %rsp, %rbp
movq %r12, %rdi
movl %ebx, %esi
movq %rbp, %rdx
callq 0x6180
movq %r14, (%r13)
movw %bx, 0x8(%r13)
movzwl (%rbp), %eax
movw %ax, 0xa(%r13)
addq $0x90, %r15
leaq 0x8(%rsp), %rsi
movq %r15, %rdi
callq 0x5816
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x6ac2(%rip), %rdi      # 0xbff0
leaq 0x1ca3(%rip), %rsi      # 0x71d8
callq 0x21d0
movq %rax, %rdi
movl %ebp, %esi
callq 0x2300
leaq 0x1ca8(%rip), %rsi      # 0x71f3
movq %rax, %rdi
callq 0x21d0
movq %rax, %rdi
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x20f0
movq %rax, %rbx
jmp 0x559f
jmp 0x558d
movq %rax, %rbx
jmp 0x55b3
jmp 0x558d
movq %rax, %rbx
jmp 0x55db
jmp 0x558d
movq %rax, %rbx
jmp 0x55c7
jmp 0x558d
movq %rax, %rbx
jmp 0x55f2
movq %rax, %rbx
jmp 0x55ff
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x38(%rsp), %rdi
jmp 0x55fa
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x58(%rsp), %rdi
jmp 0x55fa
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x78(%rsp), %rdi
jmp 0x55fa
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0xb8(%rsp), %rdi
jmp 0x55fa
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20e0
leaq 0x98(%rsp), %rdi
callq 0x20e0
movq %rbx, %rdi
callq 0x2310
nop