add interpreter code and tests for loop counter instructions
authoradam <adam@megacz.com>
Wed, 2 Jan 2008 13:34:42 +0000 (14:34 +0100)
committeradam <adam@megacz.com>
Wed, 2 Jan 2008 13:34:42 +0000 (14:34 +0100)
src/edu/berkeley/fleet/api/Instruction.java
src/edu/berkeley/fleet/assembler/Parser.java
src/edu/berkeley/fleet/assembler/fleet.g
src/edu/berkeley/fleet/ies44/InstructionEncoder.java
src/edu/berkeley/fleet/interpreter/Inbox.java
src/edu/berkeley/fleet/interpreter/InstructionPump.java
src/edu/berkeley/fleet/interpreter/Outbox.java
tests/pump/test-read-loop-counter-from-data-latch.fleet [new file with mode: 0644]
tests/pump/test-read-loop-counter.fleet [new file with mode: 0644]
tests/pump/test-use-loop-counter.fleet [new file with mode: 0644]

index e3e909f..851718d 100644 (file)
@@ -44,6 +44,45 @@ public abstract class Instruction {
         public abstract Instruction.Executable decrementCount();
     }
 
+    public static class DecrLoop extends Executable {
+        public DecrLoop(Pump pump) { super(pump, 1); }
+        public Instruction.Executable decrementCount() { return null; }
+        public boolean isRequeueing() { return false; }
+    }
+
+    public static class Counter extends Executable {
+        public static final int DATA_LATCH = -1;
+        public static final int REPEAT_COUNTER = -2;
+        public static final int LOOP_COUNTER = -3;
+        public final int source;
+        public final int dest;
+        public Instruction.Executable decrementCount() { return null; }
+        public boolean isRequeueing() { return false; }
+        public Counter(Pump pump, int source, int dest) {
+            super(pump, 1);
+            this.source = source;
+            this.dest = dest;
+        }
+        public String toString() {
+            if (source==LOOP_COUNTER && dest==DATA_LATCH) return "take loop counter;";
+            StringBuffer ret = new StringBuffer();
+            ret.append("load ");
+            switch(dest) {
+                case LOOP_COUNTER: ret.append("loop"); break;
+                case REPEAT_COUNTER: ret.append("repeat"); break;
+                default: throw new RuntimeException("invalid");
+            }
+            ret.append(" counter");
+            if (source >= 0) {
+                ret.append(" with " + source);
+            } else if (source!=DATA_LATCH) {
+                throw new RuntimeException("invalid");
+            }
+            ret.append(";");
+            return ret.toString();
+        }
+    }
+
     public static class Move extends Executable {
         public final Destination dest;
 
index aa9bab4..0e58b3f 100644 (file)
@@ -266,9 +266,27 @@ public class Parser {
                     count = tt.size()==0 ? 1 : (int)number(tt.child(0));
                     cb.add(new Instruction.Kill(pump, count));
                     continue;
-                } else if ("massacre".equals(tt.head()))    {
+                } else if ("loop".equals(tt.head()))    {
+                    cb.add(new Instruction.Counter(pump, Instruction.Counter.LOOP_COUNTER, Instruction.Counter.DATA_LATCH));
+                    continue;
+                } else if ("load".equals(tt.head()) && "loop".equals(tt.child(0).head()))    {
+                    cb.add(new Instruction.Counter(pump, Instruction.Counter.DATA_LATCH, Instruction.Counter.LOOP_COUNTER));
+                    continue;
+                } else if ("load".equals(tt.head()) && "repeat".equals(tt.child(0).head()))    {
+                    cb.add(new Instruction.Counter(pump, Instruction.Counter.DATA_LATCH, Instruction.Counter.REPEAT_COUNTER));
+                    continue;
+                } else if ("with".equals(tt.head()) && "loop".equals(tt.child(0).head()))    {
+                    cb.add(new Instruction.Counter(pump, (int)number(tt.child(1)), Instruction.Counter.LOOP_COUNTER));
+                    continue;
+                } else if ("with".equals(tt.head()) && "repeat".equals(tt.child(0).head()))    {
+                    cb.add(new Instruction.Counter(pump, (int)number(tt.child(1)), Instruction.Counter.REPEAT_COUNTER));
+                    continue;
+                } else if ("massacre".equals(tt.head())) {
                     cb.add(new Instruction.Massacre(pump));
                     continue;
+                } else if ("decrement".equals(tt.head())) {
+                    cb.add(new Instruction.DecrLoop(pump));
+                    continue;
                 } else if ("literal".equals(tt.head())) {
                     long literal = 0;
                     if (tt.child(0).head().equals("CodeBagBody")) {
index 463a1ba..0c89dea 100644 (file)
@@ -16,6 +16,11 @@ Instruction     = ^"unclog"                          ";" /ws
                 | ^"clog"                            ";" /ws
                 | ^"massacre"                        ";" /ws
                 | ^"kill"                            ";" /ws
+                |  "take" ^"loop" "counter"                            ";" /ws
+                | ^"load" (^"loop"|^"repeat") ws "counter"             ";" /ws
+                |  "load" (^"loop"|^"repeat") ws "counter" ^"with" int ";" /ws
+                | ^"decrement" "loop" "counter"                        ";" /ws
+                | ^"setflags" ws "a=" Flag ws "b=" Flag ws ";"
                 | ^"kill"     int                    ";" /ws
                 | ^"literal"  Literal  RequeueCount  ";" /ws
                 | RepeatCount Commands RequeueCount ^";" /ws
@@ -23,6 +28,17 @@ RepeatCount     = "" | ^"[*]" | "[" int "]"
 RequeueCount    = ""
                 | "," "requeue" (^"forever" | int ws "times") /ws
 
+Flag =  ^"0"
+     |  ^"1"
+     |  ^"a"
+     |  ^"b"
+     |  ^"s"
+     |  ^"z"
+     | ^"!a"
+     | ^"!b"
+     | ^"!s"
+     | ^"!z"
+
 Commands::      = Command +/ (ws "," ws)
 Command         = ^"wait"
                 | ^"nop"
index 2d9dada..5e4571f 100644 (file)
@@ -16,7 +16,6 @@ public abstract class InstructionEncoder {
     public static final int WIDTH_MASK_LITERAL     = 6;
     public static final int MASK_LITERAL           = 13;   // this is an excessive approximation
 
-
     public static final int OFFSET_MASK_MASSACRE   = 14;
     public static final int WIDTH_MASK_MASSACRE    = 26-14;
     public static final int MASK_MASSACRE          = 1;
@@ -33,10 +32,37 @@ public abstract class InstructionEncoder {
     public static final int WIDTH_MASK_CLOG        = 26-14;
     public static final int MASK_CLOG              = 2;
 
+    public static final int OFFSET_MASK_LOAD_LOOP_TO_DATA       = 14;
+    public static final int WIDTH_MASK_LOAD_LOOP_TO_DATA        = 12;
+    public static final int MASK_LOAD_LOOP_TO_DATA         = 0;
+
+    public static final int OFFSET_MASK_LOAD_LITERAL_TO_LOOP       = 14;
+    public static final int WIDTH_MASK_LOAD_LITERAL_TO_LOOP        = 12;
+    public static final int MASK_LOAD_LITERAL_TO_LOOP              = 1;
+
+    public static final int OFFSET_MASK_LOAD_LITERAL_TO_REPEAT       = 14;
+    public static final int WIDTH_MASK_LOAD_LITERAL_TO_REPEAT        = 12;
+    public static final int MASK_LOAD_LITERAL_TO_REPEAT              = 2;
+
+    public static final int OFFSET_MASK_LOAD_DATA_TO_REPEAT       = 14;
+    public static final int WIDTH_MASK_LOAD_DATA_TO_REPEAT        = 12;
+    public static final int MASK_LOAD_DATA_TO_REPEAT              = 3;
+
+    public static final int OFFSET_MASK_LOAD_DATA_TO_LOOP       = 14;
+    public static final int WIDTH_MASK_LOAD_DATA_TO_LOOP        = 12;
+    public static final int MASK_LOAD_DATA_TO_LOOP              = 4;
+
+    public static final int OFFSET_MASK_DECR_LOOP       = 14;
+    public static final int WIDTH_MASK_DECR_LOOP        = 12;
+    public static final int MASK_DECR_LOOP              = 5;
+
     public static final int OFFSET_MASK_NORMAL     = 25;
     public static final int WIDTH_MASK_NORMAL      = 1;
     public static final int MASK_NORMAL            = 1;
 
+    public static final int OFFSET_COUNTER_LITERAL     = 0;
+    public static final int WIDTH_COUNTER_LITERAL      = 6;
+
     public static final int OFFSET_COUNT           = 0;
     public static final int OFFSET_DEST            = OFFSET_COUNT+WIDTH_COUNT;
     public static final int OFFSET_CONTROL         = OFFSET_DEST+WIDTH_DEST_ADDR;
@@ -85,6 +111,21 @@ public abstract class InstructionEncoder {
 
     public Instruction readInstruction(long inst) {
         Pump name           = getBoxByInstAddr(getIntField(OFFSET_PUMP_ADDR+WIDTH_PUMP_ADDR-1, OFFSET_PUMP_ADDR, inst));
+
+        int count_literal = getIntField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1, OFFSET_COUNTER_LITERAL, inst);
+        if (getIntField(OFFSET_MASK_LOAD_LOOP_TO_DATA+WIDTH_MASK_LOAD_LOOP_TO_DATA-1, OFFSET_MASK_LOAD_LOOP_TO_DATA,inst)==MASK_LOAD_LOOP_TO_DATA)
+            return new Instruction.Counter(name, Instruction.Counter.LOOP_COUNTER, Instruction.Counter.DATA_LATCH);
+        else if (getIntField(OFFSET_MASK_LOAD_DATA_TO_REPEAT+WIDTH_MASK_LOAD_DATA_TO_REPEAT-1, OFFSET_MASK_LOAD_DATA_TO_REPEAT,inst)==MASK_LOAD_DATA_TO_REPEAT)
+            return new Instruction.Counter(name, Instruction.Counter.DATA_LATCH, Instruction.Counter.REPEAT_COUNTER);
+        else if (getIntField(OFFSET_MASK_LOAD_DATA_TO_LOOP+WIDTH_MASK_LOAD_DATA_TO_LOOP-1, OFFSET_MASK_LOAD_DATA_TO_LOOP,inst)==MASK_LOAD_DATA_TO_LOOP)
+            return new Instruction.Counter(name, Instruction.Counter.DATA_LATCH, Instruction.Counter.LOOP_COUNTER);
+        else if (getIntField(OFFSET_MASK_LOAD_LITERAL_TO_LOOP+WIDTH_MASK_LOAD_LITERAL_TO_LOOP-1, OFFSET_MASK_LOAD_LITERAL_TO_LOOP,inst)==MASK_LOAD_LITERAL_TO_LOOP)
+            return new Instruction.Counter(name, count_literal, Instruction.Counter.LOOP_COUNTER);
+        else if (getIntField(OFFSET_MASK_LOAD_LITERAL_TO_REPEAT+WIDTH_MASK_LOAD_LITERAL_TO_REPEAT-1, OFFSET_MASK_LOAD_LITERAL_TO_REPEAT,inst)==MASK_LOAD_LITERAL_TO_REPEAT)
+            return new Instruction.Counter(name, count_literal, Instruction.Counter.REPEAT_COUNTER);
+        else if (getIntField(OFFSET_MASK_DECR_LOOP+WIDTH_MASK_DECR_LOOP-1, OFFSET_MASK_DECR_LOOP,inst)==MASK_DECR_LOOP)
+            return new Instruction.DecrLoop(name);
+
         if (getIntField(OFFSET_MASK_UNCLOG+WIDTH_MASK_UNCLOG-1, OFFSET_MASK_UNCLOG,inst)==MASK_UNCLOG)
             return new Instruction.UnClog(name);
         if (getIntField(OFFSET_MASK_CLOG+WIDTH_MASK_CLOG-1, OFFSET_MASK_CLOG,inst)==MASK_CLOG)
@@ -157,6 +198,32 @@ public abstract class InstructionEncoder {
                 instr = inst.literal;
             }
 
+        } else if (d instanceof Instruction.DecrLoop) {
+            instr |= putField(OFFSET_MASK_DECR_LOOP+WIDTH_MASK_DECR_LOOP-1, OFFSET_MASK_DECR_LOOP, MASK_DECR_LOOP);
+
+        } else if (d instanceof Instruction.Counter) {
+            Instruction.Counter ic = (Instruction.Counter)d;
+            if (ic.dest == Instruction.Counter.DATA_LATCH && ic.source == Instruction.Counter.LOOP_COUNTER)
+                instr |= putField(OFFSET_MASK_LOAD_LOOP_TO_DATA+WIDTH_MASK_LOAD_LOOP_TO_DATA-1,
+                                  OFFSET_MASK_LOAD_LOOP_TO_DATA,       MASK_LOAD_LOOP_TO_DATA);
+            else if (ic.dest == Instruction.Counter.REPEAT_COUNTER && ic.source == Instruction.Counter.DATA_LATCH)
+                instr |= putField(OFFSET_MASK_LOAD_DATA_TO_REPEAT+WIDTH_MASK_LOAD_DATA_TO_REPEAT-1,
+                                  OFFSET_MASK_LOAD_DATA_TO_REPEAT,       MASK_LOAD_DATA_TO_REPEAT);
+            else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH)
+                instr |= putField(OFFSET_MASK_LOAD_DATA_TO_LOOP+WIDTH_MASK_LOAD_DATA_TO_LOOP-1,
+                                  OFFSET_MASK_LOAD_DATA_TO_LOOP,       MASK_LOAD_DATA_TO_LOOP);
+            else if (ic.dest == Instruction.Counter.REPEAT_COUNTER) {
+                instr |= putField(OFFSET_MASK_LOAD_LITERAL_TO_REPEAT+WIDTH_MASK_LOAD_LITERAL_TO_REPEAT-1,
+                                  OFFSET_MASK_LOAD_LITERAL_TO_REPEAT,       MASK_LOAD_LITERAL_TO_REPEAT);
+                instr |= putField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1,
+                                  OFFSET_COUNTER_LITERAL, ic.source);
+            } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
+                instr |= putField(OFFSET_MASK_LOAD_LITERAL_TO_LOOP+WIDTH_MASK_LOAD_LITERAL_TO_LOOP-1,
+                                  OFFSET_MASK_LOAD_LITERAL_TO_LOOP,       MASK_LOAD_LITERAL_TO_LOOP);
+                instr |= putField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1,
+                                  OFFSET_COUNTER_LITERAL, ic.source);
+            } else throw new RuntimeException();
+
         } else if (d instanceof Instruction.Move) {
             Instruction.Move inst = (Instruction.Move)d;
             instr |= putField(OFFSET_MASK_NORMAL+WIDTH_MASK_NORMAL-1, OFFSET_MASK_NORMAL,       MASK_NORMAL);
index 2b95dfc..a00be0f 100644 (file)
@@ -41,6 +41,9 @@ public class Inbox extends InstructionPump {
 
     //////////////////////////////////////////////////////////////////////////////
 
+    protected void setDataLatch(long value) { register = new Packet(getInterpreter(), null, value, null); }
+    protected long peekDataLatch() { return register.value; }
+
     /** invoked by superclass */
     protected final boolean service(Instruction.Executable instruction_) {
 
index cb4c0c2..945e863 100644 (file)
@@ -20,6 +20,8 @@ abstract class InstructionPump extends InterpreterPump {
     /** count of how many "standing instruction only" kills remain to be executed */
     private int killNextStandingInstruction = 0;
 
+    public int loopCounter = 0;
+
     InstructionPump(InterpreterShip ship, String name, String[] ports) {
         super(ship, name, ports);
     }
@@ -66,6 +68,29 @@ abstract class InstructionPump extends InterpreterPump {
     /** this will be invoked periodically; should return true to "consume" an instruction, false to leave it executing */
     protected abstract boolean service(Instruction.Executable instr);
 
+    protected abstract void setDataLatch(long value);
+    protected abstract long peekDataLatch();
+    public boolean _service(Instruction.Executable instr) {
+        if (instr instanceof Instruction.DecrLoop) {
+            if (loopCounter >= 0) loopCounter--;
+            return true;
+        }
+        if (instr instanceof Instruction.Counter) {
+            Instruction.Counter ic = (Instruction.Counter)instr;
+            if (ic.source == Instruction.Counter.LOOP_COUNTER && ic.dest == Instruction.Counter.DATA_LATCH) {
+                setDataLatch(loopCounter);
+            } else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
+                loopCounter = (int)peekDataLatch();
+                executing = null;
+            } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
+                loopCounter = ic.source;
+                executing = null;
+            }
+            return true;
+        }
+        return service(instr);
+    }
+
     protected final void service() {
         if (executing == null)
             if (instructions.size() > 0)
@@ -79,10 +104,11 @@ abstract class InstructionPump extends InterpreterPump {
             return;
         }
 
-        boolean ret = service(executing);
+        boolean ret = _service(executing);
         if (!ret) return;
-        if (executing.isRequeueing()) {
-            executing = executing.decrementCount();
+        if (executing == null) return;
+        if (executing.isRequeueing() || (loopCounter > 0)) {
+            if (loopCounter == 0) executing = executing.decrementCount();
             if (executing != null)
                 addInstruction(executing);
             executing = null;
index 4aeb320..85b3926 100644 (file)
@@ -27,6 +27,9 @@ public class Outbox extends InstructionPump {
     public Outbox(InterpreterShip ship, String name) { this(ship, name, new String[] { "" }); }
     public Outbox(InterpreterShip ship, String name, String[] ports) { super(ship, name, ports); }
 
+    protected void setDataLatch(long value) { register = value; }
+    protected long peekDataLatch() { return register; }
+
     protected final boolean service(Instruction.Executable instruction_) {
         if (clogged>0) return false;
         if (instruction_ instanceof Instruction.Clog) { clogged++; return true; }
diff --git a/tests/pump/test-read-loop-counter-from-data-latch.fleet b/tests/pump/test-read-loop-counter-from-data-latch.fleet
new file mode 100644 (file)
index 0000000..d6fcbcb
--- /dev/null
@@ -0,0 +1,22 @@
+#expect 5
+#expect 0
+#expect 5
+
+#ship debug        : Debug
+#ship memory       : Memory
+#ship fifo         : Fifo
+
+debug.in: [*] take, deliver;
+
+fifo.out:
+  take;
+  sendto debug.in;
+  load loop counter;
+  literal 0;
+  sendto debug.in;
+  take loop counter;
+  sendto debug.in;
+
+fifo.in:
+  literal 5;
+  deliver;
diff --git a/tests/pump/test-read-loop-counter.fleet b/tests/pump/test-read-loop-counter.fleet
new file mode 100644 (file)
index 0000000..0fdee1b
--- /dev/null
@@ -0,0 +1,12 @@
+#expect 5
+
+#ship debug        : Debug
+#ship memory       : Memory
+#ship fifo         : Fifo
+
+debug.in: [*] take, deliver;
+
+fifo.out:
+  load loop counter with 5;
+  take loop counter;
+  sendto debug.in;
diff --git a/tests/pump/test-use-loop-counter.fleet b/tests/pump/test-use-loop-counter.fleet
new file mode 100644 (file)
index 0000000..cc59c70
--- /dev/null
@@ -0,0 +1,25 @@
+#expect 5
+#expect 7
+#expect 5
+#expect 7
+#expect 5
+#expect 7
+
+#ship debug        : Debug
+#ship fifo         : Fifo
+#ship fifo2        : Fifo
+
+debug.in: [*] take, deliver;
+
+fifo.out: [*] take, sendto debug.in;
+
+fifo.in:
+  load loop counter with 3;
+  literal 5;
+  deliver;
+  take, deliver;
+  decrement loop counter;
+
+fifo2.out:
+  literal 7;
+  [4] sendto fifo.in;