diff options
author | Bert Lange <b.lange@hzdr.de> | 2015-04-15 13:36:55 +0200 |
---|---|---|
committer | Bert Lange <b.lange@hzdr.de> | 2015-04-15 13:36:55 +0200 |
commit | a1c964908b51599bf624bd2d253419c7e629f195 (patch) | |
tree | 06125d59e83b7dde82d1bb57bc0e09ca83451b98 /zpu/sw/simulator/com | |
parent | bbfe29a15f11548eb7c9fa71dcb4d2d18c164a53 (diff) | |
parent | 8679e4f91dcae05aef40f96629f33f0f4161f14a (diff) | |
download | zpu-a1c964908b51599bf624bd2d253419c7e629f195.zip zpu-a1c964908b51599bf624bd2d253419c7e629f195.tar.gz |
Merge branch 'master' of https://github.com/zylin/zpu
Diffstat (limited to 'zpu/sw/simulator/com')
35 files changed, 4666 insertions, 0 deletions
diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Abel.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Abel.java new file mode 100644 index 0000000..8d8667c --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Abel.java @@ -0,0 +1,109 @@ + +package com.zylin.zpu.simulator; + +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; + +public class Abel extends Simulator +{ + + protected int getIO() + { + return 0x8000; + } + + + + protected int ioRead(int addr) throws CPUException + { + switch (addr) + { + case 0xc000: + return syscall.readUART(); + + /* FIFO empty? bit 0, FIFO full bit 1(never the case) */ + case 0xc004: + return syscall.readFIFO(); + + case 0x9000: + case 0x9004: + case 0x9008: + case 0x900c: + + case 0x9010: + case 0x9014: + case 0x9018: + case 0x901c: + return readSampledTimer(addr, 0x9000); + + case 0x8800: + return readMHz(); + + default: + throw new MemoryAccessException(); + } + } + + /* + ; Read/write are on different addresses + ; The registers are 8 bits and mapped to bit[7:0] + ; + ; 0xC000 Write: Writes to UART TX FIFO (4 byte FIFO) + ; Read : Reads from UART RX FIFO (4 byte FIFO) + ; 0xC004 Read : UART status register + ; Bit 0 = RX FIFO empty + ; Bit 1 = TX FIFO full + ; 0xA000 Write: 8 LED's + */ + + /* + 0x9000 Write: bit 0: 1= reset counter + 0= counter running + bit 1: 1= sample counter (when set to 1) + 0=not used + Read : counter bit[7:0] + 0x9004 Read: counter bit [15:8] + 0x9008 Read: counter bit [23:16] + 0x900C Read: counter bit [31:24] + 0x9010 Read: counter bit [39:32] + 0x9014 Read: counter bit [47:40] + 0x9018 Read: counter bit [55:48] + 0x901C Read: counter bit [63:56] + + 0x8800 Read: unsigned 8-bit integer with FPGA frequency (in MHz) + */ + + protected void ioWrite(int addr, int val) throws MemoryAccessException + { + switch (addr) + { + case 0x9000: + writeTimerSampleReg(val); + case 0xc000: + syscall.writeUART(val); + break; + default: + throw new MemoryAccessException(); + } + } + + Abel() throws CPUException + { + } + + protected boolean emulateConfig() + { + return true; + } + + protected int getStartStack() + { + return getRAMSIZE()-8; + } + + protected int getRAMSIZE() + { + return 32768; + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/FileTracer.java b/zpu/sw/simulator/com/zylin/zpu/simulator/FileTracer.java new file mode 100644 index 0000000..6ccca24 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/FileTracer.java @@ -0,0 +1,285 @@ + +package com.zylin.zpu.simulator; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.LineNumberReader; + +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.GDBServerException; +import com.zylin.zpu.simulator.exceptions.TraceException; + +public class FileTracer implements Tracer +{ + private LineNumberReader file; + private boolean trigger; + private boolean resync; + private Simulator simulator; + private String line; + private boolean ignore; + + static class Trace + { + int pc; + int opcode; + int sp; + int stackA; + int stackB; + int intSp; + long cycle; + public boolean undefinedStackA; + public boolean undefinedStackB; + public boolean undefinedIntSp; + public void print() + { + System.err.println(Integer.toHexString(pc)+ " " + + Integer.toHexString(opcode) + " " + + Integer.toHexString(sp) + " " + + Integer.toHexString(stackA) + " " + + Integer.toHexString(stackB) + " " + + intSp + " " + + cycle); + + } + }; + private Trace[] trace= new Trace[100]; + private int current; + private String fileName; + private boolean metEnd; + + + public FileTracer(Simulator sim, String string) + { + simulator=sim; + fileName=string; + + resync=true; + + + for (int i=0; i<trace.length; i++) + { + trace[i]=new Trace(); + } + findNextTrigger(); + } + + LineNumberReader getFile() + { + if (file==null) + { + try + { + file=new LineNumberReader(new java.io.FileReader(fileName)); + } catch (FileNotFoundException e) + { + throw new RuntimeException(e); + } + } + return file; + } + + + private void findNextTrigger() throws TraceException + { + trigger=false; + try + { + for (;;) + { + line=getFile().readLine(); + if (line==null) + { + metEnd=true; + System.err.println("================== End of trace file ======================"); + break; + } + if (line.matches("^\\s*\\#.*$")) + { + /* this was a comment*/ + continue; + } + if (line.matches("^\\s*$")) + { + /* all whitespace */ + continue; + } + String[] val=line.split(" "); + + try + { + Trace t=trace[current]; + t.pc=(int) parseInt(val[0]); + t.opcode=(int) parseInt(val[1]); + t.sp=(int) parseInt(val[2]); + try + { + t.undefinedStackA=false; + t.stackA=(int) parseInt(val[3]); + } catch (NumberFormatException e) + { + t.undefinedStackA=true; + t.stackB=0; + } + + try + { + t.undefinedStackB=false; + t.stackB=(int) parseInt(val[4]); + } catch (NumberFormatException e) + { + t.undefinedStackB=true; + t.stackB=0; + } + try + { + t.undefinedIntSp=false; + t.intSp=(int) parseInt(val[5]); + } catch (NumberFormatException e) + { + t.undefinedIntSp=true; + t.intSp=0; + } + t.cycle=parseInt(val[6]); + trigger=true; + break; + } catch (NumberFormatException e) + { + /* skip this line. */ + e.printStackTrace(); + } + } + } catch (IOException e) + { + throw new TraceException(e); + } + + } + + private long parseInt(String string2) throws TraceException + { + String string = string2; + if (!string.startsWith("0x")) + { + throw new TraceException(new Exception("Trace file pasing error line " + getFile().getLineNumber())); + } + return Long.parseLong(string.substring(2), 16); + } + + public void instructionEvent() throws GDBServerException + { + if (metEnd) + { + metEnd=false; + throw new TraceException(); + } + if (resync&&trigger) + { + if (match()) + { + /* we have to wait for the first instruction in the trace to be matched */ + System.out.println("First matching instruction found!"); + resync=false; + } + } + + if (!resync&&trigger) + { + + boolean m=match(); + recordCurrent(); + current=(current+1)%trace.length; + + if (!m) + { + System.err.println("Trace file mismatch"); + dumpTraceBack(); + System.err.print("Expected by Java simulator: \n"); + simulator.printState(this); + System.err.print("Actual from ModelSim: "); + System.err.println(line); + // we now have to ignore this match. + ignore=true; + throw new TraceException(); + } + } else + { + recordCurrent(); + current=(current+1)%trace.length; + } + } + + public void dumpTraceBack() + { + System.err.println("Expected"); + System.err.println("PC SP topOfStack"); + for (int i=0; i<trace.length; i++) + { + trace[(i+current)%trace.length].print(); + } + } + + private void recordCurrent() + { + recordState(trace[current]); + } + + private void recordState(Trace trace3) + { + trace3.pc=simulator.getPc(); + trace3.sp=simulator.getSp(); + trace3.opcode=simulator.getOpcode(); + try + { + trace3.stackA=simulator.cpuReadLong(simulator.getSp()); + trace3.stackB=simulator.cpuReadLong(simulator.getSp()+4); + trace3.intSp=simulator.getIntSp(); + // trace[current].cycle=expectetdCycle(); + } catch (CPUException e1) + { + e1.printStackTrace(); + } + } + + + + boolean match() throws GDBServerException + { + if (ignore) + return true; + + return simulator.checkMatch(trace[current]); + } + + public void commit() + { + try + { + if (!resync&&trigger) + { + ignore=false; + findNextTrigger(); + } + } + catch (Throwable e) + { + e.printStackTrace(); + } + } + + public void setSp(int sp) + { + } + + public boolean onInterrupt() + { + if (trace[current].pc==0x20) + return true; + else + return false; + } + + public boolean simInterrupt() + { + return true; + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Host.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Host.java new file mode 100644 index 0000000..c1daa9f --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Host.java @@ -0,0 +1,46 @@ + +package com.zylin.zpu.simulator; + +import com.zylin.zpu.simulator.exceptions.CPUException; + +public interface Host +{ + /** generic file io error */ + public final static int EIO = 5; + + public final static int SYS_read= 4; + public final static int SYS_write= 5; + public final static int SYS_argv = 13; + public final static int SYS_exit=1; + public final static int SYS_open= 2; + public final static int SYS_close= 3; + public final static int SYS_lseek = 6; + public final static int SYS_unlink = 7; + public final static int SYS_getpid = 8; + public final static int SYS_kill = 9; + public final static int SYS_fstat = 10; + /*final static int SYS_sbrk 11 - not currently a system call, but reserved. */ + /* ARGV support. */ + public final static int SYS_argvlen= 12; + /* These are extras added for one reason or another. */ + public final static int SYS_chdir = 14; + public final static int SYS_stat = 15; + public final static int SYS_chmod = 16; + public final static int SYS_utime = 17; + public final static int SYS_time = 18; + public final static int SYS_gettimeofday =19; + public final static int SYS_times = 20; + public final static int SYS_link = 21; + public final static int SYS_ftruncate=3000; + public final static int SYS_isatty=3001; + public void syscall(Sim s) throws CPUException; + boolean doneContinue(); + public void writeUART(int val); + public int readUART() throws CPUException; + public int readFIFO(); + /** notification that the CPU is halted */ + public void halted(); + /** notification that the CPU is running */ + public void running(); + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Machine.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Machine.java new file mode 100644 index 0000000..3827378 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Machine.java @@ -0,0 +1,17 @@ + +package com.zylin.zpu.simulator; + +/** + * @author oyvind + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Style - Code Templates + */ +public interface Machine +{ + + long getPrevCycles(); + + long getCycles(); + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Phi.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Phi.java new file mode 100644 index 0000000..663e68f --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Phi.java @@ -0,0 +1,126 @@ + +package com.zylin.zpu.simulator; + +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; + +public class Phi extends Simulator +{ + @Override + protected long getSampleOffset() + { + + return super.getSampleOffset()-(0x5e7b2-0x0005E7C0); + } + + + public static void main(String[] args) + { + new SimApp(new SimFactory() + { + public Simulator create() + { + return new Phi(); + } + }).run(args); + } + + + protected int getIO() + { + return 0x08000000; + } + + + + protected int ioRead(int addr) throws CPUException + { + switch (addr) + { + + case 0x080a0020: + return interrupt?0:1; // interrupt mask + + + + /* FIFO empty? bit 0, FIFO full bit 1(never the case) */ + case 0x080a000c: + return 0x100; // buffer ready. + + case 0x080a0014: + case 0x080a0018: + return readSampledTimer(addr, 0x080a0014); + + case 0x080a0030: + return timerPending?1:0; + case 0x080a0038: + return (int)(timerInterval-1-((cycles-lastTimer)%timerInterval)); + + + default: + throw new MemoryAccessException(); + } + } + + + + protected void ioWrite(int addr, int val) throws MemoryAccessException + { + switch (addr) + { + case 0x080a0020: + interrupt=(val&1)==0; + return; + case 0x080a002c: + timer=(val&0x1)!=0; + break; + case 0x080a0030: + if ((val&0x1)!=0) + { + timerPending=false; + } + if ((val&0x2)!=0) + { + lastTimer=cycles; + } + break; + case 0x080a0034: + timerInterval=val; + return; + + case 0x080a0014: + writeTimerSampleReg(val); + case 0x080a000c: + syscall.writeUART(val); + break; + default: + throw new MemoryAccessException(); + } + } + + public Phi() throws CPUException + { + } + + protected boolean emulateConfig() + { + return true; + } + + protected int getStartStack() + { + return getRAMSIZE()-8; + } + + protected int getRAMSIZE() + { + return 2*1024*1024; + } + + + protected int getIOSIZE() + { + return 0x100000; + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/PhiFeeble.java b/zpu/sw/simulator/com/zylin/zpu/simulator/PhiFeeble.java new file mode 100644 index 0000000..79d3a38 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/PhiFeeble.java @@ -0,0 +1,34 @@ +package com.zylin.zpu.simulator; + +public class PhiFeeble extends Phi +{ + public static void main(String[] args) + { + new SimApp(new SimFactory() + { + public Simulator create() + { + return new PhiFeeble(); + } + }).run(args); + } + protected void setFeeble() + { +// feeble[NEQBRANCH] = false; +// feeble[EQ] = false; +// feeble[LOADB] = false; +// feeble[LESSTHAN] = false; +// feeble[ULESSTHAN] = false; +// feeble[STOREB] = false; +// feeble[MULT] = false; +// feeble[CALL] = true; +// feeble[POPPCREL] = true; +// feeble[LESSTHANOREQUAL] = true; +// feeble[ULESSTHANOREQUAL] = true; +// +// feeble[PUSHSPADD] = false; +// feeble[CALLPCREL] = false; +// feeble[SUB] = false; + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Sim.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Sim.java new file mode 100644 index 0000000..21450f7 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Sim.java @@ -0,0 +1,62 @@ + +package com.zylin.zpu.simulator; + +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; + +public interface Sim +{ +/** + * halts the CPU. + */ + void suspend(); + void writeByte(int i, int val) throws CPUException; + /** + * synchronous method that returns when simulator enters the halt state. + **/ + void cont(); + /** + * synchronous method that returns when simulator finishes step or otherwise enters + * the halt state. + **/ + void step(); + + int getReg(int i) throws CPUException; + + int getREGNUM(); + int readByte(int addr) throws CPUException; + + /** + * @param sp The sp to set. + * @throws CPUException + */ + void setSp(int sp) throws CPUException; + + /** + * @return Returns the sp. + */ + int getSp(); + + /** + * @param pc The pc to set. + * @throws MemoryAccessException + */ + void setPc(int pc) throws MemoryAccessException; + + /** + * @return Returns the pc. + */ + int getPc(); + + void enableAccessWatchPoint(int address, int length) throws CPUException; + + void disableAccessWatchPoint(int address, int length) throws CPUException; + + int cpuReadLong(int i) throws CPUException; + + void cpuWriteLong(int i, int retval) throws MemoryAccessException; + + int getArg(int num) throws CPUException; + void sessionStarted(); + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/SimApp.java b/zpu/sw/simulator/com/zylin/zpu/simulator/SimApp.java new file mode 100644 index 0000000..3f6e1a9 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/SimApp.java @@ -0,0 +1,177 @@ +package com.zylin.zpu.simulator; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.ServerSocketChannel; + +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.gdb.GDBServer; + +public class SimApp +{ + private static Simulator simulator; + private String[] args; + private int portNumber; + private SimFactory simFactory; + + public SimApp(SimFactory factory) + { + simFactory=factory; + } + + public void parseArgs() + { + portNumber = 4444; + if (args.length>=1) + { + portNumber=Integer.parseInt(args[0]); + } + } + + private void moreParse() + { + if (args.length>=2) + { + simulator.setTraceFile(args[1]); + } + } + + void run(String[] args) + { + this.args=args; + createSimulator(); + parseArgs(); + moreParse(); + runSimAndGDB(); + } + Object launched=new Object(); + private boolean doneLaunching; + private boolean manyGDBSessions; + public ServerSocket serverSocket; + public void runSimAndGDB() + { + try + { + serverSocket = new ServerSocket(portNumber); + try + { + serverSocket.setReuseAddress(true); + System.out.println("Listening on port " + portNumber); + setLaunchedFlag(); + do + { + try + { + runGDBServer(); + } catch (CPUException e) + { + e.printStackTrace(); + } + } while (manyGDBSessions); + } finally + { + serverSocket.close(); + } + } catch (IOException e1) + { + e1.printStackTrace(); + } finally + { + setLaunchedFlag(); + } + + } + + private void setLaunchedFlag() + { + synchronized(launched) + { + doneLaunching=true; + launched.notify(); + } + } + + public void createSimulator() + { + simulator=simFactory.create(); + simulator.suspend(); + } + + private void runGDBServer() throws CPUException + { + final GDBServer gdbServer=new GDBServer(simulator, this); + simulator.setSyscall(gdbServer); + Thread thread = new Thread(new Runnable() + { + public void run() + { + try + { + gdbServer.gdbServer(); + } + catch (Throwable e) + { + e.printStackTrace(); + } + simulator.shutdown(); + } + }); + thread.start(); + try + { + simulator.run(); + } + finally + { + try + { + thread.join(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + } + + public Simulator getSimulator() + { + return simulator; + } + + public void setPort(int i) + { + portNumber=i; + } + + /** synchronous launch of GDB server */ + public void launchGDBServer() + { + Thread t=new Thread(new Runnable() + { + + public void run() + { + runSimAndGDB(); + } + }); + t.start(); + synchronized (launched) + { + while (!doneLaunching) + { + try + { + launched.wait(2000); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + } + + + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/SimFactory.java b/zpu/sw/simulator/com/zylin/zpu/simulator/SimFactory.java new file mode 100644 index 0000000..4db85d7 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/SimFactory.java @@ -0,0 +1,8 @@ +package com.zylin.zpu.simulator; + +public interface SimFactory +{ + + Simulator create(); + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Simulator.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Simulator.java new file mode 100644 index 0000000..cf6cf41 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Simulator.java @@ -0,0 +1,2065 @@ +package com.zylin.zpu.simulator; + +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import com.zylin.zpu.simulator.FileTracer.Trace; +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.DebuggerBreakpointException; +import com.zylin.zpu.simulator.exceptions.EndSessionException; +import com.zylin.zpu.simulator.exceptions.GDBServerException; +import com.zylin.zpu.simulator.exceptions.HardwareWatchPointException; +import com.zylin.zpu.simulator.exceptions.IllegalInstructionException; +import com.zylin.zpu.simulator.exceptions.InterruptException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; + +public class Simulator implements ZPU, Machine, Sim +{ + + int minStack; + + /** + * the feeble version of the CPU, e.g. only implements + * 11 instructions. + * + * For debugging purposes it is useful to enable/disable + * each instruction + */ + boolean feeble[]=new boolean[256]; + + private long opcodeHistogram[]=new long[256]; + private long opcodeHistogramCycles[]=new long[256]; + private long opcodePairHistogram[]=new long[256*256]; + private long opcodePairHistogramCycles[]=new long[256*256]; + + /** weee! constants are 32 bit by default, so we need to assign a 64 bit + * integer in this matter. + */ + private static final long INTMASK = Long.parseLong("ffffffff", 16); + + final static int PUSHPC=59; + final static int OR=7; + final static int NOT=9; + final static int LOAD=8; + final static int STORE=12; + final static int POPPC=4; + final static int FLIP=10; + + final static int ADD=5; + final static int PUSHSP=2; + final static int POPSP=13; + final static int NOP=11; + final static int AND=6; + final static int ADDSP=16; + + final static int EMULATE=32; + final static int LOADH=34; + final static int STOREH=35; + final static int LESSTHAN=36; + final static int LESSTHANOREQUAL=37; + final static int ULESSTHAN=38; + final static int ULESSTHANOREQUAL=39; + final static int SWAP=40; + final static int MULT=41; + final static int LSHIFTRIGHT=42; + final static int ASHIFTLEFT=43; + final static int ASHIFTRIGHT=44; + final static int CALL=45; + final static int EQ=46; + final static int NEQ=47; + final static int NEG=48; + final static int SUB=49; + final static int XOR=50; + final static int LOADB=51; + final static int STOREB=52; + final static int DIV=53; + final static int MOD=54; + final static int EQBRANCH=55; + final static int NEQBRANCH=56; + final static int POPPCREL=57; + final static int CONFIG=58; + final static int SYSCALL=60; + final static int PUSHSPADD=61; + final static int MULT16X16=62; + final static int CALLPCREL=63; + final static int STORESP=64; + final static int LOADSP=64+32; + + int[] memory; + boolean[] validMemory; + protected long cycles; + protected int instructionCount; + private int sp; + private int pc; + protected boolean breakNext; + + /* halting synchronization object */ + protected Object halt = new Object(); + + private int IOSIZE=getIOSIZE(); + protected int getIOSIZE() + { + return 32768; + } + long prevCycles; + private static final int VECTORSIZE = 0x20; + private static final int VECTOR_RESET = 0; + private static final int VECTOR_INTERRUPT = 1; + private boolean hitVector; + private static final int VECTORBASE = 0x0; + private int nextVector; + protected long lastTimer; + protected boolean timer; + private boolean powerdown; + private boolean decodeMask; + + private static final int ZETA = 1; + + private static final int ABEL = 0; + + private int startStack; + + protected Host syscall; + + private long[] emulateOpcodeHistogram= new long[256]; + + private long[] emulateOpcodeHistogramCycles=new long[256]; + + private long emulateCycles;; + + public Simulator() throws CPUException + { + } + + + public void run() throws CPUException + { + syscall.running(); + + try + { + + instructionLoop(); + + + } catch (EndSessionException e) + { + /* done */ + } finally + { + } + dumpInfo(); + + System.err.println("Stack usage: " + (startStack-minStack)); + } + + private void dumpInfo() + { + dumpOpcodeHistogram(); + + //printMemoryHistorgram(); + } + + + private void dumpOpcodeHistogram() + { + System.out.println("Opcode histogram"); + dumpHistogram(opcodeHistogram, opcodeHistogramCycles); + System.out.println("Emulate histogram"); + dumpHistogram(emulateOpcodeHistogram, emulateOpcodeHistogramCycles); + System.out.println("Pair histogram"); + dumpHistogram(opcodePairHistogram, opcodePairHistogramCycles); + + + dumpGmon(); + + System.out.println("Grouping of LOADSP/STORESP/IM"); + printRange(64, 96); + printRange(96, 128); + printRange(128, 256); +// printRange(64, 65); +// printRange(65, 66); +// printRange(66, 64+32); +// printRange(96, 97); +// printRange(97, 98); +// printRange(98, 96+32); +// printRange(128, 129); +// printRange(129, 130); +// printRange(130, 131); +// printRange(131, 132); +// printRange(132, 133); +// printRange(252, 253); +// printRange(253, 254); +// printRange(254, 255); +// printRange(255, 256); + } + + + +// #define GMON_MAGIC "gmon" /* magic cookie */ +// #define GMON_VERSION 1 /* version number */ +// +// /* +// * Raw header as it appears on file (without padding): +// */ +// struct gmon_hdr +// { +// char cookie[4]; +// char version[4]; // a cyg_uint32, target-side endianness +// char spare[3 * 4]; +// }; +// +// /* types of records in this file: */ +// typedef enum +// { +// GMON_TAG_TIME_HIST = 0, GMON_TAG_CG_ARC = 1, GMON_TAG_BB_COUNT = 2 +// } +// GMON_Record_Tag; +// +// /* The histogram tag is followed by this header, and then an array of */ +// /* cyg_uint16's for the actual counts. */ +// +// struct gmon_hist_hdr +// { +// /* host-side gprof adapts to sizeof(void*) and endianness. */ +// /* It is assumed that the compiler does not insert padding around the */ +// /* cyg_uint32's or the char arrays. */ +// void* low_pc; /* base pc address of sample buffer */ +// void* high_pc; /* max pc address of sampled buffer */ +// cyg_uint32 hist_size; /* size of sample buffer */ +// cyg_uint32 prof_rate; /* profiling clock rate */ +// char dimen[15]; /* phys. dim., usually "seconds" */ +// char dimen_abbrev; /* usually 's' for "seconds" */ +// }; +// +// /* An arc tag is followed by a single arc record. self_pc corresponds to */ +// /* the location of an mcount() call, at the start of a function. from_pc */ +// /* corresponds to the return address, i.e. where the function was called */ +// /* from. count is the number of calls. */ +// +// struct gmon_cg_arc_record +// { +// void* from_pc; /* address within caller's body */ +// void* self_pc; /* address within callee's body */ +// cyg_uint32 count; /* number of arc traversals */ +// }; +// +// /* In theory gprof can also process basic block counts, as per the */ +// /* compiler's -fprofile-arcs flag. The compiler-generated basic block */ +// /* structure should contain a table of addresses and a table of counts, */ +// /* and the compiled code updates those counts. Current versions of the */ +// /* compiler (~3.2.1) do not output the table of addresses, and without */ +// /* that table gprof cannot process the counts. Possibly gprof should read */ +// /* in the .bb and .bbg files generated for gcov processing, but that does */ +// /* not happen at the moment. */ +// /* */ +// /* So for now gmon.out does not contain basic block counts and gprof */ +// /* operations that depend on it, e.g. --annotated-source, won't work. */ + + /** + * Write gmon.out file. + **/ + private void dumpGmon() + { + if (memory==null) + return; + try + { + ByteArrayOutputStream b=new ByteArrayOutputStream(); + + +// /* +// * Raw header as it appears on file (without padding): +// */ +// struct gmon_hdr +// { +// char cookie[4]; +// char version[4]; // a cyg_uint32, target-side endianness +// char spare[3 * 4]; +// }; +// #define GMON_MAGIC "gmon" /* magic cookie */ +// #define GMON_VERSION 1 /* version number */ + +// dump binary memory gmon.out &profile_gmon_hdr ((char*)&profile_gmon_hdr + sizeof(struct gmon_hdr)) + b.write("gmon".getBytes()); + writeLong(b, 1); // version + b.write(new byte[3*4]); // spare + +// GMON_TAG_TIME_HIST = 0, GMON_TAG_CG_ARC = 1, GMON_TAG_BB_COUNT = 2 + +// append binary memory gmon.out &profile_tags[0] &profile_tags[1] + b.write(new byte[]{0}); // GMON_TAG_TIME_HIST + + +// +// // The gprof documentation claims that this should be the size in +// // bytes. The implementation treats it as a count. +// profile_hist_hdr.hist_size = (cyg_uint32) ((text_size + bucket_size - 1) / bucket_size); +// profile_hist_hdr.low_pc = _start; +// profile_hist_hdr.high_pc = (void*)((cyg_uint8*)_end - 1); +// // The prof_rate is the frequency in hz. The resolution argument is +// // an interval in microseconds. +// profile_hist_hdr.prof_rate = 1000000 / resolution; +// +// // Now allocate a buffer for the histogram data. +// profile_hist_data = (cyg_uint16*) malloc(profile_hist_hdr.hist_size * sizeof(cyg_uint16)); +// if ((cyg_uint16*)0 == profile_hist_data) { +// diag_printf("profile_on(): cannot allocate histogram buffer - ignored\n"); +// return; +// } +// memset(profile_hist_data, 0, profile_hist_hdr.hist_size * sizeof(cyg_uint16)); + + + +// struct gmon_hist_hdr +// { +// /* host-side gprof adapts to sizeof(void*) and endianness. */ +// /* It is assumed that the compiler does not insert padding around the */ +// /* cyg_uint32's or the char arrays. */ +// void* low_pc; /* base pc address of sample buffer */ +// void* high_pc; /* max pc address of sampled buffer */ +// cyg_uint32 hist_size; /* size of sample buffer */ +// cyg_uint32 prof_rate; /* profiling clock rate */ +// char dimen[15]; /* phys. dim., usually "seconds" */ +// char dimen_abbrev; /* usually 's' for "seconds" */ +// }; + + + // maximum 65536 buckets. + int length=memory.length*4; + if (length > 60000) + { + length=60000; + } + int buckets[]=new int[length]; + for (long i=0; i<profile.length;i++) + { + buckets[(int)((i*(((long)buckets.length)-1))/(((long)profile.length)-1))]+=profile[(int)i]; + } + + + + // append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) + writeLong(b, 0); // low_pc + writeLong(b, memory.length*4); // high_pc + writeLong(b, buckets.length); // # of samples + writeLong(b, 64000000); // 64MHz + b.write("seconds".getBytes()); + b.write(new byte[15-"seconds".length()]); + b.write("s".getBytes()); + + + +// append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) + for (int i=0; i<buckets.length;i++) + { + int val; + val=buckets[i]; + if (val>65535) + { + val=65535; + } + writeShort(b, val); + } + + OutputStream o=new FileOutputStream("gmon.out"); + b.writeTo(o); + o.flush(); + o.close(); + + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + + } + + + private void writeLong(ByteArrayOutputStream b, int i) throws IOException + { + int val=i; + b.write(new byte[]{(byte)((val>>24)&0xff), + (byte)((val>>16)&0xff), + (byte)((val>>8)&0xff), + (byte)((val>>0)&0xff)}); + } + + + private void writeShort(ByteArrayOutputStream b, int i) throws IOException + { + int val=i; + b.write(new byte[]{ (byte)((val>>8)&0xff), + (byte)((val>>0)&0xff)}); + } + + + private void dumpHistogram(long[] ms, long[] ms2) + { + List<OpcodeSample> l=new LinkedList(); + + totalCycles = 0; + for (int i=0; i<256; i++) + { + totalCycles+=opcodeHistogramCycles[i]; + } + for (int i=0; i<ms.length; i++) + { + final int j=i; + l.add(new OpcodeSample(j, ms2[j])); + } + Collections.sort(l, new Comparator() + { + + public int compare(Object arg0, Object arg1) + { + OpcodeSample a=(OpcodeSample) arg0, b=(OpcodeSample) arg1; + if (a.count<b.count) + { + return 1; + } else if (a.count==b.count) + { + return 0; + } else + { + return -1; + } + } + }); + + for (int i=0; i<ms.length; i++) + { + if (totalCycles==0) + break; + double d = ((double)l.get(i).count/((double)totalCycles)); + if (d<0.005) + break; + double cycPerIns = ((double)ms2[l.get(i).j]/((double)ms[l.get(i).j])); + System.out.println("0x"+ Integer.toHexString(l.get(i).j) + " " + d + " " + l.get(i).count + " " + cycPerIns ); + } + } + + + private void printRange(int from, int to) + { + int totalLoadSP=0; + for (int i=from; i<to; i++) + { + totalLoadSP+=opcodeHistogram[i]; + } + + double d = ((double)totalLoadSP/((double)totalCycles)); + + System.out.println(""+ from + " " + d + " " + totalLoadSP); + } + + +// private void printMemoryHistorgram() +// { +// Arrays.sort(profile, new Comparator() +// { +// public int compare(Object o1, Object o2) +// { +// return (int)(((Profile)o2).counter- +// ((Profile)o1).counter); +// } +// }); +// System.err.println("Profiling information"); +// for (int i=0; i<1000; i++) +// { +// if (profile[i].counter==0) +// { +// break; +// } +// System.err.println("0x"+Integer.toHexString(profile[i].address)+ " " + profile[i].counter); +// } +// } + + + /** + * notify everybody that we are powering down + */ + public void shutdown() + { + powerdown=true; + /* wake up */ + synchronized(halt) + { + halt.notify(); + } + } + + + /** + * This method can be invoked in two cases: + * + * a) while the CPU is running on the simulator thread + * b) while the CPU is halted from other threads + */ + protected void resetHardwareInternal() throws CPUException + { + interrupt=false; + timer=false; + lastTimer=0; + hitVector=false; + instructionCount=0; + for (int i=0; i<memory.length; i++) + { + memory[i]=0; + } + + setPcToVector(VECTOR_RESET); // starting address + startStack=getStartStack(); + minStack=startStack; + changeSp(startStack); + + intSp=0; + + } + + + private void instructionLoop() throws EndSessionException, CPUException + { + /* wait for connection.... */ + for (;;) + { + try + { + + /* + * execute an instruction. + * + * If an exception happens while executing the instruction, + * invoke the approperiate exception vector. + * + * If a second exception occurs while invoking the + * exception(i.e. before the first instruction of the vector + * is executed), invoke the reboot exception. + */ + executeInstruction(); + } catch (DebuggerBreakpointException e1) + { + suspend(); + } catch (InterruptException e1) + { + armVector(VECTOR_INTERRUPT); + } catch (IllegalInstructionException e1) + { + suspend(); + } catch (MemoryAccessException e1) + { + suspend(); + } catch (CPUException e) + { + suspend(); + } catch (GDBServerException e) + { + suspend(); + } catch (IOException e) + { + e.printStackTrace(); + suspend(); + } catch (RuntimeException e) + { + e.printStackTrace(); + suspend(); + } finally + { + checkCommit(); + } + } + } + + + private void armVector(int vector) + { + // for now we always break as soon as we hit a vector + if (vector!=VECTOR_INTERRUPT) + { + // print(MINIMAL, "Vector " + vector + " armed at PC: " + formatHex(pc, "00000000")); + suspend(); + } + hitVector=true; + nextVector=vector; + } + + private void checkVector() throws CPUException + { + if (hitVector) + { + hitVector=false; + invokeVector(nextVector); + } + } + + + private void invokeVector(int vector) throws CPUException + { + push(pc); + setPcToVector(vector); + } + + private void setPcToVector(int vector) throws MemoryAccessException + { + setPc(VECTORSIZE*vector+VECTORBASE); + } + + private void executeInstruction() throws CPUException, EndSessionException, GDBServerException, IOException + { + for (;;) + { + checkHalt(); + + /* jump to any armed vector */ + checkVector(); + + checkInterrupts(); + + tracer.instructionEvent(); + + + + + + commit = false; + savedSp=getSp(); + savedPc=pc; + savedDecodeMask=decodeMask; + touchedPc=false; + + instruction=cpuReadByte(pc); + // electrons perish each time we attempt an instruction + tick(); + + if (((instruction&0x80)!=0)) + { + int t=((instruction<<(32-7)))>>(32-7); + + if (decodeMask) + { + int a; + a=(popIntStack()<<7)|(t&0x7f); + pushIntStack(a); + } else + { + pushIntStack(t); + } + decodeMask=true; + } else + { + decodeMask = false; + if (isAddSP(instruction)) + { + int offset=instruction - ADDSP; + int valAddr=sp+offset*4; + int a = popIntStack(); + pushIntStack(cpuReadLong(valAddr) + a); + } else if ((instruction >= LOADSP) && (instruction < LOADSP + 32)) + { + int addr; + addr = getSp(); + int offset=(instruction - LOADSP)^0x10; + addr += 4 * offset; + pushIntStack(cpuReadLong(addr)); + } else if (isStoreSP(instruction)) + { + int addr; + addr = getSp(); + int offset=(instruction - STORESP)^0x10; + addr += 4 * offset; + + cpuWriteLong(addr, popIntStack()); + } else + { + int addr; + int val; + switch (instruction) + { + case 0: + throw new DebuggerBreakpointException(); + + case PUSHPC: + pushIntStack(pc); + break; + case OR: + pushIntStack(popIntStack() | popIntStack()); + break; + case NOT: + pushIntStack(popIntStack() ^ 0xffffffff); + break; + case LOAD: + pushIntStack(cpuReadLong(popIntStack())); + break; + case PUSHSPADD: + if (feeble[PUSHSPADD]) + { + emulate(); + } else + { + int a; + int b; + a=sp; + b=popIntStack()*4; + pushIntStack(a+b); + } + break; + case STORE: + addr = popIntOrExt(); + val = popIntOrExt(); + cpuWriteLong(addr, val); + break; + case POPPC: + { + // NB!!!! does NOT flush internal stack + int a; + if (intSp>0) + { + a=popIntStack(); + } else + { + a=pop(); + } + + if ((sp>=emulateSp)&&(emulateInProgress)) + { + emulateInProgress=false; + /* we returned from an emulate instruction */ + emulateOpcodeHistogram[emulateOpcode]++; + emulateOpcodeHistogramCycles[emulateOpcode]+=cycles-emulateCycles; + } + + setPc(a); + break; + } + case POPPCREL: + if (feeble[POPPCREL]) + { + emulate(); + } else + { + setPc(popIntStack()+getPc()); + } + break; + case FLIP: + pushIntStack(flip(popIntStack())); + break; + case ADD: + pushIntStack(popIntStack() + popIntStack()); + break; + case SUB: + if (feeble[SUB]) + { + emulate(); + } else + { + int a=popIntStack(); + int b=popIntStack(); + pushIntStack(b-a); + } + break; + case PUSHSP: + pushIntStack(getSp()); + break; + case POPSP: + changeSp(popIntStack()); + intSp=0; // flush internal stack + break; + case NOP: + break; + case AND: + pushIntStack(popIntStack() & popIntStack()); + break; + case XOR: + if (feeble[XOR]) + { + emulate(); + } else + { + pushIntStack(popIntStack() ^ popIntStack()); + } + break; + case LOADB: + if (feeble[LOADB]) + { + emulate(); + } else + { + pushIntStack(cpuReadByte(popIntStack())); + } + break; + case STOREB: + if (feeble[STOREB]) + { + emulate(); + } else + { + addr = popIntStack(); + val = popIntStack(); + cpuWriteByte(addr, val); + } + break; + case LOADH: + if (feeble[LOADH]) + { + emulate(); + } else + { + pushIntStack(cpuReadWord(popIntStack())); + } + break; + case STOREH: + if (feeble[STOREH]) + { + emulate(); + } else + { + addr = popIntStack(); + val = popIntStack(); + cpuWriteWord(addr, val); + } + break; + case LESSTHAN: + if (feeble[LESSTHAN]) + { + emulate(); + } else + { + int a; + int b; + a = popIntStack(); + b = popIntStack(); + pushIntStack((a < b) ? 1 : 0); + } + break; + case LESSTHANOREQUAL: + if (feeble[LESSTHANOREQUAL]) + { + emulate(); + } else + { + int a; + int b; + a = popIntStack(); + b = popIntStack(); + pushIntStack((a <= b) ? 1 : 0); + } + break; + case ULESSTHAN: + if (feeble[ULESSTHAN]) + { + emulate(); + } else + { + long a; + long b; + a = ((long) popIntStack()) & INTMASK; + b = ((long) popIntStack()) & INTMASK; + pushIntStack((a < b) ? 1 : 0); + } + break; + case ULESSTHANOREQUAL: + if (feeble[ULESSTHANOREQUAL]) + { + emulate(); + } else + { + long a; + long b; + a = ((long) popIntStack()) & INTMASK; + b = ((long) popIntStack()) & INTMASK; + pushIntStack((a <= b) ? 1 : 0); + } + break; + + case SWAP: +// if (feeble[SWAP]) +// { +// emulate(); +// } else + { + int swapVal=popIntStack();; + pushIntStack(((swapVal >>16)&0xffff)|(swapVal<<16)); + } + break; + case MULT16X16: +// if (feeble[SWAP]) +// { +// emulate(); +// } else + { + int a=popIntStack(); + int b=popIntStack(); + pushIntStack((a&0xffff)*(b&0xffff)); + } + break; + case EQBRANCH: + if (feeble[EQBRANCH]) + { + emulate(); + } else + { + int compare; + int target; + target = popIntStack() + pc; + compare = popIntStack(); + if (compare == 0) + { + setPc(target); + } else + { + setPc(pc + 1); + } + } + break; + + case NEQBRANCH: + if (feeble[NEQBRANCH]) + { + emulate(); + } else + { + int compare; + int target; + target = popIntStack() + pc; + compare = popIntStack(); + if (compare != 0) + { + setPc(target); + } else + { + setPc(pc + 1); + } + } + break; + + case MULT: + if (feeble[MULT]) + { + emulate(); + } else + { + pushIntStack(popIntStack() * popIntStack()); + } + break; + case DIV: + if (feeble[DIV]) + { + emulate(); + } else + { + int a; + int b; + a = popIntStack(); + b = popIntStack(); + if (b == 0) + { + throw new CPUException(); + } + pushIntStack(a / b); + } + break; + case MOD: + if (feeble[MOD]) + { + emulate(); + } else + { + int a; + int b; + a = popIntStack(); + b = popIntStack(); + if (b == 0) + { + throw new CPUException(); + } + pushIntStack(a % b); + } + break; + + case LSHIFTRIGHT: + if (feeble[LSHIFTRIGHT]) + { + emulate(); + } else + { + long shift; + long valX; + int t; + shift = ((long) popIntStack()) & INTMASK; + valX = ((long) popIntStack()) & INTMASK; + t = (int) (valX >> (shift & 0x3f)); + pushIntStack(t); + } + break; + + case ASHIFTLEFT: + if (feeble[ASHIFTLEFT]) + { + emulate(); + } else + { + long shift; + long valX; + shift = ((long) popIntStack()) & INTMASK; + valX = ((long) popIntStack()) & INTMASK; + int t = (int) (valX << (shift & 0x3f)); + pushIntStack(t); + } + break; + + case ASHIFTRIGHT: + if (feeble[ASHIFTRIGHT]) + { + emulate(); + } else + { + long shift; + int valX; + shift = ((long) popIntStack()) & INTMASK; + valX = popIntStack(); + int t = valX >> (shift & 0x3f); + pushIntStack(t); + } + break; + + case CALL: + if (feeble[CALL]) + { + emulate(); + } else + { + intSp=0; // flush internal stack + int address = pop(); + push(pc + 1); + setPc(address); + } + break; + case CALLPCREL: + if (feeble[CALLPCREL]) + { + emulate(); + } else + { + intSp=0; // flush internal stack + int address = pop(); + push(pc + 1); + setPc(address+pc); + } + break; + + case EQ: + if (feeble[EQ]) + { + emulate(); + } else + { + pushIntStack((popIntStack() == popIntStack()) ? 1 : 0); + } + break; + + case NEQ: + if (feeble[NEQ]) + { + emulate(); + } else + { + pushIntStack((popIntStack() != popIntStack()) ? 1 : 0); + } + break; + + case NEG: + if (feeble[NEG]) + { + emulate(); + } else + { + pushIntStack(-popIntStack()); + } + break; + + + case CONFIG: + if (emulateConfig()) + { + emulate(); + cpu=ABEL; + } else + { + cpu = popIntStack(); + } + switch (cpu) + { + case ABEL: + System.err.println("ZPU feeble instruction set"); + for (int i = 0; i < feeble.length; i++) + { + feeble[i] = true; + } + + setFeeble(); + + break; + case ZETA: + System.err.println("ZPU full instruction set"); + for (int i = 0; i < feeble.length; i++) + { + feeble[i] = false; + } + break; + default: + break; + } + break; + + case SYSCALL: + if (feeble[SYSCALL]) + { + throw new IllegalInstructionException(); + } else + { + intSp=0; // flush internal stack + syscall.syscall(this); + } + break; + + default: + throw new IllegalInstructionException(); + } + } + } + if (!touchedPc) + { + setPc(pc + 1); + } + committed(); + + // one more instruction retired + instructionCount++; + } + } + + + protected void setFeeble() + { + feeble[NEQBRANCH] = false; + feeble[EQ] = false; + feeble[LOADB] = false; + feeble[LESSTHAN] = false; + feeble[ULESSTHAN] = false; + feeble[STOREB] = false; + feeble[MULT] = false; + feeble[CALL] = true; + feeble[POPPCREL] = true; + feeble[LESSTHANOREQUAL] = true; + feeble[ULESSTHANOREQUAL] = true; + + feeble[PUSHSPADD] = false; + feeble[CALLPCREL] = false; + feeble[SUB] = false; + } + + + private int popIntOrExt() + { + int a; + if (intSp==0) + { + a=pop(); + } else + { + a=popIntStack(); + } + return a; + } + + int intSp; + + private int emulateSp; + + private int emulateOpcode; + + private boolean emulateInProgress; + + protected boolean timerPending; + + private boolean inInterrupt; + private int popIntStack() + { +// if (intSp<=0) +// throw new IllegalInstructionException(); + intSp--; + return pop(); + } + + private void pushIntStack(int x) + { +// if (intSp>=32) +// throw new IllegalInstructionException(); + push(x); + intSp++; + } + + + + private static boolean isAddSP(int instruction) + { + return (instruction >= ADDSP) && (instruction < ADDSP + 16); + } + + + private static boolean isStoreSP(int instruction) + { + return (instruction >= STORESP) && (instruction < STORESP + 32); + } + + + protected boolean emulateConfig() + { + return false; + } + + + private void checkCommit() throws CPUException + { + if (!commit) + { + decodeMask=savedDecodeMask; + pc=savedPc; + setSp(savedSp); + committed(); + } + } + + + private void committed() + { + commit=true; + tracer.commit(); + } + + + private void emulate() throws CPUException + { + // NB! Do NOT flush internal stack +// intSp=0; // flush internal stack + /* three total overhead to emulate instruction */ + if (!emulateInProgress) + { + emulateInProgress=true; + emulateSp = sp; + emulateOpcode = getOpcode(); + emulateCycles = cycles; + } + pushIntStack(pc+1); + setPc((cpuReadByte(pc)-32)*VECTORSIZE+VECTORBASE); + } + + + + private void checkInterrupts() throws InterruptException + { + if (!tracer.simInterrupt()) + { + /* These flags are set *regardless* of interrupt state. */ + while (lastTimer+timerInterval<cycles) + { + if (timerInterval>0) + { + lastTimer+=timerInterval; + } else + { + lastTimer=cycles; + } + timerPending=true; + } + } + + if (!interrupt) + return; + + /* if we are in the middle of decoding an instruction, no interrupt */ + if (decodeMask) + { + return; + } + if (tracer.simInterrupt()) + { + if (!tracer.onInterrupt()) + { + inInterrupt=false; + } + if (inInterrupt) + { + return; + } + /* Use trace information instead of trying to figure out when an interrupt happens. We don't try + * to simulate anything more complicated than timer interrupts so we don't need to worry about source. + */ + + if (tracer.onInterrupt()&&!inInterrupt) + { + if (!timer) + { + throw new IllegalInstructionException(); + } + + inInterrupt=true; + timerPending=true; + throw new InterruptException(); + } + + } else + { + if (!timerPending) + inInterrupt=false; + + if (inInterrupt) + { + return; + } + + if (timer&&timerPending) + { + inInterrupt=true; + throw new InterruptException(); + } + } + } + + + + + private void cpuWriteWord(int addr, int val) throws MemoryAccessException + { + if ((addr&0x1)!=0) + { + throw new MemoryAccessException(); + } + for (int i=0; i<2; i++) + { + writeByte(addr+i, val>>(8*(1-i))); + } + } + + /** + * @param i + * @return + * @throws MemoryAccessException + */ + private int cpuReadWord(int addr) throws MemoryAccessException + { + if ((addr&0x1)!=0) + { + throw new MemoryAccessException(); + } + return ((readByteInternal(addr+0)&0xff)<<8) | (readByteInternal(addr+1)&0xff); + } + + private void cpuWriteByte(int addr, int val) throws MemoryAccessException + { + writeByte(addr, val); + } + + + protected boolean interrupt; + protected long timerInterval; + private boolean touchedPc; + + private boolean accessWatchPoint; + + private int accessWatchPointAddress; + + private int accessWatchPointLength; + + private boolean commit; + + private boolean savedDecodeMask; + + private int savedSp; + + private int savedPc; + + private long[] profile; + + private int cpu; + + private long sampledCycle; + + private Tracer tracer=new Tracer() + { + + public void instructionEvent() + { + + } + + public void commit() + { + } + + public void setSp(int sp) + { + } + + public void dumpTraceBack() + { + + } + + public boolean onInterrupt() + { + return false; + } + + public boolean simInterrupt() + { + return false; + } + + }; + + private int instruction; + + private long totalCycles; + + + private String traceFileName; + + private int prevOpcode; + + private long prevCycles2; + + private int prevOpcode2; + + + + + /** + * checks if the CPU should halt, and halts. Fn. returns when the + * CPU has resumed execution. + * @throws EndSessionException + */ + private void checkHalt() throws EndSessionException + { + synchronized(halt) + { + if (powerdown) + { + throw new EndSessionException(); + } + + if (breakNext) + { + breakNext=false; + + halt.notify(); + try + { + syscall.halted(); + halt.wait(); + syscall.running(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + if (powerdown) + { + throw new EndSessionException(); + } + } + } + + private int flip(int i) + { + int t=0; + for (int j=0; j<32; j++) + { + t|=((i>>j)&1)<<(31-j); + } + return t; + } + + /** the CPU is writing a long during execution */ + public void cpuWriteLong(int addr, int val) throws MemoryAccessException + { + if (accessWatchPoint&&(addr==accessWatchPointAddress)) + { + suspend(); + } + if ((addr&0x3)!=0) + { + throw new MemoryAccessException(); + } + if ((addr>=getIO())&&(addr<getIO()+IOSIZE)) + { + ioWrite(addr, val); + } else if ((addr>=0)&&(addr<=memory.length*4)) + { + memory[addr/4]=val; + validMemory[addr/4]=true; + } else + { + throw new MemoryAccessException(); + } + } + + public void writeByte(int addr, int val) throws MemoryAccessException + { + if ((addr>=0)&&(addr<memory.length*4)) + { + memory[addr/4]=(memory[addr/4]&(~(0xff<<((3-addr&3)*8))))|((val&0xff)<<((3-addr&3)*8)); + } else + { + throw new MemoryAccessException(); + } + } + + protected void ioWrite(int addr, int val) throws MemoryAccessException + { + addr-=getIO(); + /* note, big endian! */ + switch (addr) + { + case 12: + syscall.writeUART(val); + break; + case 20: + interrupt=val!=0; + break; + case 28: + timerInterval=val; + break; + case 32: + timer=val!=0; + break; + case 0x24: + syscall.writeUART(val); + break; + case 0x100: + writeTimerSampleReg(val); + break; + default: + break; + } + + } + + + + + protected void writeTimerSampleReg(int val) + { + if ((val&0x2)!=0) + { + sampledCycle=getSampleOffset(); // we need a fudge factor to make up for differences in when relative to the instruction the data is sampled. + } + } + + + protected long getSampleOffset() + { + return cycles+2+0xd-(0x8e-0x74); + } + + + + protected int ioRead(int addr) throws CPUException + { + addr-=getIO(); + /* note, big endian! */ + switch (addr) + { + case 20: + return interrupt?1:0; + + case 32: + return timer?1:0; + + case 0x24: + return syscall.readUART(); + + /* FIFO empty? bit 0, FIFO full bit 1(never the case) */ + case 0x28: + return syscall.readFIFO(); + + case 0x100: + case 0x104: + case 0x108: + case 0x10c: + + case 0x110: + case 0x114: + case 0x118: + case 0x11c: + return readSampledTimer(addr, 0x100); + + case 0x200: + return readMHz(); + + default: + throw new MemoryAccessException(); + } + } + + + + + protected int readMHz() + { + /* 90 MHz */ + return 100; + } + + + protected int readSampledTimer(int addr, int base) + { + int t=0; + t=(int)((sampledCycle>>(((addr-base)/4)*32))&0xffffffff); + return t; + } + + + + private int cpuReadByte(int addr) throws MemoryAccessException + { + return readByteInternal(addr); + } + + + /** this is the CPU reading a long word during execution */ + public int cpuReadLong(int addr) throws CPUException + { + if (accessWatchPoint&&(addr==accessWatchPointAddress)) + { + suspend(); + } + if ((addr&0x3)!=0) + { + throw new MemoryAccessException(); + } + if ((addr>=getIO())&&(addr<getIO()+IOSIZE)) + { + return ioRead(addr); + } else if ((addr>=0)&&(addr<=memory.length*4)) + { + return memory[addr/4]; + } else + { + throw new MemoryAccessException(); + } + } + + /** + * Causes a cycle to pass. + * @throws MemoryAccessException + */ + /** increase time and record how long we spent on this instruction */ + private void tick() throws MemoryAccessException + { + profile[pc]++; + int opcode; + opcode=readByte(pc); + opcodeHistogram[prevOpcode]++; + opcodeHistogramCycles[prevOpcode]+=cycles-prevCycles; + int opcodePair=groupOpcode(prevOpcode2)*256+groupOpcode(prevOpcode); + + opcodePairHistogram[opcodePair]++; + opcodePairHistogramCycles[opcodePair]+=cycles-prevCycles2; + + prevOpcode2=prevOpcode; + prevOpcode=opcode; + + + + prevCycles2=prevCycles; + prevCycles=cycles; + cycles++; + } + + private int groupOpcode(int instruction) + { + if (isAddSP(instruction)) + { + return ADDSP; + } else if ((instruction >= LOADSP) && (instruction < LOADSP + 32)) + { + return LOADSP; + } else if (isStoreSP(instruction)) + { + return STORESP; + } + + if ((instruction&0x80)!=0) + return 0x80; + return instruction; + } + + + public int readByte(int addr) throws MemoryAccessException + { + if ((addr>=0)&&(addr<memory.length*4)) + { + return readByteInternal(addr); + } else + { + throw new MemoryAccessException(); + } + } + + + protected int readByteInternal(int addr) throws MemoryAccessException + { + return (memory[addr/4]>>((3-addr&0x3)*8))&0xff; + } + + private int pop() throws CPUException + { + int val; + validMemory[getSp()/4]=false; + val=cpuReadLong(getSp()); + setSp(getSp() + 4); + return val; + } + + private void push(int imm) throws CPUException + { + setSp(getSp() - 4); + cpuWriteLong(getSp(), imm); + } + + private final class OpcodeSample + { + private final int j; + + int opcode; + + long count; + + private OpcodeSample(int j, long l) + { + this.j = j; + opcode = j; + count = l; + } + } + + + + + private void initRam() + { + memory = (new int[getRAMSIZE()/4]); + validMemory = new boolean[getRAMSIZE()/4]; + for (int i=0; i<validMemory.length; i++) + { + validMemory[i]=true; + } + + profile = new long[getRAMSIZE()]; + } + + + + public void setPc(int pc) throws MemoryAccessException + { + if ((pc<VECTORBASE)||(pc>memory.length*4)) + { + throw new MemoryAccessException(); + } + this.pc = pc; + touchedPc=true; + } + + public int getPc() + { + return pc; + } + + /** resume execution. This function returns when the CPU halts again. */ + public void cont() + { + for (;;) + { + synchronized(halt) + { + halt.notify(); + try + { + halt.wait(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + if (syscall.doneContinue()) + { + break; + } + } + } + + /** resume execution. This function returns when the CPU halts again. */ + public void step() + { + synchronized(halt) + { + suspend(); + cont(); + } + } + + + + public int getReg(int regNum) throws CPUException + { + if ((regNum>=0)&&(regNum<32)) + { + return memory[regNum]; + } else if (regNum==32) + { + return getSp(); + } else if (regNum==33) + { + return pc; + } else + { + throw new RuntimeException("Illegal getReg()"); + } + } + + public int getREGNUM() + { + return 34; + } + + public long getCycleCounter() + { + return cycles; + } + + public void addWaitStates(int num) + { + } + + /** tells simulator to enter the suspended state */ + public void suspend() + { + synchronized(halt) + { + breakNext=true; + } +// tracer.dumpTraceBack(); + } + + + public long getPrevCycles() + { + return prevCycles; + } + + public long getCycles() + { + return cycles; + } + + + public void enableAccessWatchPoint(int address, int length) throws CPUException + { + if (accessWatchPoint) + { + throw new HardwareWatchPointException(); + } + accessWatchPointAddress=address; + accessWatchPointLength=length; + accessWatchPoint=true; + } + public void disableAccessWatchPoint(int address, int length) throws CPUException + { + if (!accessWatchPoint) + { + throw new HardwareWatchPointException(); + } + if ((address!=accessWatchPointAddress)||(length!=accessWatchPointLength)) + { + throw new HardwareWatchPointException(); + } + + accessWatchPoint=false; + } + + /** POPSP changes the stack pointer */ + public void changeSp(int sp) throws CPUException + { + setSp(sp); + tracer.setSp(sp); + } + + public void setSp(int sp) throws CPUException + { + if ((sp%4)!=0) + { + throw new IllegalInstructionException(); + } + + if (sp<minStack) + { + minStack=sp; + } + + + this.sp = sp; + } + + + public int getSp() + { + return sp; + } + public int getIntSp() + { + return (intSp+(INTSTACKSIZE-1))%INTSTACKSIZE; + } + + + + + protected int getIO() + { + return 0x80000000; + } + + + protected int getRAMSIZE() + { + return (2*1024*1024); + } + + protected int getStartStack() + { + return memory.length*4-0x10000; + } + + + public void setTraceFile(String string) + { + traceFileName=string; + } + + + public void setSyscall(Host syscall) + { + this.syscall=syscall; + } + + + public void loadImage(InputStream inputStream, int length) throws IOException, CPUException + { + if (length==-1) + throw new IOException("File image length not known"); + for (int i=0; i<length; i++) + { + int t=inputStream.read(); + writeByte(0+i, t); + } + + } + + public int getArg(int num) throws CPUException + { + return cpuReadLong(getSp()+4+num*4); + } + + + public int getOpcode() throws MemoryAccessException + { + return readByte(pc); + } + + static final int INTSTACKSIZE=32; + + public boolean checkMatch(Trace trace) + { + cycles=trace.cycle; + if (!trace.undefinedIntSp) + { + if (trace.intSp!=((intSp+(INTSTACKSIZE-1))%INTSTACKSIZE)) + return false; + } + + if ((getPc() != trace.pc) || (getSp() != trace.sp) + || (getOpcode() != trace.opcode)) + { + return false; + } + + if (cpuReadLong(getSp()) == trace.stackA) + { + if (cpuReadLong(getSp() + 4) == trace.stackB) + { + return true; + } + } + if ((!validMemory[getSp()/4])||cpuReadLong(getSp()) == trace.stackA) + { + if ((!validMemory[(getSp()+4)/4])||cpuReadLong(getSp() + 4) == trace.stackB) + { +// System.out.println("Undefined memory location mismatch"); + return true; + } + } + if (!trace.undefinedIntSp) + { + if ((intSp<1)||cpuReadLong(getSp()) == trace.stackA) + { + if ((intSp<2)||cpuReadLong(getSp() + 4) == trace.stackB) + { + return true; + } + } + } + return false; + } + + + public void sessionStarted() + { + if (traceFileName!=null) + { + tracer = new FileTracer(this, traceFileName); + } + + /* Set the feeble flag to enable/disable instructions here */ + initRam(); + resetHardwareInternal(); + + + + } + + + void printState(FileTracer fileTracer) + { + System.err.println("intSp: " + getIntSp()); + System.err.println(Integer.toHexString(getPc())+ " " + + Integer.toHexString(getOpcode()) + " " + + Integer.toHexString(getSp()) + " " + + Integer.toHexString(cpuReadLong(getSp())) + " " + + Integer.toHexString(cpuReadLong(getSp()+4))); + } + + + + + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/State.java b/zpu/sw/simulator/com/zylin/zpu/simulator/State.java new file mode 100644 index 0000000..c2cb9f4 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/State.java @@ -0,0 +1,9 @@ +package com.zylin.zpu.simulator; + + +public class State +{ + + public long cycle; + public int insn; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/Tracer.java b/zpu/sw/simulator/com/zylin/zpu/simulator/Tracer.java new file mode 100644 index 0000000..31f1766 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/Tracer.java @@ -0,0 +1,21 @@ + +package com.zylin.zpu.simulator; + +import com.zylin.zpu.simulator.exceptions.GDBServerException; + +public interface Tracer +{ + + void instructionEvent() throws GDBServerException; + + void commit(); + + void setSp(int sp); + + void dumpTraceBack(); + + + boolean onInterrupt(); + + boolean simInterrupt(); +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/ZPU.java b/zpu/sw/simulator/com/zylin/zpu/simulator/ZPU.java new file mode 100644 index 0000000..84a1ca5 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/ZPU.java @@ -0,0 +1,14 @@ +package com.zylin.zpu.simulator; + +public interface ZPU +{ + /** + * number of cycles passed since reboot + */ + long getCycleCounter(); + + /** + * Wait this many cycles + */ + void addWaitStates(int i); +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/applet/ZPUApplet.java b/zpu/sw/simulator/com/zylin/zpu/simulator/applet/ZPUApplet.java new file mode 100644 index 0000000..731c8fc --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/applet/ZPUApplet.java @@ -0,0 +1,281 @@ + +package com.zylin.zpu.simulator.applet; + +import java.applet.Applet; +import java.awt.TextArea; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import javax.swing.SwingUtilities; + +import com.zylin.zpu.simulator.Host; +import com.zylin.zpu.simulator.Sim; +import com.zylin.zpu.simulator.Simulator; +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.UnsupportedSyscallException; + +public class ZPUApplet extends Applet implements Host +{ + + private static final long serialVersionUID = 1L; + private TextArea console; + private Simulator simulator; + private PipedOutputStream outputPipe; + private PipedInputStream inputPipe; + + public void init() + { + super.init(); + + console=new TextArea(); + //console.setEditable(false); + + + console.addKeyListener(new KeyListener() + { + + public void keyPressed(KeyEvent e) + { + try + { + outputPipe.write((int)e.getKeyChar()); + } catch (Throwable e1) + { + e1.printStackTrace(); + } + + } + + public void keyReleased(KeyEvent e) + { + + } + + public void keyTyped(KeyEvent e) + { + + } + }); + + //Add the text field to the applet. + add(console); + + //Set the layout manager so that the text field will be + //as wide as possible. + setLayout(new java.awt.GridLayout(1,0)); + + validate(); + initSimulator(); + + } + + + + + + public void start() + { + super.start(); + } + + + + + + public void stop() + { + simulator.shutdown(); + super.stop(); + } + + private void initSimulator() + { + final ZPUApplet me = this; + + try + { + outputPipe = new PipedOutputStream(); + inputPipe = new PipedInputStream(outputPipe); + + showStatus("Loading ZPU binary image..."); + + Thread thread = new Thread(new Runnable() { + public void run() { + try { + // lineReader=new LineNumberReader(new + // InputStreamReader(inputPipe)); + + simulator = new Simulator(); + simulator.setSyscall(me); + + String file = getParameter("executable"); + + URL url; + url = new URL(getCodeBase(), file); + showStatus("Loading: " + url.toString() +"..."); + + URLConnection connection = url.openConnection(); + + simulator.loadImage(connection.getInputStream(), connection.getContentLength()); + + simulator.run(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + thread.start(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void syscall(Sim s) throws CPUException + { + int retval=-1; + int syscallErrno=0; + int id; + id=simulator.getArg(1); + try + { + switch (id) + { + case SYS_write: + writeToConsole(); + retval=simulator.getArg(4); + break; + case SYS_read: + int i; + for (i=0; i<simulator.getArg(4); i++) + { + int t=inputPipe.read(); + simulator.writeByte(simulator.getArg(3)+i, t); + if ((t=='\n')||(t=='\r')) + { + /* done reading line */ + i++; + break; + } + } + retval=i; + break; + + case SYS_fstat: + syscallErrno=EIO; + retval=-1; + break; + + default: + simulator.suspend(); + throw new UnsupportedSyscallException(); + } + } + catch (IOException e) + { + retval=-1; + syscallErrno=EIO; + } + simulator.cpuWriteLong(simulator.getArg(0), syscallErrno); + simulator.cpuWriteLong(0, retval); + } + + private void writeToConsole() throws CPUException + { + String t=""; + for (int i=0; i<simulator.getArg(4); i++) + { + t+=(char)simulator.readByte(simulator.getArg(3)+i); + } + final String t2=t; + System.out.println(t2); + try { + SwingUtilities.invokeAndWait(new Runnable() + { + public void run() + { + console.append(t2); + } + }); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + + + public boolean doneContinue() + { + return false; + } + + + public void writeUART(final int val) + { + try { + SwingUtilities.invokeAndWait(new Runnable() + { + + public void run() + { + console.append(""+(char)(val)); + repaint(); + + } + }); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + + + + + public int readUART() throws CPUException + { + try + { + return inputPipe.read(); + } catch (IOException e) + { + e.printStackTrace(); + throw new CPUException(); + } + } + + + + + + public int readFIFO() + { + return 0; + } + + public void halted() + { + showStatus("ZPU application halted"); + } + + public void running() + { + showStatus("ZPU application running..."); + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/BadPacketException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/BadPacketException.java new file mode 100644 index 0000000..2e66ab4 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/BadPacketException.java @@ -0,0 +1,22 @@ +/* + * Created on Nov 6, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class BadPacketException extends GDBServerException +{ + + /** + * + */ + private static final long serialVersionUID = 3258131340821214260L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/CPUException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/CPUException.java new file mode 100644 index 0000000..6a3f4fe --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/CPUException.java @@ -0,0 +1,23 @@ +/* + * Created on Oct 23, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class CPUException extends GDBServerException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/DebuggerBreakpointException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/DebuggerBreakpointException.java new file mode 100644 index 0000000..2360fa8 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/DebuggerBreakpointException.java @@ -0,0 +1,10 @@ +package com.zylin.zpu.simulator.exceptions; + +public class DebuggerBreakpointException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/EndSessionException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/EndSessionException.java new file mode 100644 index 0000000..13fc875 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/EndSessionException.java @@ -0,0 +1,46 @@ +/* + * Created on Nov 16, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class EndSessionException extends Exception +{ + + public EndSessionException() + { + super(); + // TODO Auto-generated constructor stub + } + + public EndSessionException(String arg0, Throwable arg1) + { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public EndSessionException(String arg0) + { + super(arg0); + // TODO Auto-generated constructor stub + } + + public EndSessionException(Throwable arg0) + { + super(arg0); + // TODO Auto-generated constructor stub + } + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/GDBServerException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/GDBServerException.java new file mode 100644 index 0000000..8232790 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/GDBServerException.java @@ -0,0 +1,25 @@ +package com.zylin.zpu.simulator.exceptions; + + +public class GDBServerException extends RuntimeException +{ + /** + * + */ + private static final long serialVersionUID = 1L; + + public GDBServerException(NumberFormatException e) + { + super(e); + } + + public GDBServerException() + { + + } + + public GDBServerException(Exception e) + { + super(e); + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/HardwareWatchPointException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/HardwareWatchPointException.java new file mode 100644 index 0000000..a4ad3b2 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/HardwareWatchPointException.java @@ -0,0 +1,12 @@ + +package com.zylin.zpu.simulator.exceptions; + +public class HardwareWatchPointException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/IllegalInstructionException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/IllegalInstructionException.java new file mode 100644 index 0000000..a8d0802 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/IllegalInstructionException.java @@ -0,0 +1,23 @@ +/* + * Created on Oct 23, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class IllegalInstructionException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/InterruptException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/InterruptException.java new file mode 100644 index 0000000..bd74f04 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/InterruptException.java @@ -0,0 +1,23 @@ +/* + * Created on 02.jan.2005 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class InterruptException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/MemoryAccessException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/MemoryAccessException.java new file mode 100644 index 0000000..4c9ebae --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/MemoryAccessException.java @@ -0,0 +1,23 @@ +/* + * Created on Oct 23, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class MemoryAccessException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/NoAckException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/NoAckException.java new file mode 100644 index 0000000..377f9de --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/NoAckException.java @@ -0,0 +1,22 @@ +/* + * Created on Nov 6, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.exceptions; + +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class NoAckException extends GDBServerException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/TraceException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/TraceException.java new file mode 100644 index 0000000..45fda54 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/TraceException.java @@ -0,0 +1,22 @@ + +package com.zylin.zpu.simulator.exceptions; + + +public class TraceException extends GDBServerException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + public TraceException(Exception e) + { + super(e); + } + + public TraceException() + { + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnknownPacketException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnknownPacketException.java new file mode 100644 index 0000000..af8a667 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnknownPacketException.java @@ -0,0 +1,10 @@ +package com.zylin.zpu.simulator.exceptions; + +public class UnknownPacketException extends GDBServerException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnsupportedSyscallException.java b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnsupportedSyscallException.java new file mode 100644 index 0000000..6b214f1 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/exceptions/UnsupportedSyscallException.java @@ -0,0 +1,12 @@ + +package com.zylin.zpu.simulator.exceptions; + +public class UnsupportedSyscallException extends CPUException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/GDBServer.java b/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/GDBServer.java new file mode 100644 index 0000000..182e426 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/GDBServer.java @@ -0,0 +1,364 @@ +/** + * Handles TCP/IP communication between simulator and GDB + */ + +package com.zylin.zpu.simulator.gdb; + +import java.io.IOException; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.Iterator; + +import com.zylin.zpu.simulator.Host; +import com.zylin.zpu.simulator.Sim; +import com.zylin.zpu.simulator.SimApp; +import com.zylin.zpu.simulator.exceptions.BadPacketException; +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.EndSessionException; +import com.zylin.zpu.simulator.exceptions.GDBServerException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; +import com.zylin.zpu.simulator.exceptions.UnsupportedSyscallException; + +public class GDBServer implements Host +{ + /* logging filter */ + static final boolean UNKNOWN=false; + static final boolean ALL=false; + static final boolean CPUEXCEPTION = false; + static protected boolean MINIMAL=true; + static boolean PACKET=true; + static boolean REPLY=true; + static protected boolean IGNOREDEXCEPTIONS=false; + + + + protected Throwable packetException; + protected Object packetReady=new Object(); + private Packet packet; + boolean done; + private Socket sc; + public boolean alive; + static private int sessionNr; + private SimApp app; + Sim simulator; + + public GDBServer(Sim simulator, SimApp app) + { + this.simulator=simulator; + this.app=app; + } + + void print(boolean filter, String str) + { + if (filter) + { + System.out.println(str); + } + } + + /** infinite loop that waits for debug sessions to be initiated via TCP/IP */ + public void gdbServer() throws MemoryAccessException, IOException, GDBServerException, EndSessionException + { + sc=app.serverSocket.accept(); + try + { + debugSession(); + } catch (IOException e) + { + // the session failed... + if (IGNOREDEXCEPTIONS) + { + e.printStackTrace(); + } + } catch (GDBServerException e) + { + // connect failed... + if (IGNOREDEXCEPTIONS) + { + e.printStackTrace(); + } + } catch (EndSessionException e) + { + } catch (Throwable e) + { + // some terrible unforseen failure. + e.printStackTrace(); + } finally + { + sc.close(); + } + } + + + + protected void sleepABit() + { + try + { + // just to avoid locking up the machine in a busy loop when + // debugging the Simulator + Thread.sleep(2000); + } catch (InterruptedException e1) + { + e1.printStackTrace(); + } + } + + private void debugSession() throws IOException, GDBServerException, EndSessionException, MemoryAccessException + { + print(MINIMAL, "GDB server waiting for connection " + sessionNr++ + "..."); + + try + { + sessionStarted(); + + expect('+'); // connection ack. + + sessionLoop(); + } finally + { + print(MINIMAL, "Session ended"); + } + + } + + private void sessionStarted() + { + simulator.sessionStarted(); + print(MINIMAL, "Session started"); + } + + + private void sessionLoop() throws IOException, EndSessionException + { + alive=true; + while (alive) + { + try + { + /* wait for new packet to arrive and notify the packet execution thread... */ + packet=new Packet(this); + packet.receive(); + + // During execution we can receive an abort/suspend command... + packet.parseAndExecute(); + + if (!alive) + throw new EndSessionException(); + } catch (BadPacketException e) + { + // do nothing. + if (IGNOREDEXCEPTIONS) + { + e.printStackTrace(); + } + sleepABit(); + } catch (GDBServerException e) + { + if (IGNOREDEXCEPTIONS) + { + e.printStackTrace(); + } + // continue processing packets + sleepABit(); + } + } + } + + + + + void expect(char nextChar) throws IOException, GDBServerException + { + int t = read(); + if (t!=nextChar) + { + throw new BadPacketException(); + } + } + + int read() throws IOException + { + flush(); + int t=sc.getInputStream().read(); + if (t==-1) + throw new IOException(); + return t; + } + + /** + * @param value + * @return + */ + protected String printHex(int value) + { + return formatHex(value, "00000000"); + } + + /** + * @param value + * @param pad TODO + * @return + */ + protected String formatHex(int value, String pad) + { + String t=Integer.toHexString(value); + if (t.length()>pad.length()) + { + t=t.substring(0, pad.length()); + } + return pad.substring(0, pad.length()-t.length())+t; + } + + public void write(byte[] bytes) throws IOException + { + sc.getOutputStream().write(bytes); + } + + void flush() throws IOException + { + sc.getOutputStream().flush(); + } + + + private boolean enterSyscall; + + + + /* handle all sorts of IO calls, etc. by sending them to the + */ + public void syscall(Sim s) throws CPUException + { + simulator.suspend(); + enterSyscall=true; + } + + + protected void performSyscall() + { + enterSyscall=false; + try + { + int id; + id=simulator.getArg(1); + Packet syscall; + syscall=new Packet(this); + switch (id) + { + case Host.SYS_write: + syscall.invokeSyscall("write", 3, "iii"); + break; + case Host.SYS_read: + syscall.invokeSyscall("read", 3, "iii"); + break; + case Host.SYS_lseek: + syscall.invokeSyscall("lseek", 3, "iii"); + break; + case Host.SYS_open: + syscall.invokeSyscall("open", 3, "sii"); + break; + case Host.SYS_close: + syscall.invokeSyscall("close", 1, "i"); + break; + case Host.SYS_fstat: + syscall.invokeSyscall("fstat", 2, "ii"); + break; + case Host.SYS_stat: + syscall.invokeSyscall("stat", 2, "si"); + break; + case Host.SYS_isatty: + syscall.invokeSyscall("isatty", 1, "i"); + break; + case Host.SYS_unlink: + syscall.invokeSyscall("unlink", 1, "s"); + break; + default: + simulator.suspend(); + throw new UnsupportedSyscallException(); + } + simulator.cpuWriteLong(simulator.getArg(0), syscall.syscallErrno); + simulator.cpuWriteLong(0, syscall.syscallRetval); + } catch (CPUException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } catch (GDBServerException e) + { + e.printStackTrace(); + } catch (EndSessionException e) + { + e.printStackTrace(); + } + } + + public boolean doneContinue() + { + if (!enterSyscall) + return true; + performSyscall(); + return false; + } + + public int getSyscallArg(int i) throws CPUException + { + return simulator.getArg(i+2); + } + + public void writeUART(int val) + { + System.out.print((char)val); + System.out.flush(); + + + Packet p=new Packet(this); + p.reply("O" + formatHex(val, "00")); + p.sendReply(); + + + } + public int readUART() throws CPUException + { + try + { + if (System.in.available()<=0) + { + throw new MemoryAccessException(); + } + + return System.in.read(); + } catch (IOException e) + { + e.printStackTrace(); + } + return 0; + } + + public int readFIFO() + { + try + { + return System.in.available()>0?0:1; + } catch (IOException e) + { + e.printStackTrace(); + } + return 1; + } + + public void halted() + { + // TODO Auto-generated method stub + + } + + public void running() + { + // TODO Auto-generated method stub + + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/Packet.java b/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/Packet.java new file mode 100644 index 0000000..ad68947 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/gdb/Packet.java @@ -0,0 +1,472 @@ +/* + * Created on Nov 16, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.simulator.gdb; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.zylin.zpu.simulator.exceptions.BadPacketException; +import com.zylin.zpu.simulator.exceptions.CPUException; +import com.zylin.zpu.simulator.exceptions.EndSessionException; +import com.zylin.zpu.simulator.exceptions.GDBServerException; +import com.zylin.zpu.simulator.exceptions.MemoryAccessException; +import com.zylin.zpu.simulator.exceptions.NoAckException; +import com.zylin.zpu.simulator.exceptions.UnknownPacketException; + + +/** all packet related operations */ +class Packet +{ + private final GDBServer server; + + Packet(GDBServer server) + { + this.server = server; + reply=new StringBuffer(); + } + + void receive() throws IOException, GDBServerException, EndSessionException + { + int t; + /* we spool until we see a $ */ + this.server.expect('$'); + + StringBuffer packet=new StringBuffer(); + + int cc=0; + for (;;) + { + int t1; + t1=this.server.read(); + t = t1; + if (t==0x7d) + { + int t2; + t2=this.server.read(); + /* the next char is escaped after a GDB specific scheme. See + * gdb/gdb/remote.c */ + t = t2; + t^=0x20; + } else + { + if (t=='#') + { + break; + } + } + + cc+=t; + + packet.append((char)t); + } + cc&=0xff; + + String checkSum; + checkSum=""+(char)this.server.read()+(char)this.server.read(); + int readCheckSum; + readCheckSum=Integer.parseInt(checkSum, 16); + if (readCheckSum!=cc) + { + // error + dumpHex(packet.toString()); + + this.server.write("-".getBytes()); + throw new BadPacketException(); + } else + { + // ack + this.server.write("+".getBytes()); + } + + cmd=packet.toString(); + this.server.print(GDBServer.PACKET, "Got " + number + ": #$" + cmd + "#" + checkSum); + origCmd=cmd; + } + + void parseAndExecute() throws IOException, EndSessionException + { + boolean silent=false; + try + { + if (checkPrefix("g")) + { + readRegisters(); + } else if (checkPrefix("?")) + { + querySignal(); + } else if (checkPrefix("s")) + { + doStep(); + } else if (checkPrefix("m")) + { + try + { + readMemory(); + } catch (CPUException e) + { + silent=true; // happens all the time while hovering over variables in the GUI + throw e; + } + } else if (checkPrefix("c")) + { + continueExecution(); + } else if (checkPrefix("M")) + { + writeMemory(); + } else if (checkPrefix("z4")) + { + disableAccessWatchPoint(); + } else if (checkPrefix("Z4")) + { + enableAccessWatchPoint(); + } else if (checkPrefix("k")) + { + /* we must send a reply, but not wait for ack before we shut down + the connection. + */ + server.alive=false; + reply("OK"); + } else + { + throw new UnknownPacketException(); + } + } catch (UnknownPacketException e) + { + this.server.print(GDBServer.UNKNOWN, "Unknown packet: " + origCmd); + // empty reply to unknown packets + } catch (CPUException e) + { + if (!silent) + { + this.server.print(GDBServer.CPUEXCEPTION, "Exception handling GDB request"); + if (GDBServer.CPUEXCEPTION) + { + e.printStackTrace(); + } + } + reply("E01"); + } catch (GDBServerException e) + { + e.printStackTrace(); + reply("E01"); + } catch (RuntimeException e) + { + e.printStackTrace(); + reply("E01"); + } + + sendReply(); + } + + private void checkEmpty() throws GDBServerException + { + if (cmd.length()>0) + { + throw new GDBServerException(); + } + } + private void dumpHex(String arrayList2) + { + for (int i=0; i<arrayList2.length(); i++) + { + System.out.println(this.server.formatHex(arrayList2.charAt(i), "00")); + } + } + /** + * @param packetString + * @param string + * @return + */ + private boolean checkPrefix(String string) + { + if (cmd.length() < string.length()) + { + return false; + } else + { + return cmd.substring(0, string.length()).equals(string); + } + } + /** + * @throws GDBServerException + * @throws IOException + * @throws MemoryAccessException + * + */ + private void continueExecution() throws GDBServerException + { + extractString("c"); + try + { + if (!isEmpty()) + { + int pc=extractInteger(); + this.server.simulator.setPc(pc); + } + checkEmpty(); + this.server.simulator.cont(); + } catch (MemoryAccessException e) + { + if (GDBServer.IGNOREDEXCEPTIONS) + { + e.printStackTrace(); + } + } + reply("S05"); + } + private void doStep() + { + this.server.simulator.step(); + reply("S05"); + } + protected int extractInteger() throws GDBServerException + { + String number; + Pattern p=Pattern.compile("(\\-?[0-9a-fA-F]+)"); + Matcher m = p.matcher(cmd); + if (!m.find()) + { + throw new GDBServerException(); + } + number=m.group(); + extractString(number); + + try + { + return (int)Long.parseLong(number, 16); + } catch (NumberFormatException e) + { + throw new GDBServerException(e); + } + } + /** + * @param string + * @throws GDBServerException + */ + private void extractString(String string) throws GDBServerException + { + if (!checkPrefix(string)) + { + throw new GDBServerException(); + } + stripStart(string.length()); + } + /** + * @throws GDBServerException + * + */ + private void readMemory() throws CPUException, GDBServerException + { + extractString("m"); + int address=extractInteger(); + extractString(","); + int length=extractInteger(); + checkEmpty(); + + for (int i=0; i<length; i++) + { + reply(this.server.formatHex(this.server.simulator.readByte(address+i), "00")); + } + } + /** + * + */ + private void readRegisters() throws CPUException + { + for (int i=0; i<this.server.simulator.getREGNUM(); i++) + { + reply(this.server.printHex(this.server.simulator.getReg(i))); + } + } + private void writeMemory() throws GDBServerException, MemoryAccessException + { + extractString("M"); + int address=extractInteger(); + extractString(","); + int length=extractInteger(); + extractString(":"); + + for (int i=0; i<length; i++) + { + String t; + t=cmd.substring(i*2, i*2+2); + int val; + val=Integer.parseInt(t, 16); + this.server.simulator.writeByte(address+i, val); + } + reply("OK"); + + } + + private void enableAccessWatchPoint() throws GDBServerException, CPUException + { + extractString("Z4"); + extractString(","); + int address=extractInteger(); + extractString(","); + int length=extractInteger(); + checkEmpty(); + server.simulator.enableAccessWatchPoint(address, length); + + reply("OK"); + } + + private void disableAccessWatchPoint() throws GDBServerException, CPUException + { + extractString("z4"); + extractString(","); + int address=extractInteger(); + extractString(","); + int length=extractInteger(); + checkEmpty(); + server.simulator.disableAccessWatchPoint(address, length); + + reply("OK"); + } + + + private void stripStart(int length) + { + cmd=cmd.substring(length); + } + private boolean isEmpty() + { + return cmd.length()==0; + } + /** + * @param string + */ + protected void reply(String string) + { + reply.append(string); + } + void sendReply() + { + // a bit easier to debug if we can see the entire string. + StringBuffer buffer = new StringBuffer(); + buffer.append("$"); + number++; + String replyString = reply.toString(); + buffer.append(replyString); + byte[] data = replyString.toString().getBytes(); + int csum = 0; + for (int i = 0; i < data.length; i++) + { + csum += data[i]; + } + csum &= 0xff; + buffer.append("#"); + String t = Integer.toHexString(csum); + if (t.length() == 1) + { + t = "0" + t; + } + buffer.append(t); + this.server.print(GDBServer.REPLY, "Reply " + number + " : " + buffer.toString()); + try + { + this.server.write(buffer.toString().getBytes()); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + if (server.alive) + { + /* check for ack. */ + int ack; + try + { + ack = (char)this.server.read(); + } catch (IOException e) + { + throw new RuntimeException(e); + } + if (ack == '+') + { + return; + } + this.server.print(GDBServer.MINIMAL, "Retry"); + + throw new NoAckException(); + } + reply=new StringBuffer(); + } + + private void querySignal() + { + // SIGINT + // reply("S02"); + reply("S05"); + } + protected String cmd; + private int number; + private StringBuffer reply; + private String origCmd; + int syscallErrno; + int syscallRetval; + + + + void invokeSyscall(String string, int argNum, String types) throws IOException, NoAckException, GDBServerException, EndSessionException, CPUException + { + string="F"+string; + + int j=0; + for (int i=0; i<argNum; i++) + { + string+=","; + string+=Integer.toHexString(server.getSyscallArg(j)); + j++; + if (types.charAt(i)=='s') + { + string+="/" + Integer.toHexString(server.getSyscallArg(j)); + j++; + } + } + + reply(string); + sendReply(); + for (;;) + { + Packet packet=new Packet(server); + packet.receive(); + if (packet.checkPrefix("F")) + { + /* this is the reply we are waiting for */ + packet.extractString("F"); + syscallRetval=packet.extractInteger(); + syscallErrno=0; + if (packet.checkPrefix(",")) + { + /* errno is optional */ + packet.extractString(","); + syscallErrno = packet.extractInteger(); + } + break; + } else + { + /* something else... */ + try + { + packet.parseAndExecute(); + packet.sendReply(); + } catch (IOException e) + { + e.printStackTrace(); + } catch (EndSessionException e) + { + e.printStackTrace(); + } catch (RuntimeException e) + { + e.printStackTrace(); + } + } + } + } +}
\ No newline at end of file diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeDRAM.java b/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeDRAM.java new file mode 100644 index 0000000..f641595 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeDRAM.java @@ -0,0 +1,39 @@ + +package com.zylin.zpu.simulator.tools; + +import java.io.FileInputStream; +import java.io.IOException; + +public class MakeDRAM +{ + public static void main(String[] args) throws IOException + { + new MakeDRAM().run(args[0]); + } + + private void run(String string) throws IOException + { + FileInputStream file=new FileInputStream(string); + + int i=0; + while (file.available()>4) + { + byte[] tmp=new byte[4]; + file.read(tmp); + int word=0; + for (int j=0; j<4; j++) + { + word|=((int)(tmp[j])&0xff)<<((3-j)*8); + } + String str=Integer.toHexString(word); + while (str.length()<8) + { + str="0"+str; + } + + System.out.println(str); + i++; + } + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeRam.java b/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeRam.java new file mode 100644 index 0000000..4a7b233 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/simulator/tools/MakeRam.java @@ -0,0 +1,39 @@ + +package com.zylin.zpu.simulator.tools; + +import java.io.FileInputStream; +import java.io.IOException; + +public class MakeRam +{ + public static void main(String[] args) throws IOException + { + new MakeRam().run(args[0]); + } + + private void run(String string) throws IOException + { + FileInputStream file=new FileInputStream(string); + + int i=0; + while (file.available()>4) + { + byte[] tmp=new byte[4]; + file.read(tmp); + int word=0; + for (int j=0; j<4; j++) + { + word|=((int)(tmp[j])&0xff)<<((3-j)*8); + } + String str=Integer.toHexString(word); + while (str.length()<8) + { + str="0"+str; + } + + System.out.println("" + i + " => x\"" + str + "\","); + i++; + } + } + +} diff --git a/zpu/sw/simulator/com/zylin/zpu/stats/CountSequences.java b/zpu/sw/simulator/com/zylin/zpu/stats/CountSequences.java new file mode 100644 index 0000000..0f06aec --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/stats/CountSequences.java @@ -0,0 +1,94 @@ +/* + * Created on Jan 18, 2005 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Style - Code Templates + */ +package com.zylin.zpu.stats; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import com.zylin.zpu.simulator.Machine; + +public class CountSequences implements Machine +{ + + private byte[] array; + private StatKeeper statKeeper; + + public static void main(String[] args) + { + new CountSequences().run(args[0]); + } + + private void run(String string) + { + try + { + File file=new File(string); + if (file.exists()) + System.out.println("It exists!"); + FileInputStream in=new FileInputStream(file); + + try + { + array=new byte[(int) file.length()]; + + if (in.read(array)!=array.length) + throw new IOException(); + + countStats(); + + statKeeper.printStats(); + } finally + { + in.close(); + } + + } catch (FileNotFoundException e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } + + + } + + + private void countStats() + { + statKeeper=new StatKeeper(this); + for (int i=0; i<array.length; i++) + { + int j = array[i]&0xff; +// +// if ((j>=64)&&(j<96)) +// { +// j=64; +// } else if ((j>=96)&&(j<128)) +// { +// j=96; +// } else if ((j>=128)&&(j<256)) +// { +// j=128; +// } + statKeeper.countInstruction(j); + } + + } + + public long getPrevCycles() + { + return 0; + } + + public long getCycles() + { + return 0; + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/stats/DumpIt.java b/zpu/sw/simulator/com/zylin/zpu/stats/DumpIt.java new file mode 100644 index 0000000..80be11d --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/stats/DumpIt.java @@ -0,0 +1,17 @@ +/* + * Created on 26.nov.2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package com.zylin.zpu.stats; +/** + * @author oyvind + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public interface DumpIt +{ + int dumpIt(int i); +}
\ No newline at end of file diff --git a/zpu/sw/simulator/com/zylin/zpu/stats/Instruction.java b/zpu/sw/simulator/com/zylin/zpu/stats/Instruction.java new file mode 100644 index 0000000..252dd7f --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/stats/Instruction.java @@ -0,0 +1,62 @@ +package com.zylin.zpu.stats; + +public class Instruction +{ + public class DumpCycles implements DumpIt + { + public int dumpIt(int i) + { + return insn[i].cycles; + } + } + + + + public Instruction[] insn=new Instruction[256]; + public int count; + public int cycles; + + public Instruction addInstruction(int i) + { + if (insn[i]==null) + { + insn[i]=new Instruction(); + } + return insn[i]; + } + + /** + * Recursive print of statistics + */ + public void printStats() + { + System.out.println("Count dump"); + DumpIt cDump = new DumpCount(); + printCount("", cDump); + } + + /** + * Recursive print of counts + * @param string + * @param dumpIt TODO + */ + private void printCount(String string, DumpIt dumpIt) + { + for (int i=0; i<insn.length; i++) + { + if (insn[i]!=null) + { + insn[i].printCount(string + ", " + i, dumpIt); + System.out.println("Count: " + insn[i].count + string + ", " + i); + } + } + } + + class DumpCount implements DumpIt + { + public int dumpIt(int i) + { + return insn[i].count; + } + } +} diff --git a/zpu/sw/simulator/com/zylin/zpu/stats/StatKeeper.java b/zpu/sw/simulator/com/zylin/zpu/stats/StatKeeper.java new file mode 100644 index 0000000..9e16e32 --- /dev/null +++ b/zpu/sw/simulator/com/zylin/zpu/stats/StatKeeper.java @@ -0,0 +1,52 @@ +package com.zylin.zpu.stats; + +import com.zylin.zpu.simulator.Machine; +import com.zylin.zpu.simulator.State; + +public class StatKeeper +{ + private Instruction top=new Instruction(); + private int trackPos; + + private State[] state = new State[3]; + private Machine simulator; + /** + * @param simulator + */ + public StatKeeper(Machine simulator) + { + this.simulator=simulator; + for (int i=0; i<state.length; i++) + { + state[i]=new State(); + } + } + /** + * this instruction has been retired. Count it. + */ + public void countInstruction(int instruction) + { + State currentState=state[trackPos%state.length]; + currentState.cycle=simulator.getPrevCycles(); // start of instruction + currentState.insn=instruction; + trackPos++; + int backtrackNum; + backtrackNum=Math.min(trackPos, state.length); + for (int i=0; i<backtrackNum; i++) + { + Instruction t=top; + for (int j=0; j<=i; j++) + { + currentState=state[(trackPos-backtrackNum+j)%state.length]; + t=t.addInstruction(currentState.insn); + } + t.count++; + } + + } + public void printStats() + { + top.printStats(); + + } +} |