From: adam Date: Wed, 2 Jan 2008 13:34:42 +0000 (+0100) Subject: add interpreter code and tests for loop counter instructions X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=8d91736de06abed0499fdd4accaea8d5eda7ea7f;p=fleet.git add interpreter code and tests for loop counter instructions --- diff --git a/src/edu/berkeley/fleet/api/Instruction.java b/src/edu/berkeley/fleet/api/Instruction.java index e3e909f..851718d 100644 --- a/src/edu/berkeley/fleet/api/Instruction.java +++ b/src/edu/berkeley/fleet/api/Instruction.java @@ -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; diff --git a/src/edu/berkeley/fleet/assembler/Parser.java b/src/edu/berkeley/fleet/assembler/Parser.java index aa9bab4..0e58b3f 100644 --- a/src/edu/berkeley/fleet/assembler/Parser.java +++ b/src/edu/berkeley/fleet/assembler/Parser.java @@ -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")) { diff --git a/src/edu/berkeley/fleet/assembler/fleet.g b/src/edu/berkeley/fleet/assembler/fleet.g index 463a1ba..0c89dea 100644 --- a/src/edu/berkeley/fleet/assembler/fleet.g +++ b/src/edu/berkeley/fleet/assembler/fleet.g @@ -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" diff --git a/src/edu/berkeley/fleet/ies44/InstructionEncoder.java b/src/edu/berkeley/fleet/ies44/InstructionEncoder.java index 2d9dada..5e4571f 100644 --- a/src/edu/berkeley/fleet/ies44/InstructionEncoder.java +++ b/src/edu/berkeley/fleet/ies44/InstructionEncoder.java @@ -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); diff --git a/src/edu/berkeley/fleet/interpreter/Inbox.java b/src/edu/berkeley/fleet/interpreter/Inbox.java index 2b95dfc..a00be0f 100644 --- a/src/edu/berkeley/fleet/interpreter/Inbox.java +++ b/src/edu/berkeley/fleet/interpreter/Inbox.java @@ -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_) { diff --git a/src/edu/berkeley/fleet/interpreter/InstructionPump.java b/src/edu/berkeley/fleet/interpreter/InstructionPump.java index cb4c0c2..945e863 100644 --- a/src/edu/berkeley/fleet/interpreter/InstructionPump.java +++ b/src/edu/berkeley/fleet/interpreter/InstructionPump.java @@ -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; diff --git a/src/edu/berkeley/fleet/interpreter/Outbox.java b/src/edu/berkeley/fleet/interpreter/Outbox.java index 4aeb320..85b3926 100644 --- a/src/edu/berkeley/fleet/interpreter/Outbox.java +++ b/src/edu/berkeley/fleet/interpreter/Outbox.java @@ -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 index 0000000..d6fcbcb --- /dev/null +++ b/tests/pump/test-read-loop-counter-from-data-latch.fleet @@ -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 index 0000000..0fdee1b --- /dev/null +++ b/tests/pump/test-read-loop-counter.fleet @@ -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 index 0000000..cc59c70 --- /dev/null +++ b/tests/pump/test-use-loop-counter.fleet @@ -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;