// File: nus-comparch[P]cs5222-lab-prefetcher/example_prefetchers/stream_prefetcher.cc
// Function: l2_prefetcher_operate
void l2_prefetcher_operate(int cpu_num, unsigned long long int addr, unsigned long long int ip, int cache_hit)
{
  // uncomment this line to see all the information available to make prefetch decisions
  //printf("(%lld 0x%llx 0x%llx %d %d %d) ", get_current_cycle(0), addr, ip, cache_hit, get_l2_read_queue_occupancy(0), get_l2_mshr_occupancy(0));

  unsigned long long int cl_address = addr>>6;
  unsigned long long int page = cl_address>>6;
  int page_offset = cl_address&63;

  // check for a detector hit
  int detector_index = -1;

  int i;
  for(i=0; i<STREAM_DETECTOR_COUNT; i++)
    {
      if(detectors[i].page == page)
	{
	  detector_index = i;
	  break;
	}
    }

  if(detector_index == -1)
    {
      // this is a new page that doesn't have a detector yet, so allocate one
      detector_index = replacement_index;
      replacement_index++;
      if(replacement_index >= STREAM_DETECTOR_COUNT)
	{
	  replacement_index = 0;
	}

      // reset the oldest page
      detectors[detector_index].page = page;
      detectors[detector_index].direction = 0;
      detectors[detector_index].confidence = 0;
      detectors[detector_index].pf_index = page_offset;
    }

  // train on the new access
  if(page_offset > detectors[detector_index].pf_index)
    {
      // accesses outside the STREAM_WINDOW do not train the detector
      if((page_offset-detectors[detector_index].pf_index) < STREAM_WINDOW)
	{
	  if(detectors[detector_index].direction == -1)
	    {
	      // previously-set direction was wrong
	      detectors[detector_index].confidence = 0;
	    }
	  else
	    {
	      detectors[detector_index].confidence++;
	    }

	  // set the direction to +1
	  detectors[detector_index].direction = 1;
	}
    }
  else if(page_offset < detectors[detector_index].pf_index)
    {
      // accesses outside the STREAM_WINDOW do not train the detector
      if((detectors[detector_index].pf_index-page_offset) < STREAM_WINDOW)
	{
          if(detectors[detector_index].direction == 1)
            {
	      // previously-set direction was wrong
	      detectors[detector_index].confidence = 0;
            }
          else
            {
	      detectors[detector_index].confidence++;
            }

	  // set the direction to -1
          detectors[detector_index].direction = -1;
        }
    }

  // prefetch if confidence is high enough
  if(detectors[detector_index].confidence >= 2)
    {
      int i;
      for(i=0; i<PREFETCH_DEGREE; i++)
	{
	  detectors[detector_index].pf_index += detectors[detector_index].direction;

	  if((detectors[detector_index].pf_index < 0) || (detectors[detector_index].pf_index > 63))
	    {
	      // we've gone off the edge of a 4 KB page
	      break;
	    }

	  // perform prefetches
	  unsigned long long int pf_address = (page<<12)+((detectors[detector_index].pf_index)<<6);
	  
	  // check MSHR occupancy to decide whether to prefetch into the L2 or LLC
	  if(get_l2_mshr_occupancy(0) > 8)
	    {
	      // conservatively prefetch into the LLC, because MSHRs are scarce
	      l2_prefetch_line(0, addr, pf_address, FILL_LLC);
	    }
	  else
	    {
	      // MSHRs not too busy, so prefetch into L2
	      l2_prefetch_line(0, addr, pf_address, FILL_L2);
	    }
	}
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movq -0x10(%rbp), %rax
shrq $0x6, %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
shrq $0x6, %rax
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
andq $0x3f, %rax
movl %eax, -0x34(%rbp)
movl $0xffffffff, -0x38(%rbp) # imm = 0xFFFFFFFF
movl $0x0, -0x3c(%rbp)
cmpl $0x40, -0x3c(%rbp)
jge 0x40188d
movslq -0x3c(%rbp), %rcx
leaq 0xc978(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq (%rax), %rax
cmpq -0x30(%rbp), %rax
jne 0x401880
movl -0x3c(%rbp), %eax
movl %eax, -0x38(%rbp)
jmp 0x40188d
jmp 0x401882
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x401857
cmpl $-0x1, -0x38(%rbp)
jne 0x401925
movl 0xcf43(%rip), %eax      # 0x40e7e0
movl %eax, -0x38(%rbp)
movl 0xcf3a(%rip), %eax      # 0x40e7e0
addl $0x1, %eax
movl %eax, 0xcf31(%rip)      # 0x40e7e0
cmpl $0x40, 0xcf2a(%rip)     # 0x40e7e0
jl 0x4018c2
movl $0x0, 0xcf1e(%rip)      # 0x40e7e0
movq -0x30(%rbp), %rcx
movslq -0x38(%rbp), %rdx
leaq 0xc90f(%rip), %rax      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rax
movq %rcx, (%rax)
movslq -0x38(%rbp), %rcx
leaq 0xc8fa(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0x0, 0x8(%rax)
movslq -0x38(%rbp), %rcx
leaq 0xc8e1(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0x0, 0xc(%rax)
movl -0x34(%rbp), %ecx
movslq -0x38(%rbp), %rdx
leaq 0xc8c5(%rip), %rax      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rax
movl %ecx, 0x10(%rax)
movl -0x34(%rbp), %eax
movslq -0x38(%rbp), %rdx
leaq 0xc8ad(%rip), %rcx      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rcx
cmpl 0x10(%rcx), %eax
jle 0x4019cc
movl -0x34(%rbp), %eax
movslq -0x38(%rbp), %rdx
leaq 0xc88f(%rip), %rcx      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rcx
subl 0x10(%rcx), %eax
cmpl $0x10, %eax
jge 0x4019c7
movslq -0x38(%rbp), %rcx
leaq 0xc875(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
cmpl $-0x1, 0x8(%rax)
jne 0x401993
movslq -0x38(%rbp), %rcx
leaq 0xc85d(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0x0, 0xc(%rax)
jmp 0x4019ae
movslq -0x38(%rbp), %rcx
leaq 0xc842(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0xc(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0xc(%rax)
movslq -0x38(%rbp), %rcx
leaq 0xc827(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0x1, 0x8(%rax)
jmp 0x401a72
movl -0x34(%rbp), %eax
movslq -0x38(%rbp), %rdx
leaq 0xc806(%rip), %rcx      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rcx
cmpl 0x10(%rcx), %eax
jge 0x401a70
movslq -0x38(%rbp), %rcx
leaq 0xc7eb(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0x10(%rax), %eax
subl -0x34(%rbp), %eax
cmpl $0x10, %eax
jge 0x401a6e
movslq -0x38(%rbp), %rcx
leaq 0xc7ce(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
cmpl $0x1, 0x8(%rax)
jne 0x401a3a
movslq -0x38(%rbp), %rcx
leaq 0xc7b6(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0x0, 0xc(%rax)
jmp 0x401a55
movslq -0x38(%rbp), %rcx
leaq 0xc79b(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0xc(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0xc(%rax)
movslq -0x38(%rbp), %rcx
leaq 0xc780(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl $0xffffffff, 0x8(%rax)  # imm = 0xFFFFFFFF
jmp 0x401a70
jmp 0x401a72
movslq -0x38(%rbp), %rcx
leaq 0xc763(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
cmpl $0x2, 0xc(%rax)
jl 0x401b70
movl $0x0, -0x40(%rbp)
cmpl $0x2, -0x40(%rbp)
jge 0x401b6e
movslq -0x38(%rbp), %rcx
leaq 0xc736(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0x8(%rax), %ecx
movslq -0x38(%rbp), %rdx
leaq 0xc721(%rip), %rax      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rax
addl 0x10(%rax), %ecx
movl %ecx, 0x10(%rax)
movslq -0x38(%rbp), %rcx
leaq 0xc709(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
cmpl $0x0, 0x10(%rax)
jl 0x401afc
movslq -0x38(%rbp), %rcx
leaq 0xc6f1(%rip), %rax      # 0x40e1e0
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
cmpl $0x3f, 0x10(%rax)
jle 0x401afe
jmp 0x401b6e
movq -0x30(%rbp), %rax
shlq $0xc, %rax
movslq -0x38(%rbp), %rdx
leaq 0xc6cf(%rip), %rcx      # 0x40e1e0
imulq $0x18, %rdx, %rdx
addq %rdx, %rcx
movl 0x10(%rcx), %ecx
shll $0x6, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x48(%rbp)
xorl %edi, %edi
callq 0x405a80
cmpl $0x8, %eax
jle 0x401b4a
movq -0x10(%rbp), %rsi
movq -0x48(%rbp), %rdx
xorl %edi, %edi
movl $0x8, %ecx
callq 0x406220
jmp 0x401b5e
movq -0x10(%rbp), %rsi
movq -0x48(%rbp), %rdx
xorl %edi, %edi
movl $0x4, %ecx
callq 0x406220
jmp 0x401b60
movl -0x40(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
jmp 0x401a95
jmp 0x401b70
addq $0x50, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)