/*
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/>.
*/
package com.jopdesign.tools;
import com.jopdesign.sys.Const;
// uncomment for usage of the PCs com port
// import javax.comm.CommPortIdentifier;
// import javax.comm.SerialPort;
// import javax.comm.UnsupportedCommOperationException;
/**
* Simulation of the minimal IO devices
*
* @author martin
*
*/
public class IOSimMin {
protected JopSim js;
// must not interfere with constants (check at compile time) and
// within the interval [-128,-1]
protected static final int SIM_CACHE_FLUSH = -51;
protected static final int SIM_CACHE_COST = -52;
protected static final int SIM_CACHE_DUMP = -53;
// find JVM exit
protected static String exitStr = "JVM exit!";
protected char[] exitBuf = new char[exitStr.length()];
protected int cpuId;
protected static int cpuCnt = 1;
protected static boolean startCMP = false;
static boolean globalLock = false;
int moncnt = 0;
/**
* The interrupt register
*/
protected int interrupt;
/**
* Interrupt mask
*/
protected int mask;
/**
* The global enable
*/
protected boolean intEna;
/**
* Timer was triggered
*/
protected boolean timeShot;
/**
* Time for the next timer interrupt
*/
protected int nextTimerInt;
/**
* Interrupt as a number
*/
protected int intNr;
/**
* Set reference to simulation
*
* @param jsRef
* Simulation class reference
*/
public void setJopSimRef(JopSim jsRef) {
js = jsRef;
}
/**
* Set CPU ID
* @param id
* CPU id for CMP simulation
*/
public void setCpuId(int id) {
cpuId = id;
if (id + 1 > cpuCnt) {
cpuCnt = id + 1;
}
}
//
// Mapping of the second serial line to the PCs
// com port. See ejip.MainSlipUart2 for an example.
// Uncommented as javax.comm is NOT part of the standard
// JDK - Blame Sun!
// private String portName;
// private CommPortIdentifier portId;
// private InputStream is = null;
// private OutputStream os = null;
// private SerialPort serialPort;
//
// private void openSerialPort() {
// try {
// if (portId!=null) {
// try {
// is.close();
// os.close();
// is = null;
// os = null;
// } catch (Exception e1) {
// }
// serialPort.close();
// }
// portId = CommPortIdentifier.getPortIdentifier(portName);
// serialPort = (SerialPort) portId.open(getClass().toString(), 2000);
// serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_OUT
// | SerialPort.FLOWCONTROL_RTSCTS_IN);
// serialPort.setSerialPortParams(115200,
// SerialPort.DATABITS_8,
// SerialPort.STOPBITS_1,
// SerialPort.PARITY_NONE);
// is = serialPort.getInputStream();
// os = serialPort.getOutputStream();
// System.out.println("open"+portName);
// } catch (Exception e) {
// is = null;
// os = null;
// System.out.println("Problem with serial port "+portName);
// System.out.println(e.getMessage());
// // System.exit(-1);
// }
// }
public int read(int addr) {
int val;
int i;
try {
switch (addr) {
case Const.IO_STATUS:
val = Const.MSK_UA_TDRE;
if (System.in.available() != 0) {
val |= Const.MSK_UA_RDRF;
}
break;
// for sure when USB TX status is used
case Const.IO_USB_STATUS:
val = Const.MSK_UA_TDRE;
break;
case Const.IO_STATUS2:
i = 0;
// if (is!=null) {
// try {
// if (is.available()!=0) {
// i |= Const.MSK_UA_RDRF;
// }
// } catch (IOException e1) {
// e1.printStackTrace();
// } // rdrf
// }
// i |= Const.MSK_UA_TDRE; // tdre is alwais true on
// OutputStream
val = i;
break;
case Const.IO_UART:
if (System.in.available() != 0) {
val = System.in.read();
} else {
val = '_';
}
break;
case Const.IO_UART2:
i = 0;
// try {
// i = is.read();
// } catch (IOException e) {
// e.printStackTrace();
// }
val = i;
break;
//
// System device
//
case Const.IO_CNT:
val = (int)js.clkCnt;
break;
case Const.IO_US_CNT:
val = usCnt();
break;
case Const.IO_INTNR:
val = intNr;
break;
case Const.IO_EXCPT:
val = js.exceptReason;
break;
case Const.IO_CPU_ID:
val = cpuId;
break;
case Const.IO_CPUCNT:
val = cpuCnt;
break;
case SIM_CACHE_COST:
val = js.cacheCost;
break;
case SIM_CACHE_DUMP:
// trigger cache debug output
// cache.rawData();
// cache.resetCnt();
js.objectCacheSim.dumpStats();
val = js.objectCacheSim.getStats().accessCount;
break;
default:
val = 0;
System.out.println("Default read " + addr);
}
} catch (Exception e) {
System.out.println(e);
val = 0;
}
return val;
}
public void write(int addr, int val) {
switch (addr) {
case Const.IO_UART:
if (JopSim.log)
System.out.print("\t->");
System.out.print((char) val);
if (JopSim.log)
System.out.println("<-");
// check the output for JVM exit!
for (int i = 0; i < exitStr.length() - 1; ++i) {
exitBuf[i] = exitBuf[i + 1];
}
exitBuf[exitBuf.length - 1] = (char) val;
if (new String(exitBuf).equals(exitStr)) {
JopSim.exit();
}
break;
case Const.IO_USB_DATA:
// Ignore USB output
break;
case Const.IO_UART2:
// if (os==null) return;
// try {
// os.write(val&0xff);
// } catch (IOException e) {
// e.printStackTrace();
// }
break;
case Const.IO_STATUS2:
// if (serialPort!=null) {
// serialPort.setDTR(val==1);
// try {
// if ((val&0x04)==0) {
// serialPort.setSerialPortParams(2400,
// SerialPort.DATABITS_8,
// SerialPort.STOPBITS_1,
// SerialPort.PARITY_NONE);
// } else {
// serialPort.setSerialPortParams(115200,
// SerialPort.DATABITS_8,
// SerialPort.STOPBITS_1,
// SerialPort.PARITY_NONE);
// }
// if ((val&0x02)==0) {
// serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
// } else {
// serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_OUT
// | SerialPort.FLOWCONTROL_RTSCTS_IN);
// }
// } catch (UnsupportedCommOperationException e1) {
// e1.printStackTrace();
// }
// }
break;
case Const.IO_INT_ENA:
intEna = (val == 0) ? false : true;
break;
case Const.IO_TIMER:
nextTimerInt = val;
timeShot = false;
break;
case Const.IO_SWINT:
interrupt |= 1 << val;
break;
case Const.IO_WD:
break;
case Const.IO_EXCPT:
js.intExcept = true;
js.exceptReason = val;
break;
case Const.IO_LOCK:
// only used in microcode for monitor enter and exit
break;
case Const.IO_SIGNAL:
startCMP = (val != 0);
break;
case Const.IO_INTMASK:
mask = val;
break;
case Const.IO_INTCLEARALL:
interrupt = 0;
break;
case Const.IO_PERFCNT:
js.resetStat();
break;
case SIM_CACHE_COST:
js.cacheCost = val;
break;
case SIM_CACHE_FLUSH:
js.cache.flushCache();
js.objectCacheSim.flushCache();
break;
case Const.IO_DEADLINE:
js.localCnt += (val-((int) js.clkCnt));
break;
default:
System.out.println("Default write " + addr + " " + val);
}
}
/**
* Monitor enter returns true when either the global lock
* is grabbed or it is already held (moncnt>0).
* @return true if successfully entered
*/
boolean monEnter() {
intEna = false;
if (moncnt == 0) {
if (globalLock) {
return false;
} else {
++moncnt;
globalLock = true;
return true;
}
} else {
++moncnt;
return true;
}
}
void monExit() {
--moncnt;
if (moncnt == 0) {
intEna = true;
globalLock = false;
}
}
boolean intPending() {
int i;
// do the timer interrupt
if ((nextTimerInt - usCnt() < 0) && !timeShot) {
timeShot = true;
interrupt |= 1;
}
// check interrupts
int val = interrupt & mask;
if (val != 0 && intEna) {
for (i = 0; val != 0; ++i) {
if ((val & 1) != 0) {
break;
}
val >>>= 1;
}
intNr = i;
interrupt &= ~(1 << i);
intEna = false;
return true;
}
return false;
}
public int usCnt() {
// return ((int) (System.nanoTime()/1000)); // does not really work as
// expected
return ((int) System.currentTimeMillis()) * 1000;
}
}