home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzS5_src.ZIP / PROCESS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-23  |  11.0 KB  |  606 lines

  1. /*
  2.  * process.c
  3.  *
  4.  * Interpreter loop and program control
  5.  *
  6.  */
  7.  
  8. #include "frotz.h"
  9. #include "s5api.h"
  10.  
  11.  
  12. void z_sound_effect (struct sg *g)
  13. {
  14. }
  15.  
  16. /*
  17.  * load_operand
  18.  *
  19.  * Load an operand, either a variable or a constant.
  20.  *
  21.  */
  22.  
  23. void load_operand (struct sg *g, zbyte type)
  24. {
  25.     zword value;
  26.  
  27.     if (type & 2) {             /* variable */
  28.  
  29.     zbyte variable;
  30.  
  31.     CODE_BYTE (variable)
  32.  
  33.     if (variable == 0)
  34.         value = *(g->sp)++;
  35.     else if (variable < 16)
  36.         value = *(g->fp - variable);
  37.     else {
  38.         zword addr = g->h_globals + 2 * (variable - 16);
  39.         LOW_WORD (addr, value)
  40.     }
  41.  
  42.     } else if (type & 1) {         /* small constant */
  43.  
  44.     zbyte bvalue;
  45.  
  46.     CODE_BYTE (bvalue)
  47.     value = bvalue;
  48.  
  49.     } else CODE_WORD (value)         /* large constant */
  50.  
  51.     g->zargs[g->zargc++] = value;
  52. }/* load_operand */
  53.  
  54. /*
  55.  * load_all_operands
  56.  *
  57.  * Given the operand specifier byte, load all (up to four) operands
  58.  * for a VAR or EXT opcode.
  59.  *
  60.  */
  61.  
  62. void load_all_operands (struct sg *g,zbyte specifier)
  63. {
  64.     short i;
  65.  
  66.     for (i = 6; i >= 0; i -= 2) {
  67.  
  68.     zbyte type = (specifier >> i) & 0x03;
  69.  
  70.     if (type == 3)
  71.         break;
  72.  
  73.     load_operand (g,type);
  74.  
  75.     }
  76.  
  77. }/* load_all_operands */
  78.  
  79. /*
  80.  * interpret
  81.  *
  82.  * Z-code interpreter main loop
  83.  *
  84.  */
  85.  
  86. void interpret (struct sg *g)
  87. {
  88.  
  89.     do {
  90.  
  91.     zbyte opcode;
  92.  
  93.     CODE_BYTE (opcode)
  94.  
  95.     g->zargc = 0;
  96.  
  97.     if (opcode < 0x80) {            /* 2OP opcodes */
  98.  
  99.         load_operand (g,(zbyte) (opcode & 0x40) ? 2 : 1);
  100.         load_operand (g,(zbyte) (opcode & 0x20) ? 2 : 1);
  101.  
  102.         g->var_opcodes[opcode & 0x1f] (g);
  103.  
  104.     } else if (opcode < 0xb0) {        /* 1OP opcodes */
  105.  
  106.         load_operand (g,(zbyte) (opcode >> 4));
  107.  
  108.         g->op1_opcodes[opcode & 0x0f] (g);
  109.  
  110.     } else if (opcode < 0xc0) {        /* 0OP opcodes */
  111.  
  112.         g->op0_opcodes[opcode - 0xb0] (g);
  113.  
  114.     } else {                /* VAR opcodes */
  115.  
  116.         zbyte specifier1;
  117.         zbyte specifier2;
  118.  
  119.         if (opcode == 0xec || opcode == 0xfa) {    /* opcodes 0xec */
  120.         CODE_BYTE (specifier1)                  /* and 0xfa are */
  121.         CODE_BYTE (specifier2)                  /* call opcodes */
  122.         load_all_operands (g,specifier1);        /* with up to 8 */
  123.         load_all_operands (g,specifier2);         /* arguments    */
  124.         } else {
  125.         CODE_BYTE (specifier1)
  126.         load_all_operands (g,specifier1);
  127.         }
  128.  
  129.         g->var_opcodes[opcode - 0xc0] (g);
  130.  
  131.     }
  132.  
  133.     } while (g->finished == 0);
  134.  
  135.     g->finished--;
  136.  
  137. }/* interpret */
  138.  
  139. /*
  140.  * call
  141.  *
  142.  * Call a subroutine. Save PC and FP then load new PC and initialise
  143.  * new stack frame. Note that the caller may legally provide less or
  144.  * more arguments than the function actually has. The call type "ct"
  145.  * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
  146.  *
  147.  */
  148.  
  149. void call (struct sg *g,zword routine, short argc, zword *args, short ct)
  150. {
  151.     long pc;
  152.     zword value;
  153.     zbyte count;
  154.     short i;
  155.  
  156.     if (g->sp - g->stack < 4)
  157.     runtime_error (g,"Stack overflow");
  158.  
  159.     GET_PC (pc)
  160.  
  161.     *--(g->sp) = (zword) (pc >> 9);        /* for historical reasons */
  162.     *--(g->sp) = (zword) (pc & 0x1ff);    /* Frotz keeps its stack  */
  163.     *--(g->sp) = (zword) (g->fp - g->stack - 1);    /* format compatible with */
  164.     *--(g->sp) = (zword) (argc | (ct << 8));    /* Mark Howell's Zip      */
  165.  
  166.     g->fp = g->sp;
  167.  
  168.     /* Calculate byte address of routine */
  169.  
  170.     if (g->h_version <= V3)
  171.     pc = (long) routine << 1;
  172.     else if (g->h_version <= V5)
  173.     pc = (long) routine << 2;
  174.     else if (g->h_version <= V7)
  175.     pc = ((long) routine << 2) + ((long) g->h_functions_offset << 3);
  176.     else /* h_version == V8 */
  177.     pc = (long) routine << 3;
  178.  
  179.     if (pc >= g->story_size)
  180.     runtime_error (g,"Call to illegal address");
  181.  
  182.     SET_PC (pc)
  183.  
  184.     /* Initialise local variables */
  185.  
  186.     CODE_BYTE (count)
  187.  
  188.     if (count > 15)
  189.     runtime_error (g,"Call to non-routine");
  190.     if (g->sp - g->stack < count)
  191.     runtime_error (g,"Stack overflow");
  192.  
  193.     value = 0;
  194.  
  195.     for (i = 0; i < count; i++) {
  196.  
  197.     if (g->h_version <= V4)        /* V1 to V4 games provide default */
  198.         CODE_WORD (value)        /* values for all local variables */
  199.  
  200.     *--(g->sp) = (zword) ((argc-- > 0) ? args[i] : value);
  201.  
  202.     }
  203.  
  204.     /* Start main loop for direct calls */
  205.  
  206.     if (ct == 2)
  207.     interpret (g);
  208.  
  209. }/* call */
  210.  
  211. /*
  212.  * ret
  213.  *
  214.  * Return from the current subroutine and restore the previous stack
  215.  * frame. The result may be stored (0), thrown away (1) or pushed on
  216.  * the stack (2). In the latter case a direct call has been finished
  217.  * and we must exit the interpreter loop.
  218.  *
  219.  */
  220.  
  221. void ret (struct sg *g,zword value)
  222. {
  223.     long pc;
  224.     short ct;
  225.  
  226.     if (g->sp > g->fp)
  227.     runtime_error (g,"Stack underflow");
  228.  
  229.     g->sp = g->fp;
  230.  
  231.     ct = *(g->sp)++ >> 8;
  232.     g->fp = g->stack + 1 + *(g->sp)++;
  233.     pc = *(g->sp)++;
  234.     pc = ((long) *(g->sp)++ << 9) | pc;
  235.  
  236.     SET_PC (pc)
  237.  
  238.     /* Handle resulting value */
  239.  
  240.     if (ct == 0)
  241.     store (g,value);
  242.     if (ct == 2)
  243.     *--(g->sp) = value;
  244.  
  245.     /* Stop main loop for direct calls */
  246.  
  247.     if (ct == 2)
  248.     g->finished++;
  249.  
  250. }/* ret */
  251.  
  252. /*
  253.  * branch
  254.  *
  255.  * Take a jump after an instruction based on the flag, either true or
  256.  * false. The branch can be short or long; it is encoded in one or two
  257.  * bytes respectively. When bit 7 of the first byte is set, the jump
  258.  * takes place if the flag is true; otherwise it is taken if the flag
  259.  * is false. When bit 6 of the first byte is set, the branch is short;
  260.  * otherwise it is long. The offset occupies the bottom 6 bits of the
  261.  * first byte plus all the bits in the second byte for long branches.
  262.  * Uniquely, an offset of 0 means return false, and an offset of 1 is
  263.  * return true.
  264.  *
  265.  */
  266.  
  267. void branch (struct sg *g,short flag)
  268. {
  269.     long pc;
  270.     zword offset;
  271.     zbyte specifier;
  272.     zbyte off1;
  273.     zbyte off2;
  274.  
  275.     CODE_BYTE (specifier)
  276.  
  277.     off1 = specifier & 0x3f;
  278.  
  279.     if (!flag)
  280.     specifier ^= 0x80;
  281.  
  282.     if (!(specifier & 0x40)) {        /* it's a long branch */
  283.  
  284.     if (off1 & 0x20)        /* propagate sign bit */
  285.         off1 |= 0xc0;
  286.  
  287.     CODE_BYTE (off2)
  288.  
  289.     offset = (off1 << 8) | off2;
  290.  
  291.     } else offset = off1;        /* it's a short branch */
  292.  
  293.     if (specifier & 0x80)
  294.  
  295.     if (offset > 1) {        /* normal branch */
  296.  
  297.         GET_PC (pc)
  298.         pc += (short) offset - 2;
  299.         SET_PC (pc)
  300.  
  301.     } else ret (g,offset);        /* special case, return 0 or 1 */
  302.  
  303. }/* branch */
  304.  
  305. /*
  306.  * store
  307.  *
  308.  * Store an operand, either as a variable or pushed on the stack.
  309.  *
  310.  */
  311.  
  312. void store (struct sg *g,zword value)
  313. {
  314.     zbyte variable;
  315.  
  316.     CODE_BYTE (variable)
  317.     if (variable == 0)
  318.     *--(g->sp) = value;
  319.     else if (variable < 16)
  320.     *(g->fp - variable) = value;
  321.     else {
  322.     zword addr = g->h_globals + 2 * (variable - 16);
  323.     SET_WORD (addr, value)
  324.     }
  325.  
  326. }/* store */
  327.  
  328. /*
  329.  * direct_call
  330.  *
  331.  * Call the interpreter loop directly. This is necessary when
  332.  *
  333.  * - a sound effect has been finished
  334.  * - a read instruction has timed out
  335.  * - a newline countdown has hit zero
  336.  *
  337.  * The interpreter returns the result value on the stack.
  338.  *
  339.  */
  340.  
  341. short direct_call (struct sg *g,zword addr)
  342. {
  343.     zword saved_zargs[8];
  344.     short saved_zargc;
  345.     short i;
  346.  
  347.     /* Calls to address 0 return false */
  348.  
  349.     if (addr == 0)
  350.     return 0;
  351.  
  352.     /* Save operands and operand count */
  353.  
  354.     for (i = 0; i < 8; i++)
  355.     saved_zargs[i] = g->zargs[i];
  356.  
  357.     saved_zargc = g->zargc;
  358.  
  359.     /* Call routine directly */
  360.  
  361.     call (g,addr, 0, 0, 2);
  362.  
  363.     /* Restore operands and operand count */
  364.  
  365.     for (i = 0; i < 8; i++)
  366.     g->zargs[i] = saved_zargs[i];
  367.  
  368.     g->zargc = saved_zargc;
  369.  
  370.     /* Resulting value lies on top of the stack */
  371.  
  372.     return (short) *(g->sp)++;
  373.  
  374. }/* direct_call */
  375.  
  376. /*
  377.  * __extended__
  378.  *
  379.  * Load and execute an extended opcode.
  380.  *
  381.  */
  382.  
  383. void __extended__ (struct sg *g)
  384. {
  385.     zbyte opcode;
  386.     zbyte specifier;
  387.  
  388.     CODE_BYTE (opcode)
  389.     CODE_BYTE (specifier)
  390.  
  391.     load_all_operands (g,specifier);
  392.  
  393.     if (opcode < 0x1d)            /* extended opcodes from 0x1d on */
  394.     g->ext_opcodes[opcode] (g);        /* are reserved for future spec' */
  395.  
  396. }/* __extended__ */
  397.  
  398. /*
  399.  * __illegal__
  400.  *
  401.  * Exit game because an unknown opcode has been hit.
  402.  *
  403.  */
  404.  
  405. void __illegal__ (struct sg *g)
  406. {
  407.  
  408.     runtime_error (g,"Illegal opcode");
  409.  
  410. }/* __illegal__ */
  411.  
  412. /*
  413.  * z_catch, store the current stack frame for later use with z_throw.
  414.  *
  415.  *    no zargs used
  416.  *
  417.  */
  418.  
  419. void z_catch (struct sg *g)
  420. {
  421.  
  422.     store (g,(zword) (g->fp - g->stack));
  423.  
  424. }/* z_catch */
  425.  
  426. /*
  427.  * z_throw, go back to the given stack frame and return the given value.
  428.  *
  429.  *    zargs[0] = value to return
  430.  *    zargs[1] = stack frame
  431.  *
  432.  */
  433.  
  434. void z_throw (struct sg *g)
  435. {
  436.  
  437.     if (g->zargs[1] > STACK_SIZE)
  438.     runtime_error (g,"Bad stack frame");
  439.  
  440.     g->fp = g->stack + g->zargs[1];
  441.  
  442.     ret (g,g->zargs[0]);
  443.  
  444. }/* z_throw */
  445.  
  446. /*
  447.  * z_call_n, call a subroutine and discard its result.
  448.  *
  449.  *     zargs[0] = packed address of subroutine
  450.  *    zargs[1] = first argument (optional)
  451.  *    ...
  452.  *    zargs[7] = seventh argument (optional)
  453.  *
  454.  */
  455.  
  456. void z_call_n (struct sg *g)
  457. {
  458.  
  459.     if (g->zargs[0] != 0)
  460.     call (g,g->zargs[0], g->zargc - 1, g->zargs + 1, 1);
  461.  
  462. }/* z_call_n */
  463.  
  464. /*
  465.  * z_call_s, call a subroutine and store its result.
  466.  *
  467.  *     zargs[0] = packed address of subroutine
  468.  *    zargs[1] = first argument (optional)
  469.  *    ...
  470.  *    zargs[7] = seventh argument (optional)
  471.  *
  472.  */
  473.  
  474. void z_call_s (struct sg *g)
  475. {
  476.  
  477.     if (g->zargs[0] != 0)
  478.     call (g,g->zargs[0], g->zargc - 1, g->zargs + 1, 0);
  479.     else
  480.     store (g,0);
  481.  
  482. }/* z_call_s */
  483.  
  484. /*
  485.  * z_check_arg_count, branch if subroutine was called with >= n arg's.
  486.  *
  487.  *     zargs[0] = number of arguments
  488.  *
  489.  */
  490.  
  491. void z_check_arg_count (struct sg *g)
  492. {
  493.  
  494.     if (g->fp == g->stack + STACK_SIZE)
  495.     branch (g,g->zargs[0] == 0);
  496.     else
  497.     branch (g,g->zargs[0] <= (*(g->fp) & 0xff));
  498.  
  499. }/* z_check_arg_count */
  500.  
  501. /*
  502.  * z_jump, jump unconditionally to the given address.
  503.  *
  504.  *    zargs[0] = PC relative address
  505.  *
  506.  */
  507.  
  508. void z_jump (struct sg *g)
  509. {
  510.     long pc;
  511.  
  512.     GET_PC (pc)
  513.  
  514.     pc += (short)(g->zargs[0]) - 2;
  515.  
  516.     if (pc >= g->story_size)
  517.     runtime_error (g,"Jump to illegal address");
  518.  
  519.     SET_PC (pc)
  520.  
  521. }/* z_jump */
  522.  
  523. /*
  524.  * z_nop, no operation.
  525.  *
  526.  *    no zargs used
  527.  *
  528.  */
  529.  
  530. void z_nop (struct sg *g)
  531. {
  532.  
  533.     /* Do nothing */
  534.  
  535. }/* z_nop */
  536.  
  537. /*
  538.  * z_quit, stop game and exit interpreter.
  539.  *
  540.  *    no zargs used
  541.  *
  542.  */
  543.  
  544. void z_quit (struct sg *g)
  545. {
  546.  
  547.     g->finished = 9999;
  548.  
  549. }/* z_quit */
  550.  
  551. /*
  552.  * z_ret, return from a subroutine with the given value.
  553.  *
  554.  *    zargs[0] = value to return
  555.  *
  556.  */
  557.  
  558. void z_ret (struct sg *g)
  559. {
  560.  
  561.     ret (g,g->zargs[0]);
  562.  
  563. }/* z_ret */
  564.  
  565. /*
  566.  * z_ret_popped, return from a subroutine with a value popped off the stack.
  567.  *
  568.  *    no zargs used
  569.  *
  570.  */
  571.  
  572. void z_ret_popped (struct sg *g)
  573. {
  574.  
  575.     ret (g,*(g->sp)++);
  576.  
  577. }/* z_ret_popped */
  578.  
  579. /*
  580.  * z_rfalse, return from a subroutine with false (0).
  581.  *
  582.  *     no zargs used
  583.  *
  584.  */
  585.  
  586. void z_rfalse (struct sg *g)
  587. {
  588.  
  589.     ret (g,0);
  590.  
  591. }/* z_rfalse */
  592.  
  593. /*
  594.  * z_rtrue, return from a subroutine with true (1).
  595.  *
  596.  *     no zargs used
  597.  *
  598.  */
  599.  
  600. void z_rtrue (struct sg *g)
  601. {
  602.  
  603.     ret (g,1);
  604.  
  605. }/* z_rtrue */
  606.