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