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