1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, 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 Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 #include "vm_local.h"
23 
24 //#define	DEBUG_VM
25 #ifdef DEBUG_VM
26 static char	*opnames[256] = {
27 	"OP_UNDEF",
28 
29 	"OP_IGNORE",
30 
31 	"OP_BREAK",
32 
33 	"OP_ENTER",
34 	"OP_LEAVE",
35 	"OP_CALL",
36 	"OP_PUSH",
37 	"OP_POP",
38 
39 	"OP_CONST",
40 
41 	"OP_LOCAL",
42 
43 	"OP_JUMP",
44 
45 	//-------------------
46 
47 	"OP_EQ",
48 	"OP_NE",
49 
50 	"OP_LTI",
51 	"OP_LEI",
52 	"OP_GTI",
53 	"OP_GEI",
54 
55 	"OP_LTU",
56 	"OP_LEU",
57 	"OP_GTU",
58 	"OP_GEU",
59 
60 	"OP_EQF",
61 	"OP_NEF",
62 
63 	"OP_LTF",
64 	"OP_LEF",
65 	"OP_GTF",
66 	"OP_GEF",
67 
68 	//-------------------
69 
70 	"OP_LOAD1",
71 	"OP_LOAD2",
72 	"OP_LOAD4",
73 	"OP_STORE1",
74 	"OP_STORE2",
75 	"OP_STORE4",
76 	"OP_ARG",
77 
78 	"OP_BLOCK_COPY",
79 
80 	//-------------------
81 
82 	"OP_SEX8",
83 	"OP_SEX16",
84 
85 	"OP_NEGI",
86 	"OP_ADD",
87 	"OP_SUB",
88 	"OP_DIVI",
89 	"OP_DIVU",
90 	"OP_MODI",
91 	"OP_MODU",
92 	"OP_MULI",
93 	"OP_MULU",
94 
95 	"OP_BAND",
96 	"OP_BOR",
97 	"OP_BXOR",
98 	"OP_BCOM",
99 
100 	"OP_LSH",
101 	"OP_RSHI",
102 	"OP_RSHU",
103 
104 	"OP_NEGF",
105 	"OP_ADDF",
106 	"OP_SUBF",
107 	"OP_DIVF",
108 	"OP_MULF",
109 
110 	"OP_CVIF",
111 	"OP_CVFI"
112 };
113 #endif
114 
115 #if idppc
116 
117 //FIXME: these, um... look the same to me
118 #if defined(__GNUC__)
loadWord(void * addr)119 static ID_INLINE unsigned int loadWord(void *addr) {
120 	unsigned int word;
121 
122 	asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr));
123 	return word;
124 }
125 #else
__lwbrx(register void * addr,register int offset)126 static ID_INLINE unsigned int __lwbrx(register void *addr,
127 		register int offset) {
128 	register unsigned int word;
129 
130 	asm("lwbrx %0,%2,%1" : "=r" (word) : "r" (addr), "b" (offset));
131 	return word;
132 }
133 #define loadWord(addr) __lwbrx(addr,0)
134 #endif
135 
136 #else
loadWord(void * addr)137     static ID_INLINE int loadWord(void *addr) {
138 	int word;
139 	memcpy(&word, addr, 4);
140 	return LittleLong(word);
141     }
142 #endif
143 
VM_Indent(vm_t * vm)144 char *VM_Indent( vm_t *vm ) {
145 	static char	*string = "                                        ";
146 	if ( vm->callLevel > 20 ) {
147 		return string;
148 	}
149 	return string + 2 * ( 20 - vm->callLevel );
150 }
151 
VM_StackTrace(vm_t * vm,int programCounter,int programStack)152 void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
153 	int		count;
154 
155 	count = 0;
156 	do {
157 		Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
158 		programStack =  *(int *)&vm->dataBase[programStack+4];
159 		programCounter = *(int *)&vm->dataBase[programStack];
160 	} while ( programCounter != -1 && ++count < 32 );
161 
162 }
163 
164 
165 /*
166 ====================
167 VM_PrepareInterpreter
168 ====================
169 */
VM_PrepareInterpreter(vm_t * vm,vmHeader_t * header)170 void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
171 	int		op;
172 	int		pc;
173 	byte	*code;
174 	int		instruction;
175 	int		*codeBase;
176 
177 	vm->codeBase = Hunk_Alloc( vm->codeLength*4, h_high );			// we're now int aligned
178 //	memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );
179 
180 	// we don't need to translate the instructions, but we still need
181 	// to find each instructions starting point for jumps
182 	pc = 0;
183 	instruction = 0;
184 	code = (byte *)header + header->codeOffset;
185 	codeBase = (int *)vm->codeBase;
186 
187 	while ( instruction < header->instructionCount ) {
188 		vm->instructionPointers[ instruction ] = pc;
189 		instruction++;
190 
191 		op = code[ pc ];
192 		codeBase[pc] = op;
193 		if ( pc > header->codeLength ) {
194 			Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" );
195 		}
196 
197 		pc++;
198 
199 		// these are the only opcodes that aren't a single byte
200 		switch ( op ) {
201 		case OP_ENTER:
202 		case OP_CONST:
203 		case OP_LOCAL:
204 		case OP_LEAVE:
205 		case OP_EQ:
206 		case OP_NE:
207 		case OP_LTI:
208 		case OP_LEI:
209 		case OP_GTI:
210 		case OP_GEI:
211 		case OP_LTU:
212 		case OP_LEU:
213 		case OP_GTU:
214 		case OP_GEU:
215 		case OP_EQF:
216 		case OP_NEF:
217 		case OP_LTF:
218 		case OP_LEF:
219 		case OP_GTF:
220 		case OP_GEF:
221 		case OP_BLOCK_COPY:
222 			codeBase[pc+0] = loadWord(&code[pc]);
223 			pc += 4;
224 			break;
225 		case OP_ARG:
226 			codeBase[pc+0] = code[pc];
227 			pc += 1;
228 			break;
229 		default:
230 			break;
231 		}
232 
233 	}
234 	pc = 0;
235 	instruction = 0;
236 	code = (byte *)header + header->codeOffset;
237 	codeBase = (int *)vm->codeBase;
238 
239 	while ( instruction < header->instructionCount ) {
240 		op = code[ pc ];
241 		instruction++;
242 		pc++;
243 		switch ( op ) {
244 		case OP_ENTER:
245 		case OP_CONST:
246 		case OP_LOCAL:
247 		case OP_LEAVE:
248 		case OP_EQ:
249 		case OP_NE:
250 		case OP_LTI:
251 		case OP_LEI:
252 		case OP_GTI:
253 		case OP_GEI:
254 		case OP_LTU:
255 		case OP_LEU:
256 		case OP_GTU:
257 		case OP_GEU:
258 		case OP_EQF:
259 		case OP_NEF:
260 		case OP_LTF:
261 		case OP_LEF:
262 		case OP_GTF:
263 		case OP_GEF:
264 		case OP_BLOCK_COPY:
265 			switch(op) {
266 				case OP_EQ:
267 				case OP_NE:
268 				case OP_LTI:
269 				case OP_LEI:
270 				case OP_GTI:
271 				case OP_GEI:
272 				case OP_LTU:
273 				case OP_LEU:
274 				case OP_GTU:
275 				case OP_GEU:
276 				case OP_EQF:
277 				case OP_NEF:
278 				case OP_LTF:
279 				case OP_LEF:
280 				case OP_GTF:
281 				case OP_GEF:
282 				codeBase[pc] = vm->instructionPointers[codeBase[pc]];
283 				break;
284 			default:
285 				break;
286 			}
287 			pc += 4;
288 			break;
289 		case OP_ARG:
290 			pc += 1;
291 			break;
292 		default:
293 			break;
294 		}
295 
296 	}
297 }
298 
299 /*
300 ==============
301 VM_Call
302 
303 
304 Upon a system call, the stack will look like:
305 
306 sp+32	parm1
307 sp+28	parm0
308 sp+24	return stack
309 sp+20	return address
310 sp+16	local1
311 sp+14	local0
312 sp+12	arg1
313 sp+8	arg0
314 sp+4	return stack
315 sp		return address
316 
317 An interpreted function will immediately execute
318 an OP_ENTER instruction, which will subtract space for
319 locals from sp
320 ==============
321 */
322 #define	MAX_STACK	256
323 #define	STACK_MASK	(MAX_STACK-1)
324 
325 #define	DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
326 
VM_CallInterpreted(vm_t * vm,int * args)327 int	VM_CallInterpreted( vm_t *vm, int *args ) {
328 	int		stack[MAX_STACK];
329 	int		*opStack;
330 	int		programCounter;
331 	int		programStack;
332 	int		stackOnEntry;
333 	byte	*image;
334 	int		*codeImage;
335 	int		v1;
336 	int		dataMask;
337 #ifdef DEBUG_VM
338 	vmSymbol_t	*profileSymbol;
339 #endif
340 
341 	// interpret the code
342 	vm->currentlyInterpreting = qtrue;
343 
344 	// we might be called recursively, so this might not be the very top
345 	programStack = stackOnEntry = vm->programStack;
346 
347 #ifdef DEBUG_VM
348 	profileSymbol = VM_ValueToFunctionSymbol( vm, 0 );
349 	// uncomment this for debugging breakpoints
350 	vm->breakFunction = 0;
351 #endif
352 	// set up the stack frame
353 
354 	image = vm->dataBase;
355 	codeImage = (int *)vm->codeBase;
356 	dataMask = vm->dataMask;
357 
358 	// leave a free spot at start of stack so
359 	// that as long as opStack is valid, opStack-1 will
360 	// not corrupt anything
361 	opStack = stack;
362 	programCounter = 0;
363 
364 	programStack -= 48;
365 
366 	*(int *)&image[ programStack + 44] = args[9];
367 	*(int *)&image[ programStack + 40] = args[8];
368 	*(int *)&image[ programStack + 36] = args[7];
369 	*(int *)&image[ programStack + 32] = args[6];
370 	*(int *)&image[ programStack + 28] = args[5];
371 	*(int *)&image[ programStack + 24] = args[4];
372 	*(int *)&image[ programStack + 20] = args[3];
373 	*(int *)&image[ programStack + 16] = args[2];
374 	*(int *)&image[ programStack + 12] = args[1];
375 	*(int *)&image[ programStack + 8 ] = args[0];
376 	*(int *)&image[ programStack + 4 ] = 0;	// return stack
377 	*(int *)&image[ programStack ] = -1;	// will terminate the loop on return
378 
379 	VM_Debug(0);
380 
381 //	vm_debugLevel=2;
382 	// main interpreter loop, will exit when a LEAVE instruction
383 	// grabs the -1 program counter
384 
385 #define r2 codeImage[programCounter]
386 
387 	while ( 1 ) {
388 		int		opcode,	r0, r1;
389 //		unsigned int	r2;
390 
391 nextInstruction:
392 		r0 = ((int *)opStack)[0];
393 		r1 = ((int *)opStack)[-1];
394 nextInstruction2:
395 #ifdef DEBUG_VM
396 		if ( (unsigned)programCounter >= vm->codeLength ) {
397 			Com_Error( ERR_DROP, "VM pc out of range" );
398 		}
399 
400 		if ( opStack < stack ) {
401 			Com_Error( ERR_DROP, "VM opStack underflow" );
402 		}
403 		if ( opStack >= stack+MAX_STACK ) {
404 			Com_Error( ERR_DROP, "VM opStack overflow" );
405 		}
406 
407 		if ( programStack <= vm->stackBottom ) {
408 			Com_Error( ERR_DROP, "VM stack overflow" );
409 		}
410 
411 		if ( programStack & 3 ) {
412 			Com_Error( ERR_DROP, "VM program stack misaligned" );
413 		}
414 
415 		if ( vm_debugLevel > 1 ) {
416 			Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] );
417 		}
418 		profileSymbol->profileCount++;
419 #endif
420 		opcode = codeImage[ programCounter++ ];
421 
422 		switch ( opcode ) {
423 #ifdef DEBUG_VM
424 		default:
425 			Com_Error( ERR_DROP, "Bad VM instruction" );  // this should be scanned on load!
426 #endif
427 		case OP_BREAK:
428 			vm->breakCount++;
429 			goto nextInstruction2;
430 		case OP_CONST:
431 			opStack++;
432 			r1 = r0;
433 			r0 = *opStack = r2;
434 
435 			programCounter += 4;
436 			goto nextInstruction2;
437 		case OP_LOCAL:
438 			opStack++;
439 			r1 = r0;
440 			r0 = *opStack = r2+programStack;
441 
442 			programCounter += 4;
443 			goto nextInstruction2;
444 
445 		case OP_LOAD4:
446 #ifdef DEBUG_VM
447 			if ( *opStack & 3 ) {
448 				Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
449 			}
450 #endif
451 			r0 = *opStack = *(int *)&image[ r0&dataMask ];
452 			goto nextInstruction2;
453 		case OP_LOAD2:
454 			r0 = *opStack = *(unsigned short *)&image[ r0&dataMask ];
455 			goto nextInstruction2;
456 		case OP_LOAD1:
457 			r0 = *opStack = image[ r0&dataMask ];
458 			goto nextInstruction2;
459 
460 		case OP_STORE4:
461 			*(int *)&image[ r1&(dataMask & ~3) ] = r0;
462 			opStack -= 2;
463 			goto nextInstruction;
464 		case OP_STORE2:
465 			*(short *)&image[ r1&(dataMask & ~1) ] = r0;
466 			opStack -= 2;
467 			goto nextInstruction;
468 		case OP_STORE1:
469 			image[ r1&dataMask ] = r0;
470 			opStack -= 2;
471 			goto nextInstruction;
472 
473 		case OP_ARG:
474 			// single byte offset from programStack
475 			*(int *)&image[ codeImage[programCounter] + programStack ] = r0;
476 			opStack--;
477 			programCounter += 1;
478 			goto nextInstruction;
479 
480 		case OP_BLOCK_COPY:
481 			{
482 				int		*src, *dest;
483 				int		i, count, srci, desti;
484 
485 				count = r2;
486 				// MrE: copy range check
487 				srci = r0 & dataMask;
488 				desti = r1 & dataMask;
489 				count = ((srci + count) & dataMask) - srci;
490 				count = ((desti + count) & dataMask) - desti;
491 
492 				src = (int *)&image[ r0&dataMask ];
493 				dest = (int *)&image[ r1&dataMask ];
494 				if ( ( (intptr_t)src | (intptr_t)dest | count ) & 3 ) {
495 					// happens in westernq3
496 					Com_Printf( S_COLOR_YELLOW "Warning: OP_BLOCK_COPY not dword aligned\n");
497 				}
498 				count >>= 2;
499 				for ( i = count-1 ; i>= 0 ; i-- ) {
500 					dest[i] = src[i];
501 				}
502 				programCounter += 4;
503 				opStack -= 2;
504 			}
505 			goto nextInstruction;
506 
507 		case OP_CALL:
508 			// save current program counter
509 			*(int *)&image[ programStack ] = programCounter;
510 
511 			// jump to the location on the stack
512 			programCounter = r0;
513 			opStack--;
514 			if ( programCounter < 0 ) {
515 				// system call
516 				int		r;
517 //				int		temp;
518 #ifdef DEBUG_VM
519 				int		stomped;
520 
521 				if ( vm_debugLevel ) {
522 					Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter );
523 				}
524 #endif
525 				// save the stack to allow recursive VM entry
526 //				temp = vm->callLevel;
527 				vm->programStack = programStack - 4;
528 #ifdef DEBUG_VM
529 				stomped = *(int *)&image[ programStack + 4 ];
530 #endif
531 				*(int *)&image[ programStack + 4 ] = -1 - programCounter;
532 
533 //VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
534 				{
535 					intptr_t* argptr = (intptr_t *)&image[ programStack + 4 ];
536 				#if __WORDSIZE == 64
537 				// the vm has ints on the stack, we expect
538 				// longs so we have to convert it
539 					intptr_t argarr[16];
540 					int i;
541 					for (i = 0; i < 16; ++i) {
542 						argarr[i] = *(int*)&image[ programStack + 4 + 4*i ];
543 					}
544 					argptr = argarr;
545 				#endif
546 					r = vm->systemCall( argptr );
547 				}
548 
549 #ifdef DEBUG_VM
550 				// this is just our stack frame pointer, only needed
551 				// for debugging
552 				*(int *)&image[ programStack + 4 ] = stomped;
553 #endif
554 
555 				// save return value
556 				opStack++;
557 				*opStack = r;
558 				programCounter = *(int *)&image[ programStack ];
559 //				vm->callLevel = temp;
560 #ifdef DEBUG_VM
561 				if ( vm_debugLevel ) {
562 					Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
563 				}
564 #endif
565 			} else if ( (unsigned)programCounter >= vm->codeLength ) {
566 				Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" );
567 			} else {
568 				programCounter = vm->instructionPointers[ programCounter ];
569 			}
570 			goto nextInstruction;
571 
572 		// push and pop are only needed for discarded or bad function return values
573 		case OP_PUSH:
574 			opStack++;
575 			goto nextInstruction;
576 		case OP_POP:
577 			opStack--;
578 			goto nextInstruction;
579 
580 		case OP_ENTER:
581 #ifdef DEBUG_VM
582 			profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
583 #endif
584 			// get size of stack frame
585 			v1 = r2;
586 
587 			programCounter += 4;
588 			programStack -= v1;
589 #ifdef DEBUG_VM
590 			// save old stack frame for debugging traces
591 			*(int *)&image[programStack+4] = programStack + v1;
592 			if ( vm_debugLevel ) {
593 				Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );
594 				if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {
595 					// this is to allow setting breakpoints here in the debugger
596 					vm->breakCount++;
597 //					vm_debugLevel = 2;
598 //					VM_StackTrace( vm, programCounter, programStack );
599 				}
600 //				vm->callLevel++;
601 			}
602 #endif
603 			goto nextInstruction;
604 		case OP_LEAVE:
605 			// remove our stack frame
606 			v1 = r2;
607 
608 			programStack += v1;
609 
610 			// grab the saved program counter
611 			programCounter = *(int *)&image[ programStack ];
612 #ifdef DEBUG_VM
613 			profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
614 			if ( vm_debugLevel ) {
615 //				vm->callLevel--;
616 				Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
617 			}
618 #endif
619 			// check for leaving the VM
620 			if ( programCounter == -1 ) {
621 				goto done;
622 			} else if ( (unsigned)programCounter >= vm->codeLength ) {
623 				Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" );
624 			}
625 			goto nextInstruction;
626 
627 		/*
628 		===================================================================
629 		BRANCHES
630 		===================================================================
631 		*/
632 
633 		case OP_JUMP:
634 			programCounter = r0;
635 			programCounter = vm->instructionPointers[ programCounter ];
636 			opStack--;
637 			goto nextInstruction;
638 
639 		case OP_EQ:
640 			opStack -= 2;
641 			if ( r1 == r0 ) {
642 				programCounter = r2;	//vm->instructionPointers[r2];
643 				goto nextInstruction;
644 			} else {
645 				programCounter += 4;
646 				goto nextInstruction;
647 			}
648 
649 		case OP_NE:
650 			opStack -= 2;
651 			if ( r1 != r0 ) {
652 				programCounter = r2;	//vm->instructionPointers[r2];
653 				goto nextInstruction;
654 			} else {
655 				programCounter += 4;
656 				goto nextInstruction;
657 			}
658 
659 		case OP_LTI:
660 			opStack -= 2;
661 			if ( r1 < r0 ) {
662 				programCounter = r2;	//vm->instructionPointers[r2];
663 				goto nextInstruction;
664 			} else {
665 				programCounter += 4;
666 				goto nextInstruction;
667 			}
668 
669 		case OP_LEI:
670 			opStack -= 2;
671 			if ( r1 <= r0 ) {
672 				programCounter = r2;	//vm->instructionPointers[r2];
673 				goto nextInstruction;
674 			} else {
675 				programCounter += 4;
676 				goto nextInstruction;
677 			}
678 
679 		case OP_GTI:
680 			opStack -= 2;
681 			if ( r1 > r0 ) {
682 				programCounter = r2;	//vm->instructionPointers[r2];
683 				goto nextInstruction;
684 			} else {
685 				programCounter += 4;
686 				goto nextInstruction;
687 			}
688 
689 		case OP_GEI:
690 			opStack -= 2;
691 			if ( r1 >= r0 ) {
692 				programCounter = r2;	//vm->instructionPointers[r2];
693 				goto nextInstruction;
694 			} else {
695 				programCounter += 4;
696 				goto nextInstruction;
697 			}
698 
699 		case OP_LTU:
700 			opStack -= 2;
701 			if ( ((unsigned)r1) < ((unsigned)r0) ) {
702 				programCounter = r2;	//vm->instructionPointers[r2];
703 				goto nextInstruction;
704 			} else {
705 				programCounter += 4;
706 				goto nextInstruction;
707 			}
708 
709 		case OP_LEU:
710 			opStack -= 2;
711 			if ( ((unsigned)r1) <= ((unsigned)r0) ) {
712 				programCounter = r2;	//vm->instructionPointers[r2];
713 				goto nextInstruction;
714 			} else {
715 				programCounter += 4;
716 				goto nextInstruction;
717 			}
718 
719 		case OP_GTU:
720 			opStack -= 2;
721 			if ( ((unsigned)r1) > ((unsigned)r0) ) {
722 				programCounter = r2;	//vm->instructionPointers[r2];
723 				goto nextInstruction;
724 			} else {
725 				programCounter += 4;
726 				goto nextInstruction;
727 			}
728 
729 		case OP_GEU:
730 			opStack -= 2;
731 			if ( ((unsigned)r1) >= ((unsigned)r0) ) {
732 				programCounter = r2;	//vm->instructionPointers[r2];
733 				goto nextInstruction;
734 			} else {
735 				programCounter += 4;
736 				goto nextInstruction;
737 			}
738 
739 		case OP_EQF:
740 			if ( ((float *)opStack)[-1] == *(float *)opStack ) {
741 				programCounter = r2;	//vm->instructionPointers[r2];
742 				opStack -= 2;
743 				goto nextInstruction;
744 			} else {
745 				programCounter += 4;
746 				opStack -= 2;
747 				goto nextInstruction;
748 			}
749 
750 		case OP_NEF:
751 			if ( ((float *)opStack)[-1] != *(float *)opStack ) {
752 				programCounter = r2;	//vm->instructionPointers[r2];
753 				opStack -= 2;
754 				goto nextInstruction;
755 			} else {
756 				programCounter += 4;
757 				opStack -= 2;
758 				goto nextInstruction;
759 			}
760 
761 		case OP_LTF:
762 			if ( ((float *)opStack)[-1] < *(float *)opStack ) {
763 				programCounter = r2;	//vm->instructionPointers[r2];
764 				opStack -= 2;
765 				goto nextInstruction;
766 			} else {
767 				programCounter += 4;
768 				opStack -= 2;
769 				goto nextInstruction;
770 			}
771 
772 		case OP_LEF:
773 			if ( ((float *)opStack)[-1] <= *(float *)opStack ) {
774 				programCounter = r2;	//vm->instructionPointers[r2];
775 				opStack -= 2;
776 				goto nextInstruction;
777 			} else {
778 				programCounter += 4;
779 				opStack -= 2;
780 				goto nextInstruction;
781 			}
782 
783 		case OP_GTF:
784 			if ( ((float *)opStack)[-1] > *(float *)opStack ) {
785 				programCounter = r2;	//vm->instructionPointers[r2];
786 				opStack -= 2;
787 				goto nextInstruction;
788 			} else {
789 				programCounter += 4;
790 				opStack -= 2;
791 				goto nextInstruction;
792 			}
793 
794 		case OP_GEF:
795 			if ( ((float *)opStack)[-1] >= *(float *)opStack ) {
796 				programCounter = r2;	//vm->instructionPointers[r2];
797 				opStack -= 2;
798 				goto nextInstruction;
799 			} else {
800 				programCounter += 4;
801 				opStack -= 2;
802 				goto nextInstruction;
803 			}
804 
805 
806 		//===================================================================
807 
808 		case OP_NEGI:
809 			*opStack = -r0;
810 			goto nextInstruction;
811 		case OP_ADD:
812 			opStack[-1] = r1 + r0;
813 			opStack--;
814 			goto nextInstruction;
815 		case OP_SUB:
816 			opStack[-1] = r1 - r0;
817 			opStack--;
818 			goto nextInstruction;
819 		case OP_DIVI:
820 			opStack[-1] = r1 / r0;
821 			opStack--;
822 			goto nextInstruction;
823 		case OP_DIVU:
824 			opStack[-1] = ((unsigned)r1) / ((unsigned)r0);
825 			opStack--;
826 			goto nextInstruction;
827 		case OP_MODI:
828 			opStack[-1] = r1 % r0;
829 			opStack--;
830 			goto nextInstruction;
831 		case OP_MODU:
832 			opStack[-1] = ((unsigned)r1) % (unsigned)r0;
833 			opStack--;
834 			goto nextInstruction;
835 		case OP_MULI:
836 			opStack[-1] = r1 * r0;
837 			opStack--;
838 			goto nextInstruction;
839 		case OP_MULU:
840 			opStack[-1] = ((unsigned)r1) * ((unsigned)r0);
841 			opStack--;
842 			goto nextInstruction;
843 
844 		case OP_BAND:
845 			opStack[-1] = ((unsigned)r1) & ((unsigned)r0);
846 			opStack--;
847 			goto nextInstruction;
848 		case OP_BOR:
849 			opStack[-1] = ((unsigned)r1) | ((unsigned)r0);
850 			opStack--;
851 			goto nextInstruction;
852 		case OP_BXOR:
853 			opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);
854 			opStack--;
855 			goto nextInstruction;
856 		case OP_BCOM:
857 			*opStack = ~ ((unsigned)r0);
858 			goto nextInstruction;
859 
860 		case OP_LSH:
861 			opStack[-1] = r1 << r0;
862 			opStack--;
863 			goto nextInstruction;
864 		case OP_RSHI:
865 			opStack[-1] = r1 >> r0;
866 			opStack--;
867 			goto nextInstruction;
868 		case OP_RSHU:
869 			opStack[-1] = ((unsigned)r1) >> r0;
870 			opStack--;
871 			goto nextInstruction;
872 
873 		case OP_NEGF:
874 			*(float *)opStack =  -*(float *)opStack;
875 			goto nextInstruction;
876 		case OP_ADDF:
877 			*(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;
878 			opStack--;
879 			goto nextInstruction;
880 		case OP_SUBF:
881 			*(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;
882 			opStack--;
883 			goto nextInstruction;
884 		case OP_DIVF:
885 			*(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;
886 			opStack--;
887 			goto nextInstruction;
888 		case OP_MULF:
889 			*(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;
890 			opStack--;
891 			goto nextInstruction;
892 
893 		case OP_CVIF:
894 			*(float *)opStack =  (float)*opStack;
895 			goto nextInstruction;
896 		case OP_CVFI:
897 			*opStack = (int) *(float *)opStack;
898 			goto nextInstruction;
899 		case OP_SEX8:
900 			*opStack = (signed char)*opStack;
901 			goto nextInstruction;
902 		case OP_SEX16:
903 			*opStack = (short)*opStack;
904 			goto nextInstruction;
905 		}
906 	}
907 
908 done:
909 	vm->currentlyInterpreting = qfalse;
910 
911 	if ( opStack != &stack[1] ) {
912 		Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) );
913 	}
914 
915 	vm->programStack = stackOnEntry;
916 
917 	// return the result
918 	return *opStack;
919 }
920