// ICS 331 Assignment 4 Solution
// by David N. Chin
//
// An N-way set-associative cache simulation.
//
// Command-line arguments (in any order):
//	-s <cache-size>
//	-w <ways>
//	 -f (for FIFO) or -l (for LRU)
//	<tracefile> (containing memory traces in Dinero format)
// See the following URL for Dinero format:
// http://www.computing.surrey.ac.uk/personal/st/R.Peel/cs250/din-format.html
//
// The <cache-size> is the total number of memory words that the program's
// cache can store at any one time.  The <ways> is the associativity of the
// cache, for example -w 4 is a 4-way set-associative cache.  In a normal
// cache, entries include both the address and data, but in this case, the
// cache entries will include only the address tag.  Also, the cache will
// always have a block size of one memory word and use write-back (so a dirty
// bit is used).  The program will simulate memory accesses as specified in the
// <tracefile> and your the will keep track of hits, misses, and compute the
// hit ratio.  The program will print the total number of hits, misses and the
// hit ratio at the end of the program.  Misses include all reads from memory
// and all writes to memory, which happen when a dirty cache entry is evicted
// from the cache.
import java.io.*;
import java.lang.*;


public class CacheSim {
  public static void main(String[] args) {
    int size = 0, ways = 0;
    boolean lru = false;
    Cache cache;

    for( int i = 0; i < args.length; i++ ) {
      if( args[i].startsWith("-") ) {
	switch( args[i].charAt(1) ) {
	  case 's': size = Integer.parseInt(args[i+1]); break;
	  case 'w': ways = Integer.parseInt(args[i+1]); break;
	  case 'f': lru = false; break;
	  case 'l': lru = true; break;
	}
      }
    }
    if( size==0 || ways==0 ) usage();
    cache = lru ? new LruCache( size, ways ) : new FifoCache( size, ways );
    //System.out.println("size="+size+", ways="+ways+", lru="+lru);
    readTraces( args[args.length-1], cache );
  }

  // read the memory trace file line by line and call Cache.find()
  private static void readTraces( String traceFilename, Cache cache ) {
    BufferedReader input = null;
    boolean write = false;

    try {
      input = new BufferedReader( new FileReader(traceFilename) );
      String line = null;
      int address;
      while( ( line = input.readLine()) != null ) {
	if( line.startsWith("1") ) write = true;
	else write = false;
	address = Integer.parseInt( line.substring(2), 16 );
	//System.out.println("address="+address);
	cache.find( address, write );
      }
      cache.printStats();
    }
    catch (FileNotFoundException e) {
      usage();
    }
    catch (IOException e){
      e.printStackTrace();
    }
    finally {
      try {
        if (input!= null) {
          //flush and close both "input" and its underlying FileReader
          input.close();
        }
      }
      catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  private static void usage() {
    System.out.println("Usage: java CacheSim -s size -w associativity -l (for LRU) or -f (for FIFO) memory_trace_file.din (Dinero format)");
    System.exit(1);
  }
}
