fix Counter.ship software implementation to exactly match semantics of FPGA
[fleet.git] / ships / Counter.ship
1 ship: Counter
2
3 == Ports ===========================================================
4 data  in:   in1
5 data  in:   in2
6 data  in:   inOp
7   constant REPEAT_C1_V1: 0
8   constant REPEAT_C1_V2: 1
9   constant REPEAT_C2_V1: 2
10   constant REPEAT_C2_V2: 3
11   constant PASS_C1_V1:   4
12   constant PASS_C1_V2:   5
13   constant PASS_C2_V1:   6
14   constant PASS_C2_V2:   7
15   constant DROP_C1_V1:   8
16   constant DROP_C1_V2:   9
17   constant DROP_C2_V1:   10
18   constant DROP_C2_V2:   11
19   constant COUNT:        12
20 data  out:  out
21
22 == Fleeterpreter ====================================================
23
24 boolean full = false;
25 boolean op_count = false;
26 boolean op_repeat = false;
27 boolean op_pass = false;
28 boolean op_drop = false;
29 boolean op_c1 = false;
30 boolean op_c2 = false;
31 boolean op_v1 = false;
32 boolean op_v2 = false;
33 long temp = 0;
34 boolean out_draining;
35
36 public void reset() {
37   super.reset();
38   full = false;
39   temp = 0;
40   out_draining = false;
41 }
42 public void service() {
43
44   if (!box_inOp.dataReadyForShip()) full = false;
45
46   if (out_draining && box_out.readyForDataFromShip()) {
47     if (op_count) temp = temp - box_in2.peekDataForShip();
48     else          temp--;
49     if (op_pass && op_v1) box_in1.removeDataForShip();
50     if (op_pass && op_v2) box_in2.removeDataForShip();
51     out_draining = false;
52
53   } else if (box_inOp.dataReadyForShip()) {
54     long op   = box_inOp.peekDataForShip();
55     op_count  = (op & 15)==12;
56     op_repeat = ((op>>2) & 3)==0;
57     op_pass   = ((op>>2) & 3)==1;
58     op_drop   = ((op>>2) & 3)==2;
59     op_c1     = (op_repeat || op_pass || op_drop) && !(((op>>1)&1)!=0);
60     op_c2     = (op_repeat || op_pass || op_drop) &&  (((op>>1)&1)!=0);
61     op_v1     = (op_repeat || op_pass || op_drop) && !(((op>>0)&1)!=0);
62     op_v2     = (op_repeat || op_pass || op_drop) &&  (((op>>0)&1)!=0);
63     if (!full) {
64       if (op_count && box_in1.dataReadyForShip() && box_in2.dataReadyForShip()) {
65         temp = box_in1.peekDataForShip() - box_in2.peekDataForShip();
66         box_in1.removeDataForShip();
67         full = true;
68       } else if (op_c1 && box_in1.dataReadyForShip()) {
69         temp = box_in1.peekDataForShip() - 1;
70         box_in1.removeDataForShip();
71         full = true;
72       } else if (op_c2 && box_in2.dataReadyForShip()) {
73         temp = box_in2.peekDataForShip() - 1;
74         box_in2.removeDataForShip();
75         full = true;
76       }
77     } else if (temp < 0) {
78       full = false;
79       box_inOp.removeDataForShip();
80       if (op_count) box_in2.removeDataForShip();
81       else if (op_repeat && op_v1) box_in1.removeDataForShip();
82       else if (op_repeat && op_v2) box_in2.removeDataForShip();
83
84     } else if (box_out.readyForDataFromShip()) {
85       if (op_count) {
86         out_draining = true;
87         box_out.addDataFromShip(temp, (temp - box_in2.peekDataForShip()) < 0);
88       } else if (op_v1 && box_in1.dataReadyForShip()) {
89         if (op_drop) { box_in1.removeDataForShip(); temp--; }
90         else         { box_out.addDataFromShip(box_in1.peekDataForShip(), temp<=0); out_draining = true; }
91       } else if (op_v2 && box_in2.dataReadyForShip()) {
92         if (op_drop) { box_in2.removeDataForShip(); temp--; }
93         else         { box_out.addDataFromShip(box_in2.peekDataForShip(), temp<=0); out_draining = true; }
94       }
95     }
96   }
97 }
98
99 == FleetSim ==============================================================
100
101 == FPGA ==============================================================
102
103   wire [3:0]              inOp_d_trunc;
104   assign                  inOp_d_trunc = inOp_d[3:0];
105
106   reg [`WORDWIDTH-1:0] temp;
107   initial temp   = {`WORDWIDTH{1'b1}};
108   reg     out_draining;
109   reg     full;
110   initial full = 0;
111   reg c_flag;
112   wire    op_count;  assign op_count  = inOp_d_trunc==12;
113   wire    op_repeat; assign op_repeat = inOp_d[3:2]==0;
114   wire    op_pass;   assign op_pass   = inOp_d[3:2]==1;
115   wire    op_drop;   assign op_drop   = inOp_d[3:2]==2;
116   wire    op_c1;     assign op_c1     = (op_repeat || op_pass || op_drop) && !inOp_d[1];
117   wire    op_c2;     assign op_c2     = (op_repeat || op_pass || op_drop) &&  inOp_d[1];
118   wire    op_v1;     assign op_v1     = (op_repeat || op_pass || op_drop) && !inOp_d[0];
119   wire    op_v2;     assign op_v2     = (op_repeat || op_pass || op_drop) &&  inOp_d[0];
120
121   wire [`WORDWIDTH-1:0] pre_out;
122   assign  pre_out = op_v1 ? in1_d : op_v2 ? in2_d : temp;
123   assign  out_d_  = { c_flag, pre_out };
124
125   // FIXME: REPEAT with a count of zero will not work properly
126
127   wire [`WORDWIDTH-1:0] temp_minus_in2;
128   assign temp_minus_in2 = (temp - in2_d);
129
130   always @(posedge clk) begin
131     if (rst) begin
132       `reset
133       full <= 0;
134       out_draining <= 0;
135       c_flag <= 0;
136     end else begin
137       `cleanup
138       if (`inOp_empty)         full   <= 0;
139       if (out_draining && `out_empty) begin
140         if (op_count) temp   <= temp_minus_in2;
141         else          temp   <= temp - 1;
142         if (op_pass && op_v1) `drain_in1
143         if (op_pass && op_v2) `drain_in2
144         out_draining <= 0;
145       end else if (`inOp_full) begin
146         if (!full) begin
147           if (op_count && `in1_full && `in2_full) begin
148             temp  <= in1_d[`WORDWIDTH-1:0] - in2_d[`WORDWIDTH-1:0];
149             `drain_in1
150             full  <= 1;
151           end else if (op_c1 && `in1_full) begin
152             temp  <= in1_d[`WORDWIDTH-1:0]-1;
153             `drain_in1
154             full  <= 1;
155           end else if (op_c2 && `in2_full) begin
156             temp  <= in2_d[`WORDWIDTH-1:0]-1;
157             `drain_in2
158             full  <= 1;
159           end
160         end else if (temp[`WORDWIDTH-1]) begin
161           full <= 0;
162           `drain_inOp
163           if (op_count) begin
164             `drain_in2
165           end else if (op_repeat && op_v1) begin
166             `drain_in1
167           end else if (op_repeat && op_v2) begin
168             `drain_in2
169           end
170         end else if (`out_empty) begin
171           if (op_count) begin
172             `fill_out
173             out_draining <= 1;
174             c_flag <= temp_minus_in2[`WORDWIDTH-1];
175           end else if (op_v1 && `in1_full) begin
176             if (op_drop)    begin `drain_in1 temp <= temp-1; end
177             else            begin `fill_out out_draining <= 1; end
178             c_flag <= (temp==0);
179           end else if (op_v2 && `in2_full) begin
180             if (op_drop)    begin `drain_in2 temp <= temp-1; end
181             else            begin `fill_out out_draining <= 1; end
182             c_flag <= (temp==0);
183           end
184         end
185       end
186     end
187   end
188
189 == Test =================================================================
190
191 #ship counter : Counter
192 #ship debug   : Debug
193
194 #expect 6
195 #expect 3
196 #expect 0
197 #expect -1
198 #expect 2
199 #expect 1
200 #expect 0
201 #expect -1
202 #expect 2
203 #expect 2
204 #expect 2
205 #expect 2
206 #expect -1
207 #expect 9
208 #expect 9
209 #expect 9
210 #expect -1
211
212 debug.in:
213   set ilc=*;
214   recv, deliver;
215
216 counter.in1:
217   set word=9;
218   deliver;
219   set word=3;
220   deliver;
221   set word=4;
222   deliver;
223   set word=3;
224   deliver;
225
226 counter.in2:
227   set word=3;
228   deliver;
229   set word=1;
230   deliver;
231   set word=2;
232   deliver;
233   set word=9;
234   deliver;
235
236 counter.inOp:
237   set word=12;
238   deliver;
239   deliver;
240   set word=1;
241   deliver;
242   deliver;
243
244 counter.out:
245   head;
246   collect, send to debug.in;
247   set flags a=c, b=b;
248   set word=-1;
249   [a] send to debug.in;
250   tail;
251
252
253 == Contributors =========================================================
254 Adam Megacz <megacz@cs.berkeley.edu>