public int read(int address) {
		long before = System.nanoTime();
		int sets = Cache.MAX_SIZE / this.assoc / this.blockSize;
		int blockNo = address / this.blockSize;
		int pos = blockNo % sets;
		byte tag = (byte) (blockNo / sets);
		//MRU Way Prediction
		if (this.mru[pos] >= 0 && tag == this.tags[pos+this.mru[pos]]) {
			this.hit++;
			this.lruBits[pos+this.mru[pos]] = clock++;
			if ((this.hit + this.miss) % 500 == 0) {
				this.missRates.put(this.hit + this.miss, (double) this.miss / (this.hit + this.miss));
			}
			hitAT.add(System.nanoTime() - before);
			return this.data[this.blockSize * (pos + this.mru[pos]) + (address % this.blockSize)]; 
		}
		//
		for (int i = 0; i < this.assoc; i++) {
			if (tag == this.tags[pos+i]) {
				this.hit++;
				this.lruBits[pos+i] = clock++;
				this.mru[pos] = i;
				if ((this.hit + this.miss) % 500 == 0) {
					this.missRates.put(this.hit + this.miss, (double) this.miss / (this.hit + this.miss));
				}
				hitAT.add(System.nanoTime() - before);
				return this.data[this.blockSize * (pos + i) + (address % this.blockSize)]; 
			}
		}
		this.miss++;
		getFromMemory(address);
		missAT.add(System.nanoTime() - before);
		if ((this.hit + this.miss) % 500 == 0) {
			this.missRates.put(this.hit + this.miss, (double) this.miss / (this.hit + this.miss));
		}
		return address;
	}