overhaul of interpreter, update ships to match; "make test" works now
authormegacz <adam@megacz.com>
Thu, 8 Jan 2009 21:14:28 +0000 (13:14 -0800)
committermegacz <adam@megacz.com>
Thu, 8 Jan 2009 21:14:28 +0000 (13:14 -0800)
12 files changed:
ships/Alu.ship
ships/CarrySaveAdder.ship
ships/Counter.ship
ships/DDR2.ship
ships/DRAM.ship
ships/Memory.ship
ships/Rotator.ship
ships/Video.ship
src/edu/berkeley/fleet/interpreter/DebugDock.java
src/edu/berkeley/fleet/interpreter/Interpreter.java
src/edu/berkeley/fleet/interpreter/InterpreterDock.java
src/edu/berkeley/fleet/interpreter/InterpreterShip.java

index fa9dfd8..42003c6 100644 (file)
@@ -88,31 +88,41 @@ public void service() {
               b = box_in2.removeDataForShip();
               box_out.addDataFromShip(a-b); // SUB
               break;
+          case 9:
+              if (box_in1.peekDataForShip()<0 && box_in2.peekDataForShip()<0) {
+                a = box_in1.removeDataForShip();
+                b = box_in2.removeDataForShip();
+                box_out.addDataFromShip(a, false);
+                break;
+              }
+              // fall through
           case 4:
               a = box_in1.peekDataForShip();
               b = box_in2.peekDataForShip();
-              box_out.addDataFromShip(Math.max(a,b)); // MAX
-              box_out.flag_c = !(a>b);
+              box_out.addDataFromShip(Math.max(a,b), !(a>b)); // MAX
               if (a<b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
               break;
           case 5:
               a = box_in1.peekDataForShip();
               b = box_in2.peekDataForShip();
-              box_out.addDataFromShip(Math.min(a,b)); // MIN
-              box_out.flag_c = a>b;
+              box_out.addDataFromShip(Math.min(a,b), a>b); // MIN
               if (a>b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
               break;
           case 6:
               a = box_in1.removeDataForShip();
               b = box_in2.removeDataForShip();
-              box_out.addDataFromShip(0); // CMP
-              box_out.flag_c = a==b;
+              box_out.addDataFromShip(0, a==b); // CMP
               break;
-          default:
-              a = box_in1.removeDataForShip();
-              b = box_in2.removeDataForShip();
-              box_out.addDataFromShip(0);
+/*
+          case 7:
+              box_in1.removeDataForShip();      // DROP1
               break;
+          case 8:
+              box_in2.removeDataForShip();      // DROP2
+              break;
+*/
+          default:
+              throw new RuntimeException("invalid opcode: " + op);
       }
   }
 }
index edef42d..e6cddd6 100644 (file)
@@ -14,9 +14,41 @@ values, provided sequentially at {\tt in}, and produces.
 
 == Fleeterpreter ====================================================
 
+int state = 0;
+long temp;
+long out;
+public void reset() {
+  super.reset();
+  state = 0;
+  temp = 0;
+  out = 0;
+}
+private long maj(long a, long b, long c) {
+  long ret = 0;
+  for(int i=0; i<64; i++) {
+    boolean a_ = (a&(1L<<i))!=0L;
+    boolean b_ = (b&(1L<<i))!=0L;
+    boolean c_ = (c&(1L<<i))!=0L;
+    if ( (a_ && b_) || (b_ && c_) || (a_ && c_) )
+      ret |= (1L << i);
+  }
+  return ret;
+}
 public void service() {
-  if (box_in.dataReadyForShip() && box_out.readyForDataFromShip()) {
+  if (!box_out.readyForDataFromShip()) return;
+  if (state!=3 && !box_in.dataReadyForShip()) return;
+  switch(state) {
+    case 0: out = box_in.removeDataForShip(); break;
+    case 1: temp = box_in.removeDataForShip(); break;
+    case 2:
+      long in = box_in.removeDataForShip();
+      long mm = maj(temp, out, in);
+      box_out.addDataFromShip(mm << 1, ((mm >> (getFleet().getWordWidth()-1)) & 1L)!=0);
+      temp = (temp ^ out) ^ in;
+      break;
+    case 3: box_out.addDataFromShip(temp, false); break;
   }
+  state = (state+1) % 4;
 }
 
 
index f82bc14..0acc5b7 100644 (file)
@@ -20,7 +20,70 @@ data  in:   inOp
 data  out:  out
 
 == Fleeterpreter ====================================================
-public void service() { }
+
+boolean full = false;
+boolean op_count = false;
+boolean op_repeat = false;
+boolean op_pass = false;
+boolean op_drop = false;
+boolean op_c1 = false;
+boolean op_c2 = false;
+boolean op_v1 = false;
+boolean op_v2 = false;
+long temp = 0;
+
+public void reset() {
+  super.reset();
+  full = false;
+  temp = 0;
+}
+public void service() {
+
+  if (full) {
+    if (temp < 0) {
+      temp = 0;
+      full = false;
+      box_inOp.removeDataForShip();
+      if (op_count) box_in2.removeDataForShip();
+      else if (op_repeat && op_v1) box_in1.removeDataForShip();
+      else if (op_repeat && op_v2) box_in2.removeDataForShip();
+
+    } else if (box_out.readyForDataFromShip()) {
+      if (op_count) {
+        box_out.addDataFromShip(temp);
+        temp = temp - box_in2.peekDataForShip();
+      } else if (op_v1 && box_in1.dataReadyForShip()) {
+        if (op_drop) { box_in1.removeDataForShip(); temp--; }
+        else         { box_out.addDataFromShip(op_pass ? box_in1.removeDataForShip() : box_in1.peekDataForShip()); temp--; }
+      } else if (op_v2 && box_in2.dataReadyForShip()) {
+        if (op_drop) { box_in2.removeDataForShip(); temp--; }
+        else         { box_out.addDataFromShip(op_pass ? box_in2.removeDataForShip() : box_in2.peekDataForShip()); temp--; }
+      }
+      
+    }
+
+  } else if (box_inOp.dataReadyForShip()) {
+    long op   = box_inOp.peekDataForShip();
+    op_count  = (op & 15)==12;
+    op_repeat = ((op>>2) & 3)==0;
+    op_pass   = ((op>>2) & 3)==1;
+    op_drop   = ((op>>2) & 3)==2;
+    op_c1     = (op_repeat || op_pass || op_drop) && !(((op>>1)&1)!=0);
+    op_c2     = (op_repeat || op_pass || op_drop) &&  (((op>>1)&1)!=0);
+    op_v1     = (op_repeat || op_pass || op_drop) && !(((op>>0)&1)!=0);
+    op_v2     = (op_repeat || op_pass || op_drop) &&  (((op>>0)&1)!=0);
+
+    if (op_count && (!box_in1.dataReadyForShip() || !box_in2.dataReadyForShip())) return;
+    if (op_c1    &&  !box_in1.dataReadyForShip()) return;
+    if (op_c2    &&  !box_in2.dataReadyForShip()) return;
+    
+    full = true;
+
+    if (op_count) temp = box_in1.removeDataForShip() - box_in2.peekDataForShip();
+    if (op_c1)    temp = box_in1.removeDataForShip()-1;
+    if (op_c2)    temp = box_in2.removeDataForShip()-1;
+  }
+}
 
 == FleetSim ==============================================================
 
index 5360b2a..4febc7b 100644 (file)
@@ -270,6 +270,7 @@ DDR2SDRAM DDR2SDRAM(
 
 == Test ==============================================================
 
+#skip
 #expect 0
 
 #ship debug : Debug
index 978d3e0..619185f 100644 (file)
@@ -114,6 +114,7 @@ percolate inout:         ddr1_DQ            32
 
 
 == Test ========================================================
+#skip
 // expected output
 #expect 10
 
index f49d3dd..dabd06b 100644 (file)
@@ -105,55 +105,28 @@ sequence guarantee problem mentioned in the previous paragraph.
         }
         mem[addr] = val;
     }
-
-    private long stride = 0;
-    private long count = 0;
-    private long addr = 0;
-    private boolean writing = false;
-
     private Queue<Long> toDispatch = new LinkedList<Long>();
+    public void reset() {
+      super.reset();
+      mem = new long[0];
+      toDispatch.clear();
+    }
     public void service() {
-
         if (toDispatch.size() > 0) {
-            //if (!box_out.readyForDataFromShip()) return;
-            //box_out.addDataFromShip(toDispatch.remove());
-            getInterpreter().dispatch(getInterpreter().readInstruction(toDispatch.remove(), getDock("out")));
+            if (!box_out.readyForDataFromShip()) return;
+            box_out.addDataFromShip(toDispatch.remove());
         }
-
-        if (box_inCBD.dataReadyForShip() && box_out.readyForDataFromShip()) {
+        if (box_inCBD.dataReadyForShip()) {
             long val = box_inCBD.removeDataForShip();
-            long addr = val >> 6;
-            long size = val & 0x3f;
+            long addr = ((Interpreter)getFleet()).CBD_OFFSET.getval(val);
+            long size = ((Interpreter)getFleet()).CBD_SIZE.getval(val);
             for(int i=0; i<size; i++)
               toDispatch.add(readMem((int)(addr+i)));
-        }
-        if (count > 0) {
-            if (writing) {
-              if (box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
-                 writeMem((int)addr, box_inDataWrite.removeDataForShip());
-                 box_out.addDataFromShip(0);
-                 count--;
-                 addr += stride;
-              }
-            } else {
-              if (box_out.readyForDataFromShip()) {
-                 box_out.addDataFromShip(readMem((int)addr));
-                 count--;
-                 addr += stride;
-              }
-            }
-
-        } else if (box_inAddrRead.dataReadyForShip()) {
-            addr = box_inAddrRead.removeDataForShip();
-            stride = 0;
-            count = 1;
-            writing = false;
-
-        } else if (box_inAddrWrite.dataReadyForShip()) {
-            addr = box_inAddrWrite.removeDataForShip();
-            stride = 0;
-            count = 1;
-            writing = true;
+        } else if (box_inAddrWrite.dataReadyForShip() && box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
+            writeMem((int)box_inAddrWrite.removeDataForShip(), box_inDataWrite.removeDataForShip());
+            box_out.addDataFromShip(0,true);
+        } else if (box_inAddrRead.dataReadyForShip() && box_out.readyForDataFromShip()) {
+            box_out.addDataFromShip(readMem((int)box_inAddrRead.removeDataForShip()),false);
         }
     }
 
index c5bbf64..9009458 100644 (file)
@@ -26,7 +26,8 @@ public void service() {
     long data   = box_in.removeDataForShip();
     long mask = ~((-1L) << getInterpreter().getWordWidth());
     data = data & mask;
-    box_out.addDataFromShip(((data << amount) | (data >> (getInterpreter().getWordWidth()-amount))) & mask);
+    long res = ((data >> amount) | (data << (getInterpreter().getWordWidth()-amount))) & mask;
+    box_out.addDataFromShip(res, (res & (1L << (getInterpreter().getWordWidth()-1)))!=0);
   }
 }
 
index bfc01a9..ddf1af0 100644 (file)
@@ -140,6 +140,7 @@ percolate up:         vga_clkout  1
 
 == Test ==============================================================
 
+#skip
 // can't test much here; just make sure it accepts values
 
 #expect 0
index 59ba037..2ab6fc4 100644 (file)
@@ -16,14 +16,13 @@ public class DebugDock {
     public Dock getDock()                       { return dock; }
     public int getOLC()                         { return dock.olc; }
     public int getILC()                         { return dock.ilc; }
-    public Instruction getExecuting()           { return dock.executing; }
+    public Instruction getExecuting()           { return dock.instructions.peek(); }
     public Queue<Instruction> getInstructions() { return dock.instructions; }
-    public Queue<Instruction> getEpilogue()     { return dock.epilogue; }
     public boolean getDataReadyForShip()        { return dock.dataReadyForShip; }
     public boolean getReadyForDataFromShip()    { return dock.readyForDataFromShip;}
     public long getDataFromShip()               { return dock.dataFromShip; }
     public boolean getTorpedoWaiting()          { return dock.torpedoWaiting; }
-    public boolean isHatchOpen()                { return dock.hatchIsOpen; }
+    public boolean isHatchOpen()                { return !dock.requeueStageInCirculatingState; }
     public boolean getFlagA()                   { return dock.flag_a; }
     public boolean getFlagB()                   { return dock.flag_b; }
     public boolean getFlagC()                   { return dock.flag_c; }
@@ -35,9 +34,10 @@ public class DebugDock {
                 values.add(p.getValue());
         return values;
     }
+    public Queue<Instruction> getEpilogue() {
+        throw new RuntimeException("this method has been removed");
+    }
     public Queue<Instruction> getInstructionsInFabric() {
-        Queue<Instruction> instr = new LinkedList<Instruction>();
-        for (Instruction inst : dock.epilogue) instr.add(inst);
-        return instr;
+        throw new RuntimeException("this method has been removed");
     }
 }
index 752ac72..0461167 100644 (file)
@@ -9,14 +9,14 @@ import edu.berkeley.fleet.two.*;
 import edu.berkeley.fleet.assembler.*;
 import edu.berkeley.fleet.util.*;
 
-public class Interpreter extends FleetTwoFleet implements Parser.FleetWithDynamicShips {
+public class Interpreter extends FleetTwoFleet {
 
     /** used to allocate serial numbers; see InterpreterDestination for further detail */
     int maxAllocatedDestinationSerialNumber = 0;
 
     private InterpreterShip debugShip = null;
     private BlockingQueue<BitVector> debugStream = new LinkedBlockingQueue<BitVector>();
-    private HashMap<String,InterpreterShip> ships = new HashMap<String,InterpreterShip>();
+    private LinkedHashMap<String,InterpreterShip> ships = new LinkedHashMap<String,InterpreterShip>();
     public Iterator<Ship> iterator() { return (Iterator<Ship>)(Object)ships.values().iterator(); }
     public Ship getShip(String type, int ordinal) {
         for(Ship s : this)
@@ -27,7 +27,40 @@ public class Interpreter extends FleetTwoFleet implements Parser.FleetWithDynami
     }
 
     /** do not use this; it is going to go away */
-    public Interpreter() {
+    public Interpreter() { this(true); }
+    public Interpreter(boolean logging) {
+        this(new String[] {
+                "Debug",
+                "Memory",
+                "Memory",
+                "Memory",
+                "Alu",
+                "Alu",
+                "Alu",
+                "Alu",
+                "Alu",
+                "Alu",
+                "Alu",
+                "Fifo",
+                "Fifo",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Counter",
+                "Lut3",
+                "CarrySaveAdder",
+                "Rotator",
+            }, logging);
     }
 
     public Interpreter(String[] ships, boolean logging) {
@@ -46,8 +79,7 @@ public class Interpreter extends FleetTwoFleet implements Parser.FleetWithDynami
         new Packet((InterpreterPath)path, new BitVector(getWordWidth()).set(il), false).send();
     }
 
-    /** do not use this; it is going to go away */
-    public Ship createShip(String shipType, String shipname) {
+    private Ship createShip(String shipType, String shipname) {
         try {
             if (ships.get(shipname)!=null) return ships.get(shipname);
             Class c = Class.forName("edu.berkeley.fleet.interpreter."+shipType);
@@ -148,9 +180,15 @@ public class Interpreter extends FleetTwoFleet implements Parser.FleetWithDynami
         private Instruction[] instructions;
         public void flush() { }
         public void sendWord(Destination d, BitVector word) {
-            throw new RuntimeException("not implemented");
+            InterpreterPath path = (InterpreterPath)debugShip.getDock("in").getPath(d, new BitVector(1));
+            ((InterpreterDestination)d).
+                addDataFromFabric(new Packet(path, word, false));
+        }
+        public void sendToken(Destination d) {
+            InterpreterPath path = (InterpreterPath)debugShip.getDock("in").getPath(d, new BitVector(1));
+            ((InterpreterDestination)d).
+                addDataFromFabric(new Packet(path, new BitVector(getWordWidth()), true));
         }
-        public void sendToken(Destination d) { throw new RuntimeException("not implemented"); }
         public InterpreterProcess(Instruction[] instructions) {
             this.instructions = instructions;
             for(Instruction i : instructions)
index 11774ef..9dad01b 100644 (file)
@@ -1,34 +1,32 @@
 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.*;
 
 /** 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;
+    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;
 
-    Instruction executing = null;
     Queue<Instruction> instructions = new LinkedList<Instruction>();
-    Queue<Instruction> epilogue = new LinkedList<Instruction>();
     Queue<Packet> dataPackets = new LinkedList<Packet>();
     boolean dataReadyForShip = false;
     boolean readyForDataFromShip = true;
     long dataFromShip;
-    boolean torpedoWaiting = false;
+    boolean flagCFromShip;
 
     protected void reset() {
         ilc = 1;
@@ -36,16 +34,17 @@ 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;
+        requeueStageHasTailInstruction = false;
         instructions.clear();
-        epilogue.clear();
+        dataPackets.clear();
         dataReadyForShip = false;
         readyForDataFromShip = true;
-        tapl = null;
         torpedoWaiting = false;
+        flushing = false;
     }
 
     // Destinations //////////////////////////////////////////////////////////////////////////////
@@ -57,14 +56,34 @@ class InterpreterDock extends FleetTwoDock {
                 if (p.isToken()) {
                     if (torpedoWaiting) throw new RuntimeException("two torpedoes collided!");
                     torpedoWaiting = true;
-                } else {
-                    BitVector bv = p.getValue();
-                    long val = 0;
-                    for(int i=0; i<bv.length(); i++)
-                        if (bv.get(i))
-                            val |= (1L << i);
-                    epilogue.add(getInterpreter().readInstruction(val, InterpreterDock.this));    
+                    return;
                 }
+
+                Instruction inst =
+                    getInterpreter().decodeInstruction(p.getValue(),
+                                                       InterpreterDock.this /* this is wrong, but harmless */);
+
+                // FIXME: this is a bit too conservative.  In theory,
+                // it's okay to dispatch new instructions to the dock
+                // as long as we know that it will reach the updating
+                // state without any further input from the outside
+                // world -- ie that the instructions which remain to
+                // be executed before the requeue stage transitions to
+                // the updating state are all "non-blocking" (no moves
+                // with Ti=1 or Di=1)
+                if (requeueStageInCirculatingState || requeueStageHasTailInstruction)
+                    throw new RuntimeException("An instruction arrived while the requeue stage was circulating -- "+
+                                               "this means that instructions have backed up into "+
+                                               "the switch fabric, which nearly always risks deadlock! "+
+                                               "Fix your program!"+
+                                               "\n  dock: " + InterpreterDock.this +
+                                               "\n  instruction: " + inst
+                                               );
+                if (inst instanceof Instruction.Tail) {
+                    requeueStageHasTailInstruction = true;
+                    return;
+                }
+                instructions.add(inst);
             }
         };
     public InterpreterDestination dataDestination = new InterpreterDestination(this) {
@@ -83,228 +102,172 @@ 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; }
-
-    public long removeDataForShip() {
-        long val = peekDataForShip();
-        dataReadyForShip = false;
-        return val;
-    }
-    public long peekDataForShip() {
-        if (!dataReadyForShip) throw new RuntimeException();
-        BitVector bv = dataLatch;
-        long val = 0;
-        for(int i=0; i<bv.length(); i++)
-            if (bv.get(i))
-                val |= (1L << i);
-        return val;
-    }
-    public void addDataFromShip(long data) {
-        if (!readyForDataFromShip()) throw new RuntimeException();
-        readyForDataFromShip = false;
-        dataFromShip = data;
-    }
-
     protected final void service() {
 
-        if (hatchIsOpen && epilogue.size() > 0) {
-            Instruction inst = epilogue.remove();
-            if (inst instanceof Instruction.Head) {
-                // FIXME
-                return;
-            }
-            if (inst instanceof Instruction.Tail)
-                hatchIsOpen = false;
-            else
-                instructions.add(inst);
-        }
-
-        if (dataReadyForShip) return;
-
-        if (executing==null && instructions.size() > 0) {
-            executing = instructions.remove();
-            return;
-        }
-
-        if (executing==null) return;
-
-        if (executing.looping && hatchIsOpen && olc>0) return;
+        if (dataReadyForShip || flushing) return;
+        if (instructions.size()==0) return;
 
-        boolean enabled = true;
-        switch(executing.predicate) {
-            case IgnoreFlagD:  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;
+        if (instructions.peek() instanceof Instruction.Head) {
+            if (requeueStageInCirculatingState) { instructions.remove(); return; }
+            if (!requeueStageHasTailInstruction) return;
+            requeueStageHasTailInstruction = false;
+            requeueStageInCirculatingState = true;
+            instructions.remove();
             return;
         }
 
-        if (executing instanceof Instruction.Move) {
-            Instruction.Move move = (Instruction.Move)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 (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.Move) {
+                Instruction.Move move = (Instruction.Move)instructions.peek();
 
-            if (move.dataIn  && !isInputDock() && readyForDataFromShip) return;
-            if (move.dataIn  &&  isInputDock() && dataPackets.size()==0) return;
-            if (move.tokenIn &&                   dataPackets.size()==0) return;
-        }
+                if (ilc==0) { ilc = 1; break; }
 
-        if (executing.looping && olc>0)
-            instructions.add(executing);
+                if (move.interruptible && torpedoWaiting) {
+                    torpedoWaiting = false;
+                    ilc = 1;
+                    flag_d = true;
+                    break;
+                }
 
-        if (executing instanceof Instruction.Shift) {
-            /*
-            Instruction.Shift shift = (Instruction.Shift)executing;
-            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));
-            executing = null;
-            return;
-            */
-            throw new RuntimeException("FIXME");
-        }
+                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)getShip().getFleet()).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;
+                        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)getShip().getFleet()).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 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;
+            } else if (instructions.peek() instanceof Instruction.Abort) {
+                requeueStageInCirculatingState = false;
+                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");
                         }
-                    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<((FleetTwoFleet)getShip().getFleet()).SET_OLC_FROM_IMMEDIATE.valmaskwidth-1; 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!");
-            }
-            executing = null;
-            return;
-        }
-
-        Instruction.Move move = (Instruction.Move)executing;
-
-        // if ILC==0, don't even bother
-        if (ilc==0) { ilc = 1; executing = null; return; }
-
-        if (ilc==-1)     { }
-        else if (ilc==1) executing = null;
-        else             ilc--;
-
-        Packet p = null;
-        if (move.tokenIn) {
-            p = dataPackets.remove();
-            if (p.getSignal() != null) flag_c = p.getSignal().get(0);
-        }
-        if (move.dataIn) {
-            BitVector bv = null;
-            if (isInputDock()) {
-                p = dataPackets.remove();
-                bv = new BitVector(p.getValue());
-                if (p.getSignal() != null) flag_c = p.getSignal().get(0);
             } else {
-                bv = new BitVector(getInterpreter().getWordWidth()).set(dataFromShip);
-                readyForDataFromShip = true;
+                throw new RuntimeException("unimplemented instruction: " + instructions.peek());
             }
-            if (move.latchData) dataLatch = bv;
-            if (move.latchPath)
-                pathLatch = (InterpreterPath)getInterpreter().getPathByAddr(this, ((FleetTwoFleet)getShip().getFleet()).DISPATCH_PATH.getvalAsBitVector(bv.toLong()));
-            // FIXME: c-flag at output docks
-        }
+        } while(false);
 
-        if (move.path != null) pathLatch = (InterpreterPath)move.path;
+        if (requeueStageInCirculatingState)
+            instructions.add(instructions.peek());
+        instructions.remove();
+        return;
+    }
 
-        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();
+    // Interface for use by Subclasses ///////////////////////////////////////////////////////////////////////
 
-        return;
+    // 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");
+        BitVector bv = dataLatch;
+        long val = 0;
+        for(int i=0; i<bv.length(); i++)
+            if (bv.get(i))
+                val |= (1L << i);
+        return val;
+    }
+    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;
     }
 }
index 43fa15b..7f6397c 100644 (file)
@@ -26,7 +26,30 @@ abstract class InterpreterShip extends FleetTwoShip {
     public abstract void service();
 
     public final void _service() {
+
+        // service all the docks
         for(InterpreterDock p : docks.values()) p.service();
+
+        // flushing logic (must come between dock servicing and subclass)
+        boolean someflushing = false;
+        boolean allflushing = true;
+        for(InterpreterDock d : docks.values()) {
+            if (!d.isInputDock()) continue;
+            if (d.flushing) someflushing = true;
+            else allflushing = false;
+        }
+        if (allflushing) {
+            for(InterpreterDock d : docks.values())
+                if (d.isInputDock())
+                    d.flushing = false;
+            return;
+        } else if (someflushing) {
+            for(InterpreterDock d : docks.values())
+                if (d.isInputDock() && !d.flushing && d.dataReadyForShip)
+                    d.dataReadyForShip = false;
+        }
+
+        // now pass control to the subclass
         service();
     }