mild overhaul of Interpreter; now capable of performing MergeSort
[fleet.git] / src / edu / berkeley / fleet / interpreter / InterpreterDock.java
index 1610d19..5c7e9ec 100644 (file)
@@ -1,32 +1,37 @@
 package edu.berkeley.fleet.interpreter;
 import java.util.*;
-import edu.berkeley.sbp.util.ANSI;
 import edu.berkeley.fleet.two.*;
 import edu.berkeley.fleet.api.*;
-import edu.berkeley.fleet.api.Instruction;
-import static edu.berkeley.fleet.api.Predicate.*;
+import edu.berkeley.sbp.util.ANSI;
 
 /** anything that has a source (instruction horn) address on the switch fabric */
 class InterpreterDock extends FleetTwoDock {
 
     // Dock State //////////////////////////////////////////////////////////////////////////////
     
-    public boolean flag_a = false;
-    public boolean flag_b = false;
-    public boolean flag_c = false;
-    public int ilc = 1;
-    public int olc = 1;
-    public BitVector dataLatch = new BitVector(getShip().getFleet().getWordWidth());
-    public InterpreterPath pathLatch = null;
-    public InterpreterPath tapl = null;
-    public boolean hatchIsOpen = true;
-    private Instruction executing = null;
-    private Queue<Instruction> instructions = new LinkedList<Instruction>();
-    private Queue<Instruction> epilogue = new LinkedList<Instruction>();
-    private boolean dataReadyForShip = false;
-    private boolean readyForDataFromShip = true;
-    private long dataFromShip;
-    private boolean torpedoWaiting = false;
+    boolean         flag_a = false;
+    boolean         flag_b = false;
+    boolean         flag_c = false;
+    boolean         flag_d = false;
+    int             ilc    = 1;
+    int             olc    = 1;
+    final BitVector dataLatch = new BitVector(getShip().getFleet().getWordWidth());
+    InterpreterPath pathLatch = null;
+    boolean         requeueStageInCirculatingState = false;
+    boolean         flushing = false;
+
+    LinkedList<Instruction> instructions = new LinkedList<Instruction>();
+    LinkedList<Packet> dataPackets = new LinkedList<Packet>();
+
+    // HACK
+    private LinkedList<Packet> instructionsBackedUpIntoSwitchFabric = new LinkedList<Packet>();
+
+    boolean dataReadyForShip = false;
+    boolean readyForDataFromShip = true;
+
+    // FIXME: should be a BitVector
+    long dataFromShip;
+    boolean flagCFromShip;
 
     protected void reset() {
         ilc = 1;
@@ -34,26 +39,33 @@ class InterpreterDock extends FleetTwoDock {
         flag_a = false;
         flag_b = false;
         flag_c = false;
-        dataLatch = new BitVector(getShip().getFleet().getWordWidth());
+        flag_d = false;
+        dataLatch.set(0);
         pathLatch = null;
-        hatchIsOpen = true;
-        executing = null;
+        requeueStageInCirculatingState = false;
         instructions.clear();
-        epilogue.clear();
+        dataPackets.clear();
+        instructionsBackedUpIntoSwitchFabric.clear();
         dataReadyForShip = false;
         readyForDataFromShip = true;
-        tapl = null;
-        torpedoWaiting = false;
+        flushing = false;
     }
 
     // Destinations //////////////////////////////////////////////////////////////////////////////
 
     /** includes the epilogue fifo */
-    public InterpreterDestination instructionDestination = new InterpreterDestination(this, true);
-    public InterpreterDestination dataDestination = new InterpreterDestination(this, false);
+    public InterpreterDestination instructionDestination = new InterpreterDestination(this) {
+            public String toString() { return getDock()+":i"; }
+            public void addDataFromFabric(Packet p) { addInstruction(p); }
+        };
+    public InterpreterDestination dataDestination = new InterpreterDestination(this) {
+            public String toString() { return getDock()+""; }
+            public void addDataFromFabric(Packet packet) { dataPackets.add(packet); }
+        };
 
     InterpreterDock(InterpreterShip ship, DockDescription bbd) {
         super(ship, bbd);
+        ship.docks.put(bbd.getName(), this);
     }
 
     public Path getPath(Destination d, BitVector signal) { return new InterpreterPath(this, (InterpreterDestination)d, signal); }
@@ -62,232 +74,231 @@ class InterpreterDock extends FleetTwoDock {
     public int getInstructionFifoSize() { return Integer.MAX_VALUE; }
     public Interpreter getInterpreter() { return ((InterpreterShip)getShip()).getInterpreter(); }
 
-    // interface to subclass ///////////////////////////////////////////////////////////////////////
-
-    /** this will be invoked periodically; should return true to "consume" an instruction, false to leave it executing */
-
-    public boolean dataReadyForShip() { return dataReadyForShip; }
-    public final boolean readyForDataFromShip() { return readyForDataFromShip; }
+    boolean trace = false;
 
-    public long removeDataForShip() {
-        if (!dataReadyForShip) throw new RuntimeException();
-        dataReadyForShip = false;
-        BitVector bv = dataLatch;
-        long val = 0;
-        for(int i=0; i<bv.length(); i++)
-            if (bv.get(i))
-                val |= (1L << i);
-        return val;
+    private void addInstruction(Packet p) {
+        if (p.isToken() ||
+            instructionsBackedUpIntoSwitchFabric.size()!=0 ||
+            requeueStageInCirculatingState ||
+            (p2i(p) instanceof Instruction.Tail)) {
+            instructionsBackedUpIntoSwitchFabric.add(p);
+        } else {
+            instructions.add(p2i(p));
+        }
     }
-    public void addDataFromShip(long data) {
-        if (!readyForDataFromShip()) throw new RuntimeException();
-        readyForDataFromShip = false;
-        dataFromShip = data;
+    
+    private Instruction p2i(Packet p) {
+        if (p.isToken()) throw new RuntimeException();
+        return getInterpreter().decodeInstruction(p.getValue(), InterpreterDock.this /* this is wrong, but harmless */);
     }
 
     protected final void service() {
 
-        if (instructionDestination.packets.size() > 0) {
-            Packet p = instructionDestination.packets.remove();
-            if (p.isToken) {
-                if (torpedoWaiting) throw new RuntimeException("two torpedoes collided!");
-                torpedoWaiting = true;
-            } else {
-                BitVector bv = p.value;
-                long val = 0;
-                for(int i=0; i<bv.length(); i++)
-                    if (bv.get(i))
-                        val |= (1L << i);
-                epilogue.add(getInterpreter().readInstruction(val, this));
-            }
-        }
-
-        if (hatchIsOpen && epilogue.size() > 0) {
-            Instruction inst = epilogue.remove();
-            if (inst instanceof Instruction.Tail)
-                hatchIsOpen = false;
-            else
-                instructions.add(inst);
-        }
+        if (dataReadyForShip || flushing) return;
+        if (instructions.size()==0) return;
 
-        if (dataReadyForShip) return;
-
-        if (executing==null && instructions.size() > 0) executing = instructions.remove();
-        if (executing==null) return;
-
-        if (executing.looping && hatchIsOpen && olc>0) return;
-
-        boolean enabled = true;
-        switch(executing.predicate) {
-            case IgnoreOLC:  enabled =  true;   break;
-            case Default:    enabled =  olc>0;  break;
-            case FlagA:      enabled =  flag_a; break;
-            case FlagB:      enabled =  flag_b; break;
-            case FlagC:      enabled =  flag_c; break;
-            case NotFlagA:   enabled = !flag_a; break;
-            case NotFlagB:   enabled = !flag_b; break;
-            case NotFlagC:   enabled = !flag_c; break;
-            default: throw new RuntimeException();
-        }
-        if (!enabled) {
-            if (executing.looping && olc>0)
-                instructions.add(executing);
-            executing = null;
-            return;
-        }
-
-        if (executing instanceof Instruction.Move) {
-            Instruction.Move move = (Instruction.Move)executing;
-
-            if (move.interruptible && torpedoWaiting) {
-                torpedoWaiting = false;
-                executing = null;
-                ilc = 1;
-                olc = 0;
-                if (tapl != null)
-                    new Packet(tapl, new BitVector(getInterpreter().getWordWidth()), true).send();
-                hatchIsOpen = true;
-                return;
+        if (instructions.peek() instanceof Instruction.Head) {
+            if (requeueStageInCirculatingState) { instructions.remove(); return; }
+            Packet p = instructionsBackedUpIntoSwitchFabric.peek();
+            if (p!=null && !p.isToken() && p2i(p) instanceof Instruction.Tail) {
+                instructionsBackedUpIntoSwitchFabric.remove();
+                requeueStageInCirculatingState = true;
+                instructions.remove();
             }
-
-            if (move.dataIn  && !isInputDock() && readyForDataFromShip) return;
-            if (move.dataIn  &&  isInputDock() && dataDestination.packets.size()==0) return;
-            if (move.tokenIn &&                   dataDestination.packets.size()==0) return;
+            return;
         }
 
-        if (executing.looping && olc>0)
-            instructions.add(executing);
+        // in the while..false idiom block below, use "break" to
+        // consume the instruction at instructions.peek(), or "return"
+        // to leave it and retry on the next call.
+        do {
+            if (!instructions.peek().predicate.evaluate(flag_a, flag_b, flag_c, flag_d))
+                break;
+
+            if (instructions.peek() instanceof Instruction.Move) {
+                Instruction.Move move = (Instruction.Move)instructions.peek();
+
+                if (ilc==0) { ilc = 1; break; }
+
+                if (move.interruptible) {
+                    Packet p = instructionsBackedUpIntoSwitchFabric.peek();
+                    if (p!=null && p.isToken()) {
+                        instructionsBackedUpIntoSwitchFabric.remove();
+                        ilc = 1;
+                        flag_d = true;
+                        break;
+                    }
+                }
 
-        if (executing instanceof Instruction.Shift) {
-            Instruction.Shift shift = (Instruction.Shift)executing;
-            for(int i=dataLatch.length()-1; i>=19; i--)
-                dataLatch.set(i, dataLatch.get(i-19));
-            for(int i=18; i>=0; i--)
-                dataLatch.set(i, shift.immediate.get(i));
-            executing = null;
-            return;
-        }
+                if (move.dataIn  && !isInputDock() && readyForDataFromShip)  return;
+                if (move.dataIn  &&  isInputDock() && dataPackets.size()==0) return;
+                if (move.tokenIn &&                   dataPackets.size()==0) return;
 
-        if (executing instanceof Instruction.Set) {
-            Instruction.Set set = (Instruction.Set)executing;
-            switch(set.dest) {
-                case DataLatch:
-                    dataLatch = new BitVector(getInterpreter().getWordWidth()).setAndSignExtend(set.immediate);
-                    break;
-                case InnerLoopCounter:
-                    switch(set.source) {
-                        case Infinity:
-                            ilc = -1;
-                            break;
-                        case DataLatch:
-                            ilc = 0;
-                            for(int i=0; i<FleetTwoFleet.SET_ILC_FROM_IMMEDIATE.valmaskwidth-1; i++)
-                                if (dataLatch.get(i))
-                                    ilc |= (1 << i);
-                            break;
-                        case Immediate:
-                            ilc = (int)set.immediate;
-                            break;
-                        default:
-                            throw new RuntimeException("FIXME!");
+                if (move.tokenIn) {
+                    Packet p = dataPackets.remove();
+                    flag_c = p.getSignal().get(0);
+                }
+                if (move.dataIn) {
+                    BitVector bv = null;
+                    if (isInputDock()) {
+                        Packet p = dataPackets.remove();
+                        bv = new BitVector(p.getValue());
+                        flag_c = p.getSignal().get(0);
+                    } else {
+                        bv = new BitVector(getInterpreter().getWordWidth()).set(dataFromShip);
+                        readyForDataFromShip = true;
+                        if (move.latchData) flag_c = flagCFromShip;
                     }
-                    break;
-                case OuterLoopCounter:
-                    switch(set.source) {
-                        case Decrement:
-                            olc = Math.max(0,olc-1);
-                            if (olc==0) hatchIsOpen = true;
-                            break;
-                        case DataLatch:
-                            olc = 0;
-                            for(int i=0; i<FleetTwoFleet.SET_OLC_FROM_IMMEDIATE.valmaskwidth-1; i++)
-                                if (dataLatch.get(i))
-                                    olc |= (1 << i);
-                            if (olc==0) hatchIsOpen = true;
-                            break;
-                        case Immediate:
-                            olc = (int)set.immediate;
-                            if (olc==0) hatchIsOpen = true;
-                            break;
-                        default:
-                            throw new RuntimeException("FIXME!");
+                    if (move.latchData) dataLatch.set(bv);
+                    if (move.latchPath) {
+                        BitVector bvp = ((FleetTwoFleet)getShip().getFleet()).DISPATCH_PATH.getvalAsBitVector(bv);
+                        pathLatch = (InterpreterPath)getInterpreter().getPathByAddr(this, bvp);
                     }
-                    break;
+                }
+                
+                if (move.path != null) pathLatch = (InterpreterPath)move.path;
+                
+                if (move.dataOut && isInputDock())  dataReadyForShip = true;
+                if (move.dataOut && !isInputDock()) new Packet(pathLatch, new BitVector(dataLatch), false).send();
+                if (move.tokenOut)                  new Packet(pathLatch, new BitVector(getInterpreter().getWordWidth()), true).send();
+                
+                if (ilc==1)  break;
+                if (ilc!=-1) ilc--;
+                return;
 
-                case TAPL:
-                    tapl = (InterpreterPath)set.path;
+            } else if (instructions.peek() instanceof Instruction.Abort) {
+                requeueStageInCirculatingState = false;
+                LinkedList<Packet> temp = new LinkedList<Packet>();
+                while (instructionsBackedUpIntoSwitchFabric.size()!=0)
+                    temp.add(instructionsBackedUpIntoSwitchFabric.remove());
+                while (temp.size()!=0)
+                    addInstruction(temp.remove());
+                break;
+
+            } else if (instructions.peek() instanceof Instruction.Flush) {
+                flushing = true;
+                break;
+
+            } else if (instructions.peek() instanceof Instruction.Shift) {
+                Instruction.Shift shift = (Instruction.Shift)instructions.peek();
+                for(int i=dataLatch.length()-1; i>=getShip().getFleet().getShiftWidth(); i--)
+                    dataLatch.set(i, dataLatch.get(i-getShip().getFleet().getShiftWidth()));
+                BitVector shift_immediate = shift.immediate.getBitVector();
+                for(int i=getShip().getFleet().getShiftWidth()-1; i>=0; i--)
+                    dataLatch.set(i, shift_immediate.get(i));
+                break;
+
+            } else if (instructions.peek() instanceof Instruction.Set) {
+                Instruction.Set set = (Instruction.Set)instructions.peek();
+                switch(set.dest) {
+                    case DataLatch: dataLatch.setAndSignExtend(set.immediate);
                     break;
-
-                case Flags: {
-                    boolean new_flag_a = false;
-                    boolean new_flag_b = false;
-                    for(Predicate p : set.newFlagA)
-                        switch(p) {
-                            case FlagA: new_flag_a |= flag_a; break;
-                            case FlagB: new_flag_a |= flag_b; break;
-                            case FlagC: new_flag_a |= flag_c; break;
-                            case NotFlagA: new_flag_a |= !flag_a; break;
-                            case NotFlagB: new_flag_a |= !flag_b; break;
-                            case NotFlagC: new_flag_a |= !flag_c; break;
+                    case InnerLoopCounter:
+                        switch(set.source) {
+                            case Infinity:  ilc = -1; break;
+                            case Immediate: ilc = (int)set.immediate; break;
+                            case DataLatch:
+                                ilc = 0;
+                                for(int i=0; i<((FleetTwoFleet)getShip().getFleet()).SET_ILC_FROM_IMMEDIATE.valmaskwidth-1; i++)
+                                    if (dataLatch.get(i))
+                                        ilc |= (1 << i);
+                                break;
+                            default: throw new RuntimeException("impossible");
                         }
-                    for(Predicate p : set.newFlagB)
-                        switch(p) {
-                            case FlagA: new_flag_b |= flag_a; break;
-                            case FlagB: new_flag_b |= flag_b; break;
-                            case FlagC: new_flag_b |= flag_c; break;
-                            case NotFlagA: new_flag_b |= !flag_a; break;
-                            case NotFlagB: new_flag_b |= !flag_b; break;
-                            case NotFlagC: new_flag_b |= !flag_c; break;
+                        break;
+                    case OuterLoopCounter:
+                        switch(set.source) {
+                            case Decrement: olc = Math.max(0,olc-1); break;
+                            case Immediate: olc = (int)set.immediate; break;
+                            case DataLatch:
+                                olc = 0;
+                                for(int i=0; i<getShip().getFleet().getWordWidth(); i++)
+                                    if (dataLatch.get(i))
+                                        olc |= (1 << i);
+                                break;
+                            default: throw new RuntimeException("impossible");
                         }
-                    flag_a = new_flag_a;
-                    flag_b = new_flag_b;
-                    break;
+                        flag_d = olc==0;
+                        break;
+                        
+                    case Flags: {
+                        boolean new_flag_a = set.newFlagA.evaluate(flag_a, flag_b, flag_c, flag_d);
+                        boolean new_flag_b = set.newFlagB.evaluate(flag_a, flag_b, flag_c, flag_d);
+                        flag_a = new_flag_a;
+                        flag_b = new_flag_b;
+                        break;
+                    }
+                    default: throw new RuntimeException("FIXME!");
                 }
-                default:
-                    throw new RuntimeException("FIXME!");
+            } else {
+                throw new RuntimeException("unimplemented instruction: " + instructions.peek());
             }
-            executing = null;
-            return;
-        }
+        } while(false);
 
-        Instruction.Move move = (Instruction.Move)executing;
+        if (requeueStageInCirculatingState)
+            instructions.add(instructions.peek());
+        instructions.remove();
+        return;
+    }
 
-        // if ILC==0, don't even bother
-        if (ilc==0) { ilc = 1; executing = null; return; }
+    // Interface for use by Subclasses ///////////////////////////////////////////////////////////////////////
 
-        if (ilc==-1)     { }
-        else if (ilc==1) executing = null;
-        else             ilc--;
+    // all the methods below convert 64-bit longs to/from
+    // getWordWidth()-bit BitVectors by truncation and sign-extension.
 
-        Packet p = null;
-        if (move.tokenIn) {
-            p = dataDestination.packets.remove();
-            if (p.path.signal != null) flag_c = p.path.signal.get(0);
-        }
-        if (move.dataIn) {
-            BitVector bv = null;
-            if (isInputDock()) {
-                p = dataDestination.packets.remove();
-                bv = new BitVector(p.value);
-                if (p.path.signal != null) flag_c = p.path.signal.get(0);
-            } else {
-                bv = new BitVector(getInterpreter().getWordWidth()).set(dataFromShip);
-                readyForDataFromShip = true;
-            }
-            if (move.latchData) dataLatch = bv;
-            if (move.latchPath)
-                pathLatch = (InterpreterPath)getInterpreter().getPathByAddr(this, FleetTwoFleet.DISPATCH_PATH.getval(bv));
-            // FIXME: c-flag at output docks
-        }
+    protected boolean dataReadyForShip() { return dataReadyForShip; }
+    protected final boolean readyForDataFromShip() { return readyForDataFromShip; }
+    protected long removeDataForShip() {
+        long val = peekDataForShip();
+        dataReadyForShip = false;
+        return val;
+    }
+    protected long peekDataForShip() {
+        if (!dataReadyForShip)
+            throw new RuntimeException("peekDataForShip() invoked when dataReadyForShip()==false");
+        return dataLatch.toLong();
+    }
+    protected void addDataFromShip(long data) { addDataFromShip(data, false); }
+    protected void addDataFromShip(long data, boolean pending_flag_c) {
+        if (!readyForDataFromShip())
+            throw new RuntimeException("addDataFromShip() invoked when readyForDataFromShip()");
+        readyForDataFromShip = false;
+        dataFromShip = data;
+        flagCFromShip = pending_flag_c;
+    }
 
-        if (move.path != null) pathLatch = (InterpreterPath)move.path;
 
-        if (move.dataOut && isInputDock()) dataReadyForShip = true;
-        if (move.dataOut && !isInputDock())
-            new Packet(pathLatch, new BitVector(dataLatch), true).send();
-        if (move.tokenOut)
-            new Packet(pathLatch, new BitVector(getInterpreter().getWordWidth()), true).send();
+    // Debugging //////////////////////////////////////////////////////////////////////////////
 
-        return;
+    public void dumpState() {
+        if (instructions.size()==0 &&
+            dataPackets.size()==0 &&
+            instructionsBackedUpIntoSwitchFabric.size()==0 &&
+            !requeueStageInCirculatingState &&
+            !flushing &&
+            !dataReadyForShip &&
+            readyForDataFromShip)
+            return;
+        System.out.println("state of "+ANSI.green(this)+": "+
+                           (ilc==1?"":("[ilc="+(ilc==-1 ? "*" : (ilc+""))+"] "))+
+                           (olc==1?"":("[olc="+olc+"] "))+
+                           (flag_a?"[a] ":"")+
+                           (flag_b?"[b] ":"")+
+                           (flag_c?"[c] ":"")+
+                           (flag_d?"[d] ":"")+
+                           (requeueStageInCirculatingState?"[recirculating] ":"")+
+                           (flushing?"[flushing] ":"")
+                           );
+        if (!readyForDataFromShip)
+            System.out.println(ANSI.cyan("  ship has proffered: " + dataFromShip));
+        if (dataReadyForShip)
+            System.out.println(ANSI.cyan("  waiting for ship to accept: " + dataLatch.toLong()));
+        for(Instruction i : instructions)
+            System.out.println(ANSI.red("  "+i));
+        for(Packet i : instructionsBackedUpIntoSwitchFabric)
+            System.out.println(ANSI.red(ANSI.bold("  "+i+" BACKED UP")));
+        for(Packet p : dataPackets)
+            System.out.println(ANSI.cyan("  "+p));
     }
+
 }