first pass at getting mergesort to run on the interpreter
[fleet.git] / src / edu / berkeley / fleet / interpreter / InterpreterDock.java
index a0e8dc5..14fd5b3 100644 (file)
 package edu.berkeley.fleet.interpreter;
-import edu.berkeley.fleet.api.*;
-import edu.berkeley.fleet.api.Dock;
-import edu.berkeley.fleet.two.*;
 import java.util.*;
+import edu.berkeley.fleet.two.*;
+import edu.berkeley.fleet.api.*;
 
+/** anything that has a source (instruction horn) address on the switch fabric */
+class InterpreterDock extends FleetTwoDock {
 
-/** anything that has a destination address on the switch fabric */
-public abstract class InterpreterDock extends FleetTwoDock {
-        
-    private final InterpreterShip ship;
-    private final Destination[] ports;
-    private final int addr = max_addr++;
+    // Dock State //////////////////////////////////////////////////////////////////////////////
     
-    public InterpreterDock(InterpreterShip ship, String[] ports, DockDescription bbd) {
-        super(ship, bbd);
-        this.ship = ship;
-        this.ports = new Destination[ports.length];
-        for(int i=0; i<ports.length; i++)
-            this.ports[i] =
-                new InterpreterDockDestination(ports[i], this, 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         requeueStageHasTailInstruction = false;
+    boolean         torpedoWaiting = false;
+    boolean         flushing = false;
 
-    public Path getPath(Destination d, BitVector signal) {
-        throw new RuntimeException();
-    }
+    Queue<Instruction> instructions = new LinkedList<Instruction>();
+    Queue<Packet> dataPackets = new LinkedList<Packet>();
 
-    public Iterable<Destination> getDestinations() {
-        HashSet<Destination> ret = new HashSet<Destination>();
-        for(Destination d : ports) ret.add(d);
-        return ret;
-    }
+    // HACK
+    private Queue<Instruction> instructionsBackedUpIntoSwitchFabric = new LinkedList<Instruction>();
 
-    public Destination getInstructionDestination() {
-        return ports[0];
-    }
-    public Destination getDataDestination() {
-        return ports[0];
+    boolean dataReadyForShip = false;
+    boolean readyForDataFromShip = true;
+    long dataFromShip;
+    boolean flagCFromShip;
+
+    protected void reset() {
+        ilc = 1;
+        olc = 1;
+        flag_a = false;
+        flag_b = false;
+        flag_c = false;
+        flag_d = false;
+        dataLatch.set(0);
+        pathLatch = null;
+        requeueStageInCirculatingState = false;
+        requeueStageHasTailInstruction = false;
+        instructions.clear();
+        dataPackets.clear();
+        instructionsBackedUpIntoSwitchFabric.clear();
+        dataReadyForShip = false;
+        readyForDataFromShip = true;
+        torpedoWaiting = false;
+        flushing = false;
     }
 
+    // Destinations //////////////////////////////////////////////////////////////////////////////
+
+    /** includes the epilogue fifo */
+    public InterpreterDestination instructionDestination = new InterpreterDestination(this) {
+            public String toString() { return getDock()+":i"; }
+            public void addDataFromFabric(Packet p) {
+                if (p.isToken()) {
+                    if (instructionsBackedUpIntoSwitchFabric.size()!=0)
+                        throw new RuntimeException("torpedo arrived while instructions were backed up into switch fabric");
+                    if (torpedoWaiting) throw new RuntimeException("two torpedoes collided!");
+                    torpedoWaiting = true;
+                    return;
+                }
 
-    /** adds the included datum to the port from the switch fabric  side */
-    public abstract void addDataFromFabric(Packet packet);
+                Instruction inst =
+                    getInterpreter().decodeInstruction(p.getValue(),
+                                                       InterpreterDock.this /* this is wrong, but harmless */);
+                addInstruction(inst);
+            }
+        };
+    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);
+    }
 
-    abstract void service();
+    public Path getPath(Destination d, BitVector signal) { return new InterpreterPath(this, (InterpreterDestination)d, signal); }
+    public Destination getInstructionDestination() { return instructionDestination; }
+    public Destination getDataDestination() { return dataDestination; }
+    public int getInstructionFifoSize() { return Integer.MAX_VALUE; }
+    public Interpreter getInterpreter() { return ((InterpreterShip)getShip()).getInterpreter(); }
 
-    abstract void   shutdown();
+    boolean trace = false;
 
-    public   Ship   getShip()                  { return ship; }
-    public   Fleet  getFleet()                 { return getShip().getFleet(); }
-    public   String toString()                 { return ship+"."+getName(); }
-    public   int    getInstructionFifoSize() { return 4; }
+    private void addInstruction(Instruction inst) {
+        if (requeueStageInCirculatingState || requeueStageHasTailInstruction) {
+            // GROSS HACK
+            instructionsBackedUpIntoSwitchFabric.add(inst);
+            return;
+        }
+        if (inst instanceof Instruction.Tail) {
+            requeueStageHasTailInstruction = true;
+            return;
+        }
+        instructions.add(inst);
+    }
     
-    Interpreter getInterpreter() { return ((InterpreterShip)getShip()).getInterpreter(); }
+    protected final void service() {
 
-    public long getDestAddr() { return addr; }
+        if (dataReadyForShip || flushing) return;
+        if (instructions.size()==0) return;
 
-    private static int max_addr;
-    private class InterpreterDockDestination extends InterpreterDestination {
-        public String name;
-        public long addr = max_addr++;
-        public InterpreterDockDestination(String name, InterpreterDock id, boolean isInstructionDestination) {
-            super(id, isInstructionDestination);
-            this.name = name;
+        if (instructions.peek() instanceof Instruction.Head) {
+            if (requeueStageInCirculatingState) { instructions.remove(); return; }
+            if (!requeueStageHasTailInstruction) return;
+            requeueStageHasTailInstruction = false;
+            requeueStageInCirculatingState = true;
+            instructions.remove();
+            return;
         }
-        public String getDestinationName()               { return name; }
-        public Ship getShip()                    { return InterpreterDock.this.getShip(); }
-        public void addDataFromFabric(Packet packet) { InterpreterDock.this.addDataFromFabric(packet); }
-        public String toString()                 { return getShip()+"."+getName(); }
-        public long getDestAddr() { return addr; }
+
+        // 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 && torpedoWaiting) {
+                    torpedoWaiting = false;
+                    ilc = 1;
+                    flag_d = true;
+                    break;
+                }
+
+                if (move.dataIn  && !isInputDock() && readyForDataFromShip)  return;
+                if (move.dataIn  &&  isInputDock() && dataPackets.size()==0) return;
+                if (move.tokenIn &&                   dataPackets.size()==0) return;
+
+                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;
+                    }
+                    if (move.latchData) dataLatch.set(bv);
+                    if (move.latchPath) {
+                        BitVector bvp = ((FleetTwoFleet)getShip().getFleet()).DISPATCH_PATH.getvalAsBitVector(bv);
+                        pathLatch = (InterpreterPath)getInterpreter().getPathByAddr(this, bvp);
+                    }
+                }
+                
+                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;
+
+            } else if (instructions.peek() instanceof Instruction.Abort) {
+                requeueStageInCirculatingState = false;
+                // HACK
+                while (instructionsBackedUpIntoSwitchFabric.size()!=0) {
+                    Instruction i = instructionsBackedUpIntoSwitchFabric.remove();
+                    addInstruction(i);
+                    instructionsBackedUpIntoSwitchFabric.clear();
+                }
+                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()));
+                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 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");
+                        }
+                        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<((FleetTwoFleet)getShip().getFleet()).SET_OLC_FROM_IMMEDIATE.valmaskwidth-1; i++)
+                                    if (dataLatch.get(i))
+                                        olc |= (1 << i);
+                                break;
+                            default: throw new RuntimeException("impossible");
+                        }
+                        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!");
+                }
+            } else {
+                throw new RuntimeException("unimplemented instruction: " + instructions.peek());
+            }
+        } while(false);
+
+        if (requeueStageInCirculatingState)
+            instructions.add(instructions.peek());
+        instructions.remove();
+        return;
+    }
+
+    // Interface for use by Subclasses ///////////////////////////////////////////////////////////////////////
+
+    // all the methods below convert 64-bit longs to/from
+    // getWordWidth()-bit BitVectors by truncation and sign-extension.
+
+    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;
     }
 }