Implemented garglk_set_program_name(), garglk_set_program_info(), garglk_set_story_name()
[rodin/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[0x1d]) (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     __illegal__,
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 };
172
173
174 /*
175  * init_process
176  *
177  * Initialize process variables.
178  *
179  */
180
181 void init_process (void)
182 {
183     finished = 0;
184 } /* init_process */
185
186
187 /*
188  * load_operand
189  *
190  * Load an operand, either a variable or a constant.
191  *
192  */
193
194 static void load_operand (zbyte type)
195 {
196     zword value;
197
198     if (type & 2) {                     /* variable */
199
200         zbyte variable;
201
202         CODE_BYTE (variable)
203
204         if (variable == 0)
205             value = *sp++;
206         else if (variable < 16)
207             value = *(fp - variable);
208         else {
209             zword addr = h_globals + 2 * (variable - 16);
210             LOW_WORD (addr, value)
211         }
212
213     } else if (type & 1) {              /* small constant */
214
215         zbyte bvalue;
216
217         CODE_BYTE (bvalue)
218         value = bvalue;
219
220     } else CODE_WORD (value)            /* large constant */
221
222     zargs[zargc++] = value;
223
224 }/* load_operand */
225
226 /*
227  * load_all_operands
228  *
229  * Given the operand specifier byte, load all (up to four) operands
230  * for a VAR or EXT opcode.
231  *
232  */
233
234 static void load_all_operands (zbyte specifier)
235 {
236     int i;
237
238     for (i = 6; i >= 0; i -= 2) {
239
240         zbyte type = (specifier >> i) & 0x03;
241
242         if (type == 3)
243             break;
244
245         load_operand (type);
246
247     }
248
249 }/* load_all_operands */
250
251 /*
252  * interpret
253  *
254  * Z-code interpreter main loop
255  *
256  */
257
258 void interpret (void)
259 {
260     do {
261
262         zbyte opcode;
263
264         CODE_BYTE (opcode)
265
266         zargc = 0;
267
268         if (opcode < 0x80) {                    /* 2OP opcodes */
269
270             load_operand ((zbyte) (opcode & 0x40) ? 2 : 1);
271             load_operand ((zbyte) (opcode & 0x20) ? 2 : 1);
272
273             var_opcodes[opcode & 0x1f] ();
274
275         } else if (opcode < 0xb0) {             /* 1OP opcodes */
276
277             load_operand ((zbyte) (opcode >> 4));
278
279             op1_opcodes[opcode & 0x0f] ();
280
281         } else if (opcode < 0xc0) {             /* 0OP opcodes */
282
283             op0_opcodes[opcode - 0xb0] ();
284
285         } else {                                /* VAR opcodes */
286
287             zbyte specifier1;
288             zbyte specifier2;
289
290             if (opcode == 0xec || opcode == 0xfa) {     /* opcodes 0xec */
291                 CODE_BYTE (specifier1)                  /* and 0xfa are */
292                 CODE_BYTE (specifier2)                  /* call opcodes */
293                 load_all_operands (specifier1);         /* with up to 8 */
294                 load_all_operands (specifier2);         /* arguments    */
295             } else {
296                 CODE_BYTE (specifier1)
297                 load_all_operands (specifier1);
298             }
299
300             var_opcodes[opcode - 0xc0] ();
301
302         }
303
304 #if defined(DJGPP) && defined(SOUND_SUPPORT)
305     if (end_of_sound_flag)
306         end_of_sound ();
307 #endif
308
309     } while (finished == 0);
310
311     finished--;
312
313 }/* interpret */
314
315 /*
316  * call
317  *
318  * Call a subroutine. Save PC and FP then load new PC and initialise
319  * new stack frame. Note that the caller may legally provide less or
320  * more arguments than the function actually has. The call type "ct"
321  * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
322  *
323  */
324
325 void call (zword routine, int argc, zword *args, int ct)
326 {
327     long pc;
328     zword value;
329     zbyte count;
330     int i;
331
332     if (sp - stack < 4)
333         runtime_error (ERR_STK_OVF);
334
335     GET_PC (pc)
336
337     *--sp = (zword) (pc >> 9);
338     *--sp = (zword) (pc & 0x1ff);
339     *--sp = (zword) (fp - stack - 1);
340     *--sp = (zword) (argc | (ct << (f_setup.save_quetzal ? 12 : 8)));
341
342     fp = sp;
343     frame_count++;
344
345     /* Calculate byte address of routine */
346
347     if (h_version <= V3)
348         pc = (long) routine << 1;
349     else if (h_version <= V5)
350         pc = (long) routine << 2;
351     else if (h_version <= V7)
352         pc = ((long) routine << 2) + ((long) h_functions_offset << 3);
353     else /* h_version == V8 */
354         pc = (long) routine << 3;
355
356     if (pc >= story_size)
357         runtime_error (ERR_ILL_CALL_ADDR);
358
359     SET_PC (pc)
360
361     /* Initialise local variables */
362
363     CODE_BYTE (count)
364
365     if (count > 15)
366         runtime_error (ERR_CALL_NON_RTN);
367     if (sp - stack < count)
368         runtime_error (ERR_STK_OVF);
369
370     if (f_setup.save_quetzal)
371         fp[0] |= (zword) count << 8;    /* Save local var count for Quetzal. */
372
373     value = 0;
374
375     for (i = 0; i < count; i++) {
376
377         if (h_version <= V4)            /* V1 to V4 games provide default */
378             CODE_WORD (value)           /* values for all local variables */
379
380         *--sp = (zword) ((argc-- > 0) ? args[i] : value);
381
382     }
383
384     /* Start main loop for direct calls */
385
386     if (ct == 2)
387         interpret ();
388
389 }/* call */
390
391 /*
392  * ret
393  *
394  * Return from the current subroutine and restore the previous stack
395  * frame. The result may be stored (0), thrown away (1) or pushed on
396  * the stack (2). In the latter case a direct call has been finished
397  * and we must exit the interpreter loop.
398  *
399  */
400
401 void ret (zword value)
402 {
403     long pc;
404     int ct;
405
406     if (sp > fp)
407         runtime_error (ERR_STK_UNDF);
408
409     sp = fp;
410
411     ct = *sp++ >> (f_setup.save_quetzal ? 12 : 8);
412     frame_count--;
413     fp = stack + 1 + *sp++;
414     pc = *sp++;
415     pc = ((long) *sp++ << 9) | pc;
416
417     SET_PC (pc)
418
419     /* Handle resulting value */
420
421     if (ct == 0)
422         store (value);
423     if (ct == 2)
424         *--sp = value;
425
426     /* Stop main loop for direct calls */
427
428     if (ct == 2)
429         finished++;
430
431 }/* ret */
432
433 /*
434  * branch
435  *
436  * Take a jump after an instruction based on the flag, either true or
437  * false. The branch can be short or long; it is encoded in one or two
438  * bytes respectively. When bit 7 of the first byte is set, the jump
439  * takes place if the flag is true; otherwise it is taken if the flag
440  * is false. When bit 6 of the first byte is set, the branch is short;
441  * otherwise it is long. The offset occupies the bottom 6 bits of the
442  * first byte plus all the bits in the second byte for long branches.
443  * Uniquely, an offset of 0 means return false, and an offset of 1 is
444  * return true.
445  *
446  */
447
448 void branch (bool flag)
449 {
450     long pc;
451     zword offset;
452     zbyte specifier;
453     zbyte off1;
454     zbyte off2;
455
456     CODE_BYTE (specifier)
457
458     off1 = specifier & 0x3f;
459
460     if (!flag)
461         specifier ^= 0x80;
462
463     if (!(specifier & 0x40)) {          /* it's a long branch */
464
465         if (off1 & 0x20)                /* propagate sign bit */
466             off1 |= 0xc0;
467
468         CODE_BYTE (off2)
469
470         offset = (off1 << 8) | off2;
471
472     } else offset = off1;               /* it's a short branch */
473
474     if (specifier & 0x80) {
475
476         if (offset > 1) {               /* normal branch */
477
478             GET_PC (pc)
479             pc += (short) offset - 2;
480             SET_PC (pc)
481
482         } else ret (offset);            /* special case, return 0 or 1 */
483     }
484
485 }/* branch */
486
487 /*
488  * store
489  *
490  * Store an operand, either as a variable or pushed on the stack.
491  *
492  */
493
494 void store (zword value)
495 {
496     zbyte variable;
497
498     CODE_BYTE (variable)
499
500     if (variable == 0)
501         *--sp = value;
502     else if (variable < 16)
503         *(fp - variable) = value;
504     else {
505         zword addr = h_globals + 2 * (variable - 16);
506         SET_WORD (addr, value)
507     }
508
509 }/* store */
510
511 /*
512  * direct_call
513  *
514  * Call the interpreter loop directly. This is necessary when
515  *
516  * - a sound effect has been finished
517  * - a read instruction has timed out
518  * - a newline countdown has hit zero
519  *
520  * The interpreter returns the result value on the stack.
521  *
522  */
523
524 int direct_call (zword addr)
525 {
526     zword saved_zargs[8];
527     int saved_zargc;
528     int i;
529
530     /* Calls to address 0 return false */
531
532     if (addr == 0)
533         return 0;
534
535     /* Save operands and operand count */
536
537     for (i = 0; i < 8; i++)
538         saved_zargs[i] = zargs[i];
539
540     saved_zargc = zargc;
541
542     /* Call routine directly */
543
544     call (addr, 0, 0, 2);
545
546     /* Restore operands and operand count */
547
548     for (i = 0; i < 8; i++)
549         zargs[i] = saved_zargs[i];
550
551     zargc = saved_zargc;
552
553     /* Resulting value lies on top of the stack */
554
555     return (short) *sp++;
556
557 }/* direct_call */
558
559 /*
560  * __extended__
561  *
562  * Load and execute an extended opcode.
563  *
564  */
565
566 static void __extended__ (void)
567 {
568     zbyte opcode;
569     zbyte specifier;
570
571     CODE_BYTE (opcode)
572     CODE_BYTE (specifier)
573
574     load_all_operands (specifier);
575
576     if (opcode < 0x1d)                  /* extended opcodes from 0x1d on */
577         ext_opcodes[opcode] ();         /* are reserved for future spec' */
578
579 }/* __extended__ */
580
581 /*
582  * __illegal__
583  *
584  * Exit game because an unknown opcode has been hit.
585  *
586  */
587
588 static void __illegal__ (void)
589 {
590
591     runtime_error (ERR_ILL_OPCODE);
592
593 }/* __illegal__ */
594
595 /*
596  * z_catch, store the current stack frame for later use with z_throw.
597  *
598  *      no zargs used
599  *
600  */
601
602 void z_catch (void)
603 {
604
605     store (f_setup.save_quetzal ? frame_count : (zword) (fp - stack));
606
607 }/* z_catch */
608
609 /*
610  * z_throw, go back to the given stack frame and return the given value.
611  *
612  *      zargs[0] = value to return
613  *      zargs[1] = stack frame
614  *
615  */
616
617 void z_throw (void)
618 {
619
620     if (f_setup.save_quetzal) {
621         if (zargs[1] > frame_count)
622             runtime_error (ERR_BAD_FRAME);
623
624         /* Unwind the stack a frame at a time. */
625         for (; frame_count > zargs[1]; --frame_count)
626             fp = stack + 1 + fp[1];
627     } else {
628         if (zargs[1] > STACK_SIZE)
629             runtime_error (ERR_BAD_FRAME);
630
631         fp = stack + zargs[1];
632     }
633
634     ret (zargs[0]);
635
636 }/* z_throw */
637
638 /*
639  * z_call_n, call a subroutine and discard its result.
640  *
641  *      zargs[0] = packed address of subroutine
642  *      zargs[1] = first argument (optional)
643  *      ...
644  *      zargs[7] = seventh argument (optional)
645  *
646  */
647
648 void z_call_n (void)
649 {
650
651     if (zargs[0] != 0)
652         call (zargs[0], zargc - 1, zargs + 1, 1);
653
654 }/* z_call_n */
655
656 /*
657  * z_call_s, call a subroutine and store its result.
658  *
659  *      zargs[0] = packed address of subroutine
660  *      zargs[1] = first argument (optional)
661  *      ...
662  *      zargs[7] = seventh argument (optional)
663  *
664  */
665
666 void z_call_s (void)
667 {
668
669     if (zargs[0] != 0)
670         call (zargs[0], zargc - 1, zargs + 1, 0);
671     else
672         store (0);
673
674 }/* z_call_s */
675
676 /*
677  * z_check_arg_count, branch if subroutine was called with >= n arg's.
678  *
679  *      zargs[0] = number of arguments
680  *
681  */
682
683 void z_check_arg_count (void)
684 {
685
686     if (fp == stack + STACK_SIZE)
687         branch (zargs[0] == 0);
688     else
689         branch (zargs[0] <= (*fp & 0xff));
690
691 }/* z_check_arg_count */
692
693 /*
694  * z_jump, jump unconditionally to the given address.
695  *
696  *      zargs[0] = PC relative address
697  *
698  */
699
700 void z_jump (void)
701 {
702     long pc;
703
704     GET_PC (pc)
705
706     pc += (short) zargs[0] - 2;
707
708     if (pc >= story_size)
709         runtime_error (ERR_ILL_JUMP_ADDR);
710
711     SET_PC (pc)
712
713 }/* z_jump */
714
715 /*
716  * z_nop, no operation.
717  *
718  *      no zargs used
719  *
720  */
721
722 void z_nop (void)
723 {
724
725     /* Do nothing */
726
727 }/* z_nop */
728
729 /*
730  * z_quit, stop game and exit interpreter.
731  *
732  *      no zargs used
733  *
734  */
735
736 void z_quit (void)
737 {
738
739     finished = 9999;
740
741 }/* z_quit */
742
743 /*
744  * z_ret, return from a subroutine with the given value.
745  *
746  *      zargs[0] = value to return
747  *
748  */
749
750 void z_ret (void)
751 {
752
753     ret (zargs[0]);
754
755 }/* z_ret */
756
757 /*
758  * z_ret_popped, return from a subroutine with a value popped off the stack.
759  *
760  *      no zargs used
761  *
762  */
763
764 void z_ret_popped (void)
765 {
766
767     ret (*sp++);
768
769 }/* z_ret_popped */
770
771 /*
772  * z_rfalse, return from a subroutine with false (0).
773  *
774  *      no zargs used
775  *
776  */
777
778 void z_rfalse (void)
779 {
780
781     ret (0);
782
783 }/* z_rfalse */
784
785 /*
786  * z_rtrue, return from a subroutine with true (1).
787  *
788  *      no zargs used
789  *
790  */
791
792 void z_rtrue (void)
793 {
794
795     ret (1);
796
797 }/* z_rtrue */