Update interpreters to latest Garglk codebase
[projects/chimara/chimara.git] / interpreters / nitfol / op_jmp.c
1 /*  Nitfol - z-machine interpreter using Glk for output.
2     Copyright (C) 1999  Evin Robertson
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18     The author can be reached at nitfol@deja.com
19 */
20 #include "nitfol.h"
21
22
23 N_INLINE static void skip_branch(zbyte branch)
24 {
25   if(!(branch & b01000000)) /* Bit 6 clear means 'branch occupies two bytes' */
26     PC++;
27 }
28
29 N_INLINE static void take_branch(zbyte branch)
30 {
31   int o = branch & b00111111;
32
33   if(!(branch & b01000000)) {/* Bit 6 clear means 'branch occupies two bytes'*/
34     o = (o << 8) + HIBYTE(PC);
35     PC++;
36     if(branch & b00100000)
37       o = -((1 << 14) - o);
38   }
39
40   if(o == 0)
41     mop_func_return(0);
42   else if(o == 1)
43     mop_func_return(1);
44   else
45     PC += o - 2;
46
47 #ifndef FAST
48   if(PC > game_size) {
49     n_show_error(E_INSTR, "attempt to conditionally jump outside of story", o - 2);
50     PC -= o - 2;
51     return;
52   }
53 #endif
54   
55   /*  printf("cjmp %x -> %x\n", oldPC, PC); */
56 }
57
58
59 void mop_skip_branch(void)
60 {
61   zbyte branch = HIBYTE(PC);
62   PC++;
63
64   if(branch & b10000000)  /* Bit 7 set means 'branch when true' */
65     skip_branch(branch);
66   else
67     take_branch(branch);
68
69 }
70
71 void mop_take_branch(void)
72 {
73   zbyte branch = HIBYTE(PC);
74   PC++;
75
76   if(branch & b10000000)  /* Bit 7 set means 'branch when true' */
77     take_branch(branch);
78   else
79     skip_branch(branch);
80 }
81
82 void mop_cond_branch(BOOL cond)
83 {
84   zbyte branch = HIBYTE(PC);
85   PC++;
86   if((branch >> 7) ^ cond)
87     skip_branch(branch);
88   else
89     take_branch(branch);
90 }
91
92
93 void op_je(void)
94 {
95   int i;
96   for(i = 1; i < numoperands; i++)
97     if(operand[0] == operand[i]) {
98       mop_take_branch();
99       return;
100     }
101
102   mop_skip_branch();
103 }
104
105 void op_jg(void)
106 {
107   if(is_greaterthan(operand[0], operand[1]))
108     mop_take_branch();
109   else
110     mop_skip_branch();
111 }
112
113 void op_jl(void)
114 {
115   if(is_lessthan(operand[0], operand[1]))
116     mop_take_branch();
117   else
118     mop_skip_branch();
119 }
120
121 void op_jump(void)
122 {
123   operand[0] -= 2;  /* not documented in zspec */
124   if(is_neg(operand[0])) {
125 #ifndef FAST
126     if(neg(operand[0]) > PC) {
127       n_show_error(E_INSTR, "attempt to jump before beginning of story", -neg(operand[0]));
128       return;
129     }
130 #endif
131     PC -= neg(operand[0]);
132   }
133   else {
134     PC += operand[0];
135     if(PC > game_size) {
136       n_show_error(E_INSTR, "attempt to jump past end of story", operand[0]);
137       PC -= operand[0];
138       return;
139     }
140   }
141   /*  printf("jump %x -> %x\n", oldPC, PC); */
142 }
143
144 void op_jz(void)
145 {
146   mop_cond_branch(operand[0] == 0);
147 }
148
149 void op_test(void)
150 {
151   mop_cond_branch((operand[0] & operand[1]) == operand[1]);
152 }
153
154 void op_verify(void)
155 {
156   mop_cond_branch(LOWORD(HD_CHECKSUM) == z_checksum);
157 }
158
159 void op_piracy(void)
160 {
161   mop_cond_branch(aye_matey);
162 }