// File: CMU-SAFARI[P]ramulator/src/Controller.h
// Function: ramulator::Controller<ramulator::DDR3>::tick()
void tick()
    {
        clk++;
        req_queue_length_sum += readq.size() + writeq.size() + pending.size();
        read_req_queue_length_sum += readq.size() + pending.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) { // this request really accessed a row
                  read_latency_sum += req.depart - req.arrive;
                  channel->update_serving_requests(
                      req.addr_vec.data(), -1, clk);
                }
                req.callback(req);
                pending.pop_front();
            }
        }

        /*** 2. Refresh scheduler ***/
        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(wr_high_watermark * 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(wr_low_watermark * writeq.max) && readq.size() != 0)
                write_mode = false;
        }

        /*** 4. Find the best command to schedule, if any ***/

        // First check the actq (which has higher priority) to see if there
        // are requests available to service in this cycle
        Queue* queue = &actq;
        typename T::Command cmd;
        auto req = scheduler->get_head(queue->q);

        bool is_valid_req = (req != queue->q.end());

        if(is_valid_req) {
            cmd = get_first_cmd(req);
            is_valid_req = is_ready(cmd, req->addr_vec);
        }

        if (!is_valid_req) {
            queue = !write_mode ? &readq : &writeq;

            if (otherq.size())
                queue = &otherq;  // "other" requests are rare, so we give them precedence over reads/writes

            req = scheduler->get_head(queue->q);

            is_valid_req = (req != queue->q.end());

            if(is_valid_req){
                cmd = get_first_cmd(req);
                is_valid_req = is_ready(cmd, req->addr_vec);
            }
        }

        if (!is_valid_req) {
            // we couldn't find a command to schedule -- let's try to be speculative
            auto cmd = T::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) {
            req->is_first_command = false;
            int coreid = req->coreid;
            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;
            }
        }

        // issue command on behalf of request
        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)]){
        if (cmd != channel->spec->translate[int(req->type)]) {
            if(channel->spec->is_opening(cmd)) {
                // promote the request that caused issuing activation to actq
                actq.q.push_back(*req);
                queue->q.erase(req);
            }

            return;
        }

        // set a future completion time for read requests
        if (req->type == Request::Type::READ) {
            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);
            // req->callback(*req);
        }

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

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1a0, %rsp            # imm = 0x1A0
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x118(%rbp)
movq 0x1090(%rdi), %rax
addq $0x1, %rax
movq %rax, 0x1090(%rdi)
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x3fdd0
movq -0x118(%rbp), %rdi
movl %eax, -0x12c(%rbp)
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x3fdd0
movq -0x118(%rbp), %rdi
movl %eax, %ecx
movl -0x12c(%rbp), %eax
addl %ecx, %eax
movl %eax, %eax
movq %rax, -0x128(%rbp)
addq $0x1140, %rdi           # imm = 0x1140
callq 0x3fdf0
movq -0x118(%rbp), %rdi
movq %rax, %rcx
movq -0x128(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x10(%rbp)
addq $0x978, %rdi            # imm = 0x978
leaq -0x10(%rbp), %rsi
callq 0x40af0
movq -0x118(%rbp), %rdi
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x3fdd0
movq -0x118(%rbp), %rdi
movl %eax, %eax
movq %rax, -0x120(%rbp)
addq $0x1140, %rdi           # imm = 0x1140
callq 0x3fdf0
movq -0x118(%rbp), %rdi
movq %rax, %rcx
movq -0x120(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x18(%rbp)
addq $0xaa8, %rdi            # imm = 0xAA8
leaq -0x18(%rbp), %rsi
callq 0x40af0
movq -0x118(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x3fdd0
movq -0x118(%rbp), %rdi
movl %eax, -0x1c(%rbp)
addq $0xbd8, %rdi            # imm = 0xBD8
leaq -0x1c(%rbp), %rsi
callq 0x40b20
movq -0x118(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
callq 0x3fdf0
cmpq $0x0, %rax
je 0x400c2
movq -0x118(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
xorl %eax, %eax
movl %eax, %esi
callq 0x40b50
movq -0x118(%rbp), %rcx
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movq 0x38(%rax), %rax
cmpq 0x1090(%rcx), %rax
jg 0x400c0
movq -0x28(%rbp), %rax
movq 0x38(%rax), %rax
movq -0x28(%rbp), %rcx
subq 0x30(%rcx), %rax
cmpq $0x1, %rax
jle 0x4009c
movq -0x118(%rbp), %rdi
movq -0x28(%rbp), %rax
movq 0x38(%rax), %rax
movq -0x28(%rbp), %rcx
subq 0x30(%rcx), %rax
movq %rax, -0x30(%rbp)
addq $0x848, %rdi            # imm = 0x848
leaq -0x30(%rbp), %rsi
callq 0x40b80
movq -0x118(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0x138(%rbp)
movq -0x28(%rbp), %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0x138(%rbp), %rdi
movq %rax, %rsi
movq -0x118(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x40bb0
movq -0x28(%rbp), %rdi
addq $0x40, %rdi
movq -0x28(%rbp), %rsi
callq 0x40f00
movq -0x118(%rbp), %rdi
addq $0x1140, %rdi           # imm = 0x1140
callq 0x40f40
jmp 0x400c2
movq -0x118(%rbp), %rax
movq 0x10b8(%rax), %rdi
callq 0x40fb0
movq -0x118(%rbp), %rax
testb $0x1, 0x1190(%rax)
jne 0x40146
movq -0x118(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x3fdd0
movq -0x118(%rbp), %rcx
movss 0x1194(%rcx), %xmm0
movl 0x10f8(%rcx), %ecx
cvtsi2ss %rcx, %xmm1
mulss %xmm1, %xmm0
cvttss2si %xmm0, %ecx
cmpl %ecx, %eax
ja 0x40136
movq -0x118(%rbp), %rdi
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x3fdd0
cmpl $0x0, %eax
jne 0x40144
movq -0x118(%rbp), %rax
movb $0x1, 0x1190(%rax)
jmp 0x401a7
movq -0x118(%rbp), %rdi
addq $0x10e0, %rdi           # imm = 0x10E0
callq 0x3fdd0
movq -0x118(%rbp), %rcx
movss 0x1198(%rcx), %xmm0
movl 0x10f8(%rcx), %ecx
cvtsi2ss %rcx, %xmm1
mulss %xmm1, %xmm0
cvttss2si %xmm0, %ecx
cmpl %ecx, %eax
jae 0x401a5
movq -0x118(%rbp), %rdi
addq $0x10c0, %rdi           # imm = 0x10C0
callq 0x3fdd0
cmpl $0x0, %eax
je 0x401a5
movq -0x118(%rbp), %rax
movb $0x0, 0x1190(%rax)
jmp 0x401a7
movq -0x118(%rbp), %rax
movq %rax, %rcx
addq $0x1100, %rcx           # imm = 0x1100
movq %rcx, -0x38(%rbp)
movq 0x10a0(%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x41030
movq %rax, -0x48(%rbp)
movq -0x38(%rbp), %rdi
callq 0x417c0
movq %rax, -0x58(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x41790
andb $0x1, %al
movb %al, -0x49(%rbp)
testb $0x1, -0x49(%rbp)
je 0x40240
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rsi
callq 0x2f100
movl %eax, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
movl %eax, -0x13c(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq -0x118(%rbp), %rdi
movl -0x13c(%rbp), %esi
movq %rax, %rdx
addq $0x10, %rdx
callq 0x31ab0
andb $0x1, %al
movb %al, -0x49(%rbp)
testb $0x1, -0x49(%rbp)
jne 0x4034d
movq -0x118(%rbp), %rax
testb $0x1, 0x1190(%rax)
jne 0x40270
movq -0x118(%rbp), %rax
addq $0x10c0, %rax           # imm = 0x10C0
movq %rax, -0x148(%rbp)
jmp 0x40284
movq -0x118(%rbp), %rax
addq $0x10e0, %rax           # imm = 0x10E0
movq %rax, -0x148(%rbp)
movq -0x118(%rbp), %rdi
movq -0x148(%rbp), %rax
movq %rax, -0x38(%rbp)
addq $0x1120, %rdi           # imm = 0x1120
callq 0x3fdd0
cmpl $0x0, %eax
je 0x402b8
movq -0x118(%rbp), %rax
addq $0x1120, %rax           # imm = 0x1120
movq %rax, -0x38(%rbp)
movq -0x118(%rbp), %rax
movq 0x10a0(%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x41030
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x38(%rbp), %rdi
callq 0x417c0
movq %rax, -0x70(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x41790
andb $0x1, %al
movb %al, -0x49(%rbp)
testb $0x1, -0x49(%rbp)
je 0x4034b
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rsi
callq 0x2f100
movl %eax, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
movl %eax, -0x14c(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq -0x118(%rbp), %rdi
movl -0x14c(%rbp), %esi
movq %rax, %rdx
addq $0x10, %rdx
callq 0x31ab0
andb $0x1, %al
movb %al, -0x49(%rbp)
jmp 0x4034d
testb $0x1, -0x49(%rbp)
jne 0x403d9
movq -0x118(%rbp), %rax
movl $0x1, -0x7c(%rbp)
movq 0x10a8(%rax), %rsi
movl -0x7c(%rbp), %edx
leaq -0x98(%rbp), %rdi
callq 0x417f0
leaq -0x98(%rbp), %rdi
callq 0x41840
testb $0x1, %al
jne 0x403c8
movq -0x118(%rbp), %rdi
movl -0x7c(%rbp), %esi
leaq -0x98(%rbp), %rdx
callq 0x41880
jmp 0x403a3
jmp 0x403c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa0(%rbp)
movl %eax, -0xa4(%rbp)
leaq -0x98(%rbp), %rdi
callq 0x2fcd0
jmp 0x4095b
leaq -0x98(%rbp), %rdi
callq 0x2fcd0
jmp 0x40952
leaq -0x48(%rbp), %rdi
callq 0x2eb90
testb $0x1, (%rax)
je 0x406e7
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movb $0x0, (%rax)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movl 0x28(%rax), %eax
movl %eax, -0xa8(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
je 0x40427
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x40473
movq -0x118(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0x158(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0x158(%rbp), %rdi
movq %rax, %rsi
movq -0x118(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0x1, %edx
callq 0x40bb0
movq -0x118(%rbp), %rcx
movq 0x1098(%rcx), %rax
movq 0x390(%rax), %rax
movl 0x2740(%rax), %eax
movq 0x1098(%rcx), %rcx
movq 0x390(%rcx), %rcx
imull 0x2744(%rcx), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, -0xac(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
jne 0x405c9
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rsi
callq 0x311e0
testb $0x1, %al
jne 0x404e8
jmp 0x40521
movq -0x118(%rbp), %rdi
addq $0x2f8, %rdi            # imm = 0x2F8
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
callq 0x3fd50
jmp 0x405b1
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rsi
callq 0x41ba0
testb $0x1, %al
jne 0x40545
jmp 0x4057b
movq -0x118(%rbp), %rdi
addq $0x458, %rdi            # imm = 0x458
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x260, %rdi            # imm = 0x260
callq 0x3fd50
jmp 0x405af
movq -0x118(%rbp), %rdi
addq $0x3a8, %rdi            # imm = 0x3A8
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x1c8, %rdi            # imm = 0x1C8
callq 0x3fd50
jmp 0x405b1
movq -0x118(%rbp), %rdi
leaq -0xac(%rbp), %rsi
callq 0x3fe40
jmp 0x406e5
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x406e3
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rsi
callq 0x311e0
testb $0x1, %al
jne 0x40600
jmp 0x40639
movq -0x118(%rbp), %rdi
addq $0x508, %rdi            # imm = 0x508
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
callq 0x3fd50
jmp 0x406c9
movq -0x118(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rsi
callq 0x41ba0
testb $0x1, %al
jne 0x4065d
jmp 0x40693
movq -0x118(%rbp), %rdi
addq $0x668, %rdi            # imm = 0x668
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x260, %rdi            # imm = 0x260
callq 0x3fd50
jmp 0x406c7
movq -0x118(%rbp), %rdi
addq $0x5b8, %rdi            # imm = 0x5B8
movl -0xa8(%rbp), %esi
callq 0x41b70
movq %rax, %rdi
callq 0x40990
movq -0x118(%rbp), %rdi
addq $0x1c8, %rdi            # imm = 0x1C8
callq 0x3fd50
jmp 0x406c9
movq -0x118(%rbp), %rdi
addq $0x98, %rdi
leaq -0xac(%rbp), %rsi
callq 0x3fe40
jmp 0x406e5
jmp 0x406e7
movq -0x118(%rbp), %rsi
movl -0x3c(%rbp), %edx
movl %edx, -0x164(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rcx
leaq -0xe8(%rbp), %rdi
movq %rdi, -0x160(%rbp)
callq 0x41c30
movq -0x118(%rbp), %rdi
movl -0x164(%rbp), %esi
movq -0x160(%rbp), %rdx
callq 0x41880
jmp 0x40737
leaq -0xe8(%rbp), %rdi
callq 0x2fcd0
movq -0x118(%rbp), %rax
movl -0x3c(%rbp), %ecx
movl %ecx, -0x168(%rbp)
movq 0x1098(%rax), %rax
movq 0x390(%rax), %rax
movq %rax, -0x170(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq -0x170(%rbp), %rcx
movq %rax, %rdx
movl -0x168(%rbp), %eax
movslq 0x2c(%rdx), %rdx
cmpl 0x1c4(%rcx,%rdx,4), %eax
je 0x40843
movq -0x118(%rbp), %rax
movq 0x1098(%rax), %rax
movq 0x390(%rax), %rdi
movl -0x3c(%rbp), %esi
callq 0x41c80
testb $0x1, %al
jne 0x407b8
jmp 0x4083e
movq -0x118(%rbp), %rax
addq $0x1100, %rax           # imm = 0x1100
movq %rax, -0x180(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x41cf0
movq -0x180(%rbp), %rdi
movq %rax, %rsi
callq 0x41cb0
movq -0x38(%rbp), %rax
movq %rax, -0x178(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x41d60
movq -0x178(%rbp), %rdi
movq -0xf8(%rbp), %rsi
callq 0x41d10
movq %rax, -0x100(%rbp)
jmp 0x4083e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa0(%rbp)
movl %eax, -0xa4(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x2fcd0
jmp 0x4095b
jmp 0x40952
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x0, 0x2c(%rax)
jne 0x408c2
movq -0x118(%rbp), %rcx
movq 0x1090(%rcx), %rax
movq 0x1098(%rcx), %rcx
movq 0x390(%rcx), %rcx
movslq 0x2dd8(%rcx), %rcx
addq %rcx, %rax
movq %rax, -0x190(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq -0x190(%rbp), %rdx
movq %rax, %rcx
movq -0x118(%rbp), %rax
movq %rdx, 0x38(%rcx)
addq $0x1140, %rax           # imm = 0x1140
movq %rax, -0x188(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x41cf0
movq -0x188(%rbp), %rdi
movq %rax, %rsi
callq 0x41d80
leaq -0x48(%rbp), %rdi
callq 0x2eb90
cmpl $0x1, 0x2c(%rax)
jne 0x4091d
movq -0x118(%rbp), %rax
movq 0x1098(%rax), %rax
movq %rax, -0x198(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2eb90
movq %rax, %rdi
addq $0x10, %rdi
callq 0x2f270
movq -0x198(%rbp), %rdi
movq %rax, %rsi
movq -0x118(%rbp), %rax
movq 0x1090(%rax), %rcx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x40bb0
movq -0x38(%rbp), %rax
movq %rax, -0x1a0(%rbp)
leaq -0x108(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x41d60
movq -0x1a0(%rbp), %rdi
movq -0x108(%rbp), %rsi
callq 0x41d10
movq %rax, -0x110(%rbp)
addq $0x1a0, %rsp            # imm = 0x1A0
popq %rbp
retq
movq -0xa0(%rbp), %rdi
callq 0xc5d0
nopw (%rax,%rax)