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