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