// File: CMU-SAFARI[P]ramulator/src/Cache.cpp
// Function: ramulator::Cache::send(ramulator::Request)
bool Cache::send(Request req) {
  debug("level %d req.addr %lx req.type %d, index %d, tag %ld",
      int(level), req.addr, int(req.type), get_index(req.addr),
      get_tag(req.addr));

  cache_total_access++;
  if (req.type == Request::Type::WRITE) {
    cache_write_access++;
  } else {
    assert(req.type == Request::Type::READ);
    cache_read_access++;
  }
  // If there isn't a set, create it.
  auto& lines = get_lines(req.addr);
  std::list<Line>::iterator line;

  if (is_hit(lines, req.addr, &line)) {
    lines.push_back(Line(req.addr, get_tag(req.addr), false,
        line->dirty || (req.type == Request::Type::WRITE)));
    lines.erase(line);
    cachesys->hit_list.push_back(
        make_pair(cachesys->clk + latency[int(level)], req));

    debug("hit, update timestamp %ld", cachesys->clk);
    debug("hit finish time %ld",
        cachesys->clk + latency[int(level)]);

    return true;

  } else {
    debug("miss @level %d", int(level));
    cache_total_miss++;
    if (req.type == Request::Type::WRITE) {
      cache_write_miss++;
    } else {
      assert(req.type == Request::Type::READ);
      cache_read_miss++;
    }

    // The dirty bit will be set if this is a write request and @L1
    bool dirty = (req.type == Request::Type::WRITE);

    // Modify the type of the request to lower level
    if (req.type == Request::Type::WRITE) {
      req.type = Request::Type::READ;
    }

    // Look it up in MSHR entries
    assert(req.type == Request::Type::READ);
    auto mshr = hit_mshr(req.addr);
    if (mshr != mshr_entries.end()) {
      debug("hit mshr");
      cache_mshr_hit++;
      mshr->second->dirty = dirty || mshr->second->dirty;
      return true;
    }

    // All requests come to this stage will be READ, so they
    // should be recorded in MSHR entries.
    if (mshr_entries.size() == mshr_entry_num) {
      // When no MSHR entries available, the miss request
      // is stalling.
      cache_mshr_unavailable++;
      debug("no mshr entry available");
      return false;
    }

    // Check whether there is a line available
    if (all_sets_locked(lines)) {
      cache_set_unavailable++;
      return false;
    }

    auto newline = allocate_line(lines, req.addr);
    if (newline == lines.end()) {
      return false;
    }

    newline->dirty = dirty;

    // Add to MSHR entries
    mshr_entries.push_back(make_pair(req.addr, newline));

    // Send the request to next level;
    if (!is_last_level) {
      if(!lower_cache->send(req)) {
        retry_list.push_back(req);
      }
    } else {
      cachesys->wait_list.push_back(
          make_pair(cachesys->clk + latency[int(level)], req));
    }
    return true;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x270, %rsp            # imm = 0x270
movq %rsi, -0x1d8(%rbp)
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
addq $0x390, %rdi            # imm = 0x390
xorl %esi, %esi
callq 0x40970
movq -0x1d8(%rbp), %rsi
cmpl $0x1, 0x2c(%rsi)
jne 0x17d687
movq -0x1e0(%rbp), %rdi
addq $0x2f8, %rdi            # imm = 0x2F8
xorl %esi, %esi
callq 0x40970
jmp 0x17d6ca
movq -0x1d8(%rbp), %rax
cmpl $0x0, 0x2c(%rax)
jne 0x17d696
jmp 0x17d6b5
leaq 0xdd908(%rip), %rdi     # 0x25afa5
leaq 0xdd687(%rip), %rsi     # 0x25ad2b
movl $0x70, %edx
leaq 0xdd915(%rip), %rcx     # 0x25afc5
callq 0xc280
movq -0x1e0(%rbp), %rdi
addq $0x260, %rdi            # imm = 0x260
xorl %esi, %esi
callq 0x40970
movq -0x1e0(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x1800e0
movq %rax, -0x20(%rbp)
leaq -0x28(%rbp), %rdi
callq 0x180280
movq -0x1d8(%rbp), %rax
movq -0x1e0(%rbp), %rdi
movq -0x20(%rbp), %rsi
movq 0x8(%rax), %rdx
leaq -0x28(%rbp), %rcx
callq 0x17dd30
testb $0x1, %al
jne 0x17d716
jmp 0x17d8a8
movq -0x1e0(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movq -0x20(%rbp), %rcx
movq %rcx, -0x200(%rbp)
movq 0x8(%rax), %rcx
movq %rcx, -0x1f8(%rbp)
movq 0x8(%rax), %rsi
callq 0x1802e0
movq %rax, -0x1f0(%rbp)
leaq -0x28(%rbp), %rdi
callq 0x180300
movq %rax, %rcx
movb $0x1, %al
testb $0x1, 0x11(%rcx)
movb %al, -0x1e1(%rbp)
jne 0x17d778
movq -0x1d8(%rbp), %rax
cmpl $0x1, 0x2c(%rax)
sete %al
movb %al, -0x1e1(%rbp)
movq -0x1f0(%rbp), %rdx
movq -0x1f8(%rbp), %rsi
movb -0x1e1(%rbp), %al
movzbl %al, %r8d
andl $0x1, %r8d
leaq -0x40(%rbp), %rdi
movq %rdi, -0x228(%rbp)
xorl %ecx, %ecx
callq 0x180320
movq -0x200(%rbp), %rdi
movq -0x228(%rbp), %rsi
callq 0x1802a0
movq -0x20(%rbp), %rax
movq %rax, -0x220(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x1803c0
movq -0x220(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x180370
movq -0x1e0(%rbp), %rdi
movq %rax, -0x50(%rbp)
addq $0x630, %rdi            # imm = 0x630
movq %rdi, -0x218(%rbp)
callq 0x180090
movq -0x218(%rbp), %rdi
addq $0x18, %rax
movq %rax, -0x210(%rbp)
callq 0x180090
movq -0x1e0(%rbp), %rcx
movq -0x1d8(%rbp), %rdx
movq 0x50(%rax), %rax
movslq 0x5f0(%rcx), %rsi
movslq 0x618(%rcx,%rsi,4), %rcx
addq %rcx, %rax
movq %rax, -0xc0(%rbp)
leaq -0xb8(%rbp), %rdi
movq %rdi, -0x208(%rbp)
leaq -0xc0(%rbp), %rsi
callq 0x180420
movq -0x210(%rbp), %rdi
movq -0x208(%rbp), %rsi
callq 0x1803e0
jmp 0x17d870
leaq -0xb8(%rbp), %rdi
callq 0x180460
movb $0x1, -0x1(%rbp)
jmp 0x17dd09
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x180460
jmp 0x17dd17
movq -0x1e0(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
xorl %esi, %esi
callq 0x40970
movq -0x1d8(%rbp), %rax
cmpl $0x1, 0x2c(%rax)
jne 0x17d8e1
movq -0x1e0(%rbp), %rdi
addq $0x98, %rdi
xorl %esi, %esi
callq 0x40970
jmp 0x17d91d
movq -0x1d8(%rbp), %rax
cmpl $0x0, 0x2c(%rax)
jne 0x17d8f0
jmp 0x17d90f
leaq 0xdd6ae(%rip), %rdi     # 0x25afa5
leaq 0xdd42d(%rip), %rsi     # 0x25ad2b
movl $0x8a, %edx
leaq 0xdd6bb(%rip), %rcx     # 0x25afc5
callq 0xc280
movq -0x1e0(%rbp), %rdi
xorl %esi, %esi
callq 0x40970
movq -0x1d8(%rbp), %rax
cmpl $0x1, 0x2c(%rax)
sete %cl
andb $0x1, %cl
movb %cl, -0xcd(%rbp)
cmpl $0x1, 0x2c(%rax)
jne 0x17d948
movq -0x1d8(%rbp), %rax
movl $0x0, 0x2c(%rax)
movq -0x1d8(%rbp), %rax
cmpl $0x0, 0x2c(%rax)
jne 0x17d957
jmp 0x17d976
leaq 0xdd647(%rip), %rdi     # 0x25afa5
leaq 0xdd3c6(%rip), %rsi     # 0x25ad2b
movl $0x97, %edx
leaq 0xdd654(%rip), %rcx     # 0x25afc5
callq 0xc280
movq -0x1e0(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x180480
movq -0x1e0(%rbp), %rdi
movq %rax, -0xd8(%rbp)
addq $0x690, %rdi            # imm = 0x690
callq 0x180540
movq %rax, -0xe0(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
callq 0x180500
testb $0x1, %al
jne 0x17d9ca
jmp 0x17da4a
movq -0x1e0(%rbp), %rdi
addq $0x428, %rdi            # imm = 0x428
xorl %esi, %esi
callq 0x40970
movb $0x1, %al
testb $0x1, -0xcd(%rbp)
movb %al, -0x229(%rbp)
jne 0x17da11
leaq -0xd8(%rbp), %rdi
callq 0x180570
movq %rax, %rdi
addq $0x8, %rdi
callq 0x180300
movb 0x11(%rax), %al
movb %al, -0x229(%rbp)
movb -0x229(%rbp), %al
movb %al, -0x22a(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x180570
movq %rax, %rdi
addq $0x8, %rdi
callq 0x180300
movb -0x22a(%rbp), %cl
andb $0x1, %cl
movb %cl, 0x11(%rax)
movb $0x1, -0x1(%rbp)
jmp 0x17dd09
movq -0x1e0(%rbp), %rdi
addq $0x690, %rdi            # imm = 0x690
callq 0x180590
movq -0x1e0(%rbp), %rcx
movl 0x688(%rcx), %ecx
cmpq %rcx, %rax
jne 0x17da8d
movq -0x1e0(%rbp), %rdi
addq $0x4c0, %rdi            # imm = 0x4C0
xorl %esi, %esi
callq 0x40970
movb $0x0, -0x1(%rbp)
jmp 0x17dd09
movq -0x1e0(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x1805b0
testb $0x1, %al
jne 0x17daa3
jmp 0x17dac1
movq -0x1e0(%rbp), %rdi
addq $0x558, %rdi            # imm = 0x558
xorl %esi, %esi
callq 0x40970
movb $0x0, -0x1(%rbp)
jmp 0x17dd09
movq -0x1e0(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movq -0x20(%rbp), %rsi
movq 0x8(%rax), %rdx
callq 0x17ddf0
movq %rax, -0xe8(%rbp)
movq -0x20(%rbp), %rdi
callq 0x180690
movq %rax, -0xf0(%rbp)
leaq -0xe8(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x180660
testb $0x1, %al
jne 0x17db0c
jmp 0x17db15
movb $0x0, -0x1(%rbp)
jmp 0x17dd09
movb -0xcd(%rbp), %al
movb %al, -0x239(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x180300
movb -0x239(%rbp), %dl
movq -0x1d8(%rbp), %rdi
movq %rax, %rcx
movq -0x1e0(%rbp), %rax
andb $0x1, %dl
movb %dl, 0x11(%rcx)
addq $0x690, %rax            # imm = 0x690
movq %rax, -0x238(%rbp)
addq $0x8, %rdi
leaq -0xe8(%rbp), %rsi
callq 0x1806f0
movq -0x238(%rbp), %rdi
movq %rax, -0x100(%rbp)
movq %rdx, -0xf8(%rbp)
leaq -0x100(%rbp), %rsi
callq 0x1806c0
movq -0x1e0(%rbp), %rax
testb $0x1, 0x661(%rax)
jne 0x17dc50
movq -0x1d8(%rbp), %rsi
movq -0x1e0(%rbp), %rax
movq 0x658(%rax), %rax
movq %rax, -0x250(%rbp)
leaq -0x160(%rbp), %rdi
movq %rdi, -0x248(%rbp)
callq 0x42ba0
movq -0x250(%rbp), %rdi
movq -0x248(%rbp), %rsi
callq 0x17d630
movb %al, -0x23a(%rbp)
jmp 0x17dbe6
movb -0x23a(%rbp), %al
xorb $-0x1, %al
movb %al, -0x251(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x36780
movb -0x251(%rbp), %al
testb $0x1, %al
jne 0x17dc0c
jmp 0x17dc4b
movq -0x1d8(%rbp), %rsi
movq -0x1e0(%rbp), %rdi
addq $0x6a8, %rdi            # imm = 0x6A8
callq 0x41cb0
jmp 0x17dc4b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x36780
jmp 0x17dd17
jmp 0x17dd05
movq -0x1e0(%rbp), %rdi
addq $0x630, %rdi            # imm = 0x630
movq %rdi, -0x270(%rbp)
callq 0x180090
movq -0x270(%rbp), %rdi
movq %rax, -0x268(%rbp)
callq 0x180090
movq -0x1e0(%rbp), %rcx
movq -0x1d8(%rbp), %rdx
movq 0x50(%rax), %rax
movslq 0x5f0(%rcx), %rsi
movslq 0x618(%rcx,%rsi,4), %rcx
addq %rcx, %rax
movq %rax, -0x1d0(%rbp)
leaq -0x1c8(%rbp), %rdi
movq %rdi, -0x260(%rbp)
leaq -0x1d0(%rbp), %rsi
callq 0x180420
movq -0x268(%rbp), %rdi
movq -0x260(%rbp), %rsi
callq 0x1803e0
jmp 0x17dcd7
leaq -0x1c8(%rbp), %rdi
callq 0x180460
jmp 0x17dd05
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
leaq -0x1c8(%rbp), %rdi
callq 0x180460
jmp 0x17dd17
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x270, %rsp            # imm = 0x270
popq %rbp
retq
movq -0xc8(%rbp), %rdi
callq 0xc5d0
nopw %cs:(%rax,%rax)