add interpreter code and tests for loop counter instructions
[fleet.git] / src / edu / berkeley / fleet / interpreter / InstructionPump.java
1 package edu.berkeley.fleet.interpreter;
2 import edu.berkeley.sbp.util.ANSI;
3 import edu.berkeley.fleet.api.*;
4 import edu.berkeley.fleet.doc.*;
5 import edu.berkeley.fleet.api.Instruction;
6
7 import java.util.*;
8
9 /** anything that has a source (instruction horn) address on the switch fabric */
10 abstract class InstructionPump extends InterpreterPump {
11
12     public int clogged = 0;
13
14     /** the currently executing instruction */
15     private Instruction.Executable executing = null;
16
17     /** all instructions waiting to be executed (excludes executing) */
18     private Queue<Instruction.Executable> instructions = new LinkedList<Instruction.Executable>();
19
20     /** count of how many "standing instruction only" kills remain to be executed */
21     private int killNextStandingInstruction = 0;
22
23     public int loopCounter = 0;
24
25     InstructionPump(InterpreterShip ship, String name, String[] ports) {
26         super(ship, name, ports);
27     }
28
29     public void massacre() {
30         executing = null;
31         while(instructions.size() > 0)
32             instructions.remove();
33     }
34
35     public void kill(int count, boolean killOnlyStandingInstructions) {
36         if (count==0) return;
37         if (!killOnlyStandingInstructions) {
38             if (executing != null) { executing = null; count--; }
39             for(;count > 0;count--) {
40                 if (instructions.size()==0)
41                     throw new RuntimeException("deadlocked " + this + " by killing too many instructions");
42                 instructions.remove();
43             }
44         } else {
45             if (count != 1) throw new RuntimeException("this should never happen");
46             this.killNextStandingInstruction++;
47         }
48     }
49
50     /** an instruction arrives from the instruction horn */
51     void addInstruction(Instruction.Executable instr) {
52         if (killNextStandingInstruction > 0) { /* FIXME technically we should refuse to take the next instruction here */ }
53         instructions.add(instr);
54     }
55
56     protected void shutdown(boolean leaveAsInbox) {
57         if (!(executing != null || instructions.size() > 0)) return;
58         Log.println(ANSI.red(" WARNING: you left instructions on the instruction queue of port " +
59                              this + "; they are:"));
60         if (executing != null)
61             Log.println("   " + executing);
62         for(Instruction.Executable i : instructions)
63             Log.println("   " + i);
64     }
65
66     // interface to subclass ///////////////////////////////////////////////////////////////////////
67
68     /** this will be invoked periodically; should return true to "consume" an instruction, false to leave it executing */
69     protected abstract boolean service(Instruction.Executable instr);
70
71     protected abstract void setDataLatch(long value);
72     protected abstract long peekDataLatch();
73     public boolean _service(Instruction.Executable instr) {
74         if (instr instanceof Instruction.DecrLoop) {
75             if (loopCounter >= 0) loopCounter--;
76             return true;
77         }
78         if (instr instanceof Instruction.Counter) {
79             Instruction.Counter ic = (Instruction.Counter)instr;
80             if (ic.source == Instruction.Counter.LOOP_COUNTER && ic.dest == Instruction.Counter.DATA_LATCH) {
81                 setDataLatch(loopCounter);
82             } else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
83                 loopCounter = (int)peekDataLatch();
84                 executing = null;
85             } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
86                 loopCounter = ic.source;
87                 executing = null;
88             }
89             return true;
90         }
91         return service(instr);
92     }
93
94     protected final void service() {
95         if (executing == null)
96             if (instructions.size() > 0)
97                 executing = instructions.remove();
98             else
99                 return;
100
101         if (executing != null && killNextStandingInstruction>0 && executing.isStanding()) {
102             executing = null;
103             killNextStandingInstruction--;
104             return;
105         }
106
107         boolean ret = _service(executing);
108         if (!ret) return;
109         if (executing == null) return;
110         if (executing.isRequeueing() || (loopCounter > 0)) {
111             if (loopCounter == 0) executing = executing.decrementCount();
112             if (executing != null)
113                 addInstruction(executing);
114             executing = null;
115
116         } else {
117             if (executing != null && !executing.isStanding())
118                 executing = executing.decrementCount();
119         }
120     }
121
122
123 }