package edu.berkeley.fleet.interpreter;
-import edu.berkeley.sbp.util.ANSI;
+import java.util.*;
import edu.berkeley.fleet.two.*;
import edu.berkeley.fleet.api.*;
-import edu.berkeley.fleet.api.Instruction;
-import static edu.berkeley.fleet.api.Predicate.*;
-
-import java.util.*;
/** anything that has a source (instruction horn) address on the switch fabric */
-abstract class InstructionDock extends FleetTwoDock {
+class InterpreterDock extends FleetTwoDock {
- private final InterpreterShip ship;
- private final Destination[] ports;
- private final int addr = max_addr++;
+ // Dock State //////////////////////////////////////////////////////////////////////////////
-
- public Path getPath(Destination d, BitVector signal) {
- throw new RuntimeException();
- }
-
- public Iterable<Destination> getDestinations() {
- HashSet<Destination> ret = new HashSet<Destination>();
- for(Destination d : ports) ret.add(d);
- return ret;
+ 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;
+
+ Queue<Instruction> instructions = new LinkedList<Instruction>();
+ Queue<Packet> dataPackets = new LinkedList<Packet>();
+
+ // HACK
+ private Queue<Instruction> instructionsBackedUpIntoSwitchFabric = new LinkedList<Instruction>();
+
+ 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;
}
- public Destination getInstructionDestination() {
- return ports[0];
- }
- public Destination getDataDestination() {
- return ports[0];
- }
-
-
- /** adds the included datum to the port from the switch fabric side */
- public abstract void addDataFromFabric(Packet packet);
+ // 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;
+ }
+ 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); }
+ };
- abstract void shutdown();
+ InterpreterDock(InterpreterShip ship, DockDescription bbd) {
+ super(ship, bbd);
+ ship.docks.put(bbd.getName(), this);
+ }
- public Ship getShip() { return ship; }
- public Fleet getFleet() { return getShip().getFleet(); }
- public String toString() { return ship+"."+getName(); }
- public int getInstructionFifoSize() { return 4; }
-
- Interpreter getInterpreter() { return ((InterpreterShip)getShip()).getInterpreter(); }
+ 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(); }
- public long getDestAddr() { return addr; }
+ boolean trace = false;
- private static int max_addr;
- private class InterpreterDockDestination extends InterpreterDestination {
- public String name;
- public long addr = max_addr++;
- public InterpreterDockDestination(String name, InstructionDock id, boolean isInstructionDestination) {
- super(id, isInstructionDestination);
- this.name = name;
+ private void addInstruction(Instruction inst) {
+ if (requeueStageInCirculatingState || requeueStageHasTailInstruction) {
+ // GROSS HACK
+ instructionsBackedUpIntoSwitchFabric.add(inst);
+ return;
+ }
+ if (inst instanceof Instruction.Tail) {
+ requeueStageHasTailInstruction = true;
+ return;
}
- public String getDestinationName() { return name; }
- public Ship getShip() { return InstructionDock.this.getShip(); }
- public void addDataFromFabric(Packet packet) { InstructionDock.this.addDataFromFabric(packet); }
- public String toString() { return getShip()+"."+getName(); }
- public long getDestAddr() { return addr; }
+ instructions.add(inst);
}
+
+ protected final void service() {
- public int tailged = 0;
-
- public boolean flag_a = false;
- public boolean flag_b = false;
- public boolean flag_c = false;
-
- /** the currently executing instruction */
- private Instruction executing = null;
-
- /** all instructions waiting to be executed (excludes executing) */
- private Queue<Instruction> instructions = new LinkedList<Instruction>();
-
- public int loopCounter = 0;
- private int repeatCounter = 1;
-
- InstructionDock(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);
- }
+ if (dataReadyForShip || flushing) return;
+ if (instructions.size()==0) return;
- public void massacre() {
- executing = null;
- loopCounter = 0;
- repeatCounter = 1;
- while(instructions.size() > 0)
+ if (instructions.peek() instanceof Instruction.Head) {
+ if (requeueStageInCirculatingState) { instructions.remove(); return; }
+ if (!requeueStageHasTailInstruction) return;
+ requeueStageHasTailInstruction = false;
+ requeueStageInCirculatingState = true;
instructions.remove();
- }
+ return;
+ }
- public void kill() {
- repeatCounter = 1;
- if (executing != null) { executing = null; return; }
- if (instructions.size()==0)
- throw new RuntimeException("deadlocked " + this + " by killing too many instructions");
- instructions.remove();
- }
+ // 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;
- /** an instruction arrives from the instruction horn */
- void addInstruction(Instruction instr) { instructions.add(instr); }
-
- protected void shutdown(boolean leaveAsInbox) {
- if (!(executing != null || instructions.size() > 0)) return;
- Log.println(ANSI.red(" WARNING: you left instructions on the instruction queue of port " +
- this + "; they are:"));
- if (executing != null)
- Log.println(" " + executing);
- for(Instruction i : instructions)
- Log.println(" " + i);
- }
+ if (instructions.peek() instanceof Instruction.Move) {
+ Instruction.Move move = (Instruction.Move)instructions.peek();
- // interface to subclass ///////////////////////////////////////////////////////////////////////
+ if (ilc==0) { ilc = 1; break; }
- /** this will be invoked periodically; should return true to "consume" an instruction, false to leave it executing */
- protected abstract void setDataLatch(long value);
- protected abstract long peekDataLatch();
+ if (move.interruptible && torpedoWaiting) {
+ torpedoWaiting = false;
+ ilc = 1;
+ flag_d = true;
+ break;
+ }
- protected final void service() {
- /*
- if (tailged > 0) return;
- if (executing==null && instructions.size() > 0) executing = instructions.remove();
- if (executing==null) return;
-
- boolean enabled = true;
- if (executing instanceof Instruction.PredicatedInstruction) {
- Instruction.PredicatedInstruction ip = (Instruction.PredicatedInstruction)executing;
- switch(ip.predicate) {
- case IgnoreOLC: enabled = true; break;
- case Default: enabled = loopCounter!=0; break;
- case FlagA: enabled = flag_a; break;
- case FlagB: enabled = flag_b; break;
- //case FlagC: enabled = ; break;
- case NotFlagA: enabled = !flag_a; break;
- case NotFlagB: enabled = !flag_b; break;
- //case NotFlagC: enabled = loopCounter==0; break;
- }
- }
+ if (move.dataIn && !isInputDock() && readyForDataFromShip) return;
+ if (move.dataIn && isInputDock() && dataPackets.size()==0) return;
+ if (move.tokenIn && dataPackets.size()==0) return;
- int oldLoopCounter = loopCounter;
- if (enabled) {
- if (executing instanceof Instruction.Set.OLC.Decrement) loopCounter = Math.max(0, loopCounter-1);
- if (executing instanceof Instruction.Counter) {
- Instruction.Counter ic = (Instruction.Counter)executing;
- if (ic.source == Instruction.Counter.LOOP_COUNTER && ic.dest == Instruction.Counter.DATA_LATCH) {
- setDataLatch(oldLoopCounter); // FIXME: which is correct here?
- } else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
- loopCounter = (int)peekDataLatch();
- } else if (ic.dest == Instruction.Counter.REPEAT_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
- // FIXME: is there any way to load the "standing" value?
- repeatCounter = (int)peekDataLatch();
- } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
- loopCounter = ic.source;
- } else if (ic.dest == Instruction.Counter.REPEAT_COUNTER && ic.source==Instruction.Counter.STANDING) {
- repeatCounter = -1;
- } else if (ic.dest == Instruction.Counter.REPEAT_COUNTER) {
- repeatCounter = ic.source;
+ 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 if (executing instanceof Instruction.Set.Flags) {
- Instruction.Set.Flags sf = (Instruction.Set.Flags)executing;
- boolean old_c = oldLoopCounter == 0;
- boolean old_a = flag_a;
- boolean old_b = flag_b;
- flag_a =
- (((sf.flag_a & sf.FLAG_A) != 0) ? old_a : false) |
- (((sf.flag_a & sf.FLAG_NOT_A) != 0) ? !old_a : false) |
- (((sf.flag_a & sf.FLAG_B) != 0) ? old_b : false) |
- (((sf.flag_a & sf.FLAG_NOT_B) != 0) ? !old_b : false) |
- (((sf.flag_a & sf.FLAG_C) != 0) ? old_c : false) |
- (((sf.flag_a & sf.FLAG_NOT_C) != 0) ? !old_c : false);
- flag_b =
- (((sf.flag_b & sf.FLAG_A) != 0) ? old_a : false) |
- (((sf.flag_b & sf.FLAG_NOT_A) != 0) ? !old_a : false) |
- (((sf.flag_b & sf.FLAG_B) != 0) ? old_b : false) |
- (((sf.flag_b & sf.FLAG_NOT_B) != 0) ? !old_b : false) |
- (((sf.flag_b & sf.FLAG_C) != 0) ? old_c : false) |
- (((sf.flag_b & sf.FLAG_NOT_C) != 0) ? !old_c : false);
- } else if (executing instanceof Instruction.Set.OLC.Decrement) {
} else {
- if (!service(executing)) return;
+ throw new RuntimeException("unimplemented instruction: " + instructions.peek());
}
- }
+ } while(false);
- if (executing==null) return;
- if ((executing instanceof Instruction.Move) && repeatCounter > 1) {
- repeatCounter--;
- } else if ((executing instanceof Instruction.Move) && repeatCounter == -1) {
- // repeat
- } else if ((executing instanceof Instruction.PredicatedInstruction && ((Instruction.PredicatedInstruction)executing).looping) && oldLoopCounter > 0) {
- addInstruction(executing);
- executing = null;
- } else {
- executing = null;
- }
- */
+ 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;
+ }
}