// File: 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
movq %rsp, %rbp
subq $0x2c0, %rsp            # imm = 0x2C0
movw %dx, %ax
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movw %ax, -0x12(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x1b8(%rbp)
movq -0x10(%rbp), %rdi
callq 0xe500
movq %rax, %rdi
movzwl -0x12(%rbp), %esi
callq 0x104a0
testb $0x1, %al
jne 0xd923
jmp 0xdb90
movq -0x10(%rbp), %rdi
callq 0xe500
movq %rax, %rdi
movzwl -0x12(%rbp), %esi
callq 0x10580
movq -0x1b8(%rbp), %rdi
movw (%rax), %ax
movw %ax, -0x14(%rbp)
movzwl -0x14(%rbp), %esi
callq 0xe200
testb $0x1, %al
jne 0xd958
jmp 0xdaf6
leaq -0x59(%rbp), %rdi
movq %rdi, -0x1c0(%rbp)
callq 0x3440
movq -0x1c0(%rbp), %rdx
leaq 0x48cf(%rip), %rsi      # 0x12245
leaq -0x58(%rbp), %rdi
callq 0x4de0
jmp 0xd981
leaq -0x38(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x5130
jmp 0xd990
movq 0xe631(%rip), %rdi      # 0x1bfc8
leaq -0x38(%rbp), %rsi
callq 0x3220
movq %rax, -0x1c8(%rbp)
jmp 0xd9a9
movq -0x1c8(%rbp), %rdi
leaq 0x4890(%rip), %rsi      # 0x12247
callq 0x3230
movq %rax, -0x1d0(%rbp)
jmp 0xd9c5
movq -0x10(%rbp), %rdi
callq 0xe520
movq %rax, -0x1d8(%rbp)
jmp 0xd9d7
movq -0x1d8(%rbp), %rsi
movq -0x1d0(%rbp), %rdi
callq 0x3220
movq %rax, -0x1e0(%rbp)
jmp 0xd9f3
movq -0x1e0(%rbp), %rdi
leaq 0x4850(%rip), %rsi      # 0x12251
callq 0x3230
movq %rax, -0x1e8(%rbp)
jmp 0xda0f
movq -0x1e8(%rbp), %rdi
movzwl -0x12(%rbp), %esi
callq 0x3410
movq %rax, -0x1f0(%rbp)
jmp 0xda28
movq -0x1f0(%rbp), %rdi
leaq 0x4823(%rip), %rsi      # 0x12259
callq 0x3230
movq %rax, -0x1f8(%rbp)
jmp 0xda44
movq -0x1f8(%rbp), %rdi
movzwl -0x14(%rbp), %esi
callq 0x3410
movq %rax, -0x200(%rbp)
jmp 0xda5d
movq -0x200(%rbp), %rdi
leaq 0x47fa(%rip), %rsi      # 0x12265
callq 0x3230
movq %rax, -0x208(%rbp)
jmp 0xda79
movq -0x208(%rbp), %rdi
movq 0xe531(%rip), %rsi      # 0x1bfb8
callq 0x3280
jmp 0xda8e
leaq -0x38(%rbp), %rdi
callq 0x3170
leaq -0x58(%rbp), %rdi
callq 0x3170
leaq -0x59(%rbp), %rdi
callq 0x32a0
jmp 0xe1ee
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xdae8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xdadf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x3170
leaq -0x58(%rbp), %rdi
callq 0x3170
leaq -0x59(%rbp), %rdi
callq 0x32a0
jmp 0xe1f7
movq -0x1b8(%rbp), %rdi
movzwl -0x14(%rbp), %esi
callq 0xe230
testb $0x1, %al
jne 0xdb0c
jmp 0xdb4e
movq 0xe4b5(%rip), %rdi      # 0x1bfc8
leaq 0x475c(%rip), %rsi      # 0x12276
callq 0x3230
movq %rax, %rdi
movzwl -0x14(%rbp), %esi
callq 0x3410
movq %rax, %rdi
leaq 0x4748(%rip), %rsi      # 0x1227d
callq 0x3230
movq %rax, %rdi
movq 0xe474(%rip), %rsi      # 0x1bfb8
callq 0x3280
jmp 0xe1ee
movq 0xe49b(%rip), %rdi      # 0x1bff0
leaq 0x471a(%rip), %rsi      # 0x12276
callq 0x3230
movq %rax, %rdi
movzwl -0x14(%rbp), %esi
callq 0x3410
movq %rax, %rdi
leaq 0x471a(%rip), %rsi      # 0x12291
callq 0x3230
movq %rax, %rdi
movq 0xe432(%rip), %rsi      # 0x1bfb8
callq 0x3280
jmp 0xe1ee
leaq -0xb1(%rbp), %rdi
movq %rdi, -0x210(%rbp)
callq 0x3440
movq -0x210(%rbp), %rdx
leaq 0x4700(%rip), %rsi      # 0x122b1
leaq -0xb0(%rbp), %rdi
callq 0x4de0
jmp 0xdbbf
leaq -0x90(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0xe530
jmp 0xdbd4
movq 0xe3ed(%rip), %rdi      # 0x1bfc8
leaq -0x90(%rbp), %rsi
callq 0x3220
movq %rax, -0x218(%rbp)
jmp 0xdbf0
movq -0x218(%rbp), %rdi
leaq 0x46ff(%rip), %rsi      # 0x122fd
callq 0x3230
movq %rax, -0x220(%rbp)
jmp 0xdc0c
movq -0x10(%rbp), %rdi
callq 0xe520
movq %rax, -0x228(%rbp)
jmp 0xdc1e
movq -0x228(%rbp), %rsi
movq -0x220(%rbp), %rdi
callq 0x3220
movq %rax, -0x230(%rbp)
jmp 0xdc3a
movq -0x230(%rbp), %rdi
leaq 0x4678(%rip), %rsi      # 0x122c0
callq 0x3230
movq %rax, -0x238(%rbp)
jmp 0xdc56
movq -0x238(%rbp), %rdi
movzwl -0x12(%rbp), %esi
callq 0x3410
jmp 0xdc68
leaq -0x90(%rbp), %rdi
callq 0x3170
leaq -0xb0(%rbp), %rdi
callq 0x3170
leaq -0xb1(%rbp), %rdi
callq 0x32a0
movq -0x10(%rbp), %rdi
callq 0xfb00
leaq -0xb8(%rbp), %rdi
callq 0xe5e0
movq -0x1b8(%rbp), %rdi
callq 0xe270
testb $0x1, %al
jne 0xdcb6
jmp 0xded6
movq -0x1b8(%rbp), %rdi
callq 0xe2a0
movw %ax, -0xb8(%rbp)
movb $0x1, -0xb6(%rbp)
movb $0x0, -0xb5(%rbp)
movq -0x10(%rbp), %rdi
callq 0xe500
movq %rax, %rdi
movzwl -0x12(%rbp), %esi
leaq -0xb8(%rbp), %rdx
callq 0x10500
movq -0x1b8(%rbp), %rdi
movzwl -0xb8(%rbp), %esi
callq 0xe420
movq -0x1b8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq %rax, -0xc8(%rbp)
movw -0x12(%rbp), %ax
movw %ax, -0xc0(%rbp)
movw -0xb8(%rbp), %ax
movw %ax, -0xbe(%rbp)
addq $0x90, %rdi
leaq -0xc8(%rbp), %rsi
callq 0xe600
movq 0xe27d(%rip), %rdi      # 0x1bfc8
leaq 0x4575(%rip), %rsi      # 0x122c7
callq 0x3230
movq %rax, -0x248(%rbp)
leaq -0x109(%rbp), %rdi
movq %rdi, -0x240(%rbp)
callq 0x3440
movq -0x240(%rbp), %rdx
leaq 0x4554(%rip), %rsi      # 0x122d3
leaq -0x108(%rbp), %rdi
callq 0x4de0
jmp 0xdd8d
leaq -0xe8(%rbp), %rdi
leaq -0x108(%rbp), %rsi
callq 0x5130
jmp 0xdda2
movq -0x248(%rbp), %rdi
leaq -0xe8(%rbp), %rsi
callq 0x3220
movq %rax, -0x250(%rbp)
jmp 0xddbe
movq -0x250(%rbp), %rdi
leaq 0x4491(%rip), %rsi      # 0x1225d
callq 0x3230
movq %rax, -0x258(%rbp)
jmp 0xddda
movq -0x258(%rbp), %rdi
movzwl -0xb8(%rbp), %esi
callq 0x3410
movq %rax, -0x260(%rbp)
jmp 0xddf6
movq -0x260(%rbp), %rdi
movq 0xe1b4(%rip), %rsi      # 0x1bfb8
callq 0x3280
jmp 0xde0b
leaq -0xe8(%rbp), %rdi
callq 0x3170
leaq -0x108(%rbp), %rdi
callq 0x3170
leaq -0x109(%rbp), %rdi
callq 0x32a0
jmp 0xe1ec
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xde74
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xde68
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x3170
leaq -0xb0(%rbp), %rdi
callq 0x3170
leaq -0xb1(%rbp), %rdi
callq 0x32a0
jmp 0xe1f7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xdec5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xdeb9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x3170
leaq -0x108(%rbp), %rdi
callq 0x3170
leaq -0x109(%rbp), %rdi
callq 0x32a0
jmp 0xe1f7
movq 0xe0eb(%rip), %rdi      # 0x1bfc8
movq 0xe0d4(%rip), %rsi      # 0x1bfb8
callq 0x3280
leaq -0x151(%rbp), %rdi
movq %rdi, -0x268(%rbp)
callq 0x3440
movq -0x268(%rbp), %rdx
leaq 0x43ce(%rip), %rsi      # 0x122d8
leaq -0x150(%rbp), %rdi
callq 0x4de0
jmp 0xdf18
leaq -0x130(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0xe660
jmp 0xdf2d
movq 0xe094(%rip), %rdi      # 0x1bfc8
leaq -0x130(%rbp), %rsi
callq 0x3220
movq %rax, -0x270(%rbp)
jmp 0xdf49
movq -0x270(%rbp), %rdi
leaq 0x438f(%rip), %rsi      # 0x122e6
callq 0x3230
movq %rax, -0x278(%rbp)
jmp 0xdf65
movq -0x10(%rbp), %rdi
callq 0xe520
movq %rax, -0x280(%rbp)
jmp 0xdf77
movq -0x280(%rbp), %rsi
movq -0x278(%rbp), %rdi
callq 0x3220
movq %rax, -0x288(%rbp)
jmp 0xdf93
movq -0x288(%rbp), %rdi
leaq 0x431f(%rip), %rsi      # 0x122c0
callq 0x3230
movq %rax, -0x290(%rbp)
jmp 0xdfaf
movq -0x290(%rbp), %rdi
movzwl -0x12(%rbp), %esi
callq 0x3410
jmp 0xdfc1
leaq -0x130(%rbp), %rdi
callq 0x3170
leaq -0x150(%rbp), %rdi
callq 0x3170
leaq -0x151(%rbp), %rdi
callq 0x32a0
movq -0x1b8(%rbp), %rdi
callq 0xe4a0
movw %ax, -0xb8(%rbp)
movb $0x1, -0xb6(%rbp)
movb $0x0, -0xb5(%rbp)
movq 0xdfbb(%rip), %rdi      # 0x1bfc8
leaq 0x42b3(%rip), %rsi      # 0x122c7
callq 0x3230
movq %rax, -0x2a0(%rbp)
leaq -0x199(%rbp), %rdi
movq %rdi, -0x298(%rbp)
callq 0x3440
movq -0x298(%rbp), %rdx
leaq 0x42ca(%rip), %rsi      # 0x1230b
leaq -0x198(%rbp), %rdi
callq 0x4de0
jmp 0xe04f
leaq -0x178(%rbp), %rdi
leaq -0x198(%rbp), %rsi
callq 0xe660
jmp 0xe064
movq -0x2a0(%rbp), %rdi
leaq -0x178(%rbp), %rsi
callq 0x3220
movq %rax, -0x2a8(%rbp)
jmp 0xe080
movq -0x2a8(%rbp), %rdi
leaq 0x41cf(%rip), %rsi      # 0x1225d
callq 0x3230
movq %rax, -0x2b0(%rbp)
jmp 0xe09c
movq -0x2b0(%rbp), %rdi
movzwl -0xb8(%rbp), %esi
callq 0x3410
movq %rax, -0x2b8(%rbp)
jmp 0xe0b8
movq -0x2b8(%rbp), %rdi
movq 0xdef2(%rip), %rsi      # 0x1bfb8
callq 0x3280
jmp 0xe0cd
leaq -0x178(%rbp), %rdi
callq 0x3170
leaq -0x198(%rbp), %rdi
callq 0x3170
leaq -0x199(%rbp), %rdi
callq 0x32a0
movq -0x10(%rbp), %rdi
callq 0xe500
movq %rax, %rdi
leaq -0xb8(%rbp), %rdx
movzwl -0x12(%rbp), %esi
callq 0x10500
movq -0x1b8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movw -0x12(%rbp), %ax
movw %ax, -0x1a8(%rbp)
movw -0xb8(%rbp), %ax
movw %ax, -0x1a6(%rbp)
addq $0x90, %rdi
leaq -0x1b0(%rbp), %rsi
callq 0xe600
jmp 0xe1ec
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xe190
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xe184
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x130(%rbp), %rdi
callq 0x3170
leaq -0x150(%rbp), %rdi
callq 0x3170
leaq -0x151(%rbp), %rdi
callq 0x32a0
jmp 0xe1f7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xe1de
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xe1d2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x178(%rbp), %rdi
callq 0x3170
leaq -0x198(%rbp), %rdi
callq 0x3170
leaq -0x199(%rbp), %rdi
callq 0x32a0
jmp 0xe1f7
jmp 0xe1ee
addq $0x2c0, %rsp            # imm = 0x2C0
popq %rbp
retq
movq -0x68(%rbp), %rdi
callq 0x3430