fix bugs in software implementation of Choice ship
[fleet.git] / ships / Choice.ship
1 ship: Choice
2
3 == Ports ===========================================================
4 data  in:   in1
5 data  in:   in2
6
7 data  in:   in.swapIfZero
8 data  in:   in.swapIfNonZero
9 data  in:   in.swapIfNegative
10 data  in:   in.swapIfPositive
11 data  in:   in.swapIfNonNegative
12 data  in:   in.swapIfNonPositive
13
14 data  in:   in.muxIfZero
15 data  in:   in.muxIfNonZero
16 data  in:   in.muxIfNegative
17 data  in:   in.muxIfPositive
18 data  in:   in.muxIfNonNegative
19 data  in:   in.muxIfNonPositive
20
21 data  in:   in.deMuxIfZero
22 data  in:   in.deMuxIfNonZero
23 data  in:   in.deMuxIfNegative
24 data  in:   in.deMuxIfPositive
25 data  in:   in.deMuxIfNonNegative
26 data  in:   in.deMuxIfNonPositive
27
28 data  out:  out1
29 data  out:  out2
30
31 == Constants ========================================================
32
33 == TeX ==============================================================
34
35 With judicious programming of its BenkoBoxes, this ship can be used to
36 implement nearly all forms of selection and branching.
37
38 When data is available at the in port, it is examined.  Which
39 destination the datum has arrived on determines the *condition* the
40 datum should be tested for and the *action* which should be taken if
41 the condition holds true.
42
43 The latter portion of the name of the destination (IfZero,
44 If(Non)Positive, If(Non)Negative) determines the condition which the
45 datum on the in port is tested for.  The former portion (mux, demux,
46 swap) determines the *action* to be taken if the condition tests true.
47
48   action   condition    effect
49   ------   ---------    -------------------------------
50   swap     false        in1->out1   in2->out2
51   swap     true         in2->out1   in1->out2
52   mux      false        in1->out1
53   mux      true         in2->out1
54   demux    false        in1->out1
55   demux    true         in1->out2
56
57 In each case, the ship will wait for a datum to be available on all
58 input ports (and only those ports) mentioned in the appropriate row of
59 the "effect" column above, and will output them on the corresponding
60 output ports.
61
62
63 == Fleeterpreter ====================================================
64 private Packet selector;
65 public void service() {
66   if (!box_out1.readyForItemFromShip() || !box_out2.readyForItemFromShip()) return;
67   if (selector == null && !box_in.dataReadyForShip()) return;
68   if (selector == null) selector = box_in.removePacketForShip();
69   String port = selector.destination.getDestinationName();
70
71   if (port.startsWith("swap")  && (!box_in1.dataReadyForShip() || !box_in2.dataReadyForShip())) return;
72   if (port.startsWith("mux")   && (!box_in1.dataReadyForShip() || !box_in2.dataReadyForShip())) return;
73   if (port.startsWith("deMux") && (!box_in1.dataReadyForShip())) return;
74
75   long val = selector.value;
76   boolean condition = false;
77   if (port.endsWith("IfZero"))        condition = val==0;
78   if (port.endsWith("IfNonZero"))     condition = val!=0;
79   if (port.endsWith("IfPositive"))    condition = val>0;
80   if (port.endsWith("IfNegative"))    condition = val<0;
81   if (port.endsWith("IfNonPositive")) condition = val<=0;
82   if (port.endsWith("IfNonNegative")) condition = val>=0;
83   if (port.startsWith("swap")) {
84     if (condition) {
85       box_out1.addDataFromShip(box_in2.removeDataForShip());
86       box_out2.addDataFromShip(box_in1.removeDataForShip());
87       selector = null;
88     } else {
89       box_out1.addDataFromShip(box_in1.removeDataForShip());
90       box_out2.addDataFromShip(box_in2.removeDataForShip());
91       selector = null;
92     }
93   } else if (port.startsWith("mux")) {
94     box_out1.addDataFromShip(condition ? box_in2.removeDataForShip() : box_in1.removeDataForShip());
95     selector = null;
96   } else if (port.startsWith("deMux")) {
97     (condition ? box_out2 : box_out1).addDataFromShip(box_in1.removeDataForShip());
98     selector = null;
99   }
100 }
101
102 == FleetSim ==============================================================
103
104 == FPGA ==============================================================
105
106   reg                       have_in1;
107   reg [(`DATAWIDTH-1):0]    reg_in1;
108   reg                       have_in2;
109   reg [(`DATAWIDTH-1):0]    reg_in2;
110   reg                       have_in;
111   reg [(`PACKET_WIDTH-1):0] reg_in;
112   reg                       have_out1;
113   reg                       have_out2;
114   reg fire;
115
116   always @(posedge clk) begin
117     if (!have_in1) begin
118       `onread(in1_r, in1_a) have_in1 = 1; reg_in1 = in1_d; end
119       end
120     if (!have_in2) begin
121       `onread(in2_r, in2_a) have_in2 = 1; reg_in2 = in2_d; end
122       end
123     if (!have_in) begin
124       `onread(in_r, in_a)   have_in = 1;  reg_in = in_d;   end
125       end
126
127     if (have_out1) begin
128       `onwrite(out1_r, out1_d) have_out1 = 0; end
129       end
130     if (have_out2) begin
131       `onwrite(out2_r, out2_d) have_out2 = 0; end
132       end
133
134     if (have_in && !have_out1 && !have_out2) begin
135       case (reg_in[`PACKET_WIDTH-1:`DATAWIDTH])
136         00: /* in.swapIfZero */         fire = reg_in[`DATAWIDTH-1:0] == 0;
137         06: /* in.muxIfZero */          fire = reg_in[`DATAWIDTH-1:0] == 0;
138         12: /* in.deMuxIfZero */        fire = reg_in[`DATAWIDTH-1:0] == 0;
139         01: /* in.swapIfNonZero */      fire = reg_in[`DATAWIDTH-1:0] != 0;
140         07: /* in.muxIfNonZero */       fire = reg_in[`DATAWIDTH-1:0] != 0;
141         13: /* in.deMuxIfNonZero */     fire = reg_in[`DATAWIDTH-1:0] != 0;
142         02: /* in.swapIfNegative */     fire = reg_in[`DATAWIDTH-1:0] < 0;
143         08: /* in.muxIfNegative */      fire = reg_in[`DATAWIDTH-1:0] < 0;
144         14: /* in.deMuxIfNegative */    fire = reg_in[`DATAWIDTH-1:0] < 0;
145         03: /* in.swapIfPositive */     fire = reg_in[`DATAWIDTH-1:0] > 0;
146         09: /* in.muxIfPositive */      fire = reg_in[`DATAWIDTH-1:0] > 0;
147         15: /* in.deMuxIfPositive */    fire = reg_in[`DATAWIDTH-1:0] > 0;
148         04: /* in.swapIfNonNegative */  fire = reg_in[`DATAWIDTH-1:0] >= 0;
149         16: /* in.deMuxIfNonNegative */ fire = reg_in[`DATAWIDTH-1:0] >= 0;
150         10: /* in.muxIfNonNegative */   fire = reg_in[`DATAWIDTH-1:0] >= 0;
151         05: /* in.swapIfNonPositive */  fire = reg_in[`DATAWIDTH-1:0] <= 0;
152         11: /* in.muxIfNonPositive */   fire = reg_in[`DATAWIDTH-1:0] <= 0;
153         17: /* in.deMuxIfNonPositive */ fire = reg_in[`DATAWIDTH-1:0] <= 0;
154       endcase
155
156       if (reg_in[`PACKET_WIDTH-1:`DATAWIDTH] <= 5) begin
157             if (have_in1 && have_in2) begin
158               have_out1 = 1;
159               have_out2 = 1;
160               have_in1 = 0;
161               have_in2 = 0;
162               out1_d = fire ? reg_in2 : reg_in1;
163               out2_d = fire ? reg_in1 : reg_in2;
164             end
165       end else if (reg_in[`PACKET_WIDTH-1:`DATAWIDTH] <= 11) begin
166             if (fire && have_in2) begin
167               have_out1 = 1;
168               have_in2 = 0;
169               out1_d = in2_d;
170             end else if (!fire && have_in1) begin
171               have_out1 = 1;
172               have_in1 = 0;
173               out1_d = in1_d;
174             end
175       end else begin
176             if (have_in1) begin
177               if (fire) begin
178                 have_out2 = 1;
179                 out2_d = in1_d;
180                 have_in1 = 0;
181               end else begin
182                 have_out1 = 1;
183                 out1_d = in1_d;
184                 have_in1 = 0;
185               end
186             end
187       end
188    end
189   end
190
191
192
193 == Contributors =========================================================
194 Adam Megacz <megacz@cs.berkeley.edu>