// File: CMU-SAFARI[P]ramulator/src/Controller.cpp
// Function: ramulator::Controller<ramulator::TLDRAM>::tick()
void Controller<TLDRAM>::tick(){
    clk++;
    req_queue_length_sum += readq.size() + writeq.size();
    read_req_queue_length_sum += readq.size();
    write_req_queue_length_sum += writeq.size();

    /*** 1. Serve completed reads ***/
    if (pending.size()) {
        Request& req = pending[0];
        if (req.depart <= clk) {
          if (req.depart - req.arrive > 1) {
                  read_latency_sum += req.depart - req.arrive;
                  channel->update_serving_requests(
                      req.addr_vec.data(), -1, clk);
          }
            req.callback(req);
            pending.pop_front();
        }
    }

    /*** 2. Should we schedule refreshes? ***/
    refresh->tick_ref();

    /*** 3. Should we schedule writes? ***/
    if (!write_mode) {
        // yes -- write queue is almost full or read queue is empty
        if (writeq.size() >= int(0.8 * writeq.max) /*|| readq.size() == 0*/)
            write_mode = true;
    }
    else {
        // no -- write queue is almost empty and read queue is not empty
        if (writeq.size() <= int(0.2 * writeq.max) && readq.size() != 0)
            write_mode = false;
    }

    /*** 4. Find the best command to schedule, if any ***/
    Queue* queue = !write_mode ? &readq : &writeq;
    if (otherq.size())
        queue = &otherq;  // "other" requests are rare, so we give them precedence over reads/writes

    auto req = scheduler->get_head(queue->q);
    if (req == queue->q.end() || !is_ready(req)) {
        // we couldn't find a command to schedule -- let's try to be speculative
        auto cmd = TLDRAM::Command::PRE;
        vector<int> victim = rowpolicy->get_victim(cmd);
        if (!victim.empty()){
            issue_cmd(cmd, victim);
        }
        return;  // nothing more to be done this cycle
    }

    if (req->is_first_command) {
        int coreid = req->coreid;
        req->is_first_command = false;
        if (req->type == Request::Type::READ || req->type == Request::Type::WRITE) {
          channel->update_serving_requests(req->addr_vec.data(), 1, clk);
        }
        int tx = (channel->spec->prefetch_size * channel->spec->channel_width / 8);
        if (req->type == Request::Type::READ) {
            if (is_row_hit(req)) {
                ++read_row_hits[coreid];
                ++row_hits;
            } else if (is_row_open(req)) {
                ++read_row_conflicts[coreid];
                ++row_conflicts;
            } else {
                ++read_row_misses[coreid];
                ++row_misses;
            }
          read_transaction_bytes += tx;
        } else if (req->type == Request::Type::WRITE) {
          if (is_row_hit(req)) {
              ++write_row_hits[coreid];
              ++row_hits;
          } else if (is_row_open(req)) {
              ++write_row_conflicts[coreid];
              ++row_conflicts;
          } else {
              ++write_row_misses[coreid];
              ++row_misses;
          }
          write_transaction_bytes += tx;
        }
    }

    /*** 5. Change a read request to a migration request ***/
    if (req->type == Request::Type::READ) {
        req->type = Request::Type::EXTENSION;
    }

    // issue command on behalf of request
    auto cmd = get_first_cmd(req);
    issue_cmd(cmd, get_addr_vec(cmd, req));

    // check whether this is the last command (which finishes the request)
    if (cmd != channel->spec->translate[int(req->type)])
        return;

    // set a future completion time for read requests
    if (req->type == Request::Type::READ || req->type == Request::Type::EXTENSION) {
        req->depart = clk + channel->spec->read_latency;
        pending.push_back(*req);
    }
    if (req->type == Request::Type::WRITE) {
        channel->update_serving_requests(req->addr_vec.data(), -1, clk);
    }

    // remove request from queue
    queue->q.erase(req);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0xe8(%rbp)
movq 0x1090(%rdi), %rax
addq $0x1, %rax
movq %rax, 0x1090(%rdi)
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x16c510
movq -0xe8(%rbp), %rdi
movl %eax, -0xec(%rbp)
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x16c510
movq -0xe8(%rbp), %rdi
movl %eax, %ecx
movl -0xec(%rbp), %eax
addl %ecx, %eax
movl %eax, -0xc(%rbp)
addq $0x978, %rdi            # imm = 0x978
leaq -0xc(%rbp), %rsi
callq 0x40b20
movq -0xe8(%rbp), %rdi
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x16c510
movq -0xe8(%rbp), %rdi
movl %eax, -0x10(%rbp)
addq $0xaa8, %rdi            # imm = 0xAA8
leaq -0x10(%rbp), %rsi
callq 0x40b20
movq -0xe8(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x16c510
movq -0xe8(%rbp), %rdi
movl %eax, -0x14(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x14(%rbp), %rsi
callq 0x40b20
movq -0xe8(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
callq 0x3fdf0
cmpq $0x0, %rax
je 0x18792e
movq -0xe8(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
xorl %eax, %eax
movl %eax, %esi
callq 0x40b50
movq -0xe8(%rbp), %rcx
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq 0x38(%rax), %rax
cmpq 0x1090(%rcx), %rax
jg 0x18792c
movq -0x20(%rbp), %rax
movq 0x38(%rax), %rax
movq -0x20(%rbp), %rcx
subq 0x30(%rcx), %rax
cmpq $0x1, %rax
jle 0x187908
movq -0xe8(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x38(%rax), %rax
movq -0x20(%rbp), %rcx
subq 0x30(%rcx), %rax
movq %rax, -0x28(%rbp)
addq $0x848, %rdi            # imm = 0x848
leaq -0x28(%rbp), %rsi
callq 0x40b80
movq -0xe8(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0xf8(%rbp)
movq -0x20(%rbp), %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0xf8(%rbp), %rdi
movq %rax, %rsi
movq -0xe8(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x1880a0
movq -0x20(%rbp), %rdi
addq $0x40, %rdi
movq -0x20(%rbp), %rsi
callq 0x40f00
movq -0xe8(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
callq 0x40f40
jmp 0x18792e
movq -0xe8(%rbp), %rax
movq 0x10b8(%rax), %rdi
callq 0x1883f0
movq -0xe8(%rbp), %rax
testb $0x1, 0x1190(%rax)
jne 0x18799a
movq -0xe8(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x16c510
movq -0xe8(%rbp), %rcx
movl 0x10f8(%rcx), %ecx
cvtsi2sd %rcx, %xmm1
movsd 0xd399a(%rip), %xmm0    # 0x25b318
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %ecx
cmpl %ecx, %eax
jb 0x187998
movq -0xe8(%rbp), %rax
movb $0x1, 0x1190(%rax)
jmp 0x1879fb
movq -0xe8(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x16c510
movq -0xe8(%rbp), %rcx
movl 0x10f8(%rcx), %ecx
cvtsi2sd %rcx, %xmm1
movsd 0xd3959(%rip), %xmm0    # 0x25b320
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %ecx
cmpl %ecx, %eax
ja 0x1879f9
movq -0xe8(%rbp), %rdi
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x16c510
cmpl $0x0, %eax
je 0x1879f9
movq -0xe8(%rbp), %rax
movb $0x0, 0x1190(%rax)
jmp 0x1879fb
movq -0xe8(%rbp), %rax
testb $0x1, 0x1190(%rax)
jne 0x187a21
movq -0xe8(%rbp), %rax
addq $0x10c0, %rax           # imm = 0x10C0
movq %rax, -0x100(%rbp)
jmp 0x187a35
movq -0xe8(%rbp), %rax
addq $0x10e0, %rax           # imm = 0x10E0
movq %rax, -0x100(%rbp)
movq -0xe8(%rbp), %rdi
movq -0x100(%rbp), %rax
movq %rax, -0x30(%rbp)
addq $0x1120, %rdi           # imm = 0x1120
callq 0x16c510
cmpl $0x0, %eax
je 0x187a69
movq -0xe8(%rbp), %rax
addq $0x1120, %rax           # imm = 0x1120
movq %rax, -0x30(%rbp)
movq -0xe8(%rbp), %rax
movq 0x10a0(%rax), %rdi
movq -0x30(%rbp), %rsi
callq 0x188470
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
callq 0x417c0
movq %rax, -0x40(%rbp)
leaq -0x38(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x435e0
movb %al, %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, -0x101(%rbp)
jne 0x187acd
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rsi
callq 0x165960
xorb $-0x1, %al
movb %al, -0x101(%rbp)
movb -0x101(%rbp), %al
testb $0x1, %al
jne 0x187ad9
jmp 0x187b46
movq -0xe8(%rbp), %rax
movl $0x1, -0x4c(%rbp)
movq 0x10a8(%rax), %rsi
movl -0x4c(%rbp), %edx
leaq -0x68(%rbp), %rdi
callq 0x188bd0
leaq -0x68(%rbp), %rdi
callq 0x41840
testb $0x1, %al
jne 0x187b38
movq -0xe8(%rbp), %rdi
movl -0x4c(%rbp), %esi
leaq -0x68(%rbp), %rdx
callq 0x188c20
jmp 0x187b1c
jmp 0x187b38
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x2fcd0
jmp 0x18806f
leaq -0x68(%rbp), %rdi
callq 0x2fcd0
jmp 0x188066
leaq -0x38(%rbp), %rdi
callq 0x2eb90
testb $0x1, (%rax)
je 0x187e36
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movl 0x28(%rax), %eax
movl %eax, -0x78(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movb $0x0, (%rax)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
je 0x187b91
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x187bdd
movq -0xe8(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0x110(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0x110(%rbp), %rdi
movq %rax, %rsi
movq -0xe8(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0x1, %edx
callq 0x1880a0
movq -0xe8(%rbp), %rcx
movq 0x1098(%rcx), %rax
movq 0x390(%rax), %rax
movl 0x36d0(%rax), %eax
movq 0x1098(%rcx), %rcx
movq 0x390(%rcx), %rcx
imull 0x36d4(%rcx), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, -0x7c(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
jne 0x187d24
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rsi
callq 0x166bd0
testb $0x1, %al
jne 0x187c4f
jmp 0x187c85
movq -0xe8(%rbp), %rdi
addq $0x2f8, %rdi            # imm = 0x2F8
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
callq 0x3fd50
jmp 0x187d0f
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rsi
callq 0x188f20
testb $0x1, %al
jne 0x187ca9
jmp 0x187cdc
movq -0xe8(%rbp), %rdi
addq $0x458, %rdi            # imm = 0x458
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x260, %rdi            # imm = 0x260
callq 0x3fd50
jmp 0x187d0d
movq -0xe8(%rbp), %rdi
addq $0x3a8, %rdi            # imm = 0x3A8
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x1c8, %rdi            # imm = 0x1C8
callq 0x3fd50
jmp 0x187d0f
movq -0xe8(%rbp), %rdi
leaq -0x7c(%rbp), %rsi
callq 0x3fe40
jmp 0x187e34
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x187e32
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rsi
callq 0x166bd0
testb $0x1, %al
jne 0x187d5b
jmp 0x187d91
movq -0xe8(%rbp), %rdi
addq $0x508, %rdi            # imm = 0x508
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
callq 0x3fd50
jmp 0x187e1b
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rsi
callq 0x188f20
testb $0x1, %al
jne 0x187db5
jmp 0x187de8
movq -0xe8(%rbp), %rdi
addq $0x668, %rdi            # imm = 0x668
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x260, %rdi            # imm = 0x260
callq 0x3fd50
jmp 0x187e19
movq -0xe8(%rbp), %rdi
addq $0x5b8, %rdi            # imm = 0x5B8
movl -0x78(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0xe8(%rbp), %rdi
addq $0x1c8, %rdi            # imm = 0x1C8
callq 0x3fd50
jmp 0x187e1b
movq -0xe8(%rbp), %rdi
addq $0x98, %rdi
leaq -0x7c(%rbp), %rsi
callq 0x3fe40
jmp 0x187e34
jmp 0x187e36
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
jne 0x187e55
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movl $0x5, 0x2c(%rax)
movq -0xe8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rsi
callq 0x1659e0
movq -0xe8(%rbp), %rsi
movl %eax, -0xa4(%rbp)
movl -0xa4(%rbp), %edx
movl %edx, -0x11c(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rcx
leaq -0xc8(%rbp), %rdi
movq %rdi, -0x118(%rbp)
callq 0x188fb0
movq -0xe8(%rbp), %rdi
movl -0x11c(%rbp), %esi
movq -0x118(%rbp), %rdx
callq 0x188c20
jmp 0x187ecc
leaq -0xc8(%rbp), %rdi
callq 0x2fcd0
movq -0xe8(%rbp), %rax
movl -0xa4(%rbp), %ecx
movl %ecx, -0x120(%rbp)
movq 0x1098(%rax), %rax
movq 0x390(%rax), %rax
movq %rax, -0x128(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movq -0x128(%rbp), %rcx
movq %rax, %rdx
movl -0x120(%rbp), %eax
movslq 0x2c(%rdx), %rdx
cmpl 0x280(%rcx,%rdx,4), %eax
je 0x187f48
jmp 0x188066
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0xc8(%rbp), %rdi
callq 0x2fcd0
jmp 0x18806f
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
je 0x187f66
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x5, 0x2c(%rax)
jne 0x187fd6
movq -0xe8(%rbp), %rcx
movq 0x1090(%rcx), %rax
movq 0x1098(%rcx), %rcx
movq 0x390(%rcx), %rcx
movslq 0x3f48(%rcx), %rcx
addq %rcx, %rax
movq %rax, -0x138(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movq -0x138(%rbp), %rdx
movq %rax, %rcx
movq -0xe8(%rbp), %rax
movq %rdx, 0x38(%rcx)
addq $0x1140, %rax           # imm = 0x1140
movq %rax, -0x130(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x41cf0
movq -0x130(%rbp), %rdi
movq %rax, %rsi
callq 0x41d80
leaq -0x38(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x188031
movq -0xe8(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0x140(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0x140(%rbp), %rdi
movq %rax, %rsi
movq -0xe8(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x1880a0
movq -0x30(%rbp), %rax
movq %rax, -0x148(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x41d60
movq -0x148(%rbp), %rdi
movq -0xd8(%rbp), %rsi
callq 0x41d10
movq %rax, -0xe0(%rbp)
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
movq -0x70(%rbp), %rdi
callq 0xc5d0
nopl (%rax,%rax)