/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package com.jopdesign.tools; import java.util.*; /** * Extension of JopSim to simulation data caches * * @author Martin Schoeberl * */ public class DCacheSim extends JopSim { static abstract class Cache { int tag[], data[]; boolean valid[]; int rdCnt; int hitCnt; abstract int read(int addr, int val); abstract void inval(); public String toString() { int percent = 0; if (rdCnt!=0) { percent = (hitCnt*1000/rdCnt+5)/10; } return String.format("\t%3d\t& %10d & %10d & %2d\\%% \\\\", tag.length, rdCnt, hitCnt, percent); } } /** * A direct mapped cache with line size of one word. Size should be a power of 2. */ static class DirectMapped extends Cache { int shift; /** * A shift is needed for the handle cache, as handles are at * multiples of 8. * @param size Cache size. * @param shift of address bits for line determination. */ public DirectMapped(int size, int shift) { tag = new int[size]; valid = new boolean[size]; data = new int[size]; this.shift = shift; } int read(int addr, int val) { ++rdCnt; int line = (addr>>>shift)%tag.length; if (tag[line]==addr && valid[line]) { ++hitCnt; } else { tag[line] = addr; data[line] = val; valid[line] = true; } return data[line]; } @Override void inval() { for (int i=0; i<valid.length; ++i) { valid[i] = false; } } } /** * A fully associative cache with line size of one word. */ static class LRU extends Cache { public LRU(int size) { tag = new int[size]; valid = new boolean[size]; data = new int[size]; } int read(int addr, int val) { ++rdCnt; int i=0; int len = tag.length; boolean hit = false; for (i=0; i<len; ++i) { if (tag[i]==addr && valid[i]) { hit = true; ++hitCnt; break; } } if (hit) { val = data[i]; } for (i=len-1; i>0; --i) { data[i] = data[i-1]; tag[i] = tag[i-1]; valid[i] = valid[i-1]; } data[0] = val; tag[0] = addr; valid[0] = true; return data[0]; } @Override void inval() { for (int i=0; i<valid.length; ++i) { valid[i] = false; } } } // DirectMapped hcache = new DirectMapped(32, 3); final static int CNT = 10; Cache hdmcache[] = new Cache[CNT]; Cache hcache[] = new Cache[CNT]; Cache alencache[] = new Cache[CNT]; Cache mvbcache[] = new Cache[CNT]; Cache cpcache[] = new Cache[CNT]; Cache mtabcache[] = new Cache[CNT]; Cache fieldcache[] = new Cache[CNT]; Cache staticcache[] = new Cache[CNT]; Cache arraycache[] = new Cache[CNT]; DCacheSim(String fn, IOSimMin ioSim, int max) { super(fn, ioSim, max); for (int i=0; i<CNT; ++i) { hdmcache[i] = new DirectMapped(1<<i, 3); hcache[i] = new LRU(1<<i); alencache[i] = new LRU(1<<i); mvbcache[i] = new LRU(1<<i); cpcache[i] = new DirectMapped(1<<i, 0); mtabcache[i] = new DirectMapped(1<<i, 0); fieldcache[i] = new LRU(1<<i); staticcache[i] = new DirectMapped(1<<i, 0); arraycache[i] = new DirectMapped(1<<i, 0); } } int readMem(int addr, Access type) { int data = super.readMem(addr, type); for (int i=0; i<CNT; ++i) { switch (type) { case HANDLE: data = hcache[i].read(addr, data); data = hdmcache[i].read(addr, data); break; case ALEN: data = alencache[i].read(addr, data); break; case MVB: data = mvbcache[i].read(addr, data); break; case CONST: data = cpcache[i].read(addr, data); break; case MTAB: data = mtabcache[i].read(addr, data); break; case FIELD: // TODO: crashes when reading from cache // data = fieldcache[i].read(addr, data); break; case STATIC: // TODO: crashes when reading from cache // data = staticcache[i].read(addr, data); break; case ARRAY: // TODO: crashes when reading from cache // data = arraycache[i].read(addr, data); break; case CLINFO: case IFTAB: case INTERN: break; default: break; } } return data; } // do we write allocate? void writeMem(int addr, int data, Access type) { super.writeMem(addr, data, type); } void invalCache() { for (int i=0; i<CNT; ++i) { fieldcache[i].inval(); staticcache[i].inval(); arraycache[i].inval(); } } void stat() { super.stat(); System.out.println("Cache statistics"); System.out.println("Handle (DM):"); for (int i=0; i<CNT; ++i) { System.out.println(hdmcache[i]); } System.out.println("Handle (LRU):"); for (int i=0; i<CNT; ++i) { System.out.println(hcache[i]); } System.out.println("Array length (LRU):"); for (int i=0; i<CNT; ++i) { System.out.println(alencache[i]); } System.out.println("Method vector base (LRU):"); for (int i=0; i<CNT; ++i) { System.out.println(mvbcache[i]); } System.out.println("Constant pool (DM):"); for (int i=0; i<CNT; ++i) { System.out.println(cpcache[i]); } System.out.println("Method table (DM):"); for (int i=0; i<CNT; ++i) { System.out.println(mtabcache[i]); } System.out.println("Field (LRU):"); for (int i=0; i<CNT; ++i) { System.out.println(fieldcache[i]); } System.out.println("Static (DM):"); for (int i=0; i<CNT; ++i) { System.out.println(staticcache[i]); } System.out.println("Array (DM):"); for (int i=0; i<CNT; ++i) { System.out.println(arraycache[i]); } } /** * @param args */ public static void main(String args[]) { IOSimMin io; int maxInstr = getArgs(args); for (int i = 0; i < nrCpus; ++i) { io = new IOSimMin(); io.setCpuId(i); js[i] = new DCacheSim(args[0], io, maxInstr); io.setJopSimRef(js[i]); } runSimulation(); } }