/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2001-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/>.
*/
/**
* JopSim.java
*
* Simulation of JOP JVM.
*
* difference between JOP and JopSim:
* loadBc (and invokestatic)
*
* 2001-12-03 I don't need a fp!?
*/
package com.jopdesign.tools;
import com.jopdesign.sys.Const;
import com.jopdesign.timing.jop.WCETInstruction;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
public class JopSim {
public class JopSimRtsException extends RuntimeException {
private static final long serialVersionUID = 1L;
private int errCode;
public JopSimRtsException(String message, int reason) {
super(message);
this.errCode = reason;
}
public int getReason() {
return errCode;
}
}
public class JopSimFatalError extends RuntimeException {
private static final long serialVersionUID = 1L;
public JopSimFatalError(String message) {
super(message);
}
}
/**
* Classify memory access type for cache and TM experiments.
*/
enum Access {
/**
* General class info
*/
CLINFO,
/**
* Method table
*/
MTAB,
/**
* Constant pool
*/
CONST,
/**
* Interface table
*/
IFTAB,
/**
* Handle indirection
*/
HANDLE,
/**
* Array length
*/
ALEN,
/**
* Method vector base (= class reference)
*/
MVB,
/**
* Field access
*/
FIELD,
/**
* Static field access
*/
STATIC,
/**
* Array access
*/
ARRAY,
/**
* JVM internal access
*/
INTERN;
private int rdCnt;
private int wrCnt;
void incrRd() {
rdCnt++;
}
void incrWr() {
wrCnt++;
}
int getRdCnt() {
return rdCnt;
}
int getWrCnt() {
return wrCnt;
}
void reset() {
rdCnt = wrCnt = 0;
}
};
static final int MAX_MEM = 1024*1024/4;
// static final int MAX_MEM = 2*1024*1024/4; // 2MB for de2-70 board
static final int MAX_STACK = Const.STACK_SIZE; // with internal memory
static final int MEM_TEST_OFF = 256;
static final int MAX_SCRATCHPAD = 256; // 1 KB scratchpad memory
static final int MIN_IO_ADDRESS = -128;
static final int SYS_INT = 0xf0;
static final int SYS_EXC = 0xf1;
static boolean log = false;
static int nrCpus = 1;
// references to all simulation instances
static JopSim js[];
// static fields for shared heap
static int[] mem_load = new int[MAX_MEM];
static int[] mem = new int[MAX_MEM];
static int heap;
static int empty_heap;
// local fields for each CPU
int[] stack = new int[MAX_STACK];
int[] scratchMem = new int[MAX_SCRATCHPAD];
Cache cache;
IOSimMin io;
int pc, cp, vp, sp, mp;
int jjp;
int jjhp;
//
// exception handling
//
boolean intExcept;
int exceptReason;
static boolean exit = false;
static boolean stopped = false;
//
// only for statistics
//
private WCETInstruction timing;
static int[] bcTiming = new int[256];
int[] bcStat = new int[256];
int rdMemCnt;
int wrMemCnt;
int maxInstr;
int instrCnt;
long clkCnt;
int localCnt;
int maxSp;
int cacheCost;
public JopSim(String binaryFile, IOSimMin ioSim, int maxInstructions) {
ioSim.setJopSimRef(this);
maxInstr = maxInstructions;
// only first simulation object loads the memory
if (ioSim.cpuId==0) {
heap = 0;
try {
StreamTokenizer in = new StreamTokenizer(new FileReader(binaryFile));
in.wordChars( '_', '_' );
in.wordChars( ':', ':' );
in.eolIsSignificant(true);
in.slashStarComments(true);
in.slashSlashComments(true);
in.lowerCaseMode(true);
while (in.nextToken()!=StreamTokenizer.TT_EOF) {
if (in.ttype == StreamTokenizer.TT_NUMBER) {
mem_load[heap++] = (int) in.nval;
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
System.exit(-1);
}
int instr = mem_load[0];
System.out.println("Program: "+binaryFile);
System.out.println(instr + " instruction word ("+(instr*4/1024)+" KB)");
System.out.println(heap + " words mem read ("+(heap*4/1024)+" KB)");
empty_heap = heap;
// FIXME: timing should be configurable
if(nrCpus == 1) {
timing = new WCETInstruction(WCETInstruction.DEFAULT_R, WCETInstruction.DEFAULT_W);
} else {
timing = new WCETInstruction(nrCpus, WCETInstruction.DEFAULT_TIMESLOT, WCETInstruction.DEFAULT_R, WCETInstruction.DEFAULT_W);
}
for (int i=0; i<256; ++i) {
int j = timing.getCycles(i, false, 0);
if (j==-1) j = 80; // rough estimate for invokation of Java implementation
bcTiming[i] = j;
}
}
cache = new Cache(mem, this);
int ocAssoc;
if(System.getenv("OC_ASSOC") != null) {
ocAssoc = Integer.parseInt(System.getenv("OC_ASSOC"));
} else {
ocAssoc = OBJECT_CACHE_ASSOC;
}
objectCacheSim = new ObjectCacheSim(ocAssoc, OBJECT_CACHE_FIELDS);
io = ioSim;
}
JopSim(String fn, IOSimMin ioSim) {
this(fn, ioSim, 0);
}
/**
* An extra (re)start method to test several cache strategies.
*/
void start() {
rdMemCnt = 0;
wrMemCnt = 0;
instrCnt = 0;
clkCnt = 0;
localCnt = 0;
maxSp = 0;
cacheCost = 0;
for (int i=0; i<256; ++i) bcStat[i] = 0;
if (io.cpuId==0) {
heap = empty_heap;
for (int i=0; i<heap; ++i) mem[i] = mem_load[i];
}
pc = vp = 0;
sp = Const.STACK_OFF;
int ptr = readMem(1, Access.INTERN);
jjp = readMem(ptr+1, Access.INTERN);
jjhp = readMem(ptr+2, Access.INTERN);
invokestatic(ptr); // load main()
}
/**
* 'debug' functions.
*/
void noim(int instr) {
invoke(jjp+(instr<<1));
/*
System.out.println("byte code "+JopInstr.name(instr)+" ("+instr+") not implemented");
System.out.println(mp+" "+pc);
System.exit(-1);
*/
}
/**
* call function in JVM.java with constant on stack
*/
void jjvmConst(int instr) {
int idx = readOpd16u();
int val = readMem(cp+idx, Access.CONST); // read constant
// System.out.println("jjvmConst: "+instr+" "+(cp+idx)+" "+val);
stack[++sp] = val; // push on stack
invoke(jjp+(instr<<1));
}
/**
* call function in JVM.java with index in constant pool on stack
*/
void jjvmIdx(int instr) {
int idx = readOpd16u();
stack[++sp] = idx; // push on stack
invoke(jjp+(instr<<1));
}
void dump() {
System.out.print("cp="+cp+" vp="+vp+" sp="+sp+" pc="+pc);
try {
System.out.println(" Stack=[..., "+stack[sp-2]+", "+stack[sp-1]+", "+stack[sp]+"]");
} catch(ArrayIndexOutOfBoundsException ex) {
System.out.println(" Stack="+stack);
}
}
/**
* helper functions.
*/
int readInstrMem(int addr) {
// System.out.println(addr+" "+mem[addr]);
if (addr>MAX_MEM || addr<0) throw new JopSimFatalError("readInstrMem: wrong address: "+addr);
return mem[addr];
}
int copy_src = 0;
int copy_dest = 0;
int copy_pos = 0;
public static final int OBJECT_CACHE_ASSOC = 16;
public static final int OBJECT_CACHE_FIELDS = 32;
ObjectCacheSim objectCacheSim;
/**
* a plain memory read
* @param addr
* @return
*/
int readMem(int addr, Access type) {
// System.out.println(addr+" "+mem[addr]);
rdMemCnt++;
type.incrRd();
// translate addresses
if (addr >= copy_src && addr < copy_src+copy_pos) {
addr = addr - copy_src + copy_pos;
}
// that's an access to our scratchpad memory
if (addr >= Const.SCRATCHPAD_ADDRESS && addr <= Const.SCRATCHPAD_ADDRESS+MEM_TEST_OFF) {
return scratchMem[addr%MAX_SCRATCHPAD];
}
if (addr == Const.IO_EXCPT) {
return exceptReason;
}
if (addr>MAX_MEM+MEM_TEST_OFF || addr<MIN_IO_ADDRESS) {
throw new JopSimFatalError("readMem: wrong address: "+addr);
}
if (addr<0) {
return io.read(addr);
}
return mem[addr%MAX_MEM];
}
void writeMem(int addr, int data, Access type) {
wrMemCnt++;
type.incrWr();
// that's an access to our scratchpad memory
if (addr >= Const.SCRATCHPAD_ADDRESS && addr <= Const.SCRATCHPAD_ADDRESS+MEM_TEST_OFF) {
scratchMem[addr%MAX_SCRATCHPAD] = data;
return;
}
if (addr>MAX_MEM+MEM_TEST_OFF || addr<MIN_IO_ADDRESS) {
throw new JopSimFatalError("writeMem: wrong address: "+addr);
}
if (addr<0) {
io.write(addr, data);
return; // no Simulation of the Wishbone devices
}
mem[addr%MAX_MEM] = data;
}
void invalCache() {
}
int readOpd16u() {
int idx = ((cache.bc(pc)<<8) | (cache.bc(pc+1)&0x0ff)) & 0x0ffff;
pc += 2;
return idx;
}
int readOpd16s() {
int i = readOpd16u();
if ((i&0x8000) != 0) {
i |= 0xffff0000;
}
return i;
}
int readOpd8s() {
return cache.bc(pc++);
}
int readOpd8u() {
return cache.bc(pc++)&0x0ff;
}
//
// start of JVM :-)
//
void invokespecial() {
invokestatic(); // what's the difference?
}
void checkNullPointer(int addr) throws JopSimRtsException {
if(addr == 0) throw new JopSimRtsException("Null-Pointer Exception",Const.EXC_NP);
}
void invokesuper() throws JopSimRtsException {
int idx = readOpd16u();
int off = readMem(cp+idx, Access.CONST); // index in vt and arg count (-1)
int args = off & 0xff; // this is args count without obj-ref
off >>>= 8;
int ref = stack[sp-args];
checkNullPointer(ref);
// pointer to class info at cp-1
int vt = readMem(cp-1, Access.CLINFO);
// pointer to super class at offset 3
// == Const.CLASS_SUPER
int sup = readMem(vt+3, Access.CLINFO);
// the real VT is located at offset 5
// == Const.CLASS_HEADR
vt = sup+5;
// System.err.println("invsuper: cp: "+cp+" off: "+off+" args: "+args+" ref: "+ref+" vt: "+vt+" addr: "+(vt+off));
invoke(vt+off);
}
void invokevirtual() throws JopSimRtsException {
int idx = readOpd16u();
int off = readMem(cp+idx, Access.CONST); // index in vt and arg count (-1)
int args = off & 0xff; // this is args count without obj-ref
off >>>= 8;
int ref = stack[sp-args];
checkNullPointer(ref);
// pointer to method table in handle at offset 1
int vt = readMem(ref+1, Access.MVB);
// System.out.println("invvirt: off: "+off+" args: "+args+" ref: "+ref+" vt: "+vt+" addr: "+(vt+off));
invoke(vt+off);
}
void invokeinterface() throws JopSimRtsException {
int idx = readOpd16u();
readOpd16u(); // read historical argument count and 0
int off = readMem(cp+idx, Access.CONST); // index in interface table
int args = off & 0xff; // this is args count without obj-ref
off >>>= 8;
int ref = stack[sp-args];
checkNullPointer(ref);
// pointer to method table in handle at offset 1
int vt = readMem(ref+1, Access.MVB); // pointer to virtual table in obj-1
int it = readMem(vt-1, Access.CLINFO); // pointer to interface table one befor vt
int mp = readMem(it+off, Access.IFTAB);
// System.out.println("invint: off: "+off+" args: "+args+" ref: "+ref+" vt: "+vt+" mp: "+(mp));
invoke(mp);
}
/**
* invokestatic wie es in der JVM sein soll!!!
*/
void invokestatic() {
int idx = readOpd16u();
invokestatic(cp+idx);
}
void invokestatic(int ptr) {
invoke(readMem(ptr, Access.CONST));
}
/**
* do the real invoke. called with a pointer to method struct.
*/
void invoke(int new_mp) {
if (log) {
System.out.println("addr. of meth.struct="+new_mp);
}
int old_vp = vp;
int old_cp = cp;
int old_mp = mp;
mp = new_mp;
int start = readMem(mp, Access.MTAB);
int len = start & 0x03ff;
start >>>= 10;
cp = readMem(mp+1, Access.MTAB);
int locals = (cp>>>5) & 0x01f;
int args = cp & 0x01f;
cp >>>= 10;
int old_sp = sp-args;
vp = old_sp+1;
sp += locals;
// System.out.println("inv: start: "+start+" len: "+len+" locals: "+locals+" args: "+args+" cp: "+cp);
stack[++sp] = old_sp;
stack[++sp] = cache.corrPc(pc);
stack[++sp] = old_vp;
stack[++sp] = old_cp;
stack[++sp] = old_mp;
pc = cache.invoke(start, len);
}
/**
* return wie es sein sollte (oder doch nicht?)
*/
void vreturn() {
mp = stack[sp--];
cp = stack[sp--];
vp = stack[sp--];
pc = stack[sp--];
sp = stack[sp--];
int start = readMem(mp, Access.MTAB);
int len = start & 0x03ff;
start >>>= 10;
// cp = readMem(mp+1)>>>10;
pc = cache.ret(start, len, pc);
}
void ireturn() {
int val = stack[sp--];
vreturn();
stack[++sp] = val;
}
void lreturn() {
int val1 = stack[sp--];
int val2 = stack[sp--];
vreturn();
stack[++sp] = val2;
stack[++sp] = val1;
}
void waitCache(int hiddenCycles) {
int penalty = timing.calculateB(cache.lastAccessWasHit(),cache.wordsLastRead);
penalty = Math.max(0, penalty-hiddenCycles);
this.cacheCost += penalty;
this.clkCnt += penalty;
this.localCnt += penalty;
}
void putstatic() {
int addr = readOpd16u();
writeMem(addr, stack[sp--], Access.STATIC);
}
void getstatic() {
int addr = readOpd16u();
stack[++sp] = readMem(addr, Access.STATIC);
}
void putstatic_long() {
int addr = readOpd16u();
writeMem(addr+1, stack[sp--], Access.STATIC);
writeMem(addr, stack[sp--], Access.STATIC);
}
void getstatic_long() {
int addr = readOpd16u();
stack[++sp] = readMem(addr, Access.STATIC);
stack[++sp] = readMem(addr+1, Access.STATIC);
}
void putfield() {
int off = readOpd16u();
int val = stack[sp--];
int ref = stack[sp--];
checkNullPointer(ref);
ref = readMem(ref, Access.HANDLE);
writeMem(ref+off, val, Access.FIELD);
}
void getfield() {
int off = readOpd16u();
int ref = stack[sp];
checkNullPointer(ref);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
objectCacheSim.accessField(ref,off);
stack[sp] = readMem(ref+off, Access.FIELD);
}
void jopsys_putfield() {
int val = stack[sp--];
int off = stack[sp--];
int ref = stack[sp--];
checkNullPointer(ref);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
writeMem(ref+off, val, Access.FIELD);
}
void jopsys_getfield() {
int off = stack[sp--];
int ref = stack[sp];
checkNullPointer(ref);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
stack[sp] = readMem(ref+off, Access.FIELD);
}
void putfield_long() {
int off = readOpd16u();
int val_l = stack[sp--];
int val_h = stack[sp--];
int ref = stack[sp--];
checkNullPointer(ref);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
writeMem(ref+off, val_h, Access.FIELD);
writeMem(ref+off+1, val_l, Access.FIELD);
}
void getfield_long() {
int off = readOpd16u();
int ref = stack[sp];
// handle needs indirection
checkNullPointer(ref);
ref = readMem(ref, Access.HANDLE);
stack[sp] = readMem(ref+off, Access.FIELD);
stack[++sp] = readMem(ref+off+1, Access.FIELD);
}
/**
* the simulaton.
*
* sp points to TOS
*/
void interpret() {
int new_pc; // for cond. branches
int ref, val, idx, val2;
int a, b, c, d;
long la, lb;
if (localCnt>0) {
--localCnt;
return;
}
if (maxInstr!=0 && instrCnt>=maxInstr) {
exit=true;
}
//
// statistic
//
++instrCnt;
if (sp > maxSp) maxSp = sp;
int instr = cache.bc(pc++) & 0x0ff;
//
// exception and interrupt handling
//
if (intExcept) {
instr = SYS_EXC;
intExcept = false;
} else {
// check all 16 instructions for a pending interrupt
if ((instrCnt&0xf)==0) {
if (io.intPending()) {
instr = SYS_INT;
}
}
}
bcStat[instr]++;
// TODO add cache miss timing and a different timing info for
// Java implemented bytecodes
localCnt = bcTiming[instr];
clkCnt += localCnt;
--localCnt;
if (log) {
String spc = (pc-1)+" ";
while (spc.length()<4) spc = " "+spc;
String s = spc+JopInstr.name(instr);
System.out.print(s+"\t");
dump();
}
try {
switch (instr) {
case 0 : // nop
break;
case 1 : // aconst_null
stack[++sp] = 0;
break;
case 2 : // iconst_m1
stack[++sp] = -1;
break;
case 3 : // iconst_0
stack[++sp] = 0;
break;
case 4 : // iconst_1
stack[++sp] = 1;
break;
case 5 : // iconst_2
stack[++sp] = 2;
break;
case 6 : // iconst_3
stack[++sp] = 3;
break;
case 7 : // iconst_4
stack[++sp] = 4;
break;
case 8 : // iconst_5
stack[++sp] = 5;
break;
case 9 : // lconst_0
stack[++sp] = 0;
stack[++sp] = 0;
break;
case 10 : // lconst_1
stack[++sp] = 0;
stack[++sp] = 1;
break;
case 11 : // fconst_0
stack[++sp] = 0;
break;
case 12 : // fconst_1
noim(12);
break;
case 13 : // fconst_2
noim(13);
break;
case 14 : // dconst_0
stack[++sp] = 0;
stack[++sp] = 0;
break;
case 15 : // dconst_1
noim(15);
break;
case 16 : // bipush
stack[++sp] = readOpd8s();
break;
case 17 : // sipush
stack[++sp] = readOpd16s();
break;
case 18 : // ldc
stack[++sp] = readMem(cp+readOpd8u(), Access.CONST);
break;
case 19 : // ldc_w
stack[++sp] = readMem(cp+readOpd16u(), Access.CONST);
break;
case 20 : // ldc2_w
idx = readOpd16u();
stack[++sp] = readMem(cp+idx, Access.CONST);
stack[++sp] = readMem(cp+idx+1, Access.CONST);
break;
case 21 : // iload
case 23 : // fload
case 25 : // aload
idx = readOpd8u();
stack[++sp] = stack[vp+idx];
break;
case 22 : // lload
idx = readOpd8u();
stack[++sp] = stack[vp+idx];
stack[++sp] = stack[vp+idx+1];
break;
case 24 : // dload
idx = readOpd8u();
stack[++sp] = stack[vp+idx];
stack[++sp] = stack[vp+idx+1];
break;
case 42 : // aload_0
case 34 : // fload_0
case 26 : // iload_0
stack[++sp] = stack[vp];
break;
case 43 : // aload_1
case 35 : // fload_1
case 27 : // iload_1
stack[++sp] = stack[vp+1];
break;
case 44 : // aload_2
case 36 : // fload_2
case 28 : // iload_2
stack[++sp] = stack[vp+2];
break;
case 45 : // aload_3
case 37 : // fload_3
case 29 : // iload_3
stack[++sp] = stack[vp+3];
break;
case 30 : // lload_0
case 38 : // dload_0
stack[++sp] = stack[vp];
stack[++sp] = stack[vp+1];
break;
case 31 : // lload_1
case 39 : // dload_1
stack[++sp] = stack[vp+1];
stack[++sp] = stack[vp+2];
break;
case 32 : // lload_2
case 40 : // dload_2
stack[++sp] = stack[vp+2];
stack[++sp] = stack[vp+3];
break;
case 33 : // lload_3
case 41 : // dload_3
stack[++sp] = stack[vp+3];
stack[++sp] = stack[vp+4];
break;
case 50 : // aaload
case 51 : // baload
case 52 : // caload
case 48 : // faload
case 46 : // iaload
case 53 : // saload
idx = stack[sp--]; // index
ref = stack[sp--]; // ref
checkNullPointer(ref);
a = readMem(ref+1, Access.ALEN);
if (idx<0 || idx>=a) throw new JopSimRtsException("saload: index out of bounds",Const.EXC_AB);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
stack[++sp] = readMem(ref+idx, Access.ARRAY);
break;
case 47 : // laload
case 49 : // daload
idx = stack[sp--]; // index
ref = stack[sp--]; // ref
checkNullPointer(ref);
a = readMem(ref+1, Access.ALEN);
if (idx<0 || idx>=a) throw new JopSimRtsException("laload: index out of bounds",Const.EXC_AB);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
stack[++sp] = readMem(ref+idx*2, Access.ARRAY);
stack[++sp] = readMem(ref+idx*2+1, Access.ARRAY);
break;
case 58 : // astore
case 56 : // fstore
case 54 : // istore
idx = readOpd8u();
stack[vp+idx] = stack[sp--];
break;
case 55 : // lstore
idx = readOpd8u();
stack[vp+idx+1] = stack[sp--];
stack[vp+idx] = stack[sp--];
break;
case 57 : // dstore
idx = readOpd8u();
stack[vp+idx+1] = stack[sp--];
stack[vp+idx] = stack[sp--];
break;
case 75 : // astore_0
case 67 : // fstore_0
case 59 : // istore_0
stack[vp] = stack[sp--];
break;
case 76 : // astore_1
case 68 : // fstore_1
case 60 : // istore_1
stack[vp+1] = stack[sp--];
break;
case 77 : // astore_2
case 69 : // fstore_2
case 61 : // istore_2
stack[vp+2] = stack[sp--];
break;
case 78 : // astore_3
case 70 : // fstore_3
case 62 : // istore_3
stack[vp+3] = stack[sp--];
break;
case 63 : // lstore_0
case 71 : // dstore_0
stack[vp+1] = stack[sp--];
stack[vp] = stack[sp--];
break;
case 64 : // lstore_1
case 72 : // dstore_1
stack[vp+2] = stack[sp--];
stack[vp+1] = stack[sp--];
break;
case 65 : // lstore_2
case 73 : // dstore_2
stack[vp+3] = stack[sp--];
stack[vp+2] = stack[sp--];
break;
case 66 : // lstore_3
case 74 : // dstore_3
stack[vp+4] = stack[sp--];
stack[vp+3] = stack[sp--];
break;
case 83 : // aastore
noim(83);
break;
case 84 : // bastore
case 85 : // castore
case 81 : // fastore
case 79 : // iastore
case 86 : // sastore
val = stack[sp--]; // value
idx = stack[sp--]; // index
ref = stack[sp--]; // ref
checkNullPointer(ref);
a = readMem(ref+1, Access.ALEN);
if (idx<0 || idx>=a) throw new JopSimRtsException("sastore: index out of bounds",Const.EXC_AB);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
writeMem(ref+idx, val, Access.ARRAY);
break;
case 80 : // lastore
case 82 : // dastore
val = stack[sp--]; // value
val2 = stack[sp--]; // value
idx = stack[sp--]; // index
ref = stack[sp--]; // ref
checkNullPointer(ref);
a = readMem(ref+1, Access.ALEN);
if (idx<0 || idx>=a) throw new JopSimRtsException("lastore: index out of bounds",Const.EXC_AB);
// handle needs indirection
ref = readMem(ref, Access.HANDLE);
writeMem(ref+idx*2, val2, Access.ARRAY);
writeMem(ref+idx*2+1, val, Access.ARRAY);
break;
case 87 : // pop
sp--;
break;
case 88 : // pop2
sp--;
sp--;
break;
case 89 : // dup
val = stack[sp];
stack[++sp] = val;
break;
case 90 : // dup_x1
a = stack[sp--];
b = stack[sp--];
stack[++sp] = a;
stack[++sp] = b;
stack[++sp] = a;
break;
case 91 : // dup_x2
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
stack[++sp] = a;
stack[++sp] = c;
stack[++sp] = b;
stack[++sp] = a;
break;
case 92 : // dup2
a = stack[sp--];
b = stack[sp--];
stack[++sp] = b;
stack[++sp] = a;
stack[++sp] = b;
stack[++sp] = a;
break;
case 93 : // dup2_x1
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
stack[++sp] = b;
stack[++sp] = a;
stack[++sp] = c;
stack[++sp] = b;
stack[++sp] = a;
break;
case 94 : // dup2_x2
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
d = stack[sp--];
stack[++sp] = b;
stack[++sp] = a;
stack[++sp] = d;
stack[++sp] = c;
stack[++sp] = b;
stack[++sp] = a;
break;
case 95 : // swap
a = stack[sp--];
b = stack[sp--];
stack[++sp] = a;
stack[++sp] = b;
break;
case 96 : // iadd
val = stack[sp-1] + stack[sp];
stack[--sp] = val;
break;
case 97 : // ladd
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
la += lb;
stack[sp-3] = (int)(la >>> 32);
stack[sp-2] = (int)la;
sp-=2;
break;
case 98 : // fadd
noim(98);
break;
case 99 : // dadd
noim(99);
break;
case 100 : // isub
val = stack[sp-1] - stack[sp];
stack[--sp] = val;
break;
case 101 : // lsub
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
la = lb - la;
stack[sp-3] = (int)(la >>> 32);
stack[sp-2] = (int)la;
sp-=2;
break;
case 102 : // fsub
noim(102);
break;
case 103 : // dsub
noim(103);
break;
case 104 : // imul
val = stack[sp-1] * stack[sp];
stack[--sp] = val;
break;
case 105 : // lmul
noim(105);
break;
case 106 : // fmul
noim(106);
break;
case 107 : // dmul
noim(107);
break;
case 108 : // idiv
val = stack[sp-1] / stack[sp];
stack[--sp] = val;
break;
case 109 : // ldiv
noim(109);
break;
case 110 : // fdiv
noim(110);
break;
case 111 : // ddiv
noim(111);
break;
case 112 : // irem
val = stack[sp-1] % stack[sp];
stack[--sp] = val;
break;
case 113 : // lrem
noim(113);
break;
case 114 : // frem
noim(114);
break;
case 115 : // drem
noim(115);
break;
case 116 : // ineg
stack[sp] = -stack[sp];
break;
case 117 : // lneg
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
la = -la;
stack[sp-1] = (int)(la >>> 32);
stack[sp] = (int)la;
break;
case 118 : // fneg
noim(118);
break;
case 119 : // dneg
noim(119);
break;
case 120 : // ishl
val = stack[sp-1] << stack[sp];
stack[--sp] = val;
break;
case 121 : // lshl
la = ((long)stack[sp-2] << 32) | ((long)stack[sp-1] & 0xffffffffL);
la <<= stack[sp];
stack[sp-2] = (int)(la >>> 32);
stack[sp-1] = (int)la;
sp--;
break;
case 122 : // ishr
val = stack[sp-1] >> stack[sp];
stack[--sp] = val;
break;
case 123 : // lshr
la = ((long)stack[sp-2] << 32) | ((long)stack[sp-1] & 0xffffffffL);
la >>= stack[sp];
stack[sp-2] = (int)(la >>> 32);
stack[sp-1] = (int)la;
sp--;
break;
case 124 : // iushr
val = stack[sp-1] >>> stack[sp];
stack[--sp] = val;
break;
case 125 : // lushr
la = ((long)stack[sp-2] << 32) | ((long)stack[sp-1] & 0xffffffffL);
la >>>= stack[sp];
stack[sp-2] = (int)(la >>> 32);
stack[sp-1] = (int)la;
sp--;
break;
case 126 : // iand
val = stack[sp-1] & stack[sp];
stack[--sp] = val;
break;
case 127 : // land
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
la &= lb;
stack[sp-3] = (int)(la >>> 32);
stack[sp-2] = (int)la;
sp-=2;
break;
case 128 : // ior
val = stack[sp-1] | stack[sp];
stack[--sp] = val;
break;
case 129 : // lor
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
la |= lb;
stack[sp-3] = (int)(la >>> 32);
stack[sp-2] = (int)la;
sp-=2;
break;
case 130 : // ixor
val = stack[sp-1] ^ stack[sp];
stack[--sp] = val;
break;
case 131 : // lxor
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
la ^= lb;
stack[sp-3] = (int)(la >>> 32);
stack[sp-2] = (int)la;
sp-=2;
break;
case 132 : // iinc
idx = readOpd8u();
stack[vp+idx] = stack[vp+idx]+readOpd8s();
break;
case 133 : // i2l
val = stack[sp];
stack[sp] = (val >> 16) >> 16;
stack[sp+1] = val;
sp++;
break;
case 134 : // i2f
noim(134);
break;
case 135 : // i2d
noim(135);
break;
case 136 : // l2i
val = stack[sp]; // low part
--sp; // drop high word
stack[sp] = val; // low on stack
break;
case 137 : // l2f
noim(137);
break;
case 138 : // l2d
noim(138);
break;
case 139 : // f2i
noim(139);
break;
case 140 : // f2l
noim(140);
break;
case 141 : // f2d
noim(141);
break;
case 142 : // d2i
noim(142);
break;
case 143 : // d2l
noim(143);
break;
case 144 : // d2f
noim(144);
break;
case 145 : // i2b
noim(145);
break;
case 146 : // i2c
stack[sp] = stack[sp] & 0x0ffff;
break;
case 147 : // i2s
noim(147);
break;
case 148 : // lcmp
la = ((long)stack[sp-1] << 32) | ((long)stack[sp] & 0xffffffffL);
lb = ((long)stack[sp-3] << 32) | ((long)stack[sp-2] & 0xffffffffL);
stack[sp-3] = la > lb ? -1 : la < lb ? 1 : 0;
sp-=3;
break;
case 149 : // fcmpl
noim(149);
break;
case 150 : // fcmpg
noim(150);
break;
case 151 : // dcmpl
noim(151);
break;
case 152 : // dcmpg
noim(152);
break;
case 153 : // ifeq
case 198 : // ifnull
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] == 0) pc = new_pc;
break;
case 154 : // ifne
case 199 : // ifnonnull
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] != 0) pc = new_pc;
break;
case 155 : // iflt
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] < 0) pc = new_pc;
break;
case 156 : // ifge
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] >= 0) pc = new_pc;
break;
case 157 : // ifgt
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] > 0) pc = new_pc;
break;
case 158 : // ifle
new_pc = pc-1;
new_pc += readOpd16s();
sp--;
if (stack[sp+1] <= 0) pc = new_pc;
break;
case 159 : // if_icmpeq
case 165 : // if_acmpeq
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] == stack[sp+2]) pc = new_pc;
break;
case 160 : // if_icmpne
case 166 : // if_acmpne
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] != stack[sp+2]) pc = new_pc;
break;
case 161 : // if_icmplt
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] < stack[sp+2]) pc = new_pc;
break;
case 162 : // if_icmpge
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] >= stack[sp+2]) pc = new_pc;
break;
case 163 : // if_icmpgt
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] > stack[sp+2]) pc = new_pc;
break;
case 164 : // if_icmple
new_pc = pc-1;
new_pc += readOpd16s();
sp -= 2;
if (stack[sp+1] <= stack[sp+2]) pc = new_pc;
break;
case 167 : // goto
new_pc = pc-1;
new_pc += readOpd16s();
pc = new_pc;
break;
case 168 : // jsr
noim(168);
break;
case 169 : // ret
noim(169);
break;
case 170 : // tableswitch
noim(170);
break;
case 171 : // lookupswitch
noim(171);
break;
case 176 : // areturn
case 172 : // ireturn
case 174 : // freturn
ireturn();
waitCache(WCETInstruction.IRETURN_HIDDEN_LOAD_CYCLES);
break;
case 173 : // lreturn
lreturn();
waitCache(WCETInstruction.LRETURN_HIDDEN_LOAD_CYCLES);
break;
case 175 : // dreturn
lreturn();
waitCache(WCETInstruction.DRETURN_HIDDEN_LOAD_CYCLES);
break;
case 177 : // return
vreturn();
waitCache(WCETInstruction.RETURN_HIDDEN_LOAD_CYCLES);
break;
case 178 : // getstatic
getstatic();
break;
case 179 : // putstatic
putstatic();
break;
case 180 : // getfield
getfield();
break;
case 181 : // putfield
putfield();
break;
case 182 : // invokevirtual
invokevirtual();
waitCache(WCETInstruction.INVOKE_HIDDEN_LOAD_CYCLES);
break;
case 183 : // invokespecial
invokespecial();
waitCache(WCETInstruction.INVOKE_HIDDEN_LOAD_CYCLES);
break;
case 184 : // invokestatic
invokestatic();
waitCache(WCETInstruction.INVOKE_HIDDEN_LOAD_CYCLES);
break;
case 185 : // invokeinterface
invokeinterface();
waitCache(WCETInstruction.INVOKE_HIDDEN_LOAD_CYCLES);
break;
case 186 : // unused_ba
noim(186);
break;
case 187 : // new
jjvmConst(187);
/* use function in JVM.java
idx = readOpd16u();
val = readMem(cp+idx); // pointer to class struct
writeMem(heap, val+2); // pointer to method table on objectref-1
++heap;
val = readMem(val); // instance size
// TODO init object to zero
stack[++sp] = heap; // objectref
heap += val;
System.out.println("new heap: "+heap);
*/
break;
case 188 : // newarray
stack[++sp]=readOpd8u(); // use typ info
// invoke JVM.f_newarray(int count,val);
invoke(jjp+(188<<1));
/*
val = stack[sp--]; // count from stack
writeMem(heap, val);
++heap;
stack[++sp] = heap; // ref to first element
heap += val;
// System.out.println("newarray heap: "+heap);
*
*/
break;
case 189 : // anewarray
jjvmConst(189);
break;
case 190 : // arraylength
ref = stack[sp--]; // ref from stack
checkNullPointer(ref);
// lenght in handle at offset 1
stack[++sp] = readMem(ref+1, Access.ALEN);
break;
case 191 : // athrow
noim(191);
break;
case 192 : // checkcast
jjvmConst(192);
break;
case 193 : // instanceof
jjvmConst(193);
break;
case 194 : // monitorenter
invoke(jjp+(194<<1));
break;
case 195 : // monitorexit
invoke(jjp+(195<<1));
break;
case 196 : // wide
noim(196);
break;
case 197 : // multianewarray
noim(197);
/*
stack[++sp] = readOpd8u(); // push dimenensions onto the stack
// invoke JVM.f_multianewarray(int dim);
invoke(jjp+(197<<1));
readOpd16u(); // ignore type information
*/
break;
case 200 : // goto_w
noim(200);
break;
case 201 : // jsr_w
noim(201);
break;
case 202 : // breakpoint
noim(202);
break;
case 203 : // resCB
noim(203);
break;
case 204 : // jopsys_inval
invalCache();
break;
case 205 : // resCD
noim(205);
break;
case 206 : // jopsys_lock
// noim(206);
break;
case 207 : // jopsys_unlock
// noim(207);
break;
case 208 : // jopsys_null
noim(208);
break;
case 209 : // jopsys_rd
ref = stack[sp--];
stack[++sp] = readMem(ref, Access.INTERN);
break;
case 210 : // jopsys_wr
ref = stack[sp--];
val = stack[sp--];
writeMem(ref, val, Access.INTERN);
break;
case 211 : // jopsys_rdmem
ref = stack[sp--];
stack[++sp] = readMem(ref, Access.INTERN);
break;
case 212 : // jopsys_wrmem
ref = stack[sp--];
val = stack[sp--];
writeMem(ref, val, Access.INTERN);
break;
case 213 : // jopsys_rdint
ref = stack[sp--];
//
// first variables in jvm.asm
//
// mp ? // pointer to method struct
// cp ? // pointer to constants
// heap ? // start of heap
//
// jjp ? // pointer to meth. table of Java JVM functions
// jjhp ? // pointer to meth. table of Java JVM help functions
//
// moncnt ? // counter for monitor
if (ref==0) {
val = mp;
} else if (ref==1) {
val = cp;
} else if (ref==2) {
val = heap;
} else if (ref==3) {
val = jjp;
} else if (ref==4) {
val = jjhp;
} else if (ref==5) {
val = io.moncnt;
} else {
val = stack[ref];
}
stack[++sp] = val;
break;
case 214 : // jopsys_wrint
ref = stack[sp--];
val = stack[sp--];
if (ref==0) {
mp = val;
} else if (ref==1) {
cp = val;
} else if (ref==2) {
heap = val;
// System.out.println("jopsys_wrint: heap "+heap);
} else if (ref==3) {
jjp = val;
} else if (ref==4) {
jjhp = val;
} else if (ref==5) {
io.moncnt = val;
} else {
stack[ref] = val;
}
break;
case 215 : // jopsys_getsp
val = sp;
stack[++sp] = val;
break;
case 216 : // jopsys_setsp
val = stack[sp--];
sp = val;
break;
case 217 : // jopsys_getvp
stack[++sp] = vp;
break;
case 218 : // jopsys_setvp
vp = stack[sp--];
break;
case 219 : // jopsys_int2ext
// public static native void int2extMem(int intAdr, int extAdr, int cnt);
a = stack[sp--];
b = stack[sp--];
// handle needs indirection
b = readMem(b, Access.HANDLE);
c = stack[sp--];
for(; a>=0; --a) {
writeMem(b+a, stack[c+a], Access.ARRAY);
}
break;
case 220 : // jopsys_ext2int
// public static native void ext2intMem(int extAdr, int intAdr, int cnt);
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
// handle needs indirection
c = readMem(c, Access.HANDLE);
for(; a>=0; --a) {
stack[b+a] = readMem(c+a, Access.ARRAY);
}
break;
case 221 : // jopsys_nop
break;
case 222 : // jopsys_invoke
a = stack[sp--];
invoke(a);
break;
case 223 : // jopsys_cond_move
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
stack[++sp] = a!=0 ? c : b;
// noim(223);
break;
case 224 : // resE0 - getstatic_ref
getstatic();
break;
case 225 : // resE1 - putstatic_ref
jjvmIdx(225); // use JVM.java version
//putstatic();
break;
case 226 : // resE2 - getfield_ref
getfield();
break;
case 227 : // resE3 - putfield_ref
jjvmIdx(227); // use JVM.java version
//putfield();
break;
case 228 : // resE4 - getstatic_long
getstatic_long();
break;
case 229 : // resE5 - putstatic_long
putstatic_long();
break;
case 230 : // resE6 - getfield_long
getfield_long();
break;
case 231 : // resE7 - putfield_long
putfield_long();
break;
case 232 : // resE8 - jopsys_memcpy
a = stack[sp--];
b = stack[sp--];
c = stack[sp--];
if (a >= 0) {
writeMem(c+a, readMem(b+a, Access.INTERN), Access.INTERN);
copy_src = b;
copy_dest = c;
copy_pos = a+1;
} else {
copy_src = b;
copy_dest = c;
copy_pos = 0;
}
break;
case 233 : // resE9 - jopsys_getfield
jopsys_getfield();
break;
case 234 : // resEA - jopsys_putfield
jopsys_putfield();
break;
case 235 : // resEB
noim(235);
break;
case 236 : // invokesuper
invokesuper();
waitCache(WCETInstruction.INVOKE_HIDDEN_LOAD_CYCLES);
break;
case 237 : // resED
noim(237);
break;
case 238 : // resEE - jopsys_getstatic
stack[sp] = readMem(stack[sp], Access.STATIC);
break;
case 239 : // resEF - jopsys_putstatic
writeMem(stack[sp], stack[sp-1], Access.STATIC);
sp -= 2;
break;
case 240 : // sys_int
--pc; // correct wrong increment on jpc
invoke(jjhp); // interrupt() is at offset 0
break;
case 241 : // sys_exc exception handling
--pc; // correct wrong increment on jpc
invoke(jjhp+6); // exception() is at offset 3*2
break;
case 242 : // resF2
noim(242);
break;
case 243 : // resF3
noim(243);
break;
case 244 : // resF4
noim(244);
break;
case 245 : // resF5
noim(245);
break;
case 246 : // resF6
noim(246);
break;
case 247 : // resF7
noim(247);
break;
case 248 : // resF8
noim(248);
break;
case 249 : // resF9
noim(249);
break;
case 250 : // resFA
noim(250);
break;
case 251 : // resFB
noim(251);
break;
case 252 : // resFC
noim(252);
break;
case 253 : // resFD
noim(253);
break;
case 254 : // sys_noim
noim(254);
break;
case 255 : // sys_init
noim(255);
break;
default:
noim(instr);
}
} catch(JopSimRtsException rtsEx) {
this.intExcept = true;
this.exceptReason = rtsEx.getReason();
}
}
/**
* Reset all simulation counters. We are not interested in the
* startup code (GC memory clean). Maybe in class initializers?
* Invoked due to an I/O access just before invoking main().
*/
void resetStat() {
for (Access a : Access.values()) {
a.reset();
}
for (int i=0; i<bcStat.length; ++i) {
bcStat[i] = 0;
}
instrCnt = 0;
rdMemCnt = 0;
wrMemCnt = 0;
cache.resetCnt();
}
/**
* Print execution statistics.
*/
void stat() {
System.out.println();
System.out.println("CPU "+io.cpuId+":");
int sum = 0;
int sumcnt = 0;
// // that's the JopInstr version
// for (int i=0; i<256; ++i) {
// if (bcStat[i] > 0) {
// System.out.println(bcStat[i]+"\t"+(bcStat[i]*JopInstr.cnt(i))+"\t"+JopInstr.name(i));
// sum += bcStat[i];
// sumcnt += bcStat[i]*JopInstr.cnt(i);
// }
// }
// System.out.println();
// System.out.println(sum+" instructions, "+sumcnt+" cycles");
// That's the version with WCETInstruction
sum = sumcnt = 0;
for (int i=0; i<256; ++i) {
if (bcStat[i] > 0) {
int cnt = timing.getCyclesEstimate(i, false, 0);
// System.out.println(bcStat[i]+"\t"+(bcStat[i]*cnt)+"\t"+JopInstr.name(i));
sum += bcStat[i];
sumcnt += bcStat[i]*cnt;
}
}
System.out.println();
System.out.println(sum+" instructions, "+sumcnt+" cycles (no M$ cycles)");
System.out.println("CPI: "+ ((float) sumcnt/sum));
System.out.println(maxSp+" maximum sp");
// System.out.println(heap+" heap"); not the heap pointer anymore
// System.out.println();
System.out.println(instrCnt+" Instructions executed");
int insByte = cache.instrBytes();
System.out.println(insByte+" Instructions bytes");
System.out.println(((float) insByte/instrCnt)+" average Instruction length");
System.out.println();
System.out.println("\tType \t& Load & & Store & \\\\");
int ld = 0, st=0;
for (Access a : Access.values()) {
ld += a.rdCnt; st += a.wrCnt;
// System.out.printf("\t%s\t& %10d & %2d\\%% & %10d & %2d\\%% \\\\%n",
// a.name(), a.rdCnt, (a.rdCnt*1000/rdMemCnt+5)/10, a.wrCnt, (a.wrCnt*1000/wrMemCnt+5)/10);
int rdPerc = (int) ((double) a.rdCnt/(rdMemCnt + wrMemCnt)*1000);
int wrPerc = (int) ((double) a.wrCnt/(rdMemCnt + wrMemCnt)*1000);
System.out.printf("\t%s\t& %10d & %2d.%1d\\%% & %10d & %2d.%1d\\%% \\\\%n",
a.name(), a.rdCnt, rdPerc/10, rdPerc%10,
a.wrCnt, wrPerc/10, wrPerc%10);
}
System.out.println("\t\\midrule");
System.out.printf("\tSum\t& %10d & & %10d & \\\\%n", ld, st);
System.out.println();
System.out.println("memory word: "+rdMemCnt+" load "+wrMemCnt+" store");
System.out.println("memory word per instruction: "+
((float) rdMemCnt/instrCnt)+" load "+
((float) wrMemCnt/instrCnt)+" store");
System.out.println("total method cache load cycles: "+this.cacheCost);
System.out.println();
}
/**
* Stop the simulation (from the VSIS plugin)
*/
public static void cancel() {
exit = true;
stopped = true;
}
/**
* Signal detection of JVM exit!
*/
public static void exit() {
exit = true;
}
public static int getArgs(String args[]) {
log = System.getProperty("log", "false").equals("true");
nrCpus = Integer.parseInt(System.getProperty("cpucnt", "1"));
js = new JopSim[nrCpus];
int maxInstr=0;
if (args.length==1) {
maxInstr=0;
} else if (args.length==2) {
maxInstr = Integer.parseInt(args[1]);
} else {
System.out.println("usage: java JopSim file.bin [max instr]");
System.exit(-1);
}
return maxInstr;
}
/** simple runner: 1 cpu, 1 cache implementation */
public void runSim() {
cache.use(0);
start();
while(! exit) { interpret(); }
if (stopped) {
System.out.println();
System.out.println("JopSim stopped");
}
System.out.println();
stat();
cache.stat();
}
/** run simulation for multicore JOP */
public static void runSimulation() {
// loop over all cache simulations
for (int i=0; i<js[0].cache.cnt(); ++i) {
for (int j=0; j<nrCpus; ++j) {
js[j].cache.use(i);
js[j].start();
}
while (!exit) {
js[0].interpret();
if (nrCpus != 1 && IOSimMin.startCMP) {
for (int j = 1; j < nrCpus; ++j) {
js[j].interpret();
}
}
}
if (stopped) {
System.out.println();
System.out.println("JopSim stopped");
}
System.out.println();
for (int j=0; j<nrCpus; ++j) {
if (i==0) js[j].stat();
js[j].cache.stat();
}
}
}
public static void main(String args[]) {
IOSimMin io;
int maxInstr = getArgs(args);
String ioDevice = System.getProperty("ioclass");
for (int i=0; i<nrCpus; ++i) {
// select the IO simulation
if (ioDevice!=null) {
try {
io = (IOSimMin) Class.forName("com.jopdesign.tools."+ioDevice).newInstance();
} catch (Exception e) {
e.printStackTrace();
io = new IOSimMin();
}
} else {
io = new IOSimMin();
}
io.setCpuId(i);
js[i] = new JopSim(args[0], io, maxInstr);
}
runSimulation();
}
/* interface for IOSim */
public long getClkCnt() {
return clkCnt;
}
public int getExceptReason() {
return this.exceptReason;
}
public void setException(int val) {
intExcept = true;
exceptReason = val;
}
public Cache getCache() {
return cache;
}
public int getCacheCost() {
return this.cacheCost;
}
}