utilize DeferredBitVector functionality in Fleet implementations
[fleet.git] / src / edu / berkeley / fleet / api / Instruction.java
index 290fcac..a9698ed 100644 (file)
 package edu.berkeley.fleet.api;
+import java.util.*;
 
+/** a Fleet instruction; includes execution location but not full dispatch path */
 public abstract class Instruction {
 
-    public final Pump pump;
-    public Instruction(Pump pump) { this.pump = pump; }
-    public String toString() { return pump+": "; }
+    /** the dock which is to execute this instruction */
+    public final Dock      dock;
 
-    public boolean isLooping() { return true; }
-    public boolean isRepeating() { return false; }
-    public boolean isSK() { return false; }
-    public boolean isDL() { return false; }
+    /** the instruction's predicate */
+    public final Predicate predicate;
 
-    public static class Clog extends Instruction {
-        public Clog(Pump pump) { super(pump); }
-        public String toString() { return super.toString() + "clog;"; }
-        public boolean isLooping() { return false; }
+    Instruction(Dock dock, Predicate predicate) {
+        if (dock==null)      throw new RuntimeException("dock may not be null");
+        if (predicate==null) throw new RuntimeException("predicate may not be null");
+        this.dock = dock;
+        this.predicate = predicate;
     }
 
-    public static class UnClog extends Instruction {
-        public UnClog(Pump pump) { super(pump); }
-        public String toString() { return super.toString() + "unclog;"; }
-    }
+    //public abstract Instruction withLooping(boolean newLooping);
+    //public abstract Instruction withPredicate(Predicate newPredicate);
 
-    public static class Massacre extends Instruction {
-        public Massacre(Pump pump) { super(pump); }
+    public String toString() {
+        String s = predicate.toString();
+        if (s.length()>0) s = "["+s+"] ";
+        return dock+": "+s;
     }
 
-    public static class Kill extends Instruction {
-        public final int count;
-        public Kill(Pump pump, int count) { super(pump); this.count = count; }
-        public String toString() { return super.toString() + "kill"+(count==1?"":(" "+count))+";"; }
-    }
+    /**
+     *  A <tt>set</tt> instruction.
+     *
+     *  Note that immediates are supplied as Java <tt>long</tt> values
+     *  because they are actual integers with two's complement
+     *  sign-extension semantics.  This is in contrast to most other
+     *  immediate values in the API which are raw bit sequences of
+     *  fixed length -- these are represented by instances of
+     *  <tt>BitVector</tt>.
+     */
+    public static class Set extends Instruction {
 
-    public static class PredicatedInstruction extends Instruction {
-        public static final int P_ALWAYS = 0x0001;
-        public static final int P_IF_A   = 0x0002;
-        public static final int P_IF_B   = 0x0003;
-        public static final int P_IF_Z   = 0x0004;
-
-        public final int predicate;
-        public final boolean dl;
-        public boolean isDL() { return dl; }
-        
-        public PredicatedInstruction(Pump pump, boolean dl, int predicate) {
-            super(pump);
-            this.predicate = predicate;
-            this.dl = dl;
-        }
-        public String toString() {
-            String dlx = dl ? "[dl] " : "";
-            switch(predicate) {
-                case P_ALWAYS: return dlx+       super.toString();
-                case P_IF_A:   return dlx+"[a] "+super.toString();
-                case P_IF_B:   return dlx+"[b] "+super.toString();
-                case P_IF_Z:   return dlx+"[z] "+super.toString();
+        /** the destination (latch to be set) */
+        public final SetDest        dest;
+
+        /** the source (what will be put in the <tt>dest</tt> latch) */
+        public final SetSource      source;
+
+        /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
+        public final long           immediate;
+
+        /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
+        public final FlagFunction   newFlagA;
+
+        /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
+        public final FlagFunction   newFlagB;
+
+        /** basic constructor */
+        public Set(Dock dock, SetDest dest, SetSource source) { this(dock, Predicate.Default, dest, source); }
+        public Set(Dock dock, Predicate predicate, SetDest dest, SetSource source) {
+            super(dock, predicate);
+            OUTER: switch(dest) {
+                case InnerLoopCounter:
+                    switch(source) {
+                        case Infinity: case DataLatch: case Immediate: break OUTER;
+                        default: break;
+                    }
+                case OuterLoopCounter:
+                    switch(source) {
+                        case Decrement: case DataLatch: case Immediate: break OUTER;
+                        default: break;
+                    }
+                case DataLatch:
+                    if (source==SetSource.Immediate) break;
+                default: throw new RuntimeException("cannot set " + dest + " to " + source);
             }
-            throw new Error();
+            this.source = source;
+            this.dest = dest;
+            this.immediate = 0;
+            this.newFlagA = null;
+            this.newFlagB = null;
         }
-    }
 
-    public static class SetFlags extends PredicatedInstruction {
-        public static final int FLAG_Z     = 0x0001;
-        public static final int FLAG_NOT_Z = 0x0002;
-        public static final int FLAG_S     = 0x0004;
-        public static final int FLAG_NOT_S = 0x0008;
-        public static final int FLAG_B     = 0x0010;
-        public static final int FLAG_NOT_B = 0x0020;
-        public static final int FLAG_A     = 0x0040;
-        public static final int FLAG_NOT_A = 0x0080;
-
-        public final int flag_a;
-        public final int flag_b;
-        public SetFlags(Pump pump, boolean dl, int predicate, int flag_a, int flag_b) {
-            super(pump, dl, predicate);
-            this.flag_a = flag_a;
-            this.flag_b = flag_b;
+        /** constructor for set instructions with immediates */
+        public Set(Dock dock, SetDest dest, long immediate) { this(dock, Predicate.Default, dest, immediate); }
+        public Set(Dock dock, Predicate predicate, SetDest dest, long immediate) {
+            super(dock, predicate);
+            if (dest!=SetDest.InnerLoopCounter && dest!=SetDest.OuterLoopCounter && dest!=SetDest.DataLatch)
+                throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate");
+            this.source = SetSource.Immediate;
+            this.dest = dest;
+            this.immediate = immediate;
+            this.newFlagA = null;
+            this.newFlagB = null;
         }
-        public SetFlags(Pump pump, int flag_a, int flag_b) { this(pump, false, P_ALWAYS, flag_a, flag_b); }
-
-        public boolean isLooping() { return true; }
-        private String printFlag(int flag) {
-            if (flag==0) return "0";
-            if ((flag & (FLAG_Z | FLAG_NOT_Z)) == (FLAG_Z | FLAG_NOT_Z)) return "1";
-            if ((flag & (FLAG_B | FLAG_NOT_B)) == (FLAG_B | FLAG_NOT_B)) return "1";
-            if ((flag & (FLAG_A | FLAG_NOT_A)) == (FLAG_A | FLAG_NOT_A)) return "1";
-            if ((flag & (FLAG_S | FLAG_NOT_S)) == (FLAG_S | FLAG_NOT_S)) return "1";
-            String ret = "";
-            if ((flag & FLAG_A)     != 0) ret += (ret.length()>=0?"|":"") +  "a";
-            if ((flag & FLAG_NOT_A) != 0) ret += (ret.length()>=0?"|":"") + "!a";
-            if ((flag & FLAG_B)     != 0) ret += (ret.length()>=0?"|":"") +  "b";
-            if ((flag & FLAG_NOT_B) != 0) ret += (ret.length()>=0?"|":"") + "!b";
-            if ((flag & FLAG_S)     != 0) ret += (ret.length()>=0?"|":"") +  "s";
-            if ((flag & FLAG_NOT_S) != 0) ret += (ret.length()>=0?"|":"") + "!s";
-            if ((flag & FLAG_Z)     != 0) ret += (ret.length()>=0?"|":"") +  "z";
-            if ((flag & FLAG_NOT_Z) != 0) ret += (ret.length()>=0?"|":"") + "!z";
-            return ret;
+
+        /** constructor for <tt>set flags</tt> instructions */
+        public Set(Dock dock, FlagFunction newFlagA, FlagFunction newFlagB) { this(dock, Predicate.Default, newFlagA, newFlagB); }
+        public Set(Dock dock, Predicate predicate, FlagFunction newFlagA, FlagFunction newFlagB) {
+            super(dock, predicate);
+            this.source = SetSource.Immediate;
+            this.dest = SetDest.Flags;
+            this.immediate = 0;
+            this.newFlagA = newFlagA;
+            this.newFlagB = newFlagB;
         }
-        public String toString() {
-            return super.toString() + " setflags a=" + printFlag(flag_a) + ", b=" + printFlag(flag_b);
+
+        /** possible sources for the Set instruction */
+        public static enum SetSource {
+            Infinity, DataLatch, Immediate, Decrement;
+        }
+        /** possible destinations for the Set instruction */
+        public static enum SetDest {
+            InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
         }
-    }
 
-    public static class DecrLoop extends PredicatedInstruction {
-        public DecrLoop(Pump pump) { super(pump, true, P_ALWAYS); }
-        public DecrLoop(Pump pump, boolean dl, int predicate) { super(pump, dl, predicate); }
-        public boolean isDL() { return true; }
-        public boolean isLooping() { return true; }
-    }
+        /**
+         *  (Immutable) a truth table describing how to update a flag
+         *  based on the value of other flags; it is the logical OR of
+         *  a set of flag predicates.  This class is immutable; all
+         *  methods that alter the function return a new object.
+         */
+        public static class FlagFunction implements Iterable<Predicate> {
 
-    public static class Counter extends PredicatedInstruction {
-        public static final int DATA_LATCH = -1;
-        public static final int REPEAT_COUNTER = -2;
-        public static final int LOOP_COUNTER = -3;
-        public static final int STANDING = -3;
-        public final int source;
-        public final int dest;
-        public Counter(Pump pump, int source, int dest) { this(pump, false, P_ALWAYS, source, dest); }
-        public Counter(Pump pump, boolean dl, int predicate, int source, int dest) {
-            super(pump, dl, predicate);
-            this.source = source;
-            this.dest = dest;
+            /** the function that always assigns zero */
+            public static final FlagFunction ZERO = new FlagFunction();
+
+            /** the function that always assigns one */
+            public static final FlagFunction ONE  = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
+
+            private final java.util.Set<Predicate> predicates;
+
+            public Iterator<Predicate> iterator() { return predicates.iterator(); }
+
+            private FlagFunction() { this(Collections.EMPTY_SET); }
+            private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
+
+            /** returns the function which is the logical OR of this function and <tt>ff</tt> */
+            public FlagFunction add(FlagFunction ff) {
+                FlagFunction ret = this;
+                for(Predicate p : ff) ret = ret.add(p);
+                return ret;
+            }
+
+            /** returns the function which is the logical OR of this function and <tt>p</tt> */
+            public FlagFunction add(Predicate p) {
+                HashSet h = new HashSet();
+                h.addAll(predicates);
+                switch(p) {
+                    case FlagA: case NotFlagA:
+                    case FlagB: case NotFlagB:
+                    case FlagC: case NotFlagC:
+                        break;
+                    default:
+                        throw new RuntimeException("invalid predicate in FlagFunction: " + p);
+                }
+                h.add(p);
+                return new FlagFunction(h);
+            }
+
+            /** remove <tt>p</tt> from the set of terms which this function is the logical OR of */
+            public FlagFunction remove(Predicate p) {
+                HashSet h = new HashSet();
+                h.addAll(predicates);
+                h.remove(p);
+                return new FlagFunction(h);
+            }
+
+            public String toString() {
+                if (predicates.isEmpty()) return "0";
+                if (predicates.contains(Predicate.FlagA) && predicates.contains(Predicate.NotFlagA)) return "1";
+                if (predicates.contains(Predicate.FlagB) && predicates.contains(Predicate.NotFlagB)) return "1";
+                if (predicates.contains(Predicate.FlagC) && predicates.contains(Predicate.NotFlagC)) return "1";
+                StringBuffer ret = new StringBuffer();
+                boolean empty = true;
+                for(Predicate p : new Predicate[] {
+                        Predicate.FlagA, Predicate.NotFlagA,
+                        Predicate.FlagB, Predicate.NotFlagB,
+                        Predicate.FlagC, Predicate.NotFlagC })
+                    if (predicates.contains(p)) {
+                        if (!empty) ret.append("| ");
+                        ret.append(p);
+                        empty = false;
+                    }
+                return ret.toString();
+            }
+
+            public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
+                boolean ret = false;
+                for(Predicate p : this)
+                    ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
+                return ret;
+            }
         }
+
         public String toString() {
-            if (source==LOOP_COUNTER && dest==DATA_LATCH) return "take loop counter;";
-            StringBuffer ret = new StringBuffer();
-            ret.append("load ");
             switch(dest) {
-                case LOOP_COUNTER: ret.append("loop"); break;
-                case REPEAT_COUNTER: ret.append("repeat"); break;
-                default: throw new RuntimeException("invalid");
-            }
-            ret.append(" counter");
-            if (source == STANDING)
-                ret.append(" with *");
-            else if (source >= 0) {
-                ret.append(" with " + source);
-            } else if (source!=DATA_LATCH) {
-                throw new RuntimeException("invalid");
+                case InnerLoopCounter:
+                    switch(source) {
+                        case Infinity: return super.toString()+"set ilc=*;";
+                        case DataLatch: return super.toString()+"set ilc=data;";
+                        case Immediate: return super.toString()+"set ilc="+immediate+";";
+                    }
+                case OuterLoopCounter:
+                    switch(source) {
+                        case Decrement: return super.toString()+"set olc--;";
+                        case DataLatch: return super.toString()+"set olc=data;";
+                        case Immediate: return super.toString()+"set olc="+immediate+";";
+                    }
+                case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
+                case DataLatch: return super.toString()+"set word="+immediate+";";
             }
-            ret.append(";");
-            return ret.toString();
+            throw new Error("impossible");
         }
-        public boolean isLooping() { return true; }
     }
 
-    public static class Move extends PredicatedInstruction {
-        public final Destination dest;
+    /** shifts an immediate into the low-order bits of the data latch */
+    public static class Shift extends Instruction {
+        public final DeferredBitVector immediate;
+        public Shift(Dock dock, DeferredBitVector immediate) { this(dock, Predicate.Default, immediate); }
+        public Shift(final Dock dock, Predicate predicate, final DeferredBitVector arg) {
+            super(dock, predicate);
+            this.immediate = new DeferredBitVector() {
+                    public BitVector getBitVector() {
+                        BitVector ret = arg.getBitVector();
+                        if (ret.length() != dock.getShip().getFleet().getShiftWidth())
+                            throw new RuntimeException("attempt to create a Shift instruction with a "+ret.length()+
+                                                       "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
+                                                       "-bit shift instructions");
+                        return ret;
+                    }
+                };
+        }
+        public String toString() { return super.toString()+"shift "+immediate.getBitVector(); }
+    }
 
+    /** a flush instruction */
+    public static class Flush extends Instruction {
+        public Flush(Dock dock) { this(dock, Predicate.Default); }
+        public Flush(Dock dock, Predicate predicate) {
+            super(dock, predicate);
+            if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
+        }
+        public String toString() { return super.toString()+"flush;"; }
+    }
+
+    /** all communication is performed with this instruction */
+    public static class Move extends Instruction {
+
+        /** if true, this instruction is vulnerable to torpedoes */
+        public final boolean     interruptible;
+
+        /** if non-null, the path to load into the path latch */
+        public final Path        path;
+
+        /** if true, a token will be consumed before execution */
         public final boolean     tokenIn;
+
+        /** if true, data will be consumed before execution */
         public final boolean     dataIn;
-        public final boolean     latch;
-        public final boolean     dataOutDest;
+
+        /** if true, the data consumed will be copied into the data latch */
+        public final boolean     latchData;
+
+        /** if true, the data consumed will be copied into the path latch */
+        public final boolean     latchPath;
+
+        /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
         public final boolean     dataOut;
+
+        /** if true, the a token will be transmitted to the location in the path latch */
         public final boolean     tokenOut;
-        public final boolean     requeue;
-        public final boolean     ignoreUntilLast;
-
-        /** count=0 denotes a standing move */
-        public Move(Pump        pump,
-                    boolean     dl,
-                    int         predicate,
-                    Destination dest,
+
+        public Move(Dock        dock,
+                    Path        path,
                     boolean     tokenIn,
                     boolean     dataIn,
-                    boolean     latch,
-                    boolean     dataOutDest,
+                    boolean     latchData,
+                    boolean     latchPath,
                     boolean     dataOut,
-                    boolean     tokenOut,
-                    boolean     requeue,
-                    boolean     ignoreUntilLast) {
-            super(pump, dl, predicate);
-            this.dest = dest;
+                    boolean     tokenOut
+                    ) {
+            this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
+        public Move(Dock        dock,
+                    Predicate   predicate,
+                    boolean     interruptible,
+                    Path        path,
+                    boolean     tokenIn,
+                    boolean     dataIn,
+                    boolean     latchData,
+                    boolean     latchPath,
+                    boolean     dataOut,
+                    boolean     tokenOut
+                    ) {
+            super(dock, predicate);
+            this.path = path;
             this.tokenIn = tokenIn;
             this.dataIn = dataIn;
-            this.latch = latch;
-            this.dataOutDest = dataOutDest;
+            this.latchData = latchData;
+            this.latchPath = latchPath;
             this.dataOut = dataOut;
             this.tokenOut = tokenOut;
-            this.requeue = requeue;
-            this.ignoreUntilLast = ignoreUntilLast;
-            if (pump.isInbox() && tokenIn && dataIn)
-                throw new RuntimeException("cannot have both \"wait\" and \"take\"/\"recieve\" on an inbox: " + this);
-            if (pump.isOutbox() && tokenOut && dataOut)
-                throw new RuntimeException("cannot have both \"sendto\" and \"notify\" on an outbox: " + this);
-            if (latch && !dataIn)
-                throw new RuntimeException("cannot have latch bit set without dataIn bit: " + this);
+            this.interruptible = interruptible;
+            if (dock != null && dock.isInputDock() && tokenIn && dataIn)
+                throw new RuntimeException("cannot have two \"recv\"s: " + this);
+            if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
+                throw new RuntimeException("cannot have two \"send\"s: " + this);
+            if (latchData && !dataIn)
+                throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
+            if (latchPath && !dataIn)
+                throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
+            if (latchPath && path!=null)
+                throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
         }
 
         public String toString() {
-            // FIXME
-            String ret = super.toString();
-            boolean needcomma = false;
-            if (tokenIn)           { ret += (needcomma ? ", " : "") + "wait";    needcomma = true; }
-            if (dataIn && latch)  {
-                if (pump.isInbox())
-                    ret += (needcomma ? ", " : "") + "receive";
-                else
-                    ret += (needcomma ? ", " : "") + "take";
-                needcomma = true;
-            }
-            if (dataIn && !latch)  { ret += (needcomma ? ", " : "") + "dismiss"; needcomma = true; }
-            if (dataOut)  {
-                if (pump.isInbox() || dest==null)
-                    ret += (needcomma ? ", " : "") + "deliver";
-                else
-                    ret += (needcomma ? ", " : "") + "sendto "+dest;
-                needcomma = true;
+            StringBuffer ret = new StringBuffer();
+            if (tokenIn)                        ret.append(", recv token");
+            if (dataIn) {
+                if      (latchPath && latchData) ret.append(!dock.isInputDock() ? ", collect packet"  : ", recv packet");
+                if      (latchPath)              ret.append(!dock.isInputDock() ? ", collect path"    : ", recv path");
+                else if (latchData)              ret.append(!dock.isInputDock() ? ", collect"         : ", recv");
+                else                             ret.append(!dock.isInputDock() ? ", collect nothing" : ", recv nothing");
             }
-            if (tokenOut) { ret += (needcomma ? ", " : "") + "notify "+dest; needcomma = true; }
-            return ret;
+            if (dataOut && dock.isInputDock())  ret.append(", deliver");
+            if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send"  : ", send to "  + pathToString(path));
+            if (tokenOut)                       ret.append(path==null ? ", token" : ", send token to " + pathToString(path));
+            String s = ret.toString();
+            s = s.equals("") ? "nop" : s.substring(2);
+            if (interruptible) s = "[T] " + s;
+            return super.toString()+s+";";
         }
 
-        public boolean isLooping() { return true; }
-        public boolean isRepeating() { return true; }
-    }
-
-    public static class HalfLiteral extends PredicatedInstruction {
-        public final long literal;
-        public final boolean high;
-        public HalfLiteral(Pump pump, boolean dl, int predicate, long literal, int count, boolean high) {
-            super(pump, dl, predicate);
-            this.literal = literal;
-            this.high = high;
+        private String pathToString(Path path) {
+            BitVector signal = path.getSignal();
+            if (signal!=null)
+                for(int i=0; i<signal.length(); i++)
+                    if (signal.get(i))
+                        return (path.getDestination()+":"+signal.toLong());
+            return (path.getDestination()+"");
         }
-        public boolean isRequeueing() { return true; }
-        public boolean isLooping() { return true; }
     }
 
-    public static class Literal extends PredicatedInstruction {
-        public final long literal;
-        public Literal(Pump pump, boolean dl, int predicate, long literal) {
-            super(pump, dl, predicate);
-            this.literal = literal;
-        }
-        public boolean isLooping() { return true; }
-        public boolean isRequeueing() { return true; }
-        public static boolean canRepresent(long literal) {
-            long il = literal;
-            long allones = ~(-1L << 37);
-            il = literal = literal & allones;
-            if      (((il & ~(-1L << 19)) & allones) == 0)       return true;
-            else if (((il | ~(-1L << 19)) & allones) == allones) return true;
-            else if (((il &  (-1L << 19)) & allones) == 0)       return true;
-            else if (((il |  (-1L << 19)) & allones) == allones) return true;
-            return false;
-        }
+    /** a flush instruction */
+    public static class Abort extends Instruction {
+        public Abort(Dock dock, Predicate predicate) { super(dock, predicate); }
+        public String toString() { return super.toString()+"abort;"; }
     }
 
+    /** marks the start of a loop; closes the hatch */
+    public static class Head extends Instruction {
+        public Head(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
+        public String toString() { return dock+": head;"; }
+    }
 
-    public static class CodeBagDescriptor extends PredicatedInstruction {
-        // address of CBD, relative to address that this instruction was loaded from
-        public final long offset;
-        public final long size;
-        public CodeBagDescriptor(Pump pump, long offset, long size) { this(pump, false, P_ALWAYS, offset, size); }
-        public CodeBagDescriptor(Pump pump, boolean dl, int predicate, long offset, long size) {
-            super(pump, dl, predicate);
-            this.offset = offset;
-            this.size = size;
-        }
-        public String toString() {
-            String off = ""+offset;
-            if (offset > 0) off = "+"+off;
-            return "(CBD @"+off+"+"+size+"): sendto " + pump;
-        }
+    /** marks the end of a loop; closes the hatch */
+    public static class Tail extends Instruction {
+        public Tail(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
+        public String toString() { return dock+": tail;"; }
     }
 
 }