2003/09/19 05:01:37
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:35:49 +0000 (07:35 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:35:49 +0000 (07:35 +0000)
darcs-hash:20040130073549-2ba56-f15adecf41228362e120f8a6362d3a2b86b955b6.gz

30 files changed:
src/org/xwt/ByteStream.java
src/org/xwt/DoubleBuffer.java
src/org/xwt/Glyph.java [new file with mode: 0644]
src/org/xwt/HTML.java
src/org/xwt/HTTP.java
src/org/xwt/ImageDecoder.java
src/org/xwt/Main.java
src/org/xwt/Message.java
src/org/xwt/MessageQueue.java
src/org/xwt/Picture.java
src/org/xwt/Platform.java
src/org/xwt/Proxy.java
src/org/xwt/Res.java [new file with mode: 0644]
src/org/xwt/Resources.java
src/org/xwt/SOAP.java
src/org/xwt/SVG.java
src/org/xwt/Static.java
src/org/xwt/Surface.java
src/org/xwt/Template.java
src/org/xwt/ThreadMessage.java
src/org/xwt/Trap.java
src/org/xwt/Weak.java
src/org/xwt/XMLRPC.java
src/org/xwt/XWT.java
src/org/xwt/mips/Compiler.java
src/org/xwt/mips/ELF.java [new file with mode: 0644]
src/org/xwt/mips/Interpreter.java
src/org/xwt/mips/VM.java [new file with mode: 0644]
src/org/xwt/mips/linker.ld
src/org/xwt/plat/AWT.java

index ced9378..69acc89 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 
 package org.xwt;
 import java.io.*;
index f420875..6529870 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 /**
diff --git a/src/org/xwt/Glyph.java b/src/org/xwt/Glyph.java
new file mode 100644 (file)
index 0000000..0a75b0b
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.xwt;
+import org.xwt.translators.*;
+
+public class Glyph {
+    char c;
+    int line_height;    // same value for every glyph in font; the max height of all chars
+    int baseline;       // within the picture, this is the y-coordinate of the baseline
+    int advance;        // amount to increment the x-coordinate
+    Picture p;
+
+    // k1=font.res k2=(c << 16 | pointsize)
+    private static Cache glyphCache = new Cache();
+
+    public static Glyph getGlyph(Res res, int pointsize, char c) {
+        Glyph ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
+        if (ret != null) return ret;
+
+        // FEATURE: be smarter here
+        if (c < 256)
+            org.xwt.translators.Font.renderGlyphs(res, pointsize, 0, 255, glyphCache);
+        else
+            org.xwt.translators.Font.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache);
+
+        ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
+        if (ret != null) return ret;
+        throw new RuntimeException("renderGlyphs didn't create the glyph we wanted");
+    }
+}
index 022e7a0..f065f3a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.util.*;
index b7a3eb8..45c777d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.net.*;
index bfcbc7e..3a4fb6e 100644 (file)
@@ -1,8 +1,9 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] 
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
 package org.xwt;
 import java.io.*;
 import org.xwt.js.*;
 import org.xwt.util.*;
+import org.xwt.translators.*;
 
 /** Interface implemented by classes capable of decoding an image file into an int[] */
 public abstract class ImageDecoder {
index 92d0b77..4f7ec28 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.net.*;
@@ -8,6 +8,7 @@ import java.awt.*;
 import org.bouncycastle.util.encoders.Base64;
 import org.xwt.js.*;
 import org.xwt.util.*;
+import org.xwt.translators.*;
 
 /** Entry point for the XWT Engine; handles splash screen, initial xwar loading, and argument processing */
 public class Main {
index 53e26cc..30eec80 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 /** A simple interface that must be supported by any object inserted into the MessageQueue. */
index ffbe064..2f444c8 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.util.*;
index 89db921..1013cc4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 /** 
index 93d92f7..4426ca9 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.lang.reflect.*;
@@ -211,12 +211,24 @@ public class Platform {
 
     /** returns an InputStream to the builtin xwar */
     protected InputStream _getBuiltinInputStream() {
-        return this.getClass().getClassLoader().getResourceAsStream("org/xwt/builtin.xwar");
+        try {
+            return new FileInputStream("builtin.xwar");
+        } catch (Exception e) {
+            Log.log(this, e);
+            return null;
+        }
+        //return this.getClass().getClassLoader().getResourceAsStream("org/xwt/builtin.xwar");
     }
 
     /** returns an InputStream to the builtin xwar */
     protected InputStream _getFreetypeInputStream() {
-        return this.getClass().getClassLoader().getResourceAsStream("org/xwt/freetype.mips");
+        try {
+            return new FileInputStream("freetype.mips");
+        } catch (Exception e) {
+            Log.log(this, e);
+            return null;
+        }
+        //return this.getClass().getClassLoader().getResourceAsStream("org/xwt/freetype.mips");
     }
 
     /** returns the value of the environment variable key, or null if no such key exists */
index def26ca..8409fa5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.net.*;
diff --git a/src/org/xwt/Res.java b/src/org/xwt/Res.java
new file mode 100644 (file)
index 0000000..bf7b6f8
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.xwt;
+
+import java.io.*;
+
+/** base class for XWT resources */
+public abstract class Res {
+
+    public abstract InputStream getInputStream();
+    public Res getSubResource(String key) { return Null.singleton; }
+
+    public static Res stringToRes(String url) {
+        if (url.indexOf('!') == -1)
+            return new Zip(stringToRes(url.substring(0, url.lastIndexOf('!'))),
+                           url.substring(url.lastIndexOf('!') + 1));
+        if (url.startsWith("http://")) return new HTTP(url);
+        if (url.startsWith("https://")) return new HTTP(url);
+        throw new JS.Exn("invalid resource specifier");
+    }
+
+    /** the invalid resource; only causes an error if you actually try to use it */
+    public static class Null extends Res {
+        Null() { }
+        private static singleton = new Null();
+        public InputStream getInputStream() throws JS.Exn { throw new JS.Exn("invalid resource"); }
+    }
+
+    /** HTTP or HTTPS resource */
+    public static class HTTP extends Res {
+        private String url;
+        HTTP(String url) { this.url = url; }
+        public InputStream getInputStream() { return new HTTP(url).GET(); }
+        public Res getSubResource(String key) { return new HTTP(url + "/" + key); }
+    }
+
+    /** wrap a Res around a preexisting InputStream */
+    public static class IS extends Res {
+        InputStream parent;
+        IS(InputStream parent) { this.parent = parent; }
+        public InputStream getInputStream() { return parent; }
+    }
+
+    /** "unwrap" a Zip archive */
+    public static class Zip extends Res {
+        private Res parent;
+        private String path = "";
+        Zip(Res parent, String path) { this.parent = parent; this.path = path; }
+        public InputStream getInputStream() {
+            ZipInputStream zis = new ZipInputStream(parent.getInputStream());
+            ZipEntry ze = zis.getNextEntry();
+            while(ze != null && !ze.getName().equals(path)) ze = zis.getNextEntry();
+            if (ze == null) throw new JS.Exn("zip file not found in archive");
+            return zis;
+        }
+        public Res getSubResource(String key) { return new Zip(parent, path + '/' + key); }
+    }
+
+}
index 9149790..230f2fd 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.io.*;
index 7de30d3..1678068 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.io.*;
index 3af7462..9b94609 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 import java.util.*;
 
index 4d6fe81..f762df3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import org.xwt.js.*;
index 0f47dfb..182558c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import org.bouncycastle.util.encoders.Base64;
index 1bf8b2b..ee0bea5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.io.*;
index 51a4d7a..61e8964 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.util.*;
index a9023e7..5f803cb 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.util.*;
index 1963061..dc82fed 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 /** Encapsulates a weak reference; MSJVM and NSJVM don't use the standard Java2 java.lang.ref.WeakReference class */
index c4f5fc6..7cef4c2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.io.*;
index 33950f1..8efbc2c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
 import java.io.*;
@@ -70,6 +70,10 @@ public final class XWT extends JS.Obj {
             return null;
         }});
 
+        super.put("load", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
+            return Res.stringToResource(args.elementAt(0).toString());
+        }});
+
         super.put("theme", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn {
                 if (args.length() != 2) return null;
                 if (args.elementAt(0) == null || args.elementAt(1) == null) return null;
index bcfc662..f47d160 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt.imp;
+package org.xwt.mips;
 
 import java.util.*;
 import java.io.*;
@@ -19,7 +19,7 @@ import java.io.*;
 // FEATURE: emit bytecode rather than .java code (for on-the-fly classloading without javac present in "real" JVMs)
 
 /** reads a fully linked MIPS ELF binary image on stdin; writes a .java file on stdout */
-public class MIPS {
+public class Compiler {
 
     static String runs = "";
     static int last_emit = -1;
@@ -27,7 +27,7 @@ public class MIPS {
     public static void main(String[] s) throws IOException {
 
         if (s.length != 2) {
-            System.err.println("usage: java " + MIPS.class.getName() + " <classname> <binary.mips>");
+            System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
             System.exit(-1);
         }
 
diff --git a/src/org/xwt/mips/ELF.java b/src/org/xwt/mips/ELF.java
new file mode 100644 (file)
index 0000000..50f7ab3
--- /dev/null
@@ -0,0 +1,215 @@
+package org.xwt.mips;
+import java.io.*;
+
+class ELF {
+    private MyRandomAccessFile fd;
+    
+    public ELFHeader header;
+    public PHeader[] pheaders;
+    public SHeader[] sheaders;
+    
+    private boolean sectionReaderActive;
+    
+    public class ELFHeader {
+        byte klass;
+        byte data;
+        byte osabi;
+        byte abiversion;
+        
+        public static final short ET_EXEC = 2;
+        public short type;
+        public static final short EM_MIPS = 8;
+        public short machine;
+        public int version;
+        public int entry;
+        public int phoff;
+        public int shoff;
+        public int flags;
+        public short ehsize;
+        public short phentsize;
+        public short phnum;
+        public short shentsize;
+        public short shnum;
+        public short shstrndx;
+
+        private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
+        ELFHeader() throws IOException {
+            if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
+            klass = fd.readByte();
+            data = fd.readByte();
+            fd.skipFully(1); // version
+            osabi = fd.readByte();
+            abiversion = fd.readByte();
+            fd.skipFully(7);
+            type = fd.readShort();
+            machine = fd.readShort();
+            version = fd.readInt();
+            entry = fd.readInt();
+            phoff = fd.readInt();
+            shoff = fd.readInt();
+            flags = fd.readInt();
+            ehsize = fd.readShort();
+            phentsize = fd.readShort();
+            phnum = fd.readShort();
+            shentsize = fd.readShort();
+            shnum = fd.readShort();
+            shstrndx = fd.readShort();
+        }
+    }
+    
+    public class PHeader {
+        public int type;
+        public int offset;
+        public int vaddr;
+        public int paddr;
+        public int filesz;
+        public int memsz;
+        public int flags;
+        public int align;
+        
+        public static final int PF_X = 0x1;
+        public static final int PF_W = 0x2;
+        public static final int PF_R = 0x4;
+        
+        public static final int PT_LOAD = 1;
+        
+        PHeader() throws IOException {
+            type = fd.readInt();
+            offset = fd.readInt();
+            vaddr = fd.readInt();
+            paddr = fd.readInt();
+            filesz = fd.readInt();
+            memsz = fd.readInt();
+            flags = fd.readInt();
+            align = fd.readInt();
+            if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
+        }
+        
+        public boolean writable() { return (flags & PF_W) != 0; }
+        
+        public InputStream getInputStream() throws IOException {
+            return new BufferedInputStream(new SectionInputStream(
+                offset,offset+filesz));
+        }
+    }
+    
+    public class SHeader {
+        int nameidx;
+        public String name;
+        public int type;
+        public int flags;
+        public int addr;
+        public int offset;
+        public int size;
+        public int link;
+        public int info;
+        public int addralign;
+        public int entsize;
+        
+        public static final int T_NOBITS = 8;
+        
+        SHeader() throws IOException {
+            nameidx = fd.readInt();
+            type = fd.readInt();
+            flags = fd.readInt();
+            addr = fd.readInt();
+            offset = fd.readInt();
+            size = fd.readInt();
+            link = fd.readInt();
+            info = fd.readInt();
+            addralign = fd.readInt();
+            entsize = fd.readInt();
+        }
+        
+        public InputStream getInputStream() throws IOException {
+            return new BufferedInputStream(new SectionInputStream(
+                offset, type == T_NOBITS ? 0 : offset+size));
+        }
+    }
+    
+    public ELF(String file) throws IOException, ELFException {
+        fd = new MyRandomAccessFile(file,"r");
+        header = new ELFHeader();
+        pheaders = new PHeader[header.phnum];
+        for(int i=0;i<header.phnum;i++) {
+            fd.seek(header.phoff+i*header.phentsize);
+            pheaders[i] = new PHeader();
+        }
+        sheaders = new SHeader[header.shnum];
+        for(int i=0;i<header.shnum;i++) {
+            fd.seek(header.shoff+i*header.shentsize);
+            sheaders[i] = new SHeader();
+        }
+        if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
+        fd.seek(sheaders[header.shstrndx].offset);
+        byte[] a = new byte[sheaders[header.shstrndx].size];
+        fd.readFully(a);
+        for(int i=0;i<header.shnum;i++) {
+            SHeader s = sheaders[i];
+            StringBuffer sb = new StringBuffer();
+               for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
+            s.name = sb.toString();
+        }            
+    }
+        
+    public SHeader sectionWithName(String name) {
+        for(int i=0;i<sheaders.length;i++)
+            if(sheaders[i].name.equals(name))
+                return sheaders[i];
+        return null;
+    }
+    
+    public class ELFException extends IOException { ELFException(String s) { super(s); } }
+    
+    private class MyRandomAccessFile extends RandomAccessFile  {
+        MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
+        public void skipFully(int n) throws IOException {
+            while(n>0) n-= skipBytes(n);
+        }
+    }
+
+    private class SectionInputStream extends InputStream {
+        private int pos;
+        private int maxpos;
+        SectionInputStream(int start, int end) throws IOException {
+            if(sectionReaderActive)
+                throw new IOException("Section reader already active");
+            sectionReaderActive = true;
+            pos = start;
+            fd.seek(pos);
+            maxpos = end;
+        }
+        
+        private int bytesLeft() { return maxpos - pos; }
+        public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; }
+        public int read(byte[] b, int off, int len) throws IOException {
+            int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n;
+        }
+        public void close() { sectionReaderActive = false; }
+    }
+    
+    private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+    
+    public static void main(String[] args) throws IOException {
+        ELF elf = new ELF(args[0]);
+        System.out.println("Type: " + toHex(elf.header.type));
+        System.out.println("Machine: " + toHex(elf.header.machine));
+        for(int i=0;i<elf.pheaders.length;i++) {
+            ELF.PHeader ph = elf.pheaders[i];
+            System.out.println("PHeader " + toHex(i));
+            System.out.println("\tOffset: " + ph.offset);
+            System.out.println("\tVaddr: " + toHex(ph.vaddr));
+            System.out.println("\tFile Size: " + ph.filesz);
+            System.out.println("\tMem Size: " + ph.memsz);
+        }
+        for(int i=0;i<elf.sheaders.length;i++) {
+            ELF.SHeader sh = elf.sheaders[i];
+            System.out.println("SHeader " + toHex(i));
+            System.out.println("\tName: " + sh.name);
+            System.out.println("\tOffset: " + sh.offset);
+            System.out.println("\tAddr: " + toHex(sh.addr));
+            System.out.println("\tSize: " + sh.size);
+            System.out.println("\tType: " + toHex(sh.type));
+        }
+    }
+}
index ddc4d69..81aa042 100644 (file)
@@ -1,12 +1,11 @@
 // Copyright 2003 Adam Megacz
 // Author Brian Alliet
-// Based on org.xwt.imp.MIPS by Adam Megacz
-
-package org.xwt.imp;
+// Based on org.xwt.mips.Compiler by Adam Megacz
 
+package org.xwt.mips;
 import java.io.*;
 
-public class MIPSInterpreter extends MIPSEmu {
+public class Interpreter extends VM {
 
     // Registers
     private int[] registers = new int[32];
@@ -661,8 +660,8 @@ public class MIPSInterpreter extends MIPSEmu {
         registers[RA] = 0xdeadbeef;
         nextPC = pc;
     }
-    public MIPSInterpreter() { }
-    public MIPSInterpreter(String image) throws IOException { loadImage(image); }
+    public Interpreter() { }
+    public Interpreter(String image) throws IOException { loadImage(image); }
     
     // Debug functions
     // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
@@ -691,7 +690,7 @@ public class MIPSInterpreter extends MIPSEmu {
 
     public static void main(String[] argv) throws Exception {
         String image = argv[0];
-        MIPSInterpreter emu = new MIPSInterpreter();
+        Interpreter emu = new Interpreter();
         emu.loadImage(image);
         Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
         // User data
@@ -710,985 +709,4 @@ public class MIPSInterpreter extends MIPSEmu {
     }
 }
 
-abstract class MIPSEmu implements Syscalls, Errno {
-    // Register Names
-    protected final static int ZERO = 0; // Immutable, hardwired to 0
-    protected final static int AT = 1;  // Reserved for assembler
-    protected final static int K0 = 26; // Reserved for kernel 
-    protected final static int K1 = 27; // Reserved for kernel 
-    protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss)
-    protected final static int SP = 29; // Stack pointer
-    protected final static int FP = 30; // Frame Pointer
-    protected final static int RA = 31; // Return Address
-    
-    // Return values (caller saved)
-    protected final static int V0 = 2;
-    protected final static int V1 = 3;
-    // Argument Registers (caller saved)
-    protected final static int A0 = 4; 
-    protected final static int A1 = 5;
-    protected final static int A2 = 6;
-    protected final static int A3 = 7;
-    // Temporaries (caller saved)
-    protected final static int T0 = 8;
-    protected final static int T1 = 9;
-    protected final static int T2 = 10;
-    protected final static int T3 = 11;
-    protected final static int T4 = 12;
-    protected final static int T5 = 13;
-    protected final static int T6 = 14;
-    protected final static int T7 = 15;
-    protected final static int T8 = 24;
-    protected final static int T9 = 25;
-    // Saved (callee saved)
-    protected final static int S0 = 16;
-    protected final static int S1 = 17;
-    protected final static int S2 = 18;
-    protected final static int S3 = 19;
-    protected final static int S4 = 20;
-    protected final static int S5 = 21;
-    protected final static int S6 = 22;
-    protected final static int S7 = 23;
-
-    // Page Constants
-    // Page Size: 4k
-    // Total Pages: 64k
-    // Maxiumum Addressable memory 256mb
-    // 1mb of stack space
-    protected final static int PAGE_SIZE = 4096;
-    protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2);
-    protected final static int PAGE_SHIFT = 12;
-    protected final static int STACK_PAGES = 256;
-    // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the
-    // new location of INITIAL_SP
-    protected final static int TOTAL_PAGES = 65536;
-    protected final static int BRK_LIMIT = 32768;
-    // Top page is always empty
-    // next page down contains command line arguments
-    protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE;
-    // next page down contains _user_info data
-    protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE;
-    // next page down is the start of the stack
-    protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE;
-    // magic page that signified an allocated but empty (untouched) page
-    private final static int[] emptyPage = new int[0];
-    
-    // Main memory
-    protected final int[][] readPages;
-    protected final int[][] writePages;
-    
-    // Brk
-    protected int brk; // PAGE not address
-        
-    // Entry point - what start() sets pc to
-    protected int entryPoint;
-    
-    // State constants
-    public final static int UNINITIALIZED = 0;
-    public final static int INITIALIZED = 1;
-    public final static int RUNNING = 2;
-    public final static int PAUSED = 3;
-    public final static int DONE = 4;
-    
-    // State
-    protected int state = UNINITIALIZED;
-    public final int getState() { return state; }
-    protected int exitStatus;
-    
-    // File descriptors
-    private final static int OPEN_MAX = 256;
-    private FileDescriptor[] fds;
-    
-    // Temporary buffer for read/write operations
-    private byte[] _byteBuf = null;
-    private final static int MAX_CHUNK = 4*1024*1024-8;
-    
-    // Abstract methods
-    // This should start executing at pc
-    public abstract void execute() throws EmulationException;
-    // This should initialize the cpu registers to point to the entry point
-    protected abstract void _start(int pc);
-   
-    public static final int PID = 1;
-    
-    public MIPSEmu() {
-        readPages = new int[TOTAL_PAGES][];
-        writePages = new int[TOTAL_PAGES][];
-        for(int i=0;i<STACK_PAGES;i++)
-            readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
-    }
-    
-    public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
-        int n=0;
-        if((addr&3)!=0) {
-            int word = memRead(addr&~3);
-             switch(addr&3) {
-                case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break;
-                case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break;
-                case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break;
-            }
-            addr = (addr&~3)+4;
-        }
-        while(length-n > 3) {
-            int start = (addr&(PAGE_SIZE-1))>>2;
-            int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
-            int[] page = readPages[addr >>> PAGE_SHIFT];
-            if(page == null) throw new ReadFaultException(addr);
-            if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; }
-            for(int i=start;i<end;i++,addr+=4) {
-                int word = page[i];
-                a[n++] = (byte)((word>>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff);
-                a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff);
-            }
-        }
-        if(length-n > 0) {
-            int word = memRead(addr);
-            if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff);
-            if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff);
-            if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff);
-        }
-    }
-    
-    public void copyout(byte[] a, int addr, int length) throws FaultException {
-        int n=0;
-        if((addr&3)!=0) {
-            int word = memRead(addr&~3);
-             switch(addr&3) {
-                case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break;
-                case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break;
-                case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break;
-            }
-            memWrite(addr&~3,word);
-            addr = (addr&~3)+4;
-        }
-        
-        while(length-n > 3) {
-            int start = (addr&(PAGE_SIZE-1))>>2;
-            int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
-            int[] page = writePages[addr >>> PAGE_SHIFT];
-            if(page == null) throw new WriteFaultException(addr);
-            if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; }
-            for(int i=start;i<end;i++,addr+=4) {
-                int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
-                page[i] = word;
-            }
-        }
-        if(length-n > 0) {
-            int word = memRead(addr);
-            word = (word&0x00ffffff)|((a[n]&0xff)<<24);
-            if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); }
-            if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); }
-            memWrite(addr,word);
-        }
-    }
-    
-    protected final int memRead(int addr) throws ReadFaultException  {
-        if((addr & 3) != 0) throw new ReadFaultException(addr);
-        int page = addr >>> PAGE_SHIFT;
-        int entry = (addr >>> 2) & (PAGE_WORDS-1);
-        try {
-            return readPages[page][entry];
-        } catch(ArrayIndexOutOfBoundsException e) {
-            if(page < 0) throw e; // should never happen
-            if(page > readPages.length) throw new ReadFaultException(addr);
-            if(readPages[page] != emptyPage) throw e; // should never happen
-            initPage(page);
-            return 0;
-        } catch(NullPointerException e) {
-            throw new ReadFaultException(addr);
-        }
-    }
-    
-    protected final void memWrite(int addr, int value) throws WriteFaultException  {
-        if((addr & 3) != 0) throw new WriteFaultException(addr);
-        int page = addr >>> PAGE_SHIFT;
-        int entry = (addr>>>2)&(PAGE_WORDS-1);
-        try {
-            writePages[page][entry] = value;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            if(page < 0) throw e;// should never happen
-            if(page > writePages.length) throw new WriteFaultException(addr);
-            if(readPages[page] != emptyPage) throw e; // should never happen
-            initPage(page);
-            writePages[page][entry] = value;
-        } catch(NullPointerException e) {
-            throw new WriteFaultException(addr);
-        }
-    }
-    
-    protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; }
-    
-    public final int exitStatus() {
-        if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state");
-        return exitStatus;
-    }
-     
-    public final int run(String[] args) throws EmulationException {
-        start(args);
-        for(;;) {
-            execute();
-            if(state != PAUSED) break;
-            System.err.println("WARNING: Pause requested while executing run()");
-            try { Thread.sleep(500); } catch(InterruptedException e) { }
-        }
-        if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state");
-        return exitStatus();
-    }
-    
-    private void addArgs(String[] args) throws EmulationException {
-        if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state");
-        int count = args.length;
-        byte[] nullTerminator = new byte[1];
-        int total = 4; /* null last table entry  */
-        for(int i=0;i<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
-        if(total > PAGE_SIZE) throw new EmulationException("Arguments too large");
-        int start = ARGS_ADDR;
-        int addr = start + (count+1)*4;
-        int[] table = new int[count+1];
-        for(int i=0;i<count;i++) {
-            byte[] a;
-            try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw  new Error(e.getMessage()); }
-            table[i] = addr;
-
-                copyout(a,addr,a.length);
-                addr += a.length;
-                copyout(nullTerminator,addr,1);
-                addr += 1;
-
-        }
-        addr=start;
-        for(int i=0;i<count;i++) {
-            memWrite(addr,table[i]);
-            addr += 4;
-        }
-    }
-    
-    public void setUserInfo(int index, int word) throws EmulationException {
-        if(index < 0 ||  index >= 1024) throw new EmulationException("setUserInfo called with index >= 1024");
-        memWrite(USER_INFO_ADDR+index*4,word);
-    }
-    
-    public int getUserInfo(int index) throws EmulationException {
-        if(index < 0 ||  index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024");
-        return memRead(USER_INFO_ADDR+index*4);
-    }
-    
-    public final void start(String[] args) throws EmulationException {
-        if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state");
-        _start(entryPoint);
-        addArgs(args);
-        fds = new FileDescriptor[OPEN_MAX];
-        fds[0] = new InputStreamFD(System.in)   { public boolean isatty() { return true; } };
-        fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } };
-        fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } };
-        state = PAUSED;
-    }
-    
-        
-    // Syscalls
-    private int write(int fdn, int addr, int count) {
-        int n = 0;
-        int r;
-        FileDescriptor fd;
-        count = Math.min(count,MAX_CHUNK);
-        try {
-            fd = fds[fdn];
-            if(fd == null || !fd.writable()) return -EBADFD;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            return -EBADFD;
-        }
-        try {
-            byte[] buf = byteBuf(count);
-            copyin(addr,buf,count);
-            return fd.write(buf,0,count);
-        } catch(FaultException e) {
-            System.err.println(e);
-            return -EFAULT;
-        } catch(IOException e) {
-            System.err.println(e);
-            return -EIO;
-        }
-    }
-
-    private int read(int fdn, int addr, int count) {
-        FileDescriptor fd;
-        count = Math.min(count,MAX_CHUNK);
-        try {
-            fd = fds[fdn];
-            if(fd == null || !fd.readable()) return -EBADFD;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            return -EBADFD;
-        }
-        try {
-            byte[] buf = byteBuf(count);
-            int n = fd.read(buf,0,count);
-            copyout(buf,addr,n);
-            return n;
-        } catch(FaultException e) {
-            System.err.println(e);
-            return -EFAULT;
-        } catch(IOException e) {
-            System.err.println(e);
-            return -EIO;
-        }
-    }
-    
-    private int close(int fdn) {
-        FileDescriptor fd;
-        try {
-            fd = fds[fdn];
-            if(fd == null) return -EBADFD;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            return -EBADFD;
-        }
-        fds[fdn] = null;
-        fd.close();
-        return 0;
-    }
-    
-    private int stat(FileInfo fi, int addr) {
-        int size = fi.size();
-        try {
-            memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16)
-            memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode
-            memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16)
-            memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16)
-            memWrite(addr+16,size); // st_size
-            memWrite(addr+20,0); // st_atime
-            // memWrite(addr+24,0) // st_spare1
-            memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime
-            // memWrite(addr+32,0) // st_spare2
-            memWrite(addr+36,0); // st_atime
-            // memWrite(addr+40,0) // st_spare3
-            memWrite(addr+44,512); // st_bklsize;
-            memWrite(addr+48,(size+511)&(~511)); // st_blocks
-            // memWrite(addr+52,0) // st_spare4[0]
-            // memWrite(addr+56,0) // st_spare4[1]
-        } catch(FaultException e) {
-            System.err.println(e);
-            return -EFAULT;
-        }
-        return 0;
-    }
-    
-    private int fstat(int fdn, int addr) {
-        FileDescriptor fd;
-        try {
-            fd = fds[fdn];
-            if(fd == null) return -EBADFD;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            return -EBADFD;
-        }
-        return stat(fd.fileInfo(),addr);
-    }
-    
-    public int sbrk(int incr) {
-        if(incr==0) return brk<<PAGE_SHIFT;
-        int oldBrk = brk;
-        int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
-        if(newBrk >= BRK_LIMIT) {
-            System.err.println("Hit BRK_LIMIT");
-            return -ENOMEM;
-        }
-        for(int i=oldBrk;i<newBrk+256;i++)
-            readPages[i] = writePages[i] = emptyPage;
-        brk = newBrk;
-        return oldBrk<<PAGE_SHIFT;
-    }
-        
-    private int open(int addr, int flags, int mode) {
-        final int O_RDONLY = 0;
-        final int O_WRONLY = 1;
-        final int O_RDWR = 2;
-        final int O_APPEND = 0x0008;
-        final int O_CREAT = 0x0200;
-        final int O_NONBLOCK = 0x4000;
-        final int O_EXCL = 0x0800;
-        
-        if((flags & O_APPEND) != 0) {
-            System.err.println("WARNING: O_APPEND not supported");
-            return -EOPNOTSUPP;
-        }
-        if((flags & O_NONBLOCK) != 0) {
-            System.err.println("WARNING: O_NONBLOCK not supported");
-            return -EOPNOTSUPP;
-        }
-        
-        try {
-            int fdn=-1;
-            File f = new File(cstring(addr));
-            System.err.println("Opening: " + f);
-            if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
-                if(!f.createNewFile()) return -EEXIST;
-            if(f.exists()) {
-                if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
-            } else {
-                if((flags & O_CREAT) == 0) return -ENOENT;
-            }
-            for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
-            if(fdn==-1) return -ENFILE;
-            fds[fdn] = new RegularFileDescriptor(f,flags&3);
-            return fdn;
-        } catch(FaultException e) {
-            return -EFAULT;
-        } catch(FileNotFoundException e) { 
-            if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES;
-            return -ENOENT;
-        } catch(IOException e) {
-            return -EIO;
-        }
-    }
-    
-    private int seek(int fdn, int offset, int whence) {
-        FileDescriptor fd;
-        try {
-            fd = fds[fdn];
-            if(fd == null || !fd.readable()) return -EBADFD;
-        } catch(ArrayIndexOutOfBoundsException e) {
-            return -EBADFD;
-        }
-        try {
-            return fd.seek(offset,whence);
-        } catch(IOException e) {
-            System.err.println(e);
-            return -EPIPE;
-        }
-    }
-    
-    // This will only be called by raise() to invoke the default handler
-    // We don't have to worry about actually delivering the signal
-    private int kill(int pid, int signal) {
-        if(pid != PID) return -ESRCH;
-        if(signal < 0 || signal >= 32) return -EINVAL;
-        switch(signal) {
-            case 0: return 0;
-            case 17: // SIGSTOP
-            case 18: // SIGTSTP
-            case 21: // SIGTTIN
-            case 22: // SIGTTOU
-                state = PAUSED;
-                break;
-            case 19: // SIGCONT
-            case 20: // SIGCHLD
-            case 23: // SIGIO
-            case 28: // SIGWINCH
-                break;
-            default: {
-                String msg = "Terminating on signal: " + signal + "\n";
-                exitStatus = 1;
-                state = DONE;
-                if(fds[2]==null) {
-                    System.out.print(msg);
-                } else {
-                    byte[] b = msg.getBytes();
-                    try {
-                        fds[2].write(b,0,b.length);
-                    } catch(IOException e) { }
-                }
-            }
-        }
-        return 0;
-    }
-    
-    private int getpid() { return PID; }
-    
-    protected int syscall(int syscall, int a, int b, int c, int d) {
-        switch(syscall) {
-            case SYS_null: return 0;
-            case SYS_exit: exitStatus = a; state = DONE; return 0;
-            case SYS_pause: state = PAUSED; return 0;
-            case SYS_write: return write(a,b,c);
-            case SYS_fstat: return fstat(a,b);
-            case SYS_sbrk: return sbrk(a);
-            case SYS_open: return open(a,b,c);
-            case SYS_close: return close(a);
-            case SYS_read: return read(a,b,c);
-            case SYS_seek: return seek(a,b,c);
-            case SYS_kill: return kill(a,b);
-            case SYS_getpid: return getpid();
-            default:
-                System.err.println("Attempted to use unknown syscall: " + syscall);
-                return -ENOSYS;
-        }
-    }
-    
-    // Helper function to read a cstring from main memory
-    private String cstring(int addr) throws ReadFaultException {
-        StringBuffer sb = new StringBuffer();
-        for(;;) {
-            int word = memRead(addr&~3);
-            switch(addr&3) {
-                case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
-                case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
-                case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
-                case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
-            }
-        }
-    }
-     
-    // Exceptions
-    public static class ReadFaultException extends FaultException {
-        public ReadFaultException(int addr) { super(addr); }
-    }
-    public static class WriteFaultException extends FaultException {
-        public WriteFaultException(int addr) { super(addr); }
-    }
-    public static abstract class FaultException extends EmulationException {
-        private int addr;
-        public FaultException(int addr) { this.addr = addr; }
-        public String getMessage() { return "fault at: " + toHex(addr); }
-    }
-    public static class EmulationException extends Exception {
-        public EmulationException() { }
-        public EmulationException(String s) { super(s); }
-    }
-    
-    // FileInfo classes - used by stat(2)
-    static class FileInfo {
-        public static final int S_IFIFO = 0010000;
-        public static final int S_FCHR =  0020000;
-        public static final int S_IFDIR = 0040000;
-        public static final int S_IFREG = 0100000;
-        
-        public int size() { return 0; }
-        public int type() { return S_IFIFO; }
-        public long modTime() { return 0; }
-    }
-        
-    public static class FileFileInfo extends FileInfo {
-        public File f;
-        public FileFileInfo(File f) { this.f = f; }
-        public int size() { return (int)f.length(); }
-        public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; }
-        public long modTime() { return f.lastModified(); }
-    }
-
-    // File descriptor classes
-    public static abstract class FileDescriptor {
-        public boolean readable() { return false; }
-        public boolean writable() { return false; }
-        
-        private static final FileInfo nullFi = new FileInfo();
-        private FileInfo fi;
-        public FileInfo fileInfo() { return fi; }
-        
-        FileDescriptor() { this(null); }
-        FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; }
-        
-        public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
-        public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
-        
-        public int seek(int n, int whence)  throws IOException  { return -ESPIPE; }
-        public boolean isatty() { return false; }
-        
-        void close() { }
-    }
-    
-    public static class RegularFileDescriptor extends FileDescriptor {
-        private int mode;
-        private RandomAccessFile raf;
-        public boolean readable() { return mode != 1; }
-        public boolean writable() { return mode != 0; }
-        
-        RegularFileDescriptor(File f,int m) throws IOException {
-            super(new FileFileInfo(f));
-            String mode = m == 0 ? "r" : "rw";
-            this.mode = m;
-            raf = new RandomAccessFile(f,mode);
-            if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large");
-        }
-        
-        public int seek(int n, int whence) throws IOException {
-            final int SEEK_SET = 0;
-            final int SEEK_CUR = 1;
-            final int SEEK_END = 2;
-            
-            switch(whence) {
-                case SEEK_SET: break;
-                case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break;
-                case SEEK_END: n = (int)(raf.length()+n); break;
-                default: return -EINVAL;
-            }
-            raf.seek(n);
-            return n;
-        }
-        
-        public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; }
-        public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; }
-        
-        void close() { try { raf.close(); } catch(Exception e) { } }
-    }
-    
-    public class OutputStreamFD extends FileDescriptor {
-        private OutputStream os;
-        public boolean writable() { return true; }
-        public OutputStreamFD(OutputStream os) { this.os = os; }
-        public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
-    }
-    
-    public class InputStreamFD extends FileDescriptor {
-        private InputStream is;
-        public boolean readable() { return true; }
-        public InputStreamFD(InputStream is) { this.is = is; }
-        public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
-    }
-    
-    // Utility functions
-    private byte[] byteBuf(int size) {
-        if(_byteBuf==null) _byteBuf = new byte[size];
-        else if(_byteBuf.length < size)
-            _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)];
-        return _byteBuf;
-    }
-    protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
-    protected final static int min(int a, int b) { return a < b ? a : b; }
-    protected final static int max(int a, int b) { return a > b ? a : b; }
-}
-
-class ELF {
-    private MyRandomAccessFile fd;
-    
-    public ELFHeader header;
-    public PHeader[] pheaders;
-    public SHeader[] sheaders;
-    
-    private boolean sectionReaderActive;
-    
-    public class ELFHeader {
-        byte klass;
-        byte data;
-        byte osabi;
-        byte abiversion;
-        
-        public static final short ET_EXEC = 2;
-        public short type;
-        public static final short EM_MIPS = 8;
-        public short machine;
-        public int version;
-        public int entry;
-        public int phoff;
-        public int shoff;
-        public int flags;
-        public short ehsize;
-        public short phentsize;
-        public short phnum;
-        public short shentsize;
-        public short shnum;
-        public short shstrndx;
 
-        private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
-        ELFHeader() throws IOException {
-            if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
-            klass = fd.readByte();
-            data = fd.readByte();
-            fd.skipFully(1); // version
-            osabi = fd.readByte();
-            abiversion = fd.readByte();
-            fd.skipFully(7);
-            type = fd.readShort();
-            machine = fd.readShort();
-            version = fd.readInt();
-            entry = fd.readInt();
-            phoff = fd.readInt();
-            shoff = fd.readInt();
-            flags = fd.readInt();
-            ehsize = fd.readShort();
-            phentsize = fd.readShort();
-            phnum = fd.readShort();
-            shentsize = fd.readShort();
-            shnum = fd.readShort();
-            shstrndx = fd.readShort();
-        }
-    }
-    
-    public class PHeader {
-        public int type;
-        public int offset;
-        public int vaddr;
-        public int paddr;
-        public int filesz;
-        public int memsz;
-        public int flags;
-        public int align;
-        
-        public static final int PF_X = 0x1;
-        public static final int PF_W = 0x2;
-        public static final int PF_R = 0x4;
-        
-        public static final int PT_LOAD = 1;
-        
-        PHeader() throws IOException {
-            type = fd.readInt();
-            offset = fd.readInt();
-            vaddr = fd.readInt();
-            paddr = fd.readInt();
-            filesz = fd.readInt();
-            memsz = fd.readInt();
-            flags = fd.readInt();
-            align = fd.readInt();
-            if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
-        }
-        
-        public boolean writable() { return (flags & PF_W) != 0; }
-        
-        public InputStream getInputStream() throws IOException {
-            return new BufferedInputStream(new SectionInputStream(
-                offset,offset+filesz));
-        }
-    }
-    
-    public class SHeader {
-        int nameidx;
-        public String name;
-        public int type;
-        public int flags;
-        public int addr;
-        public int offset;
-        public int size;
-        public int link;
-        public int info;
-        public int addralign;
-        public int entsize;
-        
-        public static final int T_NOBITS = 8;
-        
-        SHeader() throws IOException {
-            nameidx = fd.readInt();
-            type = fd.readInt();
-            flags = fd.readInt();
-            addr = fd.readInt();
-            offset = fd.readInt();
-            size = fd.readInt();
-            link = fd.readInt();
-            info = fd.readInt();
-            addralign = fd.readInt();
-            entsize = fd.readInt();
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            return new BufferedInputStream(new SectionInputStream(
-                offset, type == T_NOBITS ? 0 : offset+size));
-        }
-    }
-    
-    public ELF(String file) throws IOException, ELFException {
-        fd = new MyRandomAccessFile(file,"r");
-        header = new ELFHeader();
-        pheaders = new PHeader[header.phnum];
-        for(int i=0;i<header.phnum;i++) {
-            fd.seek(header.phoff+i*header.phentsize);
-            pheaders[i] = new PHeader();
-        }
-        sheaders = new SHeader[header.shnum];
-        for(int i=0;i<header.shnum;i++) {
-            fd.seek(header.shoff+i*header.shentsize);
-            sheaders[i] = new SHeader();
-        }
-        if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
-        fd.seek(sheaders[header.shstrndx].offset);
-        byte[] a = new byte[sheaders[header.shstrndx].size];
-        fd.readFully(a);
-        for(int i=0;i<header.shnum;i++) {
-            SHeader s = sheaders[i];
-            StringBuffer sb = new StringBuffer();
-               for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
-            s.name = sb.toString();
-        }            
-    }
-        
-    public SHeader sectionWithName(String name) {
-        for(int i=0;i<sheaders.length;i++)
-            if(sheaders[i].name.equals(name))
-                return sheaders[i];
-        return null;
-    }
-    
-    public class ELFException extends IOException { ELFException(String s) { super(s); } }
-    
-    private class MyRandomAccessFile extends RandomAccessFile  {
-        MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
-        public void skipFully(int n) throws IOException {
-            while(n>0) n-= skipBytes(n);
-        }
-    }
-
-    private class SectionInputStream extends InputStream {
-        private int pos;
-        private int maxpos;
-        SectionInputStream(int start, int end) throws IOException {
-            if(sectionReaderActive)
-                throw new IOException("Section reader already active");
-            sectionReaderActive = true;
-            pos = start;
-            fd.seek(pos);
-            maxpos = end;
-        }
-        
-        private int bytesLeft() { return maxpos - pos; }
-        public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; }
-        public int read(byte[] b, int off, int len) throws IOException {
-            int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n;
-        }
-        public void close() { sectionReaderActive = false; }
-    }
-    
-    private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
-    
-    public static void main(String[] args) throws IOException {
-        ELF elf = new ELF(args[0]);
-        System.out.println("Type: " + toHex(elf.header.type));
-        System.out.println("Machine: " + toHex(elf.header.machine));
-        for(int i=0;i<elf.pheaders.length;i++) {
-            ELF.PHeader ph = elf.pheaders[i];
-            System.out.println("PHeader " + toHex(i));
-            System.out.println("\tOffset: " + ph.offset);
-            System.out.println("\tVaddr: " + toHex(ph.vaddr));
-            System.out.println("\tFile Size: " + ph.filesz);
-            System.out.println("\tMem Size: " + ph.memsz);
-        }
-        for(int i=0;i<elf.sheaders.length;i++) {
-            ELF.SHeader sh = elf.sheaders[i];
-            System.out.println("SHeader " + toHex(i));
-            System.out.println("\tName: " + sh.name);
-            System.out.println("\tOffset: " + sh.offset);
-            System.out.println("\tAddr: " + toHex(sh.addr));
-            System.out.println("\tSize: " + sh.size);
-            System.out.println("\tType: " + toHex(sh.type));
-        }
-    }
-}
-interface Errno {
-    public static final int EPERM = 1;
-    public static final int ENOENT = 2;
-    public static final int ESRCH = 3;
-    public static final int EINTR = 4;
-    public static final int EIO = 5;
-    public static final int ENXIO = 6;
-    public static final int ENOEXEC = 8;
-    public static final int EBADF = 9;
-    public static final int ECHILD = 10;
-    public static final int EAGAIN = 11;
-    public static final int ENOMEM = 12;
-    public static final int EACCES = 13;
-    public static final int EFAULT = 14;
-    public static final int ENOTBLK = 15;
-    public static final int EBUSY = 16;
-    public static final int EEXIST = 17;
-    public static final int EXDEV = 18;
-    public static final int ENODEV = 19;
-    public static final int ENOTDIR = 20;
-    public static final int EISDIR = 21;
-    public static final int EINVAL = 22;
-    public static final int ENFILE = 23;
-    public static final int EMFILE = 24;
-    public static final int ENOTTY = 25;
-    public static final int ETXTBSY = 26;
-    public static final int EFBIG = 27;
-    public static final int ENOSPC = 28;
-    public static final int ESPIPE = 29;
-    public static final int EROFS = 30;
-    public static final int EMLINK = 31;
-    public static final int EPIPE = 32;
-    public static final int EDOM = 33;
-    public static final int ERANGE = 34;
-    public static final int ENOMSG = 35;
-    public static final int EIDRM = 36;
-    public static final int ECHRNG = 37;
-    public static final int ELNRNG = 41;
-    public static final int EUNATCH = 42;
-    public static final int ENOCSI = 43;
-    public static final int EDEADLK = 45;
-    public static final int ENOLCK = 46;
-    public static final int EBADE = 50;
-    public static final int EBADR = 51;
-    public static final int EXFULL = 52;
-    public static final int ENOANO = 53;
-    public static final int EBADRQC = 54;
-    public static final int EBADSLT = 55;
-    public static final int EDEADLOCK = 56;
-    public static final int EBFONT = 57;
-    public static final int ENOSTR = 60;
-    public static final int ENODATA = 61;
-    public static final int ETIME = 62;
-    public static final int ENOSR = 63;
-    public static final int ENONET = 64;
-    public static final int ENOPKG = 65;
-    public static final int EREMOTE = 66;
-    public static final int ENOLINK = 67;
-    public static final int EADV = 68;
-    public static final int ESRMNT = 69;
-    public static final int ECOMM = 70;
-    public static final int EPROTO = 71;
-    public static final int EMULTIHOP = 74;
-    public static final int ELBIN = 75;
-    public static final int EDOTDOT = 76;
-    public static final int EBADMSG = 77;
-    public static final int EFTYPE = 79;
-    public static final int ENOTUNIQ = 80;
-    public static final int EBADFD = 81;
-    public static final int EREMCHG = 82;
-    public static final int ELIBACC = 83;
-    public static final int ELIBBAD = 84;
-    public static final int ELIBSCN = 85;
-    public static final int ELIBMAX = 86;
-    public static final int ELIBEXEC = 87;
-    public static final int ENOSYS = 88;
-    public static final int ENMFILE = 89;
-    public static final int ENOTEMPTY = 90;
-    public static final int ENAMETOOLONG = 91;
-    public static final int ELOOP = 92;
-    public static final int EOPNOTSUPP = 95;
-    public static final int EPFNOSUPPORT = 96;
-    public static final int ECONNRESET = 104;
-    public static final int ENOBUFS = 105;
-    public static final int EAFNOSUPPORT = 106;
-    public static final int EPROTOTYPE = 107;
-    public static final int ENOTSOCK = 108;
-    public static final int ENOPROTOOPT = 109;
-    public static final int ESHUTDOWN = 110;
-    public static final int ECONNREFUSED = 111;
-    public static final int EADDRINUSE = 112;
-    public static final int ECONNABORTED = 113;
-    public static final int ENETUNREACH = 114;
-    public static final int ENETDOWN = 115;
-    public static final int ETIMEDOUT = 116;
-    public static final int EHOSTDOWN = 117;
-    public static final int EHOSTUNREACH = 118;
-    public static final int EINPROGRESS = 119;
-    public static final int EALREADY = 120;
-    public static final int EDESTADDRREQ = 121;
-    public static final int EMSGSIZE = 122;
-    public static final int EPROTONOSUPPORT = 123;
-    public static final int ESOCKTNOSUPPORT = 124;
-    public static final int EADDRNOTAVAIL = 125;
-    public static final int ENETRESET = 126;
-    public static final int EISCONN = 127;
-    public static final int ENOTCONN = 128;
-    public static final int ETOOMANYREFS = 129;
-    public static final int EPROCLIM = 130;
-    public static final int EUSERS = 131;
-    public static final int EDQUOT = 132;
-    public static final int ESTALE = 133;
-    public static final int ENOTSUP = 134;
-    public static final int ENOMEDIUM = 135;
-    public static final int ENOSHARE = 136;
-    public static final int ECASECLASH = 137;
-    public static final int EILSEQ = 138;
-    public static final int EOVERFLOW = 139;
-    public static final int __ELASTERROR = 2000;
-}
-interface Syscalls {
-    public static final int SYS_null = 0;
-    public static final int SYS_exit = 1;
-    public static final int SYS_pause = 2;
-    public static final int SYS_open = 3;
-    public static final int SYS_close = 4;
-    public static final int SYS_read = 5;
-    public static final int SYS_write = 6;
-    public static final int SYS_sbrk = 7;
-    public static final int SYS_fstat = 8;
-    public static final int SYS_isatty = 9;
-    public static final int SYS_seek = 10;
-    public static final int SYS_kill = 11;
-    public static final int SYS_getpid = 12;
-}
diff --git a/src/org/xwt/mips/VM.java b/src/org/xwt/mips/VM.java
new file mode 100644 (file)
index 0000000..08fee29
--- /dev/null
@@ -0,0 +1,776 @@
+package org.xwt.mips;
+import java.io.*;
+
+abstract class VM implements Syscalls, Errno {
+    // Register Names
+    protected final static int ZERO = 0; // Immutable, hardwired to 0
+    protected final static int AT = 1;  // Reserved for assembler
+    protected final static int K0 = 26; // Reserved for kernel 
+    protected final static int K1 = 27; // Reserved for kernel 
+    protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss)
+    protected final static int SP = 29; // Stack pointer
+    protected final static int FP = 30; // Frame Pointer
+    protected final static int RA = 31; // Return Address
+    
+    // Return values (caller saved)
+    protected final static int V0 = 2;
+    protected final static int V1 = 3;
+    // Argument Registers (caller saved)
+    protected final static int A0 = 4; 
+    protected final static int A1 = 5;
+    protected final static int A2 = 6;
+    protected final static int A3 = 7;
+    // Temporaries (caller saved)
+    protected final static int T0 = 8;
+    protected final static int T1 = 9;
+    protected final static int T2 = 10;
+    protected final static int T3 = 11;
+    protected final static int T4 = 12;
+    protected final static int T5 = 13;
+    protected final static int T6 = 14;
+    protected final static int T7 = 15;
+    protected final static int T8 = 24;
+    protected final static int T9 = 25;
+    // Saved (callee saved)
+    protected final static int S0 = 16;
+    protected final static int S1 = 17;
+    protected final static int S2 = 18;
+    protected final static int S3 = 19;
+    protected final static int S4 = 20;
+    protected final static int S5 = 21;
+    protected final static int S6 = 22;
+    protected final static int S7 = 23;
+
+    // Page Constants
+    // Page Size: 4k
+    // Total Pages: 64k
+    // Maxiumum Addressable memory 256mb
+    // 1mb of stack space
+    protected final static int PAGE_SIZE = 4096;
+    protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2);
+    protected final static int PAGE_SHIFT = 12;
+    protected final static int STACK_PAGES = 256;
+    // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the
+    // new location of INITIAL_SP
+    protected final static int TOTAL_PAGES = 65536;
+    protected final static int BRK_LIMIT = 32768;
+    // Top page is always empty
+    // next page down contains command line arguments
+    protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE;
+    // next page down contains _user_info data
+    protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE;
+    // next page down is the start of the stack
+    protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE;
+    // magic page that signified an allocated but empty (untouched) page
+    private final static int[] emptyPage = new int[0];
+    
+    // Main memory
+    protected final int[][] readPages;
+    protected final int[][] writePages;
+    
+    // Brk
+    protected int brk; // PAGE not address
+        
+    // Entry point - what start() sets pc to
+    protected int entryPoint;
+    
+    // State constants
+    public final static int UNINITIALIZED = 0;
+    public final static int INITIALIZED = 1;
+    public final static int RUNNING = 2;
+    public final static int PAUSED = 3;
+    public final static int DONE = 4;
+    
+    // State
+    protected int state = UNINITIALIZED;
+    public final int getState() { return state; }
+    protected int exitStatus;
+    
+    // File descriptors
+    private final static int OPEN_MAX = 256;
+    private FileDescriptor[] fds;
+    
+    // Temporary buffer for read/write operations
+    private byte[] _byteBuf = null;
+    private final static int MAX_CHUNK = 4*1024*1024-8;
+    
+    // Abstract methods
+    // This should start executing at pc
+    public abstract void execute() throws EmulationException;
+    // This should initialize the cpu registers to point to the entry point
+    protected abstract void _start(int pc);
+   
+    public static final int PID = 1;
+    
+    public VM() {
+        readPages = new int[TOTAL_PAGES][];
+        writePages = new int[TOTAL_PAGES][];
+        for(int i=0;i<STACK_PAGES;i++)
+            readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
+    }
+    
+    public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
+        int n=0;
+        if((addr&3)!=0) {
+            int word = memRead(addr&~3);
+             switch(addr&3) {
+                case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break;
+                case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break;
+                case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break;
+            }
+            addr = (addr&~3)+4;
+        }
+        while(length-n > 3) {
+            int start = (addr&(PAGE_SIZE-1))>>2;
+            int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
+            int[] page = readPages[addr >>> PAGE_SHIFT];
+            if(page == null) throw new ReadFaultException(addr);
+            if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; }
+            for(int i=start;i<end;i++,addr+=4) {
+                int word = page[i];
+                a[n++] = (byte)((word>>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff);
+                a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff);
+            }
+        }
+        if(length-n > 0) {
+            int word = memRead(addr);
+            if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff);
+            if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff);
+            if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff);
+        }
+    }
+    
+    public void copyout(byte[] a, int addr, int length) throws FaultException {
+        int n=0;
+        if((addr&3)!=0) {
+            int word = memRead(addr&~3);
+             switch(addr&3) {
+                case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break;
+                case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break;
+                case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break;
+            }
+            memWrite(addr&~3,word);
+            addr = (addr&~3)+4;
+        }
+        
+        while(length-n > 3) {
+            int start = (addr&(PAGE_SIZE-1))>>2;
+            int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
+            int[] page = writePages[addr >>> PAGE_SHIFT];
+            if(page == null) throw new WriteFaultException(addr);
+            if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; }
+            for(int i=start;i<end;i++,addr+=4) {
+                int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
+                page[i] = word;
+            }
+        }
+        if(length-n > 0) {
+            int word = memRead(addr);
+            word = (word&0x00ffffff)|((a[n]&0xff)<<24);
+            if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); }
+            if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); }
+            memWrite(addr,word);
+        }
+    }
+    
+    public final int memRead(int addr) throws ReadFaultException  {
+        if((addr & 3) != 0) throw new ReadFaultException(addr);
+        int page = addr >>> PAGE_SHIFT;
+        int entry = (addr >>> 2) & (PAGE_WORDS-1);
+        try {
+            return readPages[page][entry];
+        } catch(ArrayIndexOutOfBoundsException e) {
+            if(page < 0) throw e; // should never happen
+            if(page > readPages.length) throw new ReadFaultException(addr);
+            if(readPages[page] != emptyPage) throw e; // should never happen
+            initPage(page);
+            return 0;
+        } catch(NullPointerException e) {
+            throw new ReadFaultException(addr);
+        }
+    }
+    
+    protected final void memWrite(int addr, int value) throws WriteFaultException  {
+        if((addr & 3) != 0) throw new WriteFaultException(addr);
+        int page = addr >>> PAGE_SHIFT;
+        int entry = (addr>>>2)&(PAGE_WORDS-1);
+        try {
+            writePages[page][entry] = value;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            if(page < 0) throw e;// should never happen
+            if(page > writePages.length) throw new WriteFaultException(addr);
+            if(readPages[page] != emptyPage) throw e; // should never happen
+            initPage(page);
+            writePages[page][entry] = value;
+        } catch(NullPointerException e) {
+            throw new WriteFaultException(addr);
+        }
+    }
+    
+    protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; }
+    
+    public final int exitStatus() {
+        if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state");
+        return exitStatus;
+    }
+     
+    public final int run(String[] args) throws EmulationException {
+        start(args);
+        for(;;) {
+            execute();
+            if(state != PAUSED) break;
+            System.err.println("WARNING: Pause requested while executing run()");
+            try { Thread.sleep(500); } catch(InterruptedException e) { }
+        }
+        if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state");
+        return exitStatus();
+    }
+    
+    private void addArgs(String[] args) throws EmulationException {
+        if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state");
+        int count = args.length;
+        byte[] nullTerminator = new byte[1];
+        int total = 4; /* null last table entry  */
+        for(int i=0;i<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
+        if(total > PAGE_SIZE) throw new EmulationException("Arguments too large");
+        int start = ARGS_ADDR;
+        int addr = start + (count+1)*4;
+        int[] table = new int[count+1];
+        for(int i=0;i<count;i++) {
+            byte[] a;
+            try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw  new Error(e.getMessage()); }
+            table[i] = addr;
+
+                copyout(a,addr,a.length);
+                addr += a.length;
+                copyout(nullTerminator,addr,1);
+                addr += 1;
+
+        }
+        addr=start;
+        for(int i=0;i<count;i++) {
+            memWrite(addr,table[i]);
+            addr += 4;
+        }
+    }
+    
+    public void setUserInfo(int index, int word) throws EmulationException {
+        if(index < 0 ||  index >= 1024) throw new EmulationException("setUserInfo called with index >= 1024");
+        memWrite(USER_INFO_ADDR+index*4,word);
+    }
+    
+    public int getUserInfo(int index) throws EmulationException {
+        if(index < 0 ||  index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024");
+        return memRead(USER_INFO_ADDR+index*4);
+    }
+    
+    public final void start(String[] args) throws EmulationException {
+        if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state");
+        _start(entryPoint);
+        addArgs(args);
+        fds = new FileDescriptor[OPEN_MAX];
+        fds[0] = new InputStreamFD(System.in)   { public boolean isatty() { return true; } };
+        fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } };
+        fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } };
+        state = PAUSED;
+    }
+    
+        
+    // Syscalls
+    private int write(int fdn, int addr, int count) {
+        int n = 0;
+        int r;
+        FileDescriptor fd;
+        count = Math.min(count,MAX_CHUNK);
+        try {
+            fd = fds[fdn];
+            if(fd == null || !fd.writable()) return -EBADFD;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            return -EBADFD;
+        }
+        try {
+            byte[] buf = byteBuf(count);
+            copyin(addr,buf,count);
+            return fd.write(buf,0,count);
+        } catch(FaultException e) {
+            System.err.println(e);
+            return -EFAULT;
+        } catch(IOException e) {
+            System.err.println(e);
+            return -EIO;
+        }
+    }
+
+    private int read(int fdn, int addr, int count) {
+        FileDescriptor fd;
+        count = Math.min(count,MAX_CHUNK);
+        try {
+            fd = fds[fdn];
+            if(fd == null || !fd.readable()) return -EBADFD;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            return -EBADFD;
+        }
+        try {
+            byte[] buf = byteBuf(count);
+            int n = fd.read(buf,0,count);
+            copyout(buf,addr,n);
+            return n;
+        } catch(FaultException e) {
+            System.err.println(e);
+            return -EFAULT;
+        } catch(IOException e) {
+            System.err.println(e);
+            return -EIO;
+        }
+    }
+    
+    private int close(int fdn) {
+        FileDescriptor fd;
+        try {
+            fd = fds[fdn];
+            if(fd == null) return -EBADFD;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            return -EBADFD;
+        }
+        fds[fdn] = null;
+        fd.close();
+        return 0;
+    }
+    
+    private int stat(FileInfo fi, int addr) {
+        int size = fi.size();
+        try {
+            memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16)
+            memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode
+            memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16)
+            memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16)
+            memWrite(addr+16,size); // st_size
+            memWrite(addr+20,0); // st_atime
+            // memWrite(addr+24,0) // st_spare1
+            memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime
+            // memWrite(addr+32,0) // st_spare2
+            memWrite(addr+36,0); // st_atime
+            // memWrite(addr+40,0) // st_spare3
+            memWrite(addr+44,512); // st_bklsize;
+            memWrite(addr+48,(size+511)&(~511)); // st_blocks
+            // memWrite(addr+52,0) // st_spare4[0]
+            // memWrite(addr+56,0) // st_spare4[1]
+        } catch(FaultException e) {
+            System.err.println(e);
+            return -EFAULT;
+        }
+        return 0;
+    }
+    
+    private int fstat(int fdn, int addr) {
+        FileDescriptor fd;
+        try {
+            fd = fds[fdn];
+            if(fd == null) return -EBADFD;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            return -EBADFD;
+        }
+        return stat(fd.fileInfo(),addr);
+    }
+    
+    public int sbrk(int incr) {
+        if(incr==0) return brk<<PAGE_SHIFT;
+        int oldBrk = brk;
+        int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
+        if(newBrk >= BRK_LIMIT) {
+            System.err.println("Hit BRK_LIMIT");
+            return -ENOMEM;
+        }
+        for(int i=oldBrk;i<newBrk+256;i++)
+            readPages[i] = writePages[i] = emptyPage;
+        brk = newBrk;
+        return oldBrk<<PAGE_SHIFT;
+    }
+        
+    private int open(int addr, int flags, int mode) {
+        final int O_RDONLY = 0;
+        final int O_WRONLY = 1;
+        final int O_RDWR = 2;
+        final int O_APPEND = 0x0008;
+        final int O_CREAT = 0x0200;
+        final int O_NONBLOCK = 0x4000;
+        final int O_EXCL = 0x0800;
+        
+        if((flags & O_APPEND) != 0) {
+            System.err.println("WARNING: O_APPEND not supported");
+            return -EOPNOTSUPP;
+        }
+        if((flags & O_NONBLOCK) != 0) {
+            System.err.println("WARNING: O_NONBLOCK not supported");
+            return -EOPNOTSUPP;
+        }
+        
+        try {
+            int fdn=-1;
+            File f = new File(cstring(addr));
+            System.err.println("Opening: " + f);
+            if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
+                if(!f.createNewFile()) return -EEXIST;
+            if(f.exists()) {
+                if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
+            } else {
+                if((flags & O_CREAT) == 0) return -ENOENT;
+            }
+            for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
+            if(fdn==-1) return -ENFILE;
+            fds[fdn] = new RegularFileDescriptor(f,flags&3);
+            return fdn;
+        } catch(FaultException e) {
+            return -EFAULT;
+        } catch(FileNotFoundException e) { 
+            if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES;
+            return -ENOENT;
+        } catch(IOException e) {
+            return -EIO;
+        }
+    }
+    
+    private int seek(int fdn, int offset, int whence) {
+        FileDescriptor fd;
+        try {
+            fd = fds[fdn];
+            if(fd == null || !fd.readable()) return -EBADFD;
+        } catch(ArrayIndexOutOfBoundsException e) {
+            return -EBADFD;
+        }
+        try {
+            return fd.seek(offset,whence);
+        } catch(IOException e) {
+            System.err.println(e);
+            return -EPIPE;
+        }
+    }
+    
+    // This will only be called by raise() to invoke the default handler
+    // We don't have to worry about actually delivering the signal
+    private int kill(int pid, int signal) {
+        if(pid != PID) return -ESRCH;
+        if(signal < 0 || signal >= 32) return -EINVAL;
+        switch(signal) {
+            case 0: return 0;
+            case 17: // SIGSTOP
+            case 18: // SIGTSTP
+            case 21: // SIGTTIN
+            case 22: // SIGTTOU
+                state = PAUSED;
+                break;
+            case 19: // SIGCONT
+            case 20: // SIGCHLD
+            case 23: // SIGIO
+            case 28: // SIGWINCH
+                break;
+            default: {
+                String msg = "Terminating on signal: " + signal + "\n";
+                exitStatus = 1;
+                state = DONE;
+                if(fds[2]==null) {
+                    System.out.print(msg);
+                } else {
+                    byte[] b = msg.getBytes();
+                    try {
+                        fds[2].write(b,0,b.length);
+                    } catch(IOException e) { }
+                }
+            }
+        }
+        return 0;
+    }
+    
+    private int getpid() { return PID; }
+    
+    protected int syscall(int syscall, int a, int b, int c, int d) {
+        switch(syscall) {
+            case SYS_null: return 0;
+            case SYS_exit: exitStatus = a; state = DONE; return 0;
+            case SYS_pause: state = PAUSED; return 0;
+            case SYS_write: return write(a,b,c);
+            case SYS_fstat: return fstat(a,b);
+            case SYS_sbrk: return sbrk(a);
+            case SYS_open: return open(a,b,c);
+            case SYS_close: return close(a);
+            case SYS_read: return read(a,b,c);
+            case SYS_seek: return seek(a,b,c);
+            case SYS_kill: return kill(a,b);
+            case SYS_getpid: return getpid();
+            default:
+                System.err.println("Attempted to use unknown syscall: " + syscall);
+                return -ENOSYS;
+        }
+    }
+    
+    // Helper function to read a cstring from main memory
+    private String cstring(int addr) throws ReadFaultException {
+        StringBuffer sb = new StringBuffer();
+        for(;;) {
+            int word = memRead(addr&~3);
+            switch(addr&3) {
+                case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
+                case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
+                case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
+                case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
+            }
+        }
+    }
+     
+    // Exceptions
+    public static class ReadFaultException extends FaultException {
+        public ReadFaultException(int addr) { super(addr); }
+    }
+    public static class WriteFaultException extends FaultException {
+        public WriteFaultException(int addr) { super(addr); }
+    }
+    public static abstract class FaultException extends EmulationException {
+        private int addr;
+        public FaultException(int addr) { this.addr = addr; }
+        public String getMessage() { return "fault at: " + toHex(addr); }
+    }
+    public static class EmulationException extends Exception {
+        public EmulationException() { }
+        public EmulationException(String s) { super(s); }
+    }
+    
+    // FileInfo classes - used by stat(2)
+    static class FileInfo {
+        public static final int S_IFIFO = 0010000;
+        public static final int S_FCHR =  0020000;
+        public static final int S_IFDIR = 0040000;
+        public static final int S_IFREG = 0100000;
+        
+        public int size() { return 0; }
+        public int type() { return S_IFIFO; }
+        public long modTime() { return 0; }
+    }
+        
+    public static class FileFileInfo extends FileInfo {
+        public File f;
+        public FileFileInfo(File f) { this.f = f; }
+        public int size() { return (int)f.length(); }
+        public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; }
+        public long modTime() { return f.lastModified(); }
+    }
+
+    // File descriptor classes
+    public static abstract class FileDescriptor {
+        public boolean readable() { return false; }
+        public boolean writable() { return false; }
+        
+        private static final FileInfo nullFi = new FileInfo();
+        private FileInfo fi;
+        public FileInfo fileInfo() { return fi; }
+        
+        FileDescriptor() { this(null); }
+        FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; }
+        
+        public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
+        public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
+        
+        public int seek(int n, int whence)  throws IOException  { return -ESPIPE; }
+        public boolean isatty() { return false; }
+        
+        void close() { }
+    }
+    
+    public static class RegularFileDescriptor extends FileDescriptor {
+        private int mode;
+        private RandomAccessFile raf;
+        public boolean readable() { return mode != 1; }
+        public boolean writable() { return mode != 0; }
+        
+        RegularFileDescriptor(File f,int m) throws IOException {
+            super(new FileFileInfo(f));
+            String mode = m == 0 ? "r" : "rw";
+            this.mode = m;
+            raf = new RandomAccessFile(f,mode);
+            if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large");
+        }
+        
+        public int seek(int n, int whence) throws IOException {
+            final int SEEK_SET = 0;
+            final int SEEK_CUR = 1;
+            final int SEEK_END = 2;
+            
+            switch(whence) {
+                case SEEK_SET: break;
+                case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break;
+                case SEEK_END: n = (int)(raf.length()+n); break;
+                default: return -EINVAL;
+            }
+            raf.seek(n);
+            return n;
+        }
+        
+        public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; }
+        public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; }
+        
+        void close() { try { raf.close(); } catch(Exception e) { } }
+    }
+    
+    public class OutputStreamFD extends FileDescriptor {
+        private OutputStream os;
+        public boolean writable() { return true; }
+        public OutputStreamFD(OutputStream os) { this.os = os; }
+        public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
+    }
+    
+    public class InputStreamFD extends FileDescriptor {
+        private InputStream is;
+        public boolean readable() { return true; }
+        public InputStreamFD(InputStream is) { this.is = is; }
+        public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
+    }
+    
+    // Utility functions
+    private byte[] byteBuf(int size) {
+        if(_byteBuf==null) _byteBuf = new byte[size];
+        else if(_byteBuf.length < size)
+            _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)];
+        return _byteBuf;
+    }
+    protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+    protected final static int min(int a, int b) { return a < b ? a : b; }
+    protected final static int max(int a, int b) { return a > b ? a : b; }
+}
+
+
+
+interface Errno {
+    public static final int EPERM = 1;
+    public static final int ENOENT = 2;
+    public static final int ESRCH = 3;
+    public static final int EINTR = 4;
+    public static final int EIO = 5;
+    public static final int ENXIO = 6;
+    public static final int ENOEXEC = 8;
+    public static final int EBADF = 9;
+    public static final int ECHILD = 10;
+    public static final int EAGAIN = 11;
+    public static final int ENOMEM = 12;
+    public static final int EACCES = 13;
+    public static final int EFAULT = 14;
+    public static final int ENOTBLK = 15;
+    public static final int EBUSY = 16;
+    public static final int EEXIST = 17;
+    public static final int EXDEV = 18;
+    public static final int ENODEV = 19;
+    public static final int ENOTDIR = 20;
+    public static final int EISDIR = 21;
+    public static final int EINVAL = 22;
+    public static final int ENFILE = 23;
+    public static final int EMFILE = 24;
+    public static final int ENOTTY = 25;
+    public static final int ETXTBSY = 26;
+    public static final int EFBIG = 27;
+    public static final int ENOSPC = 28;
+    public static final int ESPIPE = 29;
+    public static final int EROFS = 30;
+    public static final int EMLINK = 31;
+    public static final int EPIPE = 32;
+    public static final int EDOM = 33;
+    public static final int ERANGE = 34;
+    public static final int ENOMSG = 35;
+    public static final int EIDRM = 36;
+    public static final int ECHRNG = 37;
+    public static final int ELNRNG = 41;
+    public static final int EUNATCH = 42;
+    public static final int ENOCSI = 43;
+    public static final int EDEADLK = 45;
+    public static final int ENOLCK = 46;
+    public static final int EBADE = 50;
+    public static final int EBADR = 51;
+    public static final int EXFULL = 52;
+    public static final int ENOANO = 53;
+    public static final int EBADRQC = 54;
+    public static final int EBADSLT = 55;
+    public static final int EDEADLOCK = 56;
+    public static final int EBFONT = 57;
+    public static final int ENOSTR = 60;
+    public static final int ENODATA = 61;
+    public static final int ETIME = 62;
+    public static final int ENOSR = 63;
+    public static final int ENONET = 64;
+    public static final int ENOPKG = 65;
+    public static final int EREMOTE = 66;
+    public static final int ENOLINK = 67;
+    public static final int EADV = 68;
+    public static final int ESRMNT = 69;
+    public static final int ECOMM = 70;
+    public static final int EPROTO = 71;
+    public static final int EMULTIHOP = 74;
+    public static final int ELBIN = 75;
+    public static final int EDOTDOT = 76;
+    public static final int EBADMSG = 77;
+    public static final int EFTYPE = 79;
+    public static final int ENOTUNIQ = 80;
+    public static final int EBADFD = 81;
+    public static final int EREMCHG = 82;
+    public static final int ELIBACC = 83;
+    public static final int ELIBBAD = 84;
+    public static final int ELIBSCN = 85;
+    public static final int ELIBMAX = 86;
+    public static final int ELIBEXEC = 87;
+    public static final int ENOSYS = 88;
+    public static final int ENMFILE = 89;
+    public static final int ENOTEMPTY = 90;
+    public static final int ENAMETOOLONG = 91;
+    public static final int ELOOP = 92;
+    public static final int EOPNOTSUPP = 95;
+    public static final int EPFNOSUPPORT = 96;
+    public static final int ECONNRESET = 104;
+    public static final int ENOBUFS = 105;
+    public static final int EAFNOSUPPORT = 106;
+    public static final int EPROTOTYPE = 107;
+    public static final int ENOTSOCK = 108;
+    public static final int ENOPROTOOPT = 109;
+    public static final int ESHUTDOWN = 110;
+    public static final int ECONNREFUSED = 111;
+    public static final int EADDRINUSE = 112;
+    public static final int ECONNABORTED = 113;
+    public static final int ENETUNREACH = 114;
+    public static final int ENETDOWN = 115;
+    public static final int ETIMEDOUT = 116;
+    public static final int EHOSTDOWN = 117;
+    public static final int EHOSTUNREACH = 118;
+    public static final int EINPROGRESS = 119;
+    public static final int EALREADY = 120;
+    public static final int EDESTADDRREQ = 121;
+    public static final int EMSGSIZE = 122;
+    public static final int EPROTONOSUPPORT = 123;
+    public static final int ESOCKTNOSUPPORT = 124;
+    public static final int EADDRNOTAVAIL = 125;
+    public static final int ENETRESET = 126;
+    public static final int EISCONN = 127;
+    public static final int ENOTCONN = 128;
+    public static final int ETOOMANYREFS = 129;
+    public static final int EPROCLIM = 130;
+    public static final int EUSERS = 131;
+    public static final int EDQUOT = 132;
+    public static final int ESTALE = 133;
+    public static final int ENOTSUP = 134;
+    public static final int ENOMEDIUM = 135;
+    public static final int ENOSHARE = 136;
+    public static final int ECASECLASH = 137;
+    public static final int EILSEQ = 138;
+    public static final int EOVERFLOW = 139;
+    public static final int __ELASTERROR = 2000;
+}
+
+interface Syscalls {
+    public static final int SYS_null = 0;
+    public static final int SYS_exit = 1;
+    public static final int SYS_pause = 2;
+    public static final int SYS_open = 3;
+    public static final int SYS_close = 4;
+    public static final int SYS_read = 5;
+    public static final int SYS_write = 6;
+    public static final int SYS_sbrk = 7;
+    public static final int SYS_fstat = 8;
+    public static final int SYS_isatty = 9;
+    public static final int SYS_seek = 10;
+    public static final int SYS_kill = 11;
+    public static final int SYS_getpid = 12;
+}
index cc6b351..374cf25 100644 (file)
@@ -1,7 +1,7 @@
 SEARCH_DIR(build)
 ENTRY(_start)
-STARTUP(org/xwt/imp/crt0.c.o)
-INPUT(org/xwt/imp/syscalls.c.o)
+STARTUP(org/xwt/mips/crt0.c.o)
+INPUT(org/xwt/mips/syscalls.c.o)
 GROUP(-lc -lgcc)
 __DYNAMIC  =  0;
 
index 676378c..760c474 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt.plat;
 
 import org.xwt.*;