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
10 /* ### We could save a few cycles per operand by generating a function for
11 each operandlist type. */
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.
18 operandlist_t *fast_operandlist[0x80];
20 /* The actual immutable structures which lookup_operandlist()
22 static operandlist_t list_none = { 0, 4, NULL };
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 };
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_SL[2] = { modeform_Store, modeform_Load };
50 static operandlist_t list_SL = { 2, 4, array_SL };
51 static int array_SS[2] = { modeform_Store, modeform_Store };
52 static operandlist_t list_SS = { 2, 4, array_SS };
55 Set up the fast-lookup array of operandlists. This is called just
56 once, when the terp starts up.
61 for (ix=0; ix<0x80; ix++)
62 fast_operandlist[ix] = lookup_operandlist(ix);
65 /* lookup_operandlist():
66 Return the operandlist for a given opcode. For opcodes in the range
67 00..7F, it's faster to use the array fast_operandlist[].
69 operandlist_t *lookup_operandlist(glui32 opcode)
154 case op_streamunichar:
158 case op_getstringtbl:
160 case op_setstringtbl:
199 case op_linearsearch:
200 return &list_LLLLLLLS;
201 case op_binarysearch:
202 return &list_LLLLLLLS;
203 case op_linkedsearch:
204 return &list_LLLLLLS;
237 Read the list of operands of an instruction, and put the values
238 in inst. This assumes that the PC is at the beginning of the
239 operand mode list (right after an opcode number.) Upon return,
240 the PC will be at the beginning of the next instruction.
242 void parse_operands(instruction_t *inst, operandlist_t *oplist)
245 int numops = oplist->num_ops;
246 int argsize = oplist->arg_size;
247 glui32 modeaddr = pc;
252 pc += (numops+1) / 2;
254 for (ix=0; ix<numops; ix++) {
260 modeval = Mem1(modeaddr);
261 mode = (modeval & 0x0F);
264 mode = ((modeval >> 4) & 0x0F);
268 if (oplist->formlist[ix] == modeform_Load) {
272 case 8: /* pop off stack */
273 if (stackptr < valstackbase+4) {
274 fatal_error("Stack underflow in operand.");
277 value = Stk4(stackptr);
280 case 0: /* constant zero */
284 case 1: /* one-byte constant */
285 /* Sign-extend from 8 bits to 32 */
286 value = (glsi32)(signed char)(Mem1(pc));
290 case 2: /* two-byte constant */
291 /* Sign-extend the first byte from 8 bits to 32; the subsequent
292 byte must not be sign-extended. */
293 value = (glsi32)(signed char)(Mem1(pc));
295 value = (value << 8) | (glui32)(Mem1(pc));
299 case 3: /* four-byte constant */
300 /* Bytes must not be sign-extended. */
305 case 15: /* main memory RAM, four-byte address */
311 case 14: /* main memory RAM, two-byte address */
312 addr = (glui32)Mem2(pc);
317 case 13: /* main memory RAM, one-byte address */
318 addr = (glui32)(Mem1(pc));
323 case 7: /* main memory, four-byte address */
328 case 6: /* main memory, two-byte address */
329 addr = (glui32)Mem2(pc);
333 case 5: /* main memory, one-byte address */
334 addr = (glui32)(Mem1(pc));
339 /* cases 5, 6, 7, 13, 14, 15 all wind up here. */
343 else if (argsize == 2) {
351 case 11: /* locals, four-byte address */
356 case 10: /* locals, two-byte address */
357 addr = (glui32)Mem2(pc);
361 case 9: /* locals, one-byte address */
362 addr = (glui32)(Mem1(pc));
367 /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
368 be four-byte aligned, but we don't check this explicitly.
369 A "strict mode" interpreter probably should. It's also illegal
370 for addr to be less than zero or greater than the size of
371 the locals segment. */
376 else if (argsize == 2) {
385 fatal_error("Unknown addressing mode in load operand.");
388 inst->value[ix] = value;
391 else { /* modeform_Store */
394 case 0: /* discard value */
399 case 8: /* push on stack */
404 case 15: /* main memory RAM, four-byte address */
410 case 14: /* main memory RAM, two-byte address */
411 addr = (glui32)Mem2(pc);
416 case 13: /* main memory RAM, one-byte address */
417 addr = (glui32)(Mem1(pc));
422 case 7: /* main memory, four-byte address */
427 case 6: /* main memory, two-byte address */
428 addr = (glui32)Mem2(pc);
432 case 5: /* main memory, one-byte address */
433 addr = (glui32)(Mem1(pc));
438 /* cases 5, 6, 7 all wind up here. */
440 inst->value[ix] = addr;
443 case 11: /* locals, four-byte address */
448 case 10: /* locals, two-byte address */
449 addr = (glui32)Mem2(pc);
453 case 9: /* locals, one-byte address */
454 addr = (glui32)(Mem1(pc));
459 /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
460 be four-byte aligned, but we don't check this explicitly.
461 A "strict mode" interpreter probably should. It's also illegal
462 for addr to be less than zero or greater than the size of
463 the locals segment. */
465 /* We don't add localsbase here; the store address for desttype 2
466 is relative to the current locals segment, not an absolute
468 inst->value[ix] = addr;
474 fatal_error("Constant addressing mode in store operand.");
477 fatal_error("Unknown addressing mode in store operand.");
484 Store a result value, according to the desttype and destaddress given.
485 This is usually used to store the result of an opcode, but it's also
486 used by any code that pulls a call-stub off the stack.
488 void store_operand(glui32 desttype, glui32 destaddr, glui32 storeval)
492 case 0: /* do nothing; discard the value. */
495 case 1: /* main memory. */
496 MemW4(destaddr, storeval);
499 case 2: /* locals. */
500 destaddr += localsbase;
501 StkW4(destaddr, storeval);
504 case 3: /* push on stack. */
505 if (stackptr+4 > stacksize) {
506 fatal_error("Stack overflow in store operand.");
508 StkW4(stackptr, storeval);
513 fatal_error("Unknown destination type in store operand.");
518 void store_operand_s(glui32 desttype, glui32 destaddr, glui32 storeval)
524 case 0: /* do nothing; discard the value. */
527 case 1: /* main memory. */
528 MemW2(destaddr, storeval);
531 case 2: /* locals. */
532 destaddr += localsbase;
533 StkW2(destaddr, storeval);
536 case 3: /* push on stack. A four-byte value is actually pushed. */
537 if (stackptr+4 > stacksize) {
538 fatal_error("Stack overflow in store operand.");
540 StkW4(stackptr, storeval);
545 fatal_error("Unknown destination type in store operand.");
550 void store_operand_b(glui32 desttype, glui32 destaddr, glui32 storeval)
556 case 0: /* do nothing; discard the value. */
559 case 1: /* main memory. */
560 MemW1(destaddr, storeval);
563 case 2: /* locals. */
564 destaddr += localsbase;
565 StkW1(destaddr, storeval);
568 case 3: /* push on stack. A four-byte value is actually pushed. */
569 if (stackptr+4 > stacksize) {
570 fatal_error("Stack overflow in store operand.");
572 StkW4(stackptr, storeval);
577 fatal_error("Unknown destination type in store operand.");