fix bug in Alu.ship
[fleet.git] / ships / Alu.ship
1 ship: Alu
2
3 == Ports ===========================================================
4 data  in:   in1
5 data  in:   in2
6 data  in:   inOp
7   constant IN1: 0
8   constant IN2: 1
9   constant ADD: 2
10   constant SUB: 3
11   constant MAX: 4
12   constant MIN: 5
13   constant CMP: 6
14   constant DROP1: 7
15   constant DROP2: 8
16   constant MAXMERGE: 9
17
18 data  out:  out
19
20
21 == TeX ==============================================================
22
23 {\tt Alu} is a ``two-input'' arithmetic logic unit.  It includes
24 logic for performing arithmetic operations on a pair of arguments.
25 Currently this includes
26 addition ({\sc add}),
27 subtraction ({\sc sub}),
28 maximum ({\sc max}), and
29 minimum ({\sc min}).
30
31 \subsection*{Semantics}
32
33 When a value is present at each of {\tt in1}, {\tt in2} and {\tt
34 inOp}, these three values are consumed.  Based on the value consumed
35 at {\tt inOp}, the requested operation is performed on the values
36 consumed from {\tt in1} and {\tt in2}.  The result of this operation
37 is then made available at {\tt out}.
38
39 \subsection*{C-Flag}
40
41 \begin{verbatim}
42 IN1      - undefined; drain in1 only
43 IN2      - undefined; drain in2 only
44 ADD      - carry-out
45 SUB      - undefined
46 MAX      - if in1>in2 cflag=0 and drain in1, else cflag=1 and drain in2
47 MIN      - if in1>in2 cflag=1 and drain in2, else cflag=0 and drain in1
48 CMP      - if in1==in2 cflag=1, else cflag=0
49 DROP1    - consume in1, produce no output
50 DROP2    - consume in2, produce no output
51 MAXMERGE - if (in1<0 && in2<0) consume both, emit either, cflag=undef else act as MAX
52 \end{verbatim}
53
54 \subsection*{To Do}
55
56 The {\it link bit} and other features of \cite{ies31} are not yet
57 implemented.
58
59 The carry-in, carry-out, zero-test, negative-test, and overflow-test
60 flags typically present in a conventional processor ALU are also not
61 yet implemented.
62
63 == Fleeterpreter ====================================================
64 public void service() {
65   if (box_inOp.dataReadyForShip() &&
66       box_in1.dataReadyForShip() &&
67       box_in2.dataReadyForShip() &&
68       box_out.readyForDataFromShip()) {
69       long a;
70       long b;
71       long op     = box_inOp.removeDataForShip();
72       switch((int)op) {
73           case 0:
74               a = box_in1.removeDataForShip();
75               box_out.addDataFromShip(a); // IN1
76               break;
77           case 1:
78               b = box_in2.removeDataForShip();
79               box_out.addDataFromShip(b); // IN2
80               break;
81           case 2:
82               a = box_in1.removeDataForShip();
83               b = box_in2.removeDataForShip();
84               box_out.addDataFromShip(a+b); // ADD
85               break;
86           case 3:
87               a = box_in1.removeDataForShip();
88               b = box_in2.removeDataForShip();
89               box_out.addDataFromShip(a-b); // SUB
90               break;
91
92           case 9: // MAXMERGE
93               if (box_in1.peekDataForShip()<0 && box_in2.peekDataForShip()<0) {
94                 a = box_in1.removeDataForShip();
95                 b = box_in2.removeDataForShip();
96                 box_out.addDataFromShip(a, false);
97                 break;
98               }
99               // fall through to MAX
100           case 4:
101               a = box_in1.peekDataForShip();
102               b = box_in2.peekDataForShip();
103               box_out.addDataFromShip(Math.max(a,b), !(a>b)); // MAX
104               if (a>b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
105               break;
106
107           case 5:
108               a = box_in1.peekDataForShip();
109               b = box_in2.peekDataForShip();
110               box_out.addDataFromShip(Math.min(a,b), a>b); // MIN
111               if (a<b) box_in1.removeDataForShip(); else box_in2.removeDataForShip();
112               break;
113           case 6:
114               a = box_in1.removeDataForShip();
115               b = box_in2.removeDataForShip();
116               box_out.addDataFromShip(0, a==b); // CMP
117               break;
118 /*
119           case 7:
120               box_in1.removeDataForShip();      // DROP1
121               break;
122           case 8:
123               box_in2.removeDataForShip();      // DROP2
124               break;
125 */
126           default:
127               throw new RuntimeException("invalid opcode: " + op);
128       }
129   }
130 }
131
132 == FleetSim ==============================================================
133
134 == FPGA ==============================================================
135
136   wire [`WORDWIDTH:0]     sum;
137   wire                    cin;
138   wire [(`WORDWIDTH-1):0] in2_inverted;
139
140   wire [(`WORDWIDTH-1):0] res;
141   wire                    isplus;
142   wire                    eq;
143   wire                    cout;
144
145   wire [3:0]              inOp_d_trunc;
146   assign                  inOp_d_trunc = inOp_d[3:0];
147
148   assign isplus        = inOp_d_trunc[2:0]==2;
149   assign cin           = isplus ? 0 : 1;
150   assign in2_inverted  = isplus ? in2_d : ~in2_d;
151   assign sum           = {in1_d,cin} + {in2_inverted,cin};
152   assign res           = sum[`WORDWIDTH:1];
153   assign greater       = !res[`WORDWIDTH-1];
154   assign both_negative = in1_d[`WORDWIDTH-1] && in2_d[`WORDWIDTH-1];
155   assign eq            = in1_d == in2_d;
156   assign cout          = sum[`WORDWIDTH];
157
158   reg out_draining;
159
160   assign out_d_[`WORDWIDTH] =
161           (inOp_d_trunc==0) ? 1'b0 :
162           (inOp_d_trunc==1) ? 1'b0 :
163           (inOp_d_trunc==2) ? cout :
164           (inOp_d_trunc==3) ? cout :
165           (inOp_d_trunc==4) ? ~greater :
166           (inOp_d_trunc==5) ?  greater :
167           (inOp_d_trunc==6) ?  eq :
168           (inOp_d_trunc==9) ? ~greater :
169           0;
170
171   assign out_d_[(`WORDWIDTH-1):0] =
172           (inOp_d_trunc==0) ? (in1_d)  :
173           (inOp_d_trunc==1) ? (in2_d)  :
174           (inOp_d_trunc==2) ? (res)  :
175           (inOp_d_trunc==3) ? (res)  :
176           (inOp_d_trunc==4) ? (greater ? in1_d : in2_d)  :
177           (inOp_d_trunc==5) ? (greater ? in2_d : in1_d)  :
178           (inOp_d_trunc==6) ? {{ (`WORDWIDTH-1) {1'b0 }}, eq  } :
179           (inOp_d_trunc==9) ? (both_negative ? in1_d : (greater ? in1_d : in2_d)) :
180           0;
181
182   always @(posedge clk) begin
183     if (!rst) begin
184       `reset
185       out_draining <= 0;
186     end else begin
187       `cleanup
188       if (out_draining && `out_empty) begin
189         `drain_inOp
190         out_draining <= 0;
191         if      (inOp_d_trunc==0) `drain_in1
192         else if (inOp_d_trunc==1) `drain_in2
193         else if (inOp_d_trunc==9 &&  both_negative) begin `drain_in1 `drain_in2 end
194         else if (inOp_d_trunc==4 &&  greater) `drain_in1
195         else if (inOp_d_trunc==5 &&  greater) `drain_in2
196         else if (inOp_d_trunc==9 &&  greater) `drain_in1
197         else if (inOp_d_trunc==4 && !greater) `drain_in2
198         else if (inOp_d_trunc==5 && !greater) `drain_in1
199         else if (inOp_d_trunc==9 && !greater) `drain_in2
200         else begin
201           `drain_in1
202           `drain_in2
203         end
204       end
205       if (!out_draining && `out_empty && `in1_full && `in2_full && `inOp_full) begin
206         `fill_out
207         out_draining <= 1;
208       end
209     end
210   end
211
212 == Test ==============================================================================
213
214 // FIXME: need test for ADD carry-out c-flag
215
216 #ship debug : Debug
217 #ship alu   : Alu
218
219 #expect 17
220 #expect 1
221 #expect 9
222 #expect 8
223 #expect 8
224 #expect 1
225 #expect 9
226 #expect 0
227 #expect 0
228 #expect 1
229
230 debug.in:   set ilc=*;  recv, deliver;
231 alu.in1:
232   set word= 9;
233   set ilc=5;
234   deliver;
235   set word= 9;
236   deliver;
237
238 alu.in2:
239   set word= 8;
240   set ilc=5;
241   deliver;
242   set word= 9;
243   deliver;
244
245 alu.out:
246   set ilc=4;
247   collect, send to debug.in;
248 alu.inOp:
249  set word= Alu.inOp[ADD]; deliver;
250  set word= Alu.inOp[SUB]; deliver;
251  set word= Alu.inOp[IN1]; deliver;
252  set word= Alu.inOp[IN2]; deliver;
253  set word= Alu.inOp[MIN]; deliver;
254  set word= Alu.inOp[MAX]; deliver;
255  set word= Alu.inOp[CMP]; deliver;
256  set word= Alu.inOp[CMP]; deliver;
257
258 alu.out:
259   collect, send to debug.in;        // MIN
260   set flags a=c, b=b;
261   [a]  set word= 1;
262   [!a] set word= 0;
263   send to debug.in;
264
265   collect, send to debug.in;        // MAX
266   set flags a=c, b=b;
267   [a]  set word= 1;
268   [!a] set word= 0;
269   send to debug.in;
270
271   collect;        // CMP
272   set flags a=c, b=b;
273   [a]  set word= 1;
274   [!a] set word= 0;
275   send to debug.in;
276
277   collect;        // CMP
278   set flags a=c, b=b;
279   [a]  set word= 1;
280   [!a] set word= 0;
281   send to debug.in;
282
283 == Contributors =========================================================
284 Adam Megacz <megacz@cs.berkeley.edu>