58c86078b0c10547c6180833451ce6babf17833b
[projects/chimara/chimara.git] / interpreters / frotz / process.c
1 /* process.c - Interpreter loop and program control
2  *      Copyright (c) 1995-1997 Stefan Jokisch
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include "frotz.h"
22
23 #ifdef DJGPP
24 #include "djfrotz.h"
25 #endif
26
27
28 zword zargs[8];
29 int zargc;
30
31 static int finished = 0;
32
33 static void __extended__ (void);
34 static void __illegal__ (void);
35
36 void (*op0_opcodes[0x10]) (void) = {
37     z_rtrue,
38     z_rfalse,
39     z_print,
40     z_print_ret,
41     z_nop,
42     z_save,
43     z_restore,
44     z_restart,
45     z_ret_popped,
46     z_catch,
47     z_quit,
48     z_new_line,
49     z_show_status,
50     z_verify,
51     __extended__,
52     z_piracy
53 };
54
55 void (*op1_opcodes[0x10]) (void) = {
56     z_jz,
57     z_get_sibling,
58     z_get_child,
59     z_get_parent,
60     z_get_prop_len,
61     z_inc,
62     z_dec,
63     z_print_addr,
64     z_call_s,
65     z_remove_obj,
66     z_print_obj,
67     z_ret,
68     z_jump,
69     z_print_paddr,
70     z_load,
71     z_call_n
72 };
73
74 void (*var_opcodes[0x40]) (void) = {
75     __illegal__,
76     z_je,
77     z_jl,
78     z_jg,
79     z_dec_chk,
80     z_inc_chk,
81     z_jin,
82     z_test,
83     z_or,
84     z_and,
85     z_test_attr,
86     z_set_attr,
87     z_clear_attr,
88     z_store,
89     z_insert_obj,
90     z_loadw,
91     z_loadb,
92     z_get_prop,
93     z_get_prop_addr,
94     z_get_next_prop,
95     z_add,
96     z_sub,
97     z_mul,
98     z_div,
99     z_mod,
100     z_call_s,
101     z_call_n,
102     z_set_colour,
103     z_throw,
104     __illegal__,
105     __illegal__,
106     __illegal__,
107     z_call_s,
108     z_storew,
109     z_storeb,
110     z_put_prop,
111     z_read,
112     z_print_char,
113     z_print_num,
114     z_random,
115     z_push,
116     z_pull,
117     z_split_window,
118     z_set_window,
119     z_call_s,
120     z_erase_window,
121     z_erase_line,
122     z_set_cursor,
123     z_get_cursor,
124     z_set_text_style,
125     z_buffer_mode,
126     z_output_stream,
127     z_input_stream,
128     z_sound_effect,
129     z_read_char,
130     z_scan_table,
131     z_not,
132     z_call_n,
133     z_call_n,
134     z_tokenise,
135     z_encode_text,
136     z_copy_table,
137     z_print_table,
138     z_check_arg_count
139 };
140
141 void (*ext_opcodes[0x1e]) (void) = {
142     z_save,
143     z_restore,
144     z_log_shift,
145     z_art_shift,
146     z_set_font,
147     __illegal__, // glkify - z_draw_picture,
148     __illegal__, // glkify - z_picture_data,
149     __illegal__, // glkify - z_erase_picture,
150     __illegal__, // glkify - z_set_margins,
151     z_save_undo,
152     z_restore_undo,
153     z_print_unicode,
154     z_check_unicode,
155     z_set_true_colour, /* spec 1.1 */
156     __illegal__,
157     __illegal__,
158     __illegal__, // glkify - z_move_window,
159     __illegal__, // glkify - z_window_size,
160     __illegal__, // glkify - z_window_style,
161     __illegal__, // glkify - z_get_wind_prop,
162     __illegal__, // glkify - z_scroll_window,
163     z_pop_stack,
164     __illegal__, // glkify - z_read_mouse,
165     __illegal__, // glkify - z_mouse_window,
166     z_push_stack,
167     __illegal__, // glkify - z_put_wind_prop,
168     z_print_form,
169     z_make_menu,
170     __illegal__, // glkify - z_picture_table
171     z_buffer_screen, /* spec 1.1 */
172 };
173
174
175 /*
176  * init_proc
177  *
178  * Initialize process variables.
179  *
180  */
181
182 void init_proc (void)
183 {
184     finished = 0;
185 } /* init_proc */
186
187
188 /*
189  * load_operand
190  *
191  * Load an operand, either a variable or a constant.
192  *
193  */
194
195 static void load_operand (zbyte type)
196 {
197     zword value;
198
199     if (type & 2) {                     /* variable */
200
201         zbyte variable;
202
203         CODE_BYTE (variable)
204
205         if (variable == 0)
206             value = *sp++;
207         else if (variable < 16)
208             value = *(fp - variable);
209         else {
210             zword addr = h_globals + 2 * (variable - 16);
211             LOW_WORD (addr, value)
212         }
213
214     } else if (type & 1) {              /* small constant */
215
216         zbyte bvalue;
217
218         CODE_BYTE (bvalue)
219         value = bvalue;
220
221     } else CODE_WORD (value)            /* large constant */
222
223     zargs[zargc++] = value;
224
225 }/* load_operand */
226
227 /*
228  * load_all_operands
229  *
230  * Given the operand specifier byte, load all (up to four) operands
231  * for a VAR or EXT opcode.
232  *
233  */
234
235 static void load_all_operands (zbyte specifier)
236 {
237     int i;
238
239     for (i = 6; i >= 0; i -= 2) {
240
241         zbyte type = (specifier >> i) & 0x03;
242
243         if (type == 3)
244             break;
245
246         load_operand (type);
247
248     }
249
250 }/* load_all_operands */
251
252 /*
253  * interpret
254  *
255  * Z-code interpreter main loop
256  *
257  */
258
259 void interpret (void)
260 {
261     do {
262
263         zbyte opcode;
264
265         CODE_BYTE (opcode)
266
267         zargc = 0;
268
269         if (opcode < 0x80) {                    /* 2OP opcodes */
270
271             load_operand ((zbyte) (opcode & 0x40) ? 2 : 1);
272             load_operand ((zbyte) (opcode & 0x20) ? 2 : 1);
273
274             var_opcodes[opcode & 0x1f] ();
275
276         } else if (opcode < 0xb0) {             /* 1OP opcodes */
277
278             load_operand ((zbyte) (opcode >> 4));
279
280             op1_opcodes[opcode & 0x0f] ();
281
282         } else if (opcode < 0xc0) {             /* 0OP opcodes */
283
284             op0_opcodes[opcode - 0xb0] ();
285
286         } else {                                /* VAR opcodes */
287
288             zbyte specifier1;
289             zbyte specifier2;
290
291             if (opcode == 0xec || opcode == 0xfa) {     /* opcodes 0xec */
292                 CODE_BYTE (specifier1)                  /* and 0xfa are */
293                 CODE_BYTE (specifier2)                  /* call opcodes */
294                 load_all_operands (specifier1);         /* with up to 8 */
295                 load_all_operands (specifier2);         /* arguments    */
296             } else {
297                 CODE_BYTE (specifier1)
298                 load_all_operands (specifier1);
299             }
300
301             var_opcodes[opcode - 0xc0] ();
302
303         }
304
305 #if defined(DJGPP) && defined(SOUND_SUPPORT)
306     if (end_of_sound_flag)
307         end_of_sound ();
308 #endif
309
310     } while (finished == 0);
311
312     finished--;
313
314 }/* interpret */
315
316 /*
317  * call
318  *
319  * Call a subroutine. Save PC and FP then load new PC and initialise
320  * new stack frame. Note that the caller may legally provide less or
321  * more arguments than the function actually has. The call type "ct"
322  * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
323  *
324  */
325
326 void call (zword routine, int argc, zword *args, int ct)
327 {
328     long pc;
329     zword value;
330     zbyte count;
331     int i;
332
333     if (sp - stack < 4)
334         runtime_error (ERR_STK_OVF);
335
336     GET_PC (pc)
337
338     *--sp = (zword) (pc >> 9);
339     *--sp = (zword) (pc & 0x1ff);
340     *--sp = (zword) (fp - stack - 1);
341     *--sp = (zword) (argc | (ct << (option_save_quetzal ? 12 : 8)));
342
343     fp = sp;
344     frame_count++;
345
346     /* Calculate byte address of routine */
347
348     if (h_version <= V3)
349         pc = (long) routine << 1;
350     else if (h_version <= V5)
351         pc = (long) routine << 2;
352     else if (h_version <= V7)
353         pc = ((long) routine << 2) + ((long) h_functions_offset << 3);
354     else if (h_version <= V8)
355         pc = (long) routine << 3;
356     else /* h_version == V9 */ {
357         long indirect = (long) routine << 2;
358         HIGH_LONG(indirect, pc);
359      }
360
361     if (pc >= story_size)
362         runtime_error (ERR_ILL_CALL_ADDR);
363
364     SET_PC (pc)
365
366     /* Initialise local variables */
367
368     CODE_BYTE (count)
369
370     if (count > 15)
371         runtime_error (ERR_CALL_NON_RTN);
372     if (sp - stack < count)
373         runtime_error (ERR_STK_OVF);
374
375     if (option_save_quetzal)
376         fp[0] |= (zword) count << 8;    /* Save local var count for Quetzal. */
377
378     value = 0;
379
380     for (i = 0; i < count; i++) {
381
382         if (h_version <= V4)            /* V1 to V4 games provide default */
383             CODE_WORD (value)           /* values for all local variables */
384
385         *--sp = (zword) ((argc-- > 0) ? args[i] : value);
386
387     }
388
389     /* Start main loop for direct calls */
390
391     if (ct == 2)
392         interpret ();
393
394 }/* call */
395
396 /*
397  * ret
398  *
399  * Return from the current subroutine and restore the previous stack
400  * frame. The result may be stored (0), thrown away (1) or pushed on
401  * the stack (2). In the latter case a direct call has been finished
402  * and we must exit the interpreter loop.
403  *
404  */
405
406 void ret (zword value)
407 {
408     long pc;
409     int ct;
410
411     if (sp > fp)
412         runtime_error (ERR_STK_UNDF);
413
414     sp = fp;
415
416     ct = *sp++ >> (option_save_quetzal ? 12 : 8);
417     frame_count--;
418     fp = stack + 1 + *sp++;
419     pc = *sp++;
420     pc = ((long) *sp++ << 9) | pc;
421
422     SET_PC (pc)
423
424     /* Handle resulting value */
425
426     if (ct == 0)
427         store (value);
428     if (ct == 2)
429         *--sp = value;
430
431     /* Stop main loop for direct calls */
432
433     if (ct == 2)
434         finished++;
435
436 }/* ret */
437
438 /*
439  * branch
440  *
441  * Take a jump after an instruction based on the flag, either true or
442  * false. The branch can be short or long; it is encoded in one or two
443  * bytes respectively. When bit 7 of the first byte is set, the jump
444  * takes place if the flag is true; otherwise it is taken if the flag
445  * is false. When bit 6 of the first byte is set, the branch is short;
446  * otherwise it is long. The offset occupies the bottom 6 bits of the
447  * first byte plus all the bits in the second byte for long branches.
448  * Uniquely, an offset of 0 means return false, and an offset of 1 is
449  * return true.
450  *
451  */
452
453 void branch (bool flag)
454 {
455     long pc;
456     zword offset;
457     zbyte specifier;
458     zbyte off1;
459     zbyte off2;
460
461     CODE_BYTE (specifier)
462
463     off1 = specifier & 0x3f;
464
465     if (!flag)
466         specifier ^= 0x80;
467
468     if (!(specifier & 0x40)) {          /* it's a long branch */
469
470         if (off1 & 0x20)                /* propagate sign bit */
471             off1 |= 0xc0;
472
473         CODE_BYTE (off2)
474
475         offset = (off1 << 8) | off2;
476
477     } else offset = off1;               /* it's a short branch */
478
479     if (specifier & 0x80) {
480
481         if (offset > 1) {               /* normal branch */
482
483             GET_PC (pc)
484             pc += (short) offset - 2;
485             SET_PC (pc)
486
487         } else ret (offset);            /* special case, return 0 or 1 */
488     }
489
490 }/* branch */
491
492 /*
493  * store
494  *
495  * Store an operand, either as a variable or pushed on the stack.
496  *
497  */
498
499 void store (zword value)
500 {
501     zbyte variable;
502
503     CODE_BYTE (variable)
504
505     if (variable == 0)
506         *--sp = value;
507     else if (variable < 16)
508         *(fp - variable) = value;
509     else {
510         zword addr = h_globals + 2 * (variable - 16);
511         SET_WORD (addr, value)
512     }
513
514 }/* store */
515
516 /*
517  * direct_call
518  *
519  * Call the interpreter loop directly. This is necessary when
520  *
521  * - a sound effect has been finished
522  * - a read instruction has timed out
523  * - a newline countdown has hit zero
524  *
525  * The interpreter returns the result value on the stack.
526  *
527  */
528
529 int direct_call (zword addr)
530 {
531     zword saved_zargs[8];
532     int saved_zargc;
533     int i;
534
535     /* Calls to address 0 return false */
536
537     if (addr == 0)
538         return 0;
539
540     /* Save operands and operand count */
541
542     for (i = 0; i < 8; i++)
543         saved_zargs[i] = zargs[i];
544
545     saved_zargc = zargc;
546
547     /* Call routine directly */
548
549     call (addr, 0, 0, 2);
550
551     /* Restore operands and operand count */
552
553     for (i = 0; i < 8; i++)
554         zargs[i] = saved_zargs[i];
555
556     zargc = saved_zargc;
557
558     /* Resulting value lies on top of the stack */
559
560     return (short) *sp++;
561
562 }/* direct_call */
563
564 /*
565  * __extended__
566  *
567  * Load and execute an extended opcode.
568  *
569  */
570
571 static void __extended__ (void)
572 {
573     zbyte opcode;
574     zbyte specifier;
575
576     CODE_BYTE (opcode)
577     CODE_BYTE (specifier)
578
579     load_all_operands (specifier);
580
581     if (opcode < 0x1e)                  /* extended opcodes from 0x1e on */
582         ext_opcodes[opcode] ();         /* are reserved for future spec' */
583
584 }/* __extended__ */
585
586 /*
587  * __illegal__
588  *
589  * Exit game because an unknown opcode has been hit.
590  *
591  */
592
593 static void __illegal__ (void)
594 {
595
596     runtime_error (ERR_ILL_OPCODE);
597
598 }/* __illegal__ */
599
600 /*
601  * z_catch, store the current stack frame for later use with z_throw.
602  *
603  *      no zargs used
604  *
605  */
606
607 void z_catch (void)
608 {
609
610     store (option_save_quetzal ? frame_count : (zword) (fp - stack));
611
612 }/* z_catch */
613
614 /*
615  * z_throw, go back to the given stack frame and return the given value.
616  *
617  *      zargs[0] = value to return
618  *      zargs[1] = stack frame
619  *
620  */
621
622 void z_throw (void)
623 {
624
625     if (option_save_quetzal) {
626         if (zargs[1] > frame_count)
627             runtime_error (ERR_BAD_FRAME);
628
629         /* Unwind the stack a frame at a time. */
630         for (; frame_count > zargs[1]; --frame_count)
631             fp = stack + 1 + fp[1];
632     } else {
633         if (zargs[1] > STACK_SIZE)
634             runtime_error (ERR_BAD_FRAME);
635
636         fp = stack + zargs[1];
637     }
638
639     ret (zargs[0]);
640
641 }/* z_throw */
642
643 /*
644  * z_call_n, call a subroutine and discard its result.
645  *
646  *      zargs[0] = packed address of subroutine
647  *      zargs[1] = first argument (optional)
648  *      ...
649  *      zargs[7] = seventh argument (optional)
650  *
651  */
652
653 void z_call_n (void)
654 {
655
656     if (zargs[0] != 0)
657         call (zargs[0], zargc - 1, zargs + 1, 1);
658
659 }/* z_call_n */
660
661 /*
662  * z_call_s, call a subroutine and store its result.
663  *
664  *      zargs[0] = packed address of subroutine
665  *      zargs[1] = first argument (optional)
666  *      ...
667  *      zargs[7] = seventh argument (optional)
668  *
669  */
670
671 void z_call_s (void)
672 {
673
674     if (zargs[0] != 0)
675         call (zargs[0], zargc - 1, zargs + 1, 0);
676     else
677         store (0);
678
679 }/* z_call_s */
680
681 /*
682  * z_check_arg_count, branch if subroutine was called with >= n arg's.
683  *
684  *      zargs[0] = number of arguments
685  *
686  */
687
688 void z_check_arg_count (void)
689 {
690
691     if (fp == stack + STACK_SIZE)
692         branch (zargs[0] == 0);
693     else
694         branch (zargs[0] <= (*fp & 0xff));
695
696 }/* z_check_arg_count */
697
698 /*
699  * z_jump, jump unconditionally to the given address.
700  *
701  *      zargs[0] = PC relative address
702  *
703  */
704
705 void z_jump (void)
706 {
707     long pc;
708
709     GET_PC (pc)
710
711     pc += (short) zargs[0] - 2;
712
713     if (pc >= story_size)
714         runtime_error (ERR_ILL_JUMP_ADDR);
715
716     SET_PC (pc)
717
718 }/* z_jump */
719
720 /*
721  * z_nop, no operation.
722  *
723  *      no zargs used
724  *
725  */
726
727 void z_nop (void)
728 {
729
730     /* Do nothing */
731
732 }/* z_nop */
733
734 /*
735  * z_quit, stop game and exit interpreter.
736  *
737  *      no zargs used
738  *
739  */
740
741 void z_quit (void)
742 {
743
744     finished = 9999;
745
746 }/* z_quit */
747
748 /*
749  * z_ret, return from a subroutine with the given value.
750  *
751  *      zargs[0] = value to return
752  *
753  */
754
755 void z_ret (void)
756 {
757
758     ret (zargs[0]);
759
760 }/* z_ret */
761
762 /*
763  * z_ret_popped, return from a subroutine with a value popped off the stack.
764  *
765  *      no zargs used
766  *
767  */
768
769 void z_ret_popped (void)
770 {
771
772     ret (*sp++);
773
774 }/* z_ret_popped */
775
776 /*
777  * z_rfalse, return from a subroutine with false (0).
778  *
779  *      no zargs used
780  *
781  */
782
783 void z_rfalse (void)
784 {
785
786     ret (0);
787
788 }/* z_rfalse */
789
790 /*
791  * z_rtrue, return from a subroutine with true (1).
792  *
793  *      no zargs used
794  *
795  */
796
797 void z_rtrue (void)
798 {
799
800     ret (1);
801
802 }/* z_rtrue */