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;
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")) {
| ^"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
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"
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;
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;
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)
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);
//////////////////////////////////////////////////////////////////////////////
+ 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_) {
/** 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);
}
/** 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)
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;
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; }
--- /dev/null
+#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;
--- /dev/null
+#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;
--- /dev/null
+#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;