// File: CMU-SAFARI[P]ramulator/src/Memory.h
// Function: ramulator::Memory<ramulator::DDR3, ramulator::Controller>::page_allocator(long, int)
long page_allocator(long addr, int coreid) {
        long virtual_page_number = addr >> 12;

        switch(int(translation)) {
            case int(Translation::None): {
              return addr;
            }
            case int(Translation::Random): {
                auto target = make_pair(coreid, virtual_page_number);
                if(page_translation.find(target) == page_translation.end()) {
                    // page doesn't exist, so assign a new page
                    // make sure there are physical pages left to be assigned

                    // if physical page doesn't remain, replace a previous assigned
                    // physical page.
                    if (!free_physical_pages_remaining) {
                      physical_page_replacement++;
                      long phys_page_to_read = lrand() % free_physical_pages.size();
                      assert(free_physical_pages[phys_page_to_read] != -1);
                      page_translation[target] = phys_page_to_read;
                    } else {
                        // assign a new page
                        long phys_page_to_read = lrand() % free_physical_pages.size();
                        // if the randomly-selected page was already assigned
                        if(free_physical_pages[phys_page_to_read] != -1) {
                            long starting_page_of_search = phys_page_to_read;

                            do {
                                // iterate through the list until we find a free page
                                // TODO: does this introduce serious non-randomness?
                                ++phys_page_to_read;
                                phys_page_to_read %= free_physical_pages.size();
                            }
                            while((phys_page_to_read != starting_page_of_search) && free_physical_pages[phys_page_to_read] != -1);
                        }

                        assert(free_physical_pages[phys_page_to_read] == -1);

                        page_translation[target] = phys_page_to_read;
                        free_physical_pages[phys_page_to_read] = coreid;
                        --free_physical_pages_remaining;
                    }
                }

                // SAUGATA TODO: page size should not always be fixed to 4KB
                return (page_translation[target] << 12) | (addr & ((1 << 12) - 1));
            }
            default:
                assert(false);
        }

    }

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x18(%rbp), %rcx
sarq $0xc, %rcx
movq %rcx, -0x28(%rbp)
movl 0xb84(%rax), %eax
movl %eax, -0x64(%rbp)
testl %eax, %eax
je 0x39036
jmp 0x39029
movl -0x64(%rbp), %eax
subl $0x1, %eax
je 0x39043
jmp 0x392dc
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x392fb
leaq -0x1c(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x48850
movq -0x70(%rbp), %rdi
movl %eax, -0x38(%rbp)
movq %rdx, -0x30(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x38(%rbp), %rsi
callq 0x488b0
movq -0x70(%rbp), %rdi
movq %rax, -0x40(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
callq 0x488e0
movq %rax, -0x48(%rbp)
leaq -0x40(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x48880
testb $0x1, %al
jne 0x39099
jmp 0x392ad
movq -0x70(%rbp), %rax
cmpq $0x0, 0xbd0(%rax)
jne 0x3914c
movq -0x70(%rbp), %rdi
addq $0x528, %rdi            # imm = 0x528
xorl %esi, %esi
callq 0x40970
movq -0x70(%rbp), %rdi
callq 0x48910
movq -0x70(%rbp), %rdi
movq %rax, -0x78(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
callq 0x31ca0
movq -0x70(%rbp), %rdi
movq %rax, %rcx
movq -0x78(%rbp), %rax
xorl %edx, %edx
divq %rcx
movq %rdx, -0x50(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
movq -0x50(%rbp), %rsi
callq 0x384f0
cmpl $-0x1, (%rax)
je 0x39105
jmp 0x39124
leaq 0x218545(%rip), %rdi    # 0x251651
leaq 0x2178a6(%rip), %rsi    # 0x2509b9
movl $0x21d, %edx            # imm = 0x21D
leaq 0x21855f(%rip), %rcx    # 0x25167e
callq 0xc280
movq -0x70(%rbp), %rdi
movq -0x50(%rbp), %rax
movq %rax, -0x80(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x38(%rbp), %rsi
callq 0x48950
movq -0x80(%rbp), %rcx
movq %rcx, (%rax)
jmp 0x392ab
movq -0x70(%rbp), %rdi
callq 0x48910
movq -0x70(%rbp), %rdi
movq %rax, -0x88(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
callq 0x31ca0
movq -0x70(%rbp), %rdi
movq %rax, %rcx
movq -0x88(%rbp), %rax
xorl %edx, %edx
divq %rcx
movq %rdx, -0x58(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
movq -0x58(%rbp), %rsi
callq 0x384f0
cmpl $-0x1, (%rax)
je 0x3920a
movq -0x58(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x70(%rbp), %rdi
movq -0x58(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x58(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
callq 0x31ca0
movq %rax, %rcx
movq -0x58(%rbp), %rax
xorl %edx, %edx
divq %rcx
movq %rdx, -0x58(%rbp)
movq -0x58(%rbp), %rcx
xorl %eax, %eax
cmpq -0x60(%rbp), %rcx
movb %al, -0x89(%rbp)
je 0x391fe
movq -0x70(%rbp), %rdi
addq $0xbb8, %rdi            # imm = 0xBB8
movq -0x58(%rbp), %rsi
callq 0x384f0
cmpl $-0x1, (%rax)
setne %al
movb %al, -0x89(%rbp)
movb -0x89(%rbp), %al
testb $0x1, %al
jne 0x391a0
jmp 0x3920a
movq -0x70(%rbp), %rdi
addq $0xbb8, %rdi            # imm = 0xBB8
movq -0x58(%rbp), %rsi
callq 0x384f0
cmpl $-0x1, (%rax)
jne 0x39225
jmp 0x39244
leaq 0x2184d7(%rip), %rdi    # 0x251703
leaq 0x217786(%rip), %rsi    # 0x2509b9
movl $0x22f, %edx            # imm = 0x22F
leaq 0x21843f(%rip), %rcx    # 0x25167e
callq 0xc280
movq -0x70(%rbp), %rdi
movq -0x58(%rbp), %rax
movq %rax, -0x98(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x38(%rbp), %rsi
callq 0x48950
movq -0x98(%rbp), %rcx
movq -0x70(%rbp), %rdi
movq %rcx, (%rax)
movl -0x1c(%rbp), %eax
movl %eax, -0x90(%rbp)
addq $0xbb8, %rdi            # imm = 0xBB8
movq -0x58(%rbp), %rsi
callq 0x384f0
movl -0x90(%rbp), %edx
movq %rax, %rcx
movq -0x70(%rbp), %rax
movl %edx, (%rcx)
movq 0xbd0(%rax), %rcx
addq $-0x1, %rcx
movq %rcx, 0xbd0(%rax)
jmp 0x392ad
movq -0x70(%rbp), %rdi
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x38(%rbp), %rsi
callq 0x48950
movq (%rax), %rax
shlq $0xc, %rax
movq -0x18(%rbp), %rcx
andq $0xfff, %rcx            # imm = 0xFFF
orq %rcx, %rax
movq %rax, -0x8(%rbp)
jmp 0x392fb
leaq 0x21687e(%rip), %rdi    # 0x24fb61
leaq 0x2176cf(%rip), %rsi    # 0x2509b9
movl $0x23b, %edx            # imm = 0x23B
leaq 0x218388(%rip), %rcx    # 0x25167e
callq 0xc280
movq -0x8(%rbp), %rax
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax,%rax)