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 = &param_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 = &param_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