// File: CMU-SAFARI[P]ramulator/src/Main.cpp
// Function: void run_cputrace<ramulator::DDR3>(ramulator::Config const&, ramulator::Memory<ramulator::DDR3, ramulator::Controller>&, std::vector<char const*, std::allocator<char const*>> const&)
void run_cputrace(const Config& configs, Memory<T, Controller>& memory, const std::vector<const char *>& files)
{
    int cpu_tick = configs.get_cpu_tick();
    int mem_tick = configs.get_mem_tick();
    auto send = bind(&Memory<T, Controller>::send, &memory, placeholders::_1);
    Processor proc(configs, files, send, memory);

    long warmup_insts = configs.get_warmup_insts();
    bool is_warming_up = (warmup_insts != 0);

    for(long i = 0; is_warming_up; i++){
        proc.tick();
        Stats::curTick++;
        if (i % cpu_tick == (cpu_tick - 1))
            for (int j = 0; j < mem_tick; j++)
                memory.tick();

        is_warming_up = false;
        for(int c = 0; c < proc.cores.size(); c++){
            if(proc.cores[c]->get_insts() < warmup_insts)
                is_warming_up = true;
        }

        if (is_warming_up && proc.has_reached_limit()) {
            printf("WARNING: The end of the input trace file was reached during warmup. "
                    "Consider changing warmup_insts in the config file. \n");
            break;
        }

    }

    warmup_complete = true;
    printf("Warmup complete! Resetting stats...\n");
    Stats::reset_stats();
    proc.reset_stats();
    assert(proc.get_insts() == 0);

    printf("Starting the simulation...\n");

    int tick_mult = cpu_tick * mem_tick;
    for (long i = 0; ; i++) {
        if (((i % tick_mult) % mem_tick) == 0) { // When the CPU is ticked cpu_tick times,
                                                 // the memory controller should be ticked mem_tick times
            proc.tick();
            Stats::curTick++; // processor clock, global, for Statistics

            if (configs.calc_weighted_speedup()) {
                if (proc.has_reached_limit()) {
                    break;
                }
            } else {
                if (configs.is_early_exit()) {
                    if (proc.finished())
                    break;
                } else {
                if (proc.finished() && (memory.pending_requests() == 0))
                    break;
                }
            }
        }

        if (((i % tick_mult) % cpu_tick) == 0) // TODO_hasan: Better if the processor ticks the memory controller
            memory.tick();

    }
    // This a workaround for statistics set only initially lost in the end
    memory.finish();
    Stats::statlist.printall();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x900, %rsp            # imm = 0x900
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
callq 0x49d30
movl %eax, -0x1c(%rbp)
movq -0x8(%rbp), %rdi
callq 0x49d50
movl %eax, -0x20(%rbp)
movq $0x0, -0x40(%rbp)
movq $0x21, -0x48(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x50(%rbp)
movq 0x328cfa(%rip), %rcx    # 0x34dfb8
leaq -0x38(%rbp), %rdi
movq %rdi, -0x8b8(%rbp)
leaq -0x48(%rbp), %rsi
leaq -0x50(%rbp), %rdx
callq 0x49d70
movq -0x8(%rbp), %rax
movq %rax, -0x8c0(%rbp)
movq -0x18(%rbp), %rsi
leaq -0x850(%rbp), %rdi
callq 0x49db0
movq -0x8b8(%rbp), %rsi
leaq -0x870(%rbp), %rdi
callq 0x49ea0
jmp 0x25306
movq -0x8c0(%rbp), %rsi
movq -0x10(%rbp), %r8
leaq -0x838(%rbp), %rdi
leaq -0x850(%rbp), %rdx
leaq -0x870(%rbp), %rcx
callq 0x1f6e20
jmp 0x2532d
leaq -0x870(%rbp), %rdi
callq 0x49f40
leaq -0x850(%rbp), %rdi
callq 0x1c120
movq -0x8(%rbp), %rdi
callq 0x49f60
movq %rax, -0x8c8(%rbp)
jmp 0x25357
movq -0x8c8(%rbp), %rax
movq %rax, -0x888(%rbp)
cmpq $0x0, -0x888(%rbp)
setne %al
andb $0x1, %al
movb %al, -0x889(%rbp)
movq $0x0, -0x898(%rbp)
testb $0x1, -0x889(%rbp)
je 0x2555e
leaq -0x838(%rbp), %rdi
callq 0x1f79c0
jmp 0x2539e
leaq 0x329ff3(%rip), %rax    # 0x34f398
movq (%rax), %rcx
addq $0x1, %rcx
leaq 0x329fe5(%rip), %rax    # 0x34f398
movq %rcx, (%rax)
movq -0x898(%rbp), %rax
movslq -0x1c(%rbp), %rcx
cqto
idivq %rcx
movl -0x1c(%rbp), %eax
subl $0x1, %eax
cltq
cmpq %rax, %rdx
jne 0x2547a
movl $0x0, -0x89c(%rbp)
movl -0x89c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x25478
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x18(%rax), %rax
callq *%rax
jmp 0x253ff
jmp 0x25401
movl -0x89c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x89c(%rbp)
jmp 0x253e1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x878(%rbp)
movl %eax, -0x87c(%rbp)
jmp 0x25444
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x878(%rbp)
movl %eax, -0x87c(%rbp)
leaq -0x870(%rbp), %rdi
callq 0x49f40
leaq -0x850(%rbp), %rdi
callq 0x1c120
jmp 0x25790
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x878(%rbp)
movl %eax, -0x87c(%rbp)
leaq -0x838(%rbp), %rdi
callq 0x4a2e0
jmp 0x25790
jmp 0x2547a
movb $0x0, -0x889(%rbp)
movl $0x0, -0x8a0(%rbp)
movslq -0x8a0(%rbp), %rax
movq %rax, -0x8d0(%rbp)
leaq -0x838(%rbp), %rdi
callq 0x49f80
movq %rax, %rcx
movq -0x8d0(%rbp), %rax
cmpq %rcx, %rax
jae 0x2550a
movslq -0x8a0(%rbp), %rsi
leaq -0x838(%rbp), %rdi
callq 0x49fa0
movq %rax, %rdi
callq 0x49fc0
movq %rax, %rdi
callq 0x1f8740
movq %rax, -0x8d8(%rbp)
jmp 0x254e0
movq -0x8d8(%rbp), %rax
cmpq -0x888(%rbp), %rax
jge 0x254f7
movb $0x1, -0x889(%rbp)
jmp 0x254f9
movl -0x8a0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8a0(%rbp)
jmp 0x2548b
testb $0x1, -0x889(%rbp)
je 0x25545
leaq -0x838(%rbp), %rdi
callq 0x1f8620
movb %al, -0x8d9(%rbp)
jmp 0x25527
movb -0x8d9(%rbp), %al
testb $0x1, %al
jne 0x25533
jmp 0x25545
leaq 0x22c1f6(%rip), %rdi    # 0x251730
xorl %eax, %eax
callq 0xc070
jmp 0x25543
jmp 0x2555e
jmp 0x25547
movq -0x898(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x898(%rbp)
jmp 0x25383
movb $0x1, 0x328e0d(%rip)    # 0x34e372
leaq 0x22c23d(%rip), %rdi    # 0x2517a9
xorl %eax, %eax
callq 0xc070
jmp 0x25575
callq 0x224f60
jmp 0x2557c
leaq -0x838(%rbp), %rdi
callq 0x1f8770
jmp 0x2558a
leaq -0x838(%rbp), %rdi
callq 0x1f86c0
movq %rax, -0x8e8(%rbp)
jmp 0x2559f
movq -0x8e8(%rbp), %rax
cmpq $0x0, %rax
jne 0x255ae
jmp 0x255cd
leaq 0x22c219(%rip), %rdi    # 0x2517ce
leaq 0x22a54b(%rip), %rsi    # 0x24fb07
movl $0x76, %edx
leaq 0x22c21c(%rip), %rcx    # 0x2517e4
callq 0xc280
leaq 0x22c284(%rip), %rdi    # 0x251858
xorl %eax, %eax
callq 0xc070
jmp 0x255dd
movl -0x1c(%rbp), %eax
imull -0x20(%rbp), %eax
movl %eax, -0x8a4(%rbp)
movq $0x0, -0x8b0(%rbp)
movq -0x8b0(%rbp), %rax
movslq -0x8a4(%rbp), %rcx
cqto
idivq %rcx
movq %rdx, %rax
movslq -0x20(%rbp), %rcx
cqto
idivq %rcx
cmpq $0x0, %rdx
jne 0x2570f
leaq -0x838(%rbp), %rdi
callq 0x1f79c0
jmp 0x2562c
leaq 0x329d65(%rip), %rax    # 0x34f398
movq (%rax), %rcx
incq %rcx
movq %rcx, (%rax)
movq -0x8(%rbp), %rdi
callq 0x49fe0
movb %al, -0x8e9(%rbp)
jmp 0x2564d
movb -0x8e9(%rbp), %al
testb $0x1, %al
jne 0x25659
jmp 0x25683
leaq -0x838(%rbp), %rdi
callq 0x1f8620
movb %al, -0x8ea(%rbp)
jmp 0x2566d
movb -0x8ea(%rbp), %al
testb $0x1, %al
jne 0x25679
jmp 0x2567e
jmp 0x2575e
jmp 0x2570d
movq -0x8(%rbp), %rdi
callq 0x4a000
movb %al, -0x8eb(%rbp)
jmp 0x25694
movb -0x8eb(%rbp), %al
testb $0x1, %al
jne 0x256a0
jmp 0x256c7
leaq -0x838(%rbp), %rdi
callq 0x1f83b0
movb %al, -0x8ec(%rbp)
jmp 0x256b4
movb -0x8ec(%rbp), %al
testb $0x1, %al
jne 0x256c0
jmp 0x256c5
jmp 0x2575e
jmp 0x2570b
leaq -0x838(%rbp), %rdi
callq 0x1f83b0
movb %al, -0x8ed(%rbp)
jmp 0x256db
movb -0x8ed(%rbp), %al
testb $0x1, %al
jne 0x256e7
jmp 0x25709
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
movl %eax, -0x8f4(%rbp)
jmp 0x256fc
movl -0x8f4(%rbp), %eax
cmpl $0x0, %eax
jne 0x25709
jmp 0x2575e
jmp 0x2570b
jmp 0x2570d
jmp 0x2570f
movq -0x8b0(%rbp), %rax
movslq -0x8a4(%rbp), %rcx
cqto
idivq %rcx
movq %rdx, %rax
movslq -0x1c(%rbp), %rcx
cqto
idivq %rcx
cmpq $0x0, %rdx
jne 0x25745
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x18(%rax), %rax
callq *%rax
jmp 0x25743
jmp 0x25745
jmp 0x25747
movq -0x8b0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x8b0(%rbp)
jmp 0x255f5
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x30(%rax), %rax
callq *%rax
jmp 0x2576d
leaq 0x329a0c(%rip), %rdi    # 0x34f180
callq 0x4a1e0
jmp 0x2577b
leaq -0x838(%rbp), %rdi
callq 0x4a2e0
addq $0x900, %rsp            # imm = 0x900
popq %rbp
retq
movq -0x878(%rbp), %rdi
callq 0xc5d0
nopl (%rax)