// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x868, %rsp            # imm = 0x868
movq %rsi, %rbx
movq %rdi, %rbp
movslq 0x3c(%rdi), %rax
movq %rax, 0x10(%rsp)
movl 0x40(%rdi), %eax
movl %eax, 0xc(%rsp)
leaq 0x68(%rsp), %r15
movq $0x21, (%r15)
andq $0x0, 0x8(%r15)
movq %rsi, 0x10(%r15)
leaq 0x30(%rsp), %rdi
movq %rdx, %rsi
callq 0x21f36
leaq 0x48(%rsp), %rdi
movq %r15, %rsi
callq 0x21f84
leaq 0x80(%rsp), %rdi
leaq 0x30(%rsp), %rdx
leaq 0x48(%rsp), %rcx
movq %rbp, %rsi
movq %rbx, %r8
callq 0xb9a04
leaq 0x48(%rsp), %rdi
callq 0x96b6a
leaq 0x30(%rsp), %rdi
callq 0x13cb8
movq 0x50(%rbp), %r13
testq %r13, %r13
setne %r14b
xorl %r15d, %r15d
movl 0xc(%rsp), %eax
testl %eax, %eax
movl $0x0, %ecx
cmovgl %eax, %ecx
movl %ecx, 0x1c(%rsp)
movq 0x10(%rsp), %rax
decq %rax
movq %rax, 0x28(%rsp)
pushq $0x1
popq %r12
movq %rbp, 0x20(%rsp)
testb $0x1, %r14b
je 0x18166
leaq 0x80(%rsp), %rdi
callq 0xba07e
leaq 0x11f224(%rip), %rax    # 0x1372f8
incq (%rax)
movq %r15, %rax
cqto
idivq 0x10(%rsp)
movl 0x1c(%rsp), %ebp
cmpq 0x28(%rsp), %rdx
jne 0x180fc
subl $0x1, %ebp
jb 0x180fc
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x18(%rax)
jmp 0x180ec
xorl %ebp, %ebp
xorl %r14d, %r14d
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rcx
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbp, %rcx
jbe 0x18136
movq (%rax,%rbp,8), %rdi
callq 0xba708
cmpq %r13, %rax
movzbl %r14b, %r14d
cmovll %r12d, %r14d
incq %rbp
jmp 0x18101
testb $0x1, %r14b
movq 0x20(%rsp), %rbp
je 0x18152
leaq 0x80(%rsp), %rdi
callq 0xba6a4
testb %al, %al
jne 0x1815a
incq %r15
jmp 0x180b6
leaq 0xbf574(%rip), %rdi     # 0xd76d5
callq 0xb400
movb $0x1, 0x11e165(%rip)    # 0x1362d2
leaq 0xbf5d9(%rip), %rdi     # 0xd774d
callq 0xb400
callq 0xc5dac
leaq 0x80(%rsp), %rdi
callq 0xba712
leaq 0x80(%rsp), %rdi
callq 0xba6da
testq %rax, %rax
jne 0x1827e
leaq 0xbf5c9(%rip), %rdi     # 0xd7771
callq 0xb400
movq 0x10(%rsp), %rax
imull 0xc(%rsp), %eax
movslq %eax, %r12
xorl %r15d, %r15d
leaq 0x80(%rsp), %r14
movq %r15, %rax
cqto
idivq %r12
movq %rdx, %r13
movl %r13d, %eax
cltd
idivl 0xc(%rsp)
testl %edx, %edx
jne 0x18217
movq %r14, %rdi
callq 0xba07e
leaq 0x11f10d(%rip), %rax    # 0x1372f8
incq (%rax)
cmpq $0x0, 0x48(%rbp)
je 0x181ff
movq %r14, %rdi
callq 0xba6a4
jmp 0x18213
movq %rbp, %rdi
callq 0x21fcc
testb %al, %al
je 0x18231
movq %r14, %rdi
callq 0xba576
testb %al, %al
jne 0x1824a
movl %r13d, %eax
cltd
idivl 0x10(%rsp)
testl %edx, %edx
jne 0x1822c
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x18(%rax)
incq %r15
jmp 0x181c5
movq %r14, %rdi
callq 0xba576
testb %al, %al
je 0x18217
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x28(%rax)
testl %eax, %eax
jne 0x18217
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x30(%rax)
leaq 0x11ee86(%rip), %rdi    # 0x1370e0
callq 0x22084
leaq 0x80(%rsp), %rdi
callq 0x22106
addq $0x868, %rsp            # imm = 0x868
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xbac8f(%rip), %rdi     # 0xd2f14
leaq 0xb9071(%rip), %rsi     # 0xd12fd
leaq 0xbac97(%rip), %rcx     # 0xd2f2a
pushq $0x76
popq %rdx
callq 0xb210
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x96b6a
jmp 0x182ad
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x13cb8
jmp 0x182d3
jmp 0x182c3
jmp 0x182c3
jmp 0x182c3
jmp 0x182c3
jmp 0x182c3
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
callq 0x22106
movq %rbx, %rdi
callq 0xb4d0