1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/glulx/glulx.h"
24 
25 namespace Glk {
26 namespace Glulx {
27 
28 /**
29  * The actual immutable structures which lookup_operandlist() returns.
30  */
31 static const operandlist_t list_none = { 0, 4, nullptr };
32 
33 static const int array_S[1] = { modeform_Store };
34 static const operandlist_t list_S = { 1, 4, &array_S[0] };
35 static const int array_LS[2] = { modeform_Load, modeform_Store };
36 static const operandlist_t list_LS = { 2, 4, &array_LS[0] };
37 static const int array_LLS[3] = { modeform_Load, modeform_Load, modeform_Store };
38 static const operandlist_t list_LLS = { 3, 4, &array_LLS[0] };
39 static const int array_LLLS[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Store };
40 static const operandlist_t list_LLLS = { 4, 4, &array_LLLS[0] };
41 static const int array_LLLLS[5] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
42 static const operandlist_t list_LLLLS = { 5, 4, &array_LLLLS[0] };
43 /* static const int array_LLLLLS[6] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
44 static const operandlist_t list_LLLLLS = { 6, 4, &array_LLLLLS }; */ /* not currently used */
45 static const int array_LLLLLLS[7] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
46 static const operandlist_t list_LLLLLLS = { 7, 4, &array_LLLLLLS[0] };
47 static const int array_LLLLLLLS[8] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Load, modeform_Store };
48 static const operandlist_t list_LLLLLLLS = { 8, 4, &array_LLLLLLLS[0] };
49 
50 static const int array_L[1] = { modeform_Load };
51 static const operandlist_t list_L = { 1, 4, &array_L[0] };
52 static const int array_LL[2] = { modeform_Load, modeform_Load };
53 static const operandlist_t list_LL = { 2, 4, &array_LL[0] };
54 static const int array_LLL[3] = { modeform_Load, modeform_Load, modeform_Load };
55 static const operandlist_t list_LLL = { 3, 4, &array_LLL[0] };
56 static const operandlist_t list_2LS = { 2, 2, &array_LS[0] };
57 static const operandlist_t list_1LS = { 2, 1, &array_LS[0] };
58 static const int array_LLLL[4] = { modeform_Load, modeform_Load, modeform_Load, modeform_Load };
59 static const operandlist_t list_LLLL = { 4, 4, &array_LLLL[0] };
60 static const int array_SL[2] = { modeform_Store, modeform_Load };
61 static const operandlist_t list_SL = { 2, 4, &array_SL[0] };
62 static const int array_SS[2] = { modeform_Store, modeform_Store };
63 static const operandlist_t list_SS = { 2, 4, &array_SS[0] };
64 static const int array_LLSS[4] = { modeform_Load, modeform_Load, modeform_Store, modeform_Store };
65 static const operandlist_t list_LLSS = { 4, 4, &array_LLSS[0] };
66 
init_operands()67 void Glulx::init_operands() {
68 	for (int ix = 0; ix < 0x80; ix++)
69 		fast_operandlist[ix] = lookup_operandlist(ix);
70 }
71 
lookup_operandlist(uint opcode)72 const operandlist_t *Glulx::lookup_operandlist(uint opcode) {
73 	switch (opcode) {
74 	case op_nop:
75 		return &list_none;
76 
77 	case op_add:
78 	case op_sub:
79 	case op_mul:
80 	case op_div:
81 	case op_mod:
82 	case op_bitand:
83 	case op_bitor:
84 	case op_bitxor:
85 	case op_shiftl:
86 	case op_sshiftr:
87 	case op_ushiftr:
88 		return &list_LLS;
89 
90 	case op_neg:
91 	case op_bitnot:
92 		return &list_LS;
93 
94 	case op_jump:
95 	case op_jumpabs:
96 		return &list_L;
97 	case op_jz:
98 	case op_jnz:
99 		return &list_LL;
100 	case op_jeq:
101 	case op_jne:
102 	case op_jlt:
103 	case op_jge:
104 	case op_jgt:
105 	case op_jle:
106 	case op_jltu:
107 	case op_jgeu:
108 	case op_jgtu:
109 	case op_jleu:
110 		return &list_LLL;
111 
112 	case op_call:
113 		return &list_LLS;
114 	case op_return:
115 		return &list_L;
116 	case op_catch:
117 		return &list_SL;
118 	case op_throw:
119 		return &list_LL;
120 	case op_tailcall:
121 		return &list_LL;
122 
123 	case op_sexb:
124 	case op_sexs:
125 		return &list_LS;
126 
127 	case op_copy:
128 		return &list_LS;
129 	case op_copys:
130 		return &list_2LS;
131 	case op_copyb:
132 		return &list_1LS;
133 	case op_aload:
134 	case op_aloads:
135 	case op_aloadb:
136 	case op_aloadbit:
137 		return &list_LLS;
138 	case op_astore:
139 	case op_astores:
140 	case op_astoreb:
141 	case op_astorebit:
142 		return &list_LLL;
143 
144 	case op_stkcount:
145 		return &list_S;
146 	case op_stkpeek:
147 		return &list_LS;
148 	case op_stkswap:
149 		return &list_none;
150 	case op_stkroll:
151 		return &list_LL;
152 	case op_stkcopy:
153 		return &list_L;
154 
155 	case op_streamchar:
156 	case op_streamunichar:
157 	case op_streamnum:
158 	case op_streamstr:
159 		return &list_L;
160 	case op_getstringtbl:
161 		return &list_S;
162 	case op_setstringtbl:
163 		return &list_L;
164 	case op_getiosys:
165 		return &list_SS;
166 	case op_setiosys:
167 		return &list_LL;
168 
169 	case op_random:
170 		return &list_LS;
171 	case op_setrandom:
172 		return &list_L;
173 
174 	case op_verify:
175 		return &list_S;
176 	case op_restart:
177 		return &list_none;
178 	case op_save:
179 	case op_restore:
180 		return &list_LS;
181 	case op_saveundo:
182 	case op_restoreundo:
183 		return &list_S;
184 	case op_protect:
185 		return &list_LL;
186 
187 	case op_quit:
188 		return &list_none;
189 
190 	case op_gestalt:
191 		return &list_LLS;
192 
193 	case op_debugtrap:
194 		return &list_L;
195 
196 	case op_getmemsize:
197 		return &list_S;
198 	case op_setmemsize:
199 		return &list_LS;
200 
201 	case op_linearsearch:
202 		return &list_LLLLLLLS;
203 	case op_binarysearch:
204 		return &list_LLLLLLLS;
205 	case op_linkedsearch:
206 		return &list_LLLLLLS;
207 
208 	case op_glk:
209 		return &list_LLS;
210 
211 	case op_callf:
212 		return &list_LS;
213 	case op_callfi:
214 		return &list_LLS;
215 	case op_callfii:
216 		return &list_LLLS;
217 	case op_callfiii:
218 		return &list_LLLLS;
219 
220 	case op_mzero:
221 		return &list_LL;
222 	case op_mcopy:
223 		return &list_LLL;
224 	case op_malloc:
225 		return &list_LS;
226 	case op_mfree:
227 		return &list_L;
228 
229 	case op_accelfunc:
230 	case op_accelparam:
231 		return &list_LL;
232 
233 #ifdef FLOAT_SUPPORT
234 
235 	case op_numtof:
236 	case op_ftonumz:
237 	case op_ftonumn:
238 	case op_ceil:
239 	case op_floor:
240 	case op_sqrt:
241 	case op_exp:
242 	case op_log:
243 		return &list_LS;
244 	case op_fadd:
245 	case op_fsub:
246 	case op_fmul:
247 	case op_fdiv:
248 	case op_pow:
249 	case op_atan2:
250 		return &list_LLS;
251 	case op_fmod:
252 		return &list_LLSS;
253 	case op_sin:
254 	case op_cos:
255 	case op_tan:
256 	case op_asin:
257 	case op_acos:
258 	case op_atan:
259 		return &list_LS;
260 	case op_jfeq:
261 	case op_jfne:
262 		return &list_LLLL;
263 	case op_jflt:
264 	case op_jfle:
265 	case op_jfgt:
266 	case op_jfge:
267 		return &list_LLL;
268 	case op_jisnan:
269 	case op_jisinf:
270 		return &list_LL;
271 
272 #endif /* FLOAT_SUPPORT */
273 
274 #ifdef GLULX_EXTEND_OPERANDS
275 		GLULX_EXTEND_OPERANDS
276 #endif /* GLULX_EXTEND_OPERANDS */
277 
278 	default:
279 		return nullptr;
280 	}
281 }
282 
parse_operands(oparg_t * args,const operandlist_t * oplist)283 void Glulx::parse_operands(oparg_t *args, const operandlist_t *oplist) {
284 	int ix;
285 	oparg_t *curarg;
286 	int numops = oplist->num_ops;
287 	int argsize = oplist->arg_size;
288 	uint modeaddr = pc;
289 	int modeval = 0;
290 
291 	pc += (numops + 1) / 2;
292 
293 	for (ix = 0, curarg = args; ix < numops; ix++, curarg++) {
294 		int mode;
295 		uint value;
296 		uint addr;
297 
298 		curarg->desttype = 0;
299 
300 		if ((ix & 1) == 0) {
301 			modeval = Mem1(modeaddr);
302 			mode = (modeval & 0x0F);
303 		} else {
304 			mode = ((modeval >> 4) & 0x0F);
305 			modeaddr++;
306 		}
307 
308 		if (oplist->formlist[ix] == modeform_Load) {
309 
310 			switch (mode) {
311 
312 			case 8: /* pop off stack */
313 				if (stackptr < valstackbase + 4) {
314 					fatal_error("Stack underflow in operand.");
315 				}
316 				stackptr -= 4;
317 				value = Stk4(stackptr);
318 				break;
319 
320 			case 0: /* constant zero */
321 				value = 0;
322 				break;
323 
324 			case 1: /* one-byte constant */
325 				/* Sign-extend from 8 bits to 32 */
326 				value = (int)(signed char)(Mem1(pc));
327 				pc++;
328 				break;
329 
330 			case 2: /* two-byte constant */
331 				/* Sign-extend the first byte from 8 bits to 32; the subsequent
332 				   byte must not be sign-extended. */
333 				value = (int)(signed char)(Mem1(pc));
334 				pc++;
335 				value = (value << 8) | (uint)(Mem1(pc));
336 				pc++;
337 				break;
338 
339 			case 3: /* four-byte constant */
340 				/* Bytes must not be sign-extended. */
341 				value = Mem4(pc);
342 				pc += 4;
343 				break;
344 
345 			case 15: /* main memory RAM, four-byte address */
346 				addr = Mem4(pc);
347 				addr += ramstart;
348 				pc += 4;
349 				goto MainMemAddr;
350 
351 			case 14: /* main memory RAM, two-byte address */
352 				addr = (uint)Mem2(pc);
353 				addr += ramstart;
354 				pc += 2;
355 				goto MainMemAddr;
356 
357 			case 13: /* main memory RAM, one-byte address */
358 				addr = (uint)(Mem1(pc));
359 				addr += ramstart;
360 				pc++;
361 				goto MainMemAddr;
362 
363 			case 7: /* main memory, four-byte address */
364 				addr = Mem4(pc);
365 				pc += 4;
366 				goto MainMemAddr;
367 
368 			case 6: /* main memory, two-byte address */
369 				addr = (uint)Mem2(pc);
370 				pc += 2;
371 				goto MainMemAddr;
372 
373 			case 5: /* main memory, one-byte address */
374 				addr = (uint)(Mem1(pc));
375 				pc++;
376 				/* fall through */
377 
378 MainMemAddr:
379 				/* cases 5, 6, 7, 13, 14, 15 all wind up here. */
380 				if (argsize == 4) {
381 					value = Mem4(addr);
382 				} else if (argsize == 2) {
383 					value = Mem2(addr);
384 				} else {
385 					value = Mem1(addr);
386 				}
387 				break;
388 
389 			case 11: /* locals, four-byte address */
390 				addr = Mem4(pc);
391 				pc += 4;
392 				goto LocalsAddr;
393 
394 			case 10: /* locals, two-byte address */
395 				addr = (uint)Mem2(pc);
396 				pc += 2;
397 				goto LocalsAddr;
398 
399 			case 9: /* locals, one-byte address */
400 				addr = (uint)(Mem1(pc));
401 				pc++;
402 				/* fall through */
403 
404 LocalsAddr:
405 				/* cases 9, 10, 11 all wind up here. It's illegal for addr to not
406 				   be four-byte aligned, but we don't check this explicitly.
407 				   A "strict mode" interpreter probably should. It's also illegal
408 				   for addr to be less than zero or greater than the size of
409 				   the locals segment. */
410 				addr += localsbase;
411 				if (argsize == 4) {
412 					value = Stk4(addr);
413 				} else if (argsize == 2) {
414 					value = Stk2(addr);
415 				} else {
416 					value = Stk1(addr);
417 				}
418 				break;
419 
420 			default:
421 				value = 0;
422 				fatal_error("Unknown addressing mode in load operand.");
423 			}
424 
425 			curarg->value = value;
426 
427 		} else { /* modeform_Store */
428 			switch (mode) {
429 
430 			case 0: /* discard value */
431 				curarg->desttype = 0;
432 				curarg->value = 0;
433 				break;
434 
435 			case 8: /* push on stack */
436 				curarg->desttype = 3;
437 				curarg->value = 0;
438 				break;
439 
440 			case 15: /* main memory RAM, four-byte address */
441 				addr = Mem4(pc);
442 				addr += ramstart;
443 				pc += 4;
444 				goto WrMainMemAddr;
445 
446 			case 14: /* main memory RAM, two-byte address */
447 				addr = (uint)Mem2(pc);
448 				addr += ramstart;
449 				pc += 2;
450 				goto WrMainMemAddr;
451 
452 			case 13: /* main memory RAM, one-byte address */
453 				addr = (uint)(Mem1(pc));
454 				addr += ramstart;
455 				pc++;
456 				goto WrMainMemAddr;
457 
458 			case 7: /* main memory, four-byte address */
459 				addr = Mem4(pc);
460 				pc += 4;
461 				goto WrMainMemAddr;
462 
463 			case 6: /* main memory, two-byte address */
464 				addr = (uint)Mem2(pc);
465 				pc += 2;
466 				goto WrMainMemAddr;
467 
468 			case 5: /* main memory, one-byte address */
469 				addr = (uint)(Mem1(pc));
470 				pc++;
471 				/* fall through */
472 
473 WrMainMemAddr:
474 				/* cases 5, 6, 7 all wind up here. */
475 				curarg->desttype = 1;
476 				curarg->value = addr;
477 				break;
478 
479 			case 11: /* locals, four-byte address */
480 				addr = Mem4(pc);
481 				pc += 4;
482 				goto WrLocalsAddr;
483 
484 			case 10: /* locals, two-byte address */
485 				addr = (uint)Mem2(pc);
486 				pc += 2;
487 				goto WrLocalsAddr;
488 
489 			case 9: /* locals, one-byte address */
490 				addr = (uint)(Mem1(pc));
491 				pc++;
492 				/* fall through */
493 
494 WrLocalsAddr:
495 				/* cases 9, 10, 11 all wind up here. It's illegal for addr to not
496 				   be four-byte aligned, but we don't check this explicitly.
497 				   A "strict mode" interpreter probably should. It's also illegal
498 				   for addr to be less than zero or greater than the size of
499 				   the locals segment. */
500 				curarg->desttype = 2;
501 				/* We don't add localsbase here; the store address for desttype 2
502 				   is relative to the current locals segment, not an absolute
503 				   stack position. */
504 				curarg->value = addr;
505 				break;
506 
507 			case 1:
508 			case 2:
509 			case 3:
510 				fatal_error("Constant addressing mode in store operand.");
511 				break;
512 
513 			default:
514 				fatal_error("Unknown addressing mode in store operand.");
515 			}
516 		}
517 	}
518 }
519 
store_operand(uint desttype,uint destaddr,uint storeval)520 void Glulx::store_operand(uint desttype, uint destaddr, uint storeval) {
521 	switch (desttype) {
522 
523 	case 0: /* do nothing; discard the value. */
524 		return;
525 
526 	case 1: /* main memory. */
527 		MemW4(destaddr, storeval);
528 		return;
529 
530 	case 2: /* locals. */
531 		destaddr += localsbase;
532 		StkW4(destaddr, storeval);
533 		return;
534 
535 	case 3: /* push on stack. */
536 		if (stackptr + 4 > stacksize) {
537 			fatal_error("Stack overflow in store operand.");
538 		}
539 		StkW4(stackptr, storeval);
540 		stackptr += 4;
541 		return;
542 
543 	default:
544 		fatal_error("Unknown destination type in store operand.");
545 
546 	}
547 }
548 
store_operand_s(uint desttype,uint destaddr,uint storeval)549 void Glulx::store_operand_s(uint desttype, uint destaddr, uint storeval) {
550 	storeval &= 0xFFFF;
551 
552 	switch (desttype) {
553 
554 	case 0: /* do nothing; discard the value. */
555 		return;
556 
557 	case 1: /* main memory. */
558 		MemW2(destaddr, storeval);
559 		return;
560 
561 	case 2: /* locals. */
562 		destaddr += localsbase;
563 		StkW2(destaddr, storeval);
564 		return;
565 
566 	case 3: /* push on stack. A four-byte value is actually pushed. */
567 		if (stackptr + 4 > stacksize) {
568 			fatal_error("Stack overflow in store operand.");
569 		}
570 		StkW4(stackptr, storeval);
571 		stackptr += 4;
572 		return;
573 
574 	default:
575 		fatal_error("Unknown destination type in store operand.");
576 
577 	}
578 }
579 
store_operand_b(uint desttype,uint destaddr,uint storeval)580 void Glulx::store_operand_b(uint desttype, uint destaddr, uint storeval) {
581 	storeval &= 0xFF;
582 
583 	switch (desttype) {
584 
585 	case 0: /* do nothing; discard the value. */
586 		return;
587 
588 	case 1: /* main memory. */
589 		MemW1(destaddr, storeval);
590 		return;
591 
592 	case 2: /* locals. */
593 		destaddr += localsbase;
594 		StkW1(destaddr, storeval);
595 		return;
596 
597 	case 3: /* push on stack. A four-byte value is actually pushed. */
598 		if (stackptr + 4 > stacksize) {
599 			fatal_error("Stack overflow in store operand.");
600 		}
601 		StkW4(stackptr, storeval);
602 		stackptr += 4;
603 		return;
604 
605 	default:
606 		fatal_error("Unknown destination type in store operand.");
607 
608 	}
609 }
610 
611 } // End of namespace Glulx
612 } // End of namespace Glk
613