allow data->token
[fleet.git] / src / edu / berkeley / fleet / interpreter / Outbox.java
1 package edu.berkeley.fleet.interpreter;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.fleet.api.Instruction;
4
5 public abstract class Outbox extends InstructionPort {
6
7     /** are we ready to accept another item from the ship? */
8     private boolean readyForItemFromShip = true;
9
10     /** data which has been presented by the ship and is waiting to depart */
11     private int     itemPresentedByShip;
12
13     /** number of tokens queued on the trigger input */
14     private int     triggersReceived = 0;
15
16     private Interpreter getInterpreter() { return ((InterpreterShip)getShip()).getInterpreter(); }
17
18     protected Outbox(InterpreterShip ship, String name) {
19         super(ship, name);
20     }
21
22     public final boolean readyForItemFromShip() {
23         return readyForItemFromShip;
24     }
25
26     void addDataFromFabric(int datum)  { addTokenFromFabric(); }
27     final void addTokenFromFabric() {
28         triggersReceived++;
29     }
30
31     int register;
32     protected final boolean service(Instruction.Executable instruction) {
33
34         // if no instruction waiting, do nothing
35         if (instruction == null) return false;
36
37         // check firing conditions
38         if (instruction.tokenIn && triggersReceived <= 0) return false;
39         if (instruction.dataIn && readyForItemFromShip) return false;
40         
41         // consume trigger
42         if (instruction.tokenIn) triggersReceived--;
43
44         // consume item
45         if (instruction.dataIn) {
46             readyForItemFromShip = true;
47             if (instruction.latch) 
48                 register = itemPresentedByShip;
49         }
50
51         if (instruction.dataOut) {
52
53             // if item to be transmitted, send it
54             send((InterpreterBenkoBox)instruction.dest, register);
55             if (instruction.tokenOut)
56                 throw new RuntimeException("outboxes may not send acks!");
57
58         } else if (instruction.tokenOut) {
59
60             // if no item was sent, we might still send an ack
61             getInterpreter().sendToken(this, (InterpreterBenkoBox)instruction.dest);
62         }
63
64         return true;
65     }
66
67     /** this is invoked to transmit data; the subclass decides if it is a token or not */
68     protected abstract void send(InterpreterBenkoBox port, int data);
69
70     /** subclass invokes this to add an item from the ship */
71     protected final void addItemFromShip(int data) {
72         if (!readyForItemFromShip)
73             throw new RuntimeException("tried to add an item to an outbox which was not ready!  you have a buggy ship!");
74         readyForItemFromShip = false;
75         itemPresentedByShip = data;
76     }
77
78     void shutdown() {
79         if (!readyForItemFromShip)
80             Log.println(Log.red(" WARNING: you left a value ("+itemPresentedByShip+") on outbox port " + this));
81         if (triggersReceived > 0)
82             Log.println(Log.red(" WARNING: you left a token on the trigger input to port " + this));
83         super.shutdown(false);
84     }
85 }