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