Updated interpreters
[projects/chimara/chimara.git] / interpreters / glulxe / operand.c
1 /* operand.c: Glulxe code for instruction operands, reading and writing.
2     Designed by Andrew Plotkin <erkyrath@eblong.com>
3     http://eblong.com/zarf/glulx/index.html
4 */
5
6 #include "glk.h"
7 #include "glulxe.h"
8 #include "opcodes.h"
9
10 /* ### We could save a few cycles per operand by generating a function for
11    each operandlist type. */
12
13 /* fast_operandlist[]:
14    This is a handy array in which to look up operandlists quickly.
15    It stores the operandlists for the first 128 opcodes, which are
16    the ones used most frequently.
17 */
18 operandlist_t *fast_operandlist[0x80];
19
20 /* The actual immutable structures which lookup_operandlist()
21    returns. */
22 static operandlist_t list_none = { 0, 4, NULL };
23
24 static int array_S[1] = { modeform_Store };
25 static operandlist_t list_S = { 1, 4, array_S };
26 static int array_LS[2] = { modeform_Load, modeform_Store };
27 static operandlist_t list_LS = { 2, 4, array_LS };
28 static int array_LLS[3] = { modeform_Load, modeform_Load, modeform_Store };
29 static operandlist_t list_LLS = { 3, 4, array_LLS };
30 static int array_LLLS[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Store };
31 static operandlist_t list_LLLS = { 4, 4, array_LLLS };
32 static int array_LLLLS[5] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
33 static operandlist_t list_LLLLS = { 5, 4, array_LLLLS };
34 static int array_LLLLLS[6] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
35 static operandlist_t list_LLLLLS = { 6, 4, array_LLLLLS };
36 static int array_LLLLLLS[7] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
37 static operandlist_t list_LLLLLLS = { 7, 4, array_LLLLLLS };
38 static int array_LLLLLLLS[8] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
39 static operandlist_t list_LLLLLLLS = { 8, 4, array_LLLLLLLS };
40
41 static int array_L[1] = { modeform_Load };
42 static operandlist_t list_L = { 1, 4, array_L };
43 static int array_LL[2] = { modeform_Load, modeform_Load };
44 static operandlist_t list_LL = { 2, 4, array_LL };
45 static int array_LLL[3] = { modeform_Load, modeform_Load, modeform_Load };
46 static operandlist_t list_LLL = { 3, 4, array_LLL };
47 static operandlist_t list_2LS = { 2, 2, array_LS };
48 static operandlist_t list_1LS = { 2, 1, array_LS };
49 static int array_LLLL[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load };
50 static operandlist_t list_LLLL = { 4, 4, array_LLLL };
51 static int array_SL[2] = { modeform_Store, modeform_Load };
52 static operandlist_t list_SL = { 2, 4, array_SL };
53 static int array_SS[2] = { modeform_Store, modeform_Store };
54 static operandlist_t list_SS = { 2, 4, array_SS };
55 static int array_LLSS[4] = { modeform_Load, modeform_Load, modeform_Store, modeform_Store };
56 static operandlist_t list_LLSS = { 4, 4, array_LLSS };
57
58 /* init_operands():
59    Set up the fast-lookup array of operandlists. This is called just
60    once, when the terp starts up. 
61 */
62 void init_operands()
63 {
64   int ix;
65   for (ix=0; ix<0x80; ix++)
66     fast_operandlist[ix] = lookup_operandlist(ix);
67 }
68
69 /* lookup_operandlist():
70    Return the operandlist for a given opcode. For opcodes in the range
71    00..7F, it's faster to use the array fast_operandlist[]. 
72 */
73 operandlist_t *lookup_operandlist(glui32 opcode)
74 {
75   switch (opcode) {
76   case op_nop: 
77     return &list_none;
78
79   case op_add:
80   case op_sub:
81   case op_mul:
82   case op_div:
83   case op_mod:
84   case op_bitand:
85   case op_bitor:
86   case op_bitxor:
87   case op_shiftl:
88   case op_sshiftr:
89   case op_ushiftr:
90     return &list_LLS;
91
92   case op_neg:
93   case op_bitnot:
94     return &list_LS;
95
96   case op_jump:
97   case op_jumpabs:
98     return &list_L;
99   case op_jz:
100   case op_jnz:
101     return &list_LL;
102   case op_jeq:
103   case op_jne:
104   case op_jlt:
105   case op_jge:
106   case op_jgt:
107   case op_jle:
108   case op_jltu:
109   case op_jgeu:
110   case op_jgtu:
111   case op_jleu:
112     return &list_LLL;
113
114   case op_call:
115     return &list_LLS;
116   case op_return:
117     return &list_L;
118   case op_catch:
119     return &list_SL;
120   case op_throw:
121     return &list_LL;
122   case op_tailcall:
123     return &list_LL;
124
125   case op_sexb:
126   case op_sexs:
127     return &list_LS;
128
129   case op_copy:
130     return &list_LS;
131   case op_copys:
132     return &list_2LS;
133   case op_copyb:
134     return &list_1LS;
135   case op_aload:
136   case op_aloads:
137   case op_aloadb:
138   case op_aloadbit:
139     return &list_LLS;
140   case op_astore:
141   case op_astores:
142   case op_astoreb:
143   case op_astorebit:
144     return &list_LLL;
145
146   case op_stkcount:
147     return &list_S;
148   case op_stkpeek:
149     return &list_LS;
150   case op_stkswap: 
151     return &list_none;
152   case op_stkroll:
153     return &list_LL;
154   case op_stkcopy:
155     return &list_L;
156
157   case op_streamchar:
158   case op_streamunichar:
159   case op_streamnum:
160   case op_streamstr:
161     return &list_L;
162   case op_getstringtbl:
163     return &list_S;
164   case op_setstringtbl:
165     return &list_L;
166   case op_getiosys:
167     return &list_SS;
168   case op_setiosys:
169     return &list_LL;
170
171   case op_random:
172     return &list_LS;
173   case op_setrandom:
174     return &list_L;
175
176   case op_verify:
177     return &list_S;
178   case op_restart:
179     return &list_none;
180   case op_save:
181   case op_restore:
182     return &list_LS;
183   case op_saveundo:
184   case op_restoreundo:
185     return &list_S;
186   case op_protect:
187     return &list_LL;
188
189   case op_quit:
190     return &list_none;
191
192   case op_gestalt:
193     return &list_LLS;
194
195   case op_debugtrap: 
196     return &list_L;
197
198   case op_getmemsize:
199     return &list_S;
200   case op_setmemsize:
201     return &list_LS;
202
203   case op_linearsearch:
204     return &list_LLLLLLLS;
205   case op_binarysearch:
206     return &list_LLLLLLLS;
207   case op_linkedsearch:
208     return &list_LLLLLLS;
209
210   case op_glk:
211     return &list_LLS;
212
213   case op_callf:
214     return &list_LS;
215   case op_callfi:
216     return &list_LLS;
217   case op_callfii:
218     return &list_LLLS;
219   case op_callfiii:
220     return &list_LLLLS;
221
222   case op_mzero:
223     return &list_LL;
224   case op_mcopy:
225     return &list_LLL;
226   case op_malloc:
227     return &list_LS;
228   case op_mfree:
229     return &list_L;
230
231   case op_accelfunc:
232   case op_accelparam:
233     return &list_LL;
234
235 #ifdef FLOAT_SUPPORT
236
237   case op_numtof:
238   case op_ftonumz:
239   case op_ftonumn:
240   case op_ceil:
241   case op_floor:
242   case op_sqrt:
243   case op_exp:
244   case op_log:
245     return &list_LS;
246   case op_fadd:
247   case op_fsub:
248   case op_fmul:
249   case op_fdiv:
250   case op_pow:
251   case op_atan2:
252     return &list_LLS;
253   case op_fmod:
254     return &list_LLSS;
255   case op_sin:
256   case op_cos:
257   case op_tan:
258   case op_asin:
259   case op_acos:
260   case op_atan:
261     return &list_LS;
262   case op_jfeq:
263   case op_jfne:
264     return &list_LLLL;
265   case op_jflt:
266   case op_jfle:
267   case op_jfgt:
268   case op_jfge:
269     return &list_LLL;
270   case op_jisnan:
271   case op_jisinf:
272     return &list_LL;
273
274 #endif /* FLOAT_SUPPORT */
275
276   default: 
277     return NULL;
278   }
279 }
280
281 /* parse_operands():
282    Read the list of operands of an instruction, and put the values
283    in args. This assumes that the PC is at the beginning of the
284    operand mode list (right after an opcode number.) Upon return,
285    the PC will be at the beginning of the next instruction.
286
287    This also assumes that args points at an allocated array of 
288    MAX_OPERANDS oparg_t structures.
289 */
290 void parse_operands(oparg_t *args, operandlist_t *oplist)
291 {
292   int ix;
293   oparg_t *curarg;
294   int numops = oplist->num_ops;
295   int argsize = oplist->arg_size;
296   glui32 modeaddr = pc;
297   int modeval;
298
299   pc += (numops+1) / 2;
300
301   for (ix=0, curarg=args; ix<numops; ix++, curarg++) {
302     int mode;
303     glui32 value;
304     glui32 addr;
305
306     curarg->desttype = 0;
307
308     if ((ix & 1) == 0) {
309       modeval = Mem1(modeaddr);
310       mode = (modeval & 0x0F);
311     }
312     else {
313       mode = ((modeval >> 4) & 0x0F);
314       modeaddr++;
315     }
316
317     if (oplist->formlist[ix] == modeform_Load) {
318
319       switch (mode) {
320
321       case 8: /* pop off stack */
322         if (stackptr < valstackbase+4) {
323           fatal_error("Stack underflow in operand.");
324         }
325         stackptr -= 4;
326         value = Stk4(stackptr);
327         break;
328
329       case 0: /* constant zero */
330         value = 0;
331         break;
332
333       case 1: /* one-byte constant */
334         /* Sign-extend from 8 bits to 32 */
335         value = (glsi32)(signed char)(Mem1(pc));
336         pc++;
337         break;
338
339       case 2: /* two-byte constant */
340         /* Sign-extend the first byte from 8 bits to 32; the subsequent
341            byte must not be sign-extended. */
342         value = (glsi32)(signed char)(Mem1(pc));
343         pc++;
344         value = (value << 8) | (glui32)(Mem1(pc));
345         pc++;
346         break;
347
348       case 3: /* four-byte constant */
349         /* Bytes must not be sign-extended. */
350         value = Mem4(pc);
351         pc += 4;
352         break;
353
354       case 15: /* main memory RAM, four-byte address */
355         addr = Mem4(pc);
356         addr += ramstart;
357         pc += 4;
358         goto MainMemAddr; 
359
360       case 14: /* main memory RAM, two-byte address */
361         addr = (glui32)Mem2(pc);
362         addr += ramstart;
363         pc += 2;
364         goto MainMemAddr; 
365
366       case 13: /* main memory RAM, one-byte address */
367         addr = (glui32)(Mem1(pc));
368         addr += ramstart;
369         pc++;
370         goto MainMemAddr; 
371         
372       case 7: /* main memory, four-byte address */
373         addr = Mem4(pc);
374         pc += 4;
375         goto MainMemAddr;
376
377       case 6: /* main memory, two-byte address */
378         addr = (glui32)Mem2(pc);
379         pc += 2;
380         goto MainMemAddr;
381
382       case 5: /* main memory, one-byte address */
383         addr = (glui32)(Mem1(pc));
384         pc++;
385         /* fall through */
386
387       MainMemAddr:
388         /* cases 5, 6, 7, 13, 14, 15 all wind up here. */
389         if (argsize == 4) {
390           value = Mem4(addr);
391         }
392         else if (argsize == 2) {
393           value = Mem2(addr);
394         }
395         else {
396           value = Mem1(addr);
397         }
398         break;
399
400       case 11: /* locals, four-byte address */
401         addr = Mem4(pc);
402         pc += 4;
403         goto LocalsAddr;
404
405       case 10: /* locals, two-byte address */
406         addr = (glui32)Mem2(pc);
407         pc += 2;
408         goto LocalsAddr; 
409
410       case 9: /* locals, one-byte address */
411         addr = (glui32)(Mem1(pc));
412         pc++;
413         /* fall through */
414
415       LocalsAddr:
416         /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
417            be four-byte aligned, but we don't check this explicitly. 
418            A "strict mode" interpreter probably should. It's also illegal
419            for addr to be less than zero or greater than the size of
420            the locals segment. */
421         addr += localsbase;
422         if (argsize == 4) {
423           value = Stk4(addr);
424         }
425         else if (argsize == 2) {
426           value = Stk2(addr);
427         }
428         else {
429           value = Stk1(addr);
430         }
431         break;
432
433       default:
434         fatal_error("Unknown addressing mode in load operand.");
435       }
436
437       curarg->value = value;
438
439     }
440     else {  /* modeform_Store */
441       switch (mode) {
442
443       case 0: /* discard value */
444         curarg->desttype = 0;
445         curarg->value = 0;
446         break;
447
448       case 8: /* push on stack */
449         curarg->desttype = 3;
450         curarg->value = 0;
451         break;
452
453       case 15: /* main memory RAM, four-byte address */
454         addr = Mem4(pc);
455         addr += ramstart;
456         pc += 4;
457         goto WrMainMemAddr; 
458
459       case 14: /* main memory RAM, two-byte address */
460         addr = (glui32)Mem2(pc);
461         addr += ramstart;
462         pc += 2;
463         goto WrMainMemAddr; 
464
465       case 13: /* main memory RAM, one-byte address */
466         addr = (glui32)(Mem1(pc));
467         addr += ramstart;
468         pc++;
469         goto WrMainMemAddr; 
470
471       case 7: /* main memory, four-byte address */
472         addr = Mem4(pc);
473         pc += 4;
474         goto WrMainMemAddr;
475
476       case 6: /* main memory, two-byte address */
477         addr = (glui32)Mem2(pc);
478         pc += 2;
479         goto WrMainMemAddr;
480
481       case 5: /* main memory, one-byte address */
482         addr = (glui32)(Mem1(pc));
483         pc++;
484         /* fall through */
485
486       WrMainMemAddr:
487         /* cases 5, 6, 7 all wind up here. */
488         curarg->desttype = 1;
489         curarg->value = addr;
490         break;
491
492       case 11: /* locals, four-byte address */
493         addr = Mem4(pc);
494         pc += 4;
495         goto WrLocalsAddr;
496
497       case 10: /* locals, two-byte address */
498         addr = (glui32)Mem2(pc);
499         pc += 2;
500         goto WrLocalsAddr; 
501
502       case 9: /* locals, one-byte address */
503         addr = (glui32)(Mem1(pc));
504         pc++;
505         /* fall through */
506
507       WrLocalsAddr:
508         /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
509            be four-byte aligned, but we don't check this explicitly. 
510            A "strict mode" interpreter probably should. It's also illegal
511            for addr to be less than zero or greater than the size of
512            the locals segment. */
513         curarg->desttype = 2;
514         /* We don't add localsbase here; the store address for desttype 2
515            is relative to the current locals segment, not an absolute
516            stack position. */
517         curarg->value = addr;
518         break;
519
520       case 1:
521       case 2:
522       case 3:
523         fatal_error("Constant addressing mode in store operand.");
524
525       default:
526         fatal_error("Unknown addressing mode in store operand.");
527       }
528     }
529   }
530 }
531
532 /* store_operand():
533    Store a result value, according to the desttype and destaddress given.
534    This is usually used to store the result of an opcode, but it's also
535    used by any code that pulls a call-stub off the stack.
536 */
537 void store_operand(glui32 desttype, glui32 destaddr, glui32 storeval)
538 {
539   switch (desttype) {
540
541   case 0: /* do nothing; discard the value. */
542     return;
543
544   case 1: /* main memory. */
545     MemW4(destaddr, storeval);
546     return;
547
548   case 2: /* locals. */
549     destaddr += localsbase;
550     StkW4(destaddr, storeval);
551     return;
552
553   case 3: /* push on stack. */
554     if (stackptr+4 > stacksize) {
555       fatal_error("Stack overflow in store operand.");
556     }
557     StkW4(stackptr, storeval);
558     stackptr += 4;
559     return;
560
561   default:
562     fatal_error("Unknown destination type in store operand.");
563
564   }
565 }
566
567 void store_operand_s(glui32 desttype, glui32 destaddr, glui32 storeval)
568 {
569   storeval &= 0xFFFF;
570
571   switch (desttype) {
572
573   case 0: /* do nothing; discard the value. */
574     return;
575
576   case 1: /* main memory. */
577     MemW2(destaddr, storeval);
578     return;
579
580   case 2: /* locals. */
581     destaddr += localsbase;
582     StkW2(destaddr, storeval);
583     return;
584
585   case 3: /* push on stack. A four-byte value is actually pushed. */
586     if (stackptr+4 > stacksize) {
587       fatal_error("Stack overflow in store operand.");
588     }
589     StkW4(stackptr, storeval);
590     stackptr += 4;
591     return;
592
593   default:
594     fatal_error("Unknown destination type in store operand.");
595
596   }
597 }
598
599 void store_operand_b(glui32 desttype, glui32 destaddr, glui32 storeval)
600 {
601   storeval &= 0xFF;
602
603   switch (desttype) {
604
605   case 0: /* do nothing; discard the value. */
606     return;
607
608   case 1: /* main memory. */
609     MemW1(destaddr, storeval);
610     return;
611
612   case 2: /* locals. */
613     destaddr += localsbase;
614     StkW1(destaddr, storeval);
615     return;
616
617   case 3: /* push on stack. A four-byte value is actually pushed. */
618     if (stackptr+4 > stacksize) {
619       fatal_error("Stack overflow in store operand.");
620     }
621     StkW4(stackptr, storeval);
622     stackptr += 4;
623     return;
624
625   default:
626     fatal_error("Unknown destination type in store operand.");
627
628   }
629 }