Pristine Ack-5.5
[Ack-5.5.git] / util / int / do_misc.c
1 /*
2  * Sources of the "MISCELLANEOUS" group instructions
3  */
4
5 /* $Id: do_misc.c,v 2.8 1994/06/24 10:46:42 ceriel Exp $ */
6
7 #include        <em_abs.h>
8 #include        "logging.h"
9 #include        "global.h"
10 #include        "log.h"
11 #include        "trap.h"
12 #include        "warn.h"
13 #include        "mem.h"
14 #include        "memdirect.h"
15 #include        "shadow.h"
16 #include        "text.h"
17 #include        "read.h"
18 #include        "fra.h"
19 #include        "rsb.h"
20 #include        "linfil.h"
21
22 extern int running;                     /* from main.c */
23
24 /* Two useful but unofficial registers */
25 long LIN;
26 ptr FIL;
27
28 PRIVATE index_jump(), range_check(), search_jump();
29 PRIVATE gto();
30
31 #define asp(l)          newSP(SP + arg_f(l))
32
33 DoASP(l)
34         register long l;
35 {
36         /* ASP f: Adjust the stack pointer by f */
37
38         LOG(("@M6 DoASP(%ld)", l));
39         asp(l);
40 }
41
42 DoASS(l)
43         register size l;
44 {
45         /* ASS w: Adjust the stack pointer by w-byte integer */
46
47         LOG(("@M6 DoASS(%ld)", l));
48         spoilFRA();
49         l = spop(arg_wi(l));
50         asp(l);
51 }
52
53 #define block_move(a1,a2,n)     \
54                 if (in_stack(a1)) { \
55                         if (in_stack(a2)) st_mvs(a1, a2, n); \
56                         else st_mvd(a1, a2, n); } \
57                 else {  if (in_stack(a2)) dt_mvs(a1, a2, n); \
58                         else dt_mvd(a1, a2, n); }
59
60 DoBLM(l)
61         register size l;
62 {
63         /* BLM z: Block move z bytes; first pop destination addr, then source addr */
64         register ptr dp1, dp2;          /* Destination Pointers */
65
66         LOG(("@M6 DoBLM(%ld)", l));
67         spoilFRA();
68         dp1 = dppop();
69         dp2 = dppop();
70         block_move(dp1, dp2, arg_z(l));
71 }
72
73 DoBLS(l)
74         register size l;
75 {
76         /* BLS w: Block move, size is in w-byte integer on top of stack */
77         register ptr dp1, dp2;
78
79         LOG(("@M6 DoBLS(%ld)", l));
80         spoilFRA();
81         l = upop(arg_wi(l));
82         dp1 = dppop();
83         dp2 = dppop();
84         block_move(dp1, dp2, arg_z(l));
85 }
86
87 DoCSA(l)
88         register size l;
89 {
90         /* CSA w: Case jump; address of jump table at top of stack */
91
92         LOG(("@M6 DoCSA(%ld)", l));
93         spoilFRA();
94         index_jump(arg_wi(l));
95 }
96
97 DoCSB(l)
98         register size l;
99 {
100         /* CSB w: Table lookup jump; address of jump table at top of stack */
101
102         LOG(("@M6 DoCSB(%ld)", l));
103         spoilFRA();
104         search_jump(arg_wi(l));
105 }
106
107 DoDCH()
108 {
109         /* DCH -: Follow dynamic chain, convert LB to LB of caller */
110         register ptr lb;
111
112         LOG(("@M6 DoDCH()"));
113         spoilFRA();
114         lb = dppop();
115         if (!is_LB(lb)) {
116                 wtrap(WDCHBADLB, ESTACK);
117         }
118         dppush(st_lddp(lb + rsb_LB));
119 }
120
121 DoDUP(arg)
122         size arg;
123 {
124         /* DUP s: Duplicate top s bytes */
125         register ptr oldSP = SP;
126
127         LOG(("@M6 DoDUP(%ld)", arg));
128         spoilFRA();
129         st_inc(arg_s(arg));
130         st_mvs(SP, oldSP, arg);
131 }
132
133 DoDUS(l)
134         register size l;
135 {
136         /* DUS w: Duplicate top w bytes */
137         register ptr oldSP;
138
139         LOG(("@M6 DoDUS(%ld)", l));
140         spoilFRA();
141         l = upop(arg_wi(l));
142         oldSP = SP;
143         st_inc(arg_s(l));
144         st_mvs(SP, oldSP, l);
145 }
146
147 DoEXG(l)
148         register size l;
149 {
150         /* EXG w: Exchange top w bytes */
151         register ptr oldSP = SP;
152
153         LOG(("@M6 DoEXG(%ld)", l));
154         spoilFRA();
155         st_inc(arg_w(l));
156         st_mvs(SP, oldSP, l);
157         st_mvs(oldSP, oldSP + l, l);
158         st_mvs(oldSP + l, SP, l);
159         st_dec(l);
160 }
161
162 DoFIL(arg)
163         register unsigned long arg;
164 {
165         /* FIL g: File name (external 4 := g) */
166         register ptr p = i2p(arg);
167
168         LOG(("@M6 DoFIL(%lu)", p));
169         spoilFRA();
170         if (p > HB) {
171                 wtrap(WILLFIL, EILLINS);
172         }
173         putFIL(arg_g(p));
174 }
175
176 DoGTO(arg)
177         register unsigned long arg;
178 {
179         /* GTO g: Non-local goto, descriptor at g */
180         register ptr p = i2p(arg);
181
182         LOG(("@M6 DoGTO(%lu)", p));
183         gto(arg_gto(p));
184 }
185
186 DoLIM()
187 {
188         /* LIM -: Load 16 bit ignore mask */
189         LOG(("@M6 DoLIM()"));
190         spoilFRA();
191         wpush(IgnMask);
192 }
193
194 DoLIN(l)
195         register unsigned long l;
196 {
197         /* LIN n: Line number (external 0 := n) */
198
199         LOG(("@M6 DoLIN(%lu)", l));
200         spoilFRA();
201         putLIN((long) arg_lin(l));
202 }
203
204 DoLNI()
205 {
206         /* LNI -: Line number increment */
207         LOG(("@M6 DoLNI()"));
208         spoilFRA();
209         putLIN((long)getLIN() + 1);
210 }
211
212 DoLOR(l)
213         register long l;
214 {
215         /* LOR r: Load register (0=LB, 1=SP, 2=HP) */
216
217         LOG(("@M6 DoLOR(%ld)", l));
218         spoilFRA();
219         switch ((int) arg_r(l)) {
220         case 0:
221                 dppush(LB);
222                 break;
223         case 1:
224                 dppush(SP);
225                 break;
226         case 2:
227                 dppush(HP);
228                 break;
229         }
230 }
231
232 DoLPB()
233 {
234         /* LPB -: Convert local base to argument base */
235         register ptr lb;
236
237         LOG(("@M6 DoLPB()"));
238         spoilFRA();
239         lb = dppop();
240         if (!is_LB(lb)) {
241                 wtrap(WLPBBADLB, ESTACK);
242         }
243         dppush(lb + rsbsize);
244 }
245
246 DoMON()
247 {
248         /* MON -: Monitor call */
249         LOG(("@M6 DoMON()"));
250         spoilFRA();
251         moncall();
252 }
253
254 DoNOP()
255 {
256         /* NOP -: No operation */
257         LOG(("@M6 DoNOP()"));
258         spoilFRA();
259         message("NOP instruction");
260 }
261
262 DoRCK(l)
263         register size l;
264 {
265         /* RCK w: Range check; trap on error */
266
267         LOG(("@M6 DoRCK(%ld)", l));
268         spoilFRA();
269         range_check(arg_wi(l));
270 }
271
272 DoRTT()
273 {
274         /* RTT -: Return from trap */
275         LOG(("@M6 DoRTT()"));
276
277         switch (poprsb(1)) {
278         case RSB_STP:
279                 warning(WRTTEMPTY);
280                 running = 0;            /* stop the machine */
281                 return;
282         case RSB_CAL:
283                 warning(WRTTCALL);
284                 return;
285         case RSB_RTT:
286                 /* OK */
287                 break;
288         case RSB_NRT:
289                 warning(WRTTNRTT);
290                 running = 0;            /* stop the machine */
291                 return;
292         default:
293                 warning(WRTTBAD);
294                 return;
295         }
296
297         /* pop the trap number */
298         uwpop();
299         
300         /* restore the Function Return Area */
301         FRA_def = uwpop();
302         FRASize = uwpop();
303         popFRA(FRASize);
304 }
305
306 DoSIG()
307 {
308         /* SIG -: Trap errors to proc identifier on top of stack, \-2 resets default */
309         register long tpi = spop(psize);
310
311         LOG(("@M6 DoSIG()"));
312         spoilFRA();
313         if (OnTrap == TR_HALT) {
314                 npush(-2L, psize);
315         }
316         else    npush(TrapPI, psize);
317         if (tpi == -2) {
318                 OnTrap = TR_HALT;
319                 TrapPI = 0;
320         }
321         else {
322                 tpi = arg_p(tpi);       /* do not test earlier! */
323                 OnTrap = TR_TRAP;
324                 TrapPI = tpi;
325         }
326 }
327
328 DoSIM()
329 {
330         /* SIM -: Store 16 bit ignore mask */
331         LOG(("@M6 DoSIM()"));
332         spoilFRA();
333         IgnMask = (uwpop() | PreIgnMask) & MASK2;
334 }
335
336 DoSTR(l)
337         register long l;
338 {
339         /* STR r: Store register (0=LB, 1=SP, 2=HP) */
340
341         LOG(("@M6 DoSTR(%ld)", l));
342         spoilFRA();
343         switch ((int) arg_r(l)) {
344         case 0:
345                 newLB(dppop());
346                 pop_frames();
347                 break;
348         case 1:
349                 newSP(dppop());
350                 break;
351         case 2:
352                 newHP(dppop());
353                 break;
354         }
355 }
356
357 DoTRP()
358 {
359         /* TRP -: Cause trap to occur (Error number on stack) */
360         register unsigned int tr = (unsigned int)uwpop();
361
362         LOG(("@M6 DoTRP()"));
363         spoilFRA();
364         if (tr > 15 || !(IgnMask&BIT(tr))) {
365                 wtrap(WTRP, (int)tr);
366         }
367 }
368
369
370 /* Service routines */
371
372 PRIVATE gto(p)
373         ptr p;
374 {
375         register ptr old_LB = LB;
376         register ptr new_PC = dt_ldip(p);
377         register ptr new_SP = dt_lddp(p + psize);
378         register ptr new_LB = dt_lddp(p + (2 * psize));
379
380         while (old_LB < new_LB) {
381                 PI = st_lds(old_LB + rsb_PI, psize);
382                 old_LB = st_lddp(old_LB + rsb_LB);
383         }
384         if (old_LB != new_LB) {
385                 wtrap(WGTORSB, EBADGTO);
386         }
387
388         newLB(new_LB);
389         pop_frames();
390         newSP(new_SP);
391         newPC(new_PC);
392 }
393
394 /*
395         The LIN and FIL routines.
396         The values of LIN and FIL are kept in EM machine registers
397         (variables LIN and FIL) and in the data space.
398 */
399
400 putLIN(lin)
401         long lin;
402 {
403         dt_unprot(i2p(LINO_AD), (long)LINSIZE);
404         dt_stn(i2p(LINO_AD), lin, (long)LINSIZE);
405         LIN = lin;
406         dt_prot(i2p(LINO_AD), (long)LINSIZE);
407 }
408
409 putFIL(fil)
410         ptr fil;
411 {
412         dt_unprot(i2p(FILN_AD), psize);
413         dt_stdp(i2p(FILN_AD), fil);
414         FIL = fil;
415         dt_prot(i2p(FILN_AD), psize);
416 }
417
418 /********************************************************
419  *              Case jump by indexing                   *
420  *                                                      *
421  *      1. pop case descriptor pointer.                 *
422  *      2. pop table index.                             *
423  *      3. Calculate (table index) - (lower bound).     *
424  *      4. Check if in range.                           *
425  *      5. If in range: load Program Counter value.     *
426  *      6. Else: load default value.                    *
427  ********************************************************/
428
429 PRIVATE index_jump(nbytes)
430         size nbytes;
431 {
432         register ptr cdp = dppop();     /* Case Descriptor Pointer */
433         register long t_index =         /* Table INDEX */
434                         spop(nbytes) - mem_lds(cdp + psize, nbytes);
435         register ptr nPC = 0;           /* New Program Counter */
436
437         if (t_index >= 0 && t_index <= mem_lds(cdp + nbytes + psize, nbytes)) {
438                 nPC = mem_ldip(cdp + (2 * nbytes) + ((t_index + 1) * psize));
439         }
440         if (nPC == 0 && (nPC = mem_ldip(cdp)) == 0) {
441                 trap(ECASE);
442         }
443         newPC(nPC);
444 }
445
446 /********************************************************
447  *              Case jump by table search               *
448  *                                                      *
449  *      1. pop case descriptor pointer.                 *
450  *      2. pop search value.                            *
451  *      3. Load number of table entries.                *
452  *      4. Check if search value in table.              *
453  *      5. If found: load Program Counter value.        *
454  *      6. Else: load default value.                    *
455  ********************************************************/
456
457 PRIVATE search_jump(nbytes)
458         size nbytes;
459 {
460         register ptr cdp = dppop();     /* Case Descriptor Pointer */
461         register long sv = spop(nbytes);/* Search Value */
462         register long nt =              /* Number of Table-entries */
463                         mem_lds(cdp + psize, nbytes);
464         register ptr nPC;               /* New Program Counter */
465
466         while (--nt >= 0) {
467                 if (sv == mem_lds(cdp + (nt+1) * (nbytes+psize), nbytes)) {
468                         nPC = mem_ldip(cdp + nbytes + (nt+1)*(nbytes+psize));
469                         if (nPC == 0)
470                                 trap(ECASE);
471                         newPC(nPC);
472                         return;
473                 }
474         }
475         nPC = mem_ldip(cdp);
476         if (nPC == 0)
477                 trap(ECASE);
478         newPC(nPC);
479 }
480
481 /********************************************************
482  *                      Range check                     *
483  *                                                      *
484  *      1. Load range descriptor.                       *
485  *      2. Check against lower and upper bound.         *
486  *      3. Generate trap if necessary.                  *
487  *      4. DON'T remove integer.                        *
488  ********************************************************/
489
490 PRIVATE range_check(nbytes)
491         size nbytes;
492 {
493         register ptr rdp = dppop();     /* Range check Descriptor Pointer */
494         register long cv =              /* Check Value */
495                         st_lds(SP, nbytes);
496
497         if (must_test && !(IgnMask&BIT(ERANGE))) {
498                 if (    cv < mem_lds(rdp, nbytes)
499                 ||      cv > mem_lds(rdp + nbytes, nbytes)
500                 ) {
501                         trap(ERANGE);
502                 }
503         }
504 }