1 /*
2 Jump
3 */
4
5 #include "jump.h"
6
7 #include "addr.h"
8 #include "head.h"
9 #include "interp.h"
10 #include "mem.h"
11 #include "page.h"
12 #include "pc.h"
13 #include "shared.h"
14 #include "stack.h"
15 #include "stop.h"
16 #include "support.h"
17 #include "var.h"
18
19 #define PROCEDURE 0
20 #define FUNCTION 0x0100
21 #define EMPTY_PAGE 0xFFFE
22
23 static byte local_params;
24
call(word type)25 static void call(word type)
26 {
27 extern word param_stack[];
28
29 int num_params = param_stack[0] - 1;
30 word packed = param_stack[1];
31 word *param_ptr = ¶m_stack[2];
32 long_word addr = ad_code_addr(packed);
33 int vars;
34
35 if(addr == 0)
36 {
37 if(type != PROCEDURE)
38 store(0);
39 }
40 else
41 {
42 stk_push(pc_page());
43 stk_push(pc_offset());
44 stk_push(type | local_params);
45 stk_link();
46
47 set_pc(pg_page(addr), pg_offset(addr));
48
49 local_params = num_params;
50
51 /* Global variables 1 to 15 are Local variables, which
52 reside on the stack (and so are local to each procedure). */
53
54 vars = (int) next_byte();
55 if(vars > ((int) LOCAL_VARS - 1))
56 {
57 display((byte *) "Bad loc num");
58 vars = LOCAL_VARS - 1;
59 }
60 if(num_params > vars)
61 {
62 #if 0
63 display("Bad optional num");
64 #endif
65 num_params = vars;
66 }
67 vars -= num_params;
68 while(num_params--)
69 stk_push(*param_ptr++);
70 while(vars--)
71 stk_push(0);
72 }
73 }
74
std_gosub(void)75 static void std_gosub(void)
76 {
77 extern word param_stack[];
78
79 int num_params = param_stack[0] - 1;
80 word packed = param_stack[1];
81 word *param_ptr = ¶m_stack[2];
82 long_word addr = ad_code_addr(packed);
83
84 if(addr == 0)
85 {
86 store(0);
87 }
88 else
89 {
90 int vars;
91
92 stk_push(pc_page());
93 stk_push(pc_offset());
94 stk_link();
95
96 set_pc(pg_page(addr), pg_offset(addr));
97
98 vars = (int) next_byte();
99 while(vars--)
100 {
101 word parameter = next_word();
102 if(--num_params >= 0)
103 parameter = *param_ptr++;
104 stk_push(parameter);
105 }
106 }
107 }
108
adv_gosub(void)109 static void adv_gosub(void)
110 {
111 call(FUNCTION);
112 }
113
std_rtn(word value)114 static void std_rtn(word value)
115 {
116 word page, offset;
117 stk_unlink();
118 offset = stk_pop();
119 page = stk_pop();
120
121 if(page == EMPTY_PAGE)
122 {
123 quit();
124 }
125 else
126 {
127 set_pc(page, offset);
128 store(value);
129 }
130 }
131
adv_rtn(word value)132 static void adv_rtn(word value)
133 {
134 word type, page, offset;
135
136 stk_unlink();
137 type = stk_pop();
138 local_params = (byte) type;
139 offset = stk_pop();
140 page = stk_pop();
141
142 if(page == EMPTY_PAGE)
143 {
144 quit();
145 }
146 else
147 {
148 set_pc(page, offset);
149 if(type & FUNCTION)
150 store(value);
151 }
152 }
153
gosub2(word address)154 void gosub2(word address)
155 {
156 extern word param_stack[];
157 param_stack[0] = 1;
158 param_stack[1] = address;
159 active_gosub();
160 }
161
gosub4(void)162 void gosub4(void)
163 {
164 call(PROCEDURE);
165 }
166
gosub5(word address)167 void gosub5(word address)
168 {
169 extern word param_stack[];
170
171 param_stack[0] = 1;
172 param_stack[1] = address;
173 gosub4();
174 }
175
jump(word offset)176 void jump(word offset)
177 {
178 move_pc(offset - 2);
179 }
180
ret_true(void)181 void ret_true(void)
182 {
183 active_return(1);
184 }
185
ret_false(void)186 void ret_false(void)
187 {
188 active_return(0);
189 }
190
ret_value(word result)191 void ret_value(word result)
192 {
193 byte branch = next_byte();
194 word offset = branch & 0x3F;
195
196 /* Bit 6 indicates signed 14 bit branch */
197 if((branch & 0x40) == 0)
198 {
199 /* Get 14 bit quantity */
200 offset = make_word(offset, next_byte());
201 /* Sign extend from 14 to 16 bits */
202 if(offset & 0x2000) offset |= 0xC000;
203 }
204 else
205 {
206 /* Unsigned 6 bit branch */
207 }
208 /* Top bit set implies branch if true */
209 if(result == (branch >> 7))
210 {
211 switch(offset)
212 {
213 case 0:
214 ret_false();
215 break;
216 case 1:
217 ret_true();
218 break;
219 default:
220 jump(offset);
221 break;
222 }
223 }
224 }
225
adv_pop_stack(void)226 void adv_pop_stack(void)
227 {
228 store(-stk_encode_var());
229 }
230
rts(void)231 void rts(void)
232 {
233 active_return(stk_pop());
234 }
235
active_gosub(void)236 void active_gosub(void)
237 {
238 if(hd_five())
239 adv_gosub();
240 else
241 std_gosub();
242 }
243
active_return(word param)244 void active_return(word param)
245 {
246 if(hd_five())
247 adv_rtn(param);
248 else
249 std_rtn(param);
250 }
251
special_gosub(word address)252 word special_gosub(word address)
253 {
254 extern word param_stack[];
255
256 word value;
257 bool old_stop = stopped();
258 set_stop(0);
259
260 stk_push(pc_page());
261 set_pc(EMPTY_PAGE, pc_offset());
262 param_stack[0] = 1;
263 param_stack[1] = address;
264 active_gosub();
265 execute_opcode();
266 value = stk_pop();
267 set_pc(stk_pop(), pc_offset());
268 set_stop(old_stop);
269 return value;
270 }
271
throw_away_stack_frame(word value,word stack_offset)272 void throw_away_stack_frame(word value, word stack_offset)
273 {
274 stk_throw(stack_offset);
275 active_return(value);
276 }
277
num_local_params(word num_params)278 void num_local_params(word num_params)
279 {
280 ret_value(num_params <= (word) local_params);
281 }
282