add Rotator ship
[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 executing = null;
16
17     /** all instructions waiting to be executed (excludes executing) */
18     private Queue<Instruction> instructions = new LinkedList<Instruction>();
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     public int repeatCounter = 1;
25
26     InstructionPump(InterpreterShip ship, String name, String[] ports) {
27         super(ship, name, ports);
28     }
29
30     public void massacre() {
31         executing = null;
32         while(instructions.size() > 0)
33             instructions.remove();
34     }
35
36     public void kill(int count, boolean killOnlyStandingInstructions) {
37         if (count==0) return;
38         if (!killOnlyStandingInstructions) {
39             if (executing != null) { executing = null; count--; }
40             for(;count > 0;count--) {
41                 if (instructions.size()==0)
42                     throw new RuntimeException("deadlocked " + this + " by killing too many instructions");
43                 instructions.remove();
44             }
45         } else {
46             if (count != 1) throw new RuntimeException("this should never happen");
47             this.killNextStandingInstruction++;
48         }
49     }
50
51     /** an instruction arrives from the instruction horn */
52     void addInstruction(Instruction instr) {
53         if (killNextStandingInstruction > 0) { /* FIXME technically we should refuse to take the next instruction here */ }
54         instructions.add(instr);
55     }
56
57     protected void shutdown(boolean leaveAsInbox) {
58         if (!(executing != null || instructions.size() > 0)) return;
59         Log.println(ANSI.red(" WARNING: you left instructions on the instruction queue of port " +
60                              this + "; they are:"));
61         if (executing != null)
62             Log.println("   " + executing);
63         for(Instruction i : instructions)
64             Log.println("   " + i);
65     }
66
67     // interface to subclass ///////////////////////////////////////////////////////////////////////
68
69     /** this will be invoked periodically; should return true to "consume" an instruction, false to leave it executing */
70     protected abstract boolean service(Instruction instr);
71
72     protected abstract void setDataLatch(long value);
73     protected abstract long peekDataLatch();
74
75     protected final void service() {
76         if (clogged > 0) return;
77         if (executing==null && instructions.size() > 0) executing = instructions.remove();
78         if (executing==null) return;
79
80         int oldLoopCounter = loopCounter;
81         if (executing.isDL()) loopCounter = Math.max(0, loopCounter-1);
82
83         if (executing instanceof Instruction.Counter) {
84             Instruction.Counter ic = (Instruction.Counter)executing;
85             if (ic.source == Instruction.Counter.LOOP_COUNTER && ic.dest == Instruction.Counter.DATA_LATCH) {
86                 setDataLatch(loopCounter);
87             } else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
88                 loopCounter = (int)peekDataLatch();
89             } else if (ic.dest == Instruction.Counter.REPEAT_COUNTER && ic.source == Instruction.Counter.DATA_LATCH) {
90                 repeatCounter = (int)peekDataLatch();
91             } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
92                 loopCounter = ic.source;
93             } else if (ic.dest == Instruction.Counter.REPEAT_COUNTER) {
94                 repeatCounter = ic.source;
95             }
96         } else if (executing instanceof Instruction.DecrLoop) {
97             executing = null;
98             return;
99         } else if (executing instanceof Instruction.Clog) {
100             clogged++;
101             executing = null;
102             return;
103         } else {
104             if (!service(executing)) return;
105         }
106
107         if (executing==null) return;
108         if (executing.isRepeating() && repeatCounter > 1) {
109             repeatCounter--;
110         } else if (executing.isLooping() && oldLoopCounter > 0) {
111             addInstruction(executing);
112             executing = null;
113         } else if (executing.isStanding()) {
114         } else {
115             executing = null;
116         }
117     }
118
119
120 }