Pristine Ack-5.5
[Ack-5.5.git] / util / int / do_intar.c
1 /*
2  * Sources of the "INTEGER ARITHMETIC" group instructions
3  */
4
5 /* $Id: do_intar.c,v 2.5 1994/06/24 10:46:29 ceriel Exp $ */
6
7 #include        <em_abs.h>
8 #include        "logging.h"
9 #include        "global.h"
10 #include        "log.h"
11 #include        "mem.h"
12 #include        "trap.h"
13 #include        "warn.h"
14 #include        "text.h"
15 #include        "fra.h"
16
17 PRIVATE long adi(), sbi(), dvi(), mli(), rmi(), ngi(), sli(), sri();
18
19 DoADI(l)
20         register size l;
21 {
22         /* ADI w: Addition (*) */
23         register long t = spop(arg_wi(l));
24
25         LOG(("@I6 DoADI(%ld)", l));
26         spoilFRA();
27         npush(adi(spop(l), t, l), l);
28 }
29
30 DoSBI(l)
31         register size l;
32 {
33         /* SBI w: Subtraction (*) */
34         register long t = spop(arg_wi(l));
35
36         LOG(("@I6 DoSBI(%ld)", l));
37         spoilFRA();
38         npush(sbi(spop(l), t, l), l);
39 }
40
41 DoMLI(l)
42         register size l;
43 {
44         /* MLI w: Multiplication (*) */
45         register long t = spop(arg_wi(l));
46
47         LOG(("@I6 DoMLI(%ld)", l));
48         spoilFRA();
49         npush(mli(spop(l), t, l), l);
50 }
51
52 DoDVI(l)
53         register size l;
54 {
55         /* DVI w: Division (*) */
56         register long t = spop(arg_wi(l));
57
58         LOG(("@I6 DoDVI(%ld)", l));
59         spoilFRA();
60         npush(dvi(spop(l), t), l);
61 }
62
63 DoRMI(l)
64         register size l;
65 {
66         /* RMI w: Remainder (*) */
67         register long t = spop(arg_wi(l));
68
69         LOG(("@I6 DoRMI(%ld)", l));
70         spoilFRA();
71         npush(rmi(spop(l), t), l);
72 }
73
74 DoNGI(l)
75         register size l;
76 {
77         /* NGI w: Negate (two's complement) (*) */
78
79         LOG(("@I6 DoNGI(%ld)", l));
80         spoilFRA();
81         l = arg_wi(l);
82         npush(ngi(spop(l), l), l);
83 }
84
85 DoSLI(l)
86         register size l;
87 {
88         /* SLI w: Shift left (*) */
89         register long t = swpop();
90
91         LOG(("@I6 DoSLI(%ld)", l));
92         spoilFRA();
93         l = arg_wi(l);
94         npush(sli(spop(l), t, l), l);
95 }
96
97 DoSRI(l)
98         register size l;
99 {
100         /* SRI w: Shift right (*) */
101         register long t = swpop();
102
103         LOG(("@I6 DoSRI(%ld)", l));
104         spoilFRA();
105         l = arg_wi(l);
106         npush(sri(spop(l), t, l), l);
107 }
108
109 #define i_maxs(n)               ((n == 2) ? I_MAXS2 : I_MAXS4)
110 #define i_mins(n)               ((n == 2) ? I_MINS2 : I_MINS4)
111
112 PRIVATE long adi(w1, w2, nbytes)                /* returns w1 + w2 */
113         long w1, w2;
114         size nbytes;
115 {
116         if (must_test && !(IgnMask&BIT(EIOVFL))) {
117                 if (w1 > 0 && w2 > 0) {
118                         if (i_maxs(nbytes) - w1 < w2)
119                                 trap(EIOVFL);
120                 }
121                 else if (w1 < 0 && w2 < 0) {
122                         if (i_mins(nbytes) - w1 > w2)
123                                 trap(EIOVFL);
124                 }
125         }
126         return (w1 + w2);
127 }
128
129 PRIVATE long sbi(w1, w2, nbytes)                /* returns w1 - w2 */
130         long w1, w2;
131         size nbytes;
132 {
133         if (must_test && !(IgnMask&BIT(EIOVFL))) {
134                 if (w2 < 0 && w1 > 0) {
135                         if (i_maxs(nbytes) + w2 < w1)
136                                 trap(EIOVFL);
137                 }
138                 else if (w2 > 0 && w1 < 0) {
139                         if (i_mins(nbytes) + w2 > w1) {
140                                 trap(EIOVFL);
141                         }
142                 }
143         }
144         return (w1 - w2);
145 }
146
147 #define labs(w)         ((w < 0) ? (-w) : w)
148
149 PRIVATE long mli(w1, w2, nbytes)                /* returns w1 * w2 */
150         long w1, w2;
151         size nbytes;
152 {
153         if (w1 == 0 || w2 == 0)
154                 return (0L);
155
156         if (must_test && !(IgnMask&BIT(EIOVFL))) {
157                 if ((w1 > 0 && w2 > 0) || (w2 < 0 && w1 < 0)) {
158                         if (    w1 == i_mins(nbytes) || w2 == i_mins(nbytes)
159                         ||      (i_maxs(nbytes) / labs(w1)) < labs(w2)
160                         ) {
161                                 trap(EIOVFL);
162                         }
163                 }
164                 else if (w1 > 0) {
165                         if (i_mins(nbytes) / w1 > w2)
166                                 trap(EIOVFL);
167                 }
168                 else if (i_mins(nbytes) / w2 > w1) {
169                         trap(EIOVFL);
170                 }
171         }
172         return (w1 * w2);
173 }
174
175 PRIVATE long dvi(w1, w2)
176         long w1, w2;
177 {
178         if (w2 == 0) {
179                 if (!(IgnMask&BIT(EIDIVZ))) {
180                         trap(EIDIVZ);
181                 }
182                 else    return (0L);
183         }
184         return (w1 / w2);
185 }
186
187 PRIVATE long rmi(w1, w2)
188         long w1, w2;
189 {
190         if (w2 == 0) {
191                 if (!(IgnMask&BIT(EIDIVZ))) {
192                         trap(EIDIVZ);
193                 }
194                 else    return (0L);
195         }
196         return (w1 % w2);
197 }
198
199 PRIVATE long ngi(w1, nbytes)
200         long w1;
201         size nbytes;
202 {
203         if (must_test && !(IgnMask&BIT(EIOVFL))) {
204                 if (w1 == i_mins(nbytes)) {
205                         trap(EIOVFL);
206                 }
207         }
208         return (-w1);
209 }
210
211 PRIVATE long sli(w1, w2, nbytes)        /* w1 << w2 */
212         long w1, w2;
213         size nbytes;
214 {
215         if (must_test) {
216 #ifdef  LOGGING
217                 /* check shift distance */
218                 if (w2 < 0)     {
219                         warning(WSHNEG);
220                         w2 = 0;
221                 }
222                 if (w2 >= nbytes*8)     {
223                         warning(WSHLARGE);
224                         w2 = nbytes*8 - 1;
225                 }
226 #endif  /* LOGGING */
227         
228                 if (!(IgnMask&BIT(EIOVFL))) {
229                         /* check overflow */
230                         if (    (w1 >= 0 && (w1 >> (nbytes*8 - w2)) != 0)
231                         ||      (w1 < 0 && (w1 >> (nbytes*8 - w2)) != -1)
232                         ) {
233                                 trap(EIOVFL);
234                         }
235                 }
236         }       
237
238         /* calculate result */
239         return (w1 << w2);
240 }
241
242 /*ARGSUSED*/
243 PRIVATE long sri(w1, w2, nbytes)        /* w1 >> w2 */
244         long w1, w2;
245         size nbytes;
246 {
247 #ifdef  LOGGING
248         if (must_test) {
249                 /* check shift distance */
250                 if (w2 < 0)     {
251                         warning(WSHNEG);
252                         w2 = 0;
253                 }
254                 if (w2 >= nbytes*8)     {
255                         warning(WSHLARGE);
256                         w2 = nbytes*8 - 1;
257                 }
258         }
259 #endif  /* LOGGING */
260         
261         /* calculate result */
262         return (w1 >> w2);
263 }
264