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 // vm_ppc.c
23 // ppc dynamic compiler
24
25 #include "vm_local.h"
26 #include <sys/mman.h>
27
28 #define DEBUG_VM 0
29
30 #if DEBUG_VM
31 static char *opnames[256] = {
32 "OP_UNDEF",
33
34 "OP_IGNORE",
35
36 "OP_BREAK",
37
38 "OP_ENTER",
39 "OP_LEAVE",
40 "OP_CALL",
41 "OP_PUSH",
42 "OP_POP",
43
44 "OP_CONST",
45
46 "OP_LOCAL",
47
48 "OP_JUMP",
49
50 //-------------------
51
52 "OP_EQ",
53 "OP_NE",
54
55 "OP_LTI",
56 "OP_LEI",
57 "OP_GTI",
58 "OP_GEI",
59
60 "OP_LTU",
61 "OP_LEU",
62 "OP_GTU",
63 "OP_GEU",
64
65 "OP_EQF",
66 "OP_NEF",
67
68 "OP_LTF",
69 "OP_LEF",
70 "OP_GTF",
71 "OP_GEF",
72
73 //-------------------
74
75 "OP_LOAD1",
76 "OP_LOAD2",
77 "OP_LOAD4",
78 "OP_STORE1",
79 "OP_STORE2",
80 "OP_STORE4",
81 "OP_ARG",
82
83 "OP_BLOCK_COPY",
84
85 //-------------------
86
87 "OP_SEX8",
88 "OP_SEX16",
89
90 "OP_NEGI",
91 "OP_ADD",
92 "OP_SUB",
93 "OP_DIVI",
94 "OP_DIVU",
95 "OP_MODI",
96 "OP_MODU",
97 "OP_MULI",
98 "OP_MULU",
99
100 "OP_BAND",
101 "OP_BOR",
102 "OP_BXOR",
103 "OP_BCOM",
104
105 "OP_LSH",
106 "OP_RSHI",
107 "OP_RSHU",
108
109 "OP_NEGF",
110 "OP_ADDF",
111 "OP_SUBF",
112 "OP_DIVF",
113 "OP_MULF",
114
115 "OP_CVIF",
116 "OP_CVFI"
117 };
118 #endif
119
120 typedef enum {
121 R_REAL_STACK = 1,
122 // registers 3-11 are the parameter passing registers
123
124 // state
125 R_STACK = 3, // local
126 R_OPSTACK, // global
127
128 // constants
129 R_MEMBASE, // global
130 R_MEMMASK,
131 R_ASMCALL, // global
132 R_INSTRUCTIONS, // global
133 R_NUM_INSTRUCTIONS, // global
134 R_CVM, // currentVM
135
136 // temps
137 R_TOP = 11,
138 R_SECOND = 12,
139 R_EA = 2 // effective address calculation
140
141 } regNums_t;
142
143 #define RG_REAL_STACK r1
144 #define RG_STACK r3
145 #define RG_OPSTACK r4
146 #define RG_MEMBASE r5
147 #define RG_MEMMASK r6
148 #define RG_ASMCALL r7
149 #define RG_INSTRUCTIONS r8
150 #define RG_NUM_INSTRUCTIONS r9
151 #define RG_CVM r10
152 #define RG_TOP r12
153 #define RG_SECOND r13
154 #define RG_EA r14
155
156 // The deepest value I saw in the Quake3 games was 9.
157 #define OP_STACK_MAX_DEPTH 16
158
159 // These are all volatile and thus must be saved upon entry to the VM code.
160 // NOTE: These are General Purpose Registers (GPR) numbers like the
161 // R_ definitions in the regNums_t enum above (31 is the max)
162 static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
163 {
164 16, 17, 18, 19,
165 20, 21, 22, 23,
166 24, 25, 26, 27,
167 28, 29, 30, 31
168 };
169
170 static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
171
172 // We use different registers for the floating point
173 // operand stack (these are volatile in the PPC ABI)
174 // NOTE: these are Floating Point Register (FPR) numbers, not
175 // General Purpose Register (GPR) numbers
176 static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
177 {
178 0, 1, 2, 3,
179 4, 5, 6, 7,
180 8, 9, 10, 11,
181 12, 13, 14, 15
182 };
183
184 static int opStackRegType[OP_STACK_MAX_DEPTH] =
185 {
186 0, 0, 0, 0,
187 0, 0, 0, 0,
188 0, 0, 0, 0,
189 0, 0, 0, 0
190 };
191
192 // this doesn't have the low order bits set for instructions i'm not using...
193 typedef enum {
194 PPC_TDI = 0x08000000,
195 PPC_TWI = 0x0c000000,
196 PPC_MULLI = 0x1c000000,
197 PPC_SUBFIC = 0x20000000,
198 PPC_CMPI = 0x28000000,
199 PPC_CMPLI = 0x2c000000,
200 PPC_ADDIC = 0x30000000,
201 PPC_ADDIC_ = 0x34000000,
202 PPC_ADDI = 0x38000000,
203 PPC_ADDIS = 0x3c000000,
204 PPC_BC = 0x40000000,
205 PPC_SC = 0x44000000,
206 PPC_B = 0x48000000,
207
208 PPC_MCRF = 0x4c000000,
209 PPC_BCLR = 0x4c000020,
210 PPC_RFID = 0x4c000000,
211 PPC_CRNOR = 0x4c000000,
212 PPC_RFI = 0x4c000000,
213 PPC_CRANDC = 0x4c000000,
214 PPC_ISYNC = 0x4c000000,
215 PPC_CRXOR = 0x4c000000,
216 PPC_CRNAND = 0x4c000000,
217 PPC_CREQV = 0x4c000000,
218 PPC_CRORC = 0x4c000000,
219 PPC_CROR = 0x4c000000,
220 //------------
221 PPC_BCCTR = 0x4c000420,
222 PPC_RLWIMI = 0x50000000,
223 PPC_RLWINM = 0x54000000,
224 PPC_RLWNM = 0x5c000000,
225 PPC_ORI = 0x60000000,
226 PPC_ORIS = 0x64000000,
227 PPC_XORI = 0x68000000,
228 PPC_XORIS = 0x6c000000,
229 PPC_ANDI_ = 0x70000000,
230 PPC_ANDIS_ = 0x74000000,
231 PPC_RLDICL = 0x78000000,
232 PPC_RLDICR = 0x78000000,
233 PPC_RLDIC = 0x78000000,
234 PPC_RLDIMI = 0x78000000,
235 PPC_RLDCL = 0x78000000,
236 PPC_RLDCR = 0x78000000,
237 PPC_CMP = 0x7c000000,
238 PPC_TW = 0x7c000000,
239 PPC_SUBFC = 0x7c000010,
240 PPC_MULHDU = 0x7c000000,
241 PPC_ADDC = 0x7c000014,
242 PPC_MULHWU = 0x7c000000,
243 PPC_MFCR = 0x7c000000,
244 PPC_LWAR = 0x7c000000,
245 PPC_LDX = 0x7c000000,
246 PPC_LWZX = 0x7c00002e,
247 PPC_SLW = 0x7c000030,
248 PPC_CNTLZW = 0x7c000000,
249 PPC_SLD = 0x7c000000,
250 PPC_AND = 0x7c000038,
251 PPC_CMPL = 0x7c000040,
252 PPC_SUBF = 0x7c000050,
253 PPC_LDUX = 0x7c000000,
254 //------------
255 PPC_DCBST = 0x7c000000,
256 PPC_LWZUX = 0x7c00006c,
257 PPC_CNTLZD = 0x7c000000,
258 PPC_ANDC = 0x7c000000,
259 PPC_TD = 0x7c000000,
260 PPC_MULHD = 0x7c000000,
261 PPC_MULHW = 0x7c000000,
262 PPC_MTSRD = 0x7c000000,
263 PPC_MFMSR = 0x7c000000,
264 PPC_LDARX = 0x7c000000,
265 PPC_DCBF = 0x7c000000,
266 PPC_LBZX = 0x7c0000ae,
267 PPC_NEG = 0x7c000000,
268 PPC_MTSRDIN = 0x7c000000,
269 PPC_LBZUX = 0x7c000000,
270 PPC_NOR = 0x7c0000f8,
271 PPC_SUBFE = 0x7c000000,
272 PPC_ADDE = 0x7c000000,
273 PPC_MTCRF = 0x7c000000,
274 PPC_MTMSR = 0x7c000000,
275 PPC_STDX = 0x7c000000,
276 PPC_STWCX_ = 0x7c000000,
277 PPC_STWX = 0x7c00012e,
278 PPC_MTMSRD = 0x7c000000,
279 PPC_STDUX = 0x7c000000,
280 PPC_STWUX = 0x7c00016e,
281 PPC_SUBFZE = 0x7c000000,
282 PPC_ADDZE = 0x7c000000,
283 PPC_MTSR = 0x7c000000,
284 PPC_STDCX_ = 0x7c000000,
285 PPC_STBX = 0x7c0001ae,
286 PPC_SUBFME = 0x7c000000,
287 PPC_MULLD = 0x7c000000,
288 //------------
289 PPC_ADDME = 0x7c000000,
290 PPC_MULLW = 0x7c0001d6,
291 PPC_MTSRIN = 0x7c000000,
292 PPC_DCBTST = 0x7c000000,
293 PPC_STBUX = 0x7c000000,
294 PPC_ADD = 0x7c000214,
295 PPC_DCBT = 0x7c000000,
296 PPC_LHZX = 0x7c00022e,
297 PPC_EQV = 0x7c000000,
298 PPC_TLBIE = 0x7c000000,
299 PPC_ECIWX = 0x7c000000,
300 PPC_LHZUX = 0x7c000000,
301 PPC_XOR = 0x7c000278,
302 PPC_MFSPR = 0x7c0002a6,
303 PPC_LWAX = 0x7c000000,
304 PPC_LHAX = 0x7c000000,
305 PPC_TLBIA = 0x7c000000,
306 PPC_MFTB = 0x7c000000,
307 PPC_LWAUX = 0x7c000000,
308 PPC_LHAUX = 0x7c000000,
309 PPC_STHX = 0x7c00032e,
310 PPC_ORC = 0x7c000338,
311 PPC_SRADI = 0x7c000000,
312 PPC_SLBIE = 0x7c000000,
313 PPC_ECOWX = 0x7c000000,
314 PPC_STHUX = 0x7c000000,
315 PPC_OR = 0x7c000378,
316 PPC_DIVDU = 0x7c000000,
317 PPC_DIVWU = 0x7c000396,
318 PPC_MTSPR = 0x7c0003a6,
319 PPC_DCBI = 0x7c000000,
320 PPC_NAND = 0x7c000000,
321 PPC_DIVD = 0x7c000000,
322 //------------
323 PPC_DIVW = 0x7c0003d6,
324 PPC_SLBIA = 0x7c000000,
325 PPC_MCRXR = 0x7c000000,
326 PPC_LSWX = 0x7c000000,
327 PPC_LWBRX = 0x7c000000,
328 PPC_LFSX = 0x7c00042e,
329 PPC_SRW = 0x7c000430,
330 PPC_SRD = 0x7c000000,
331 PPC_TLBSYNC = 0x7c000000,
332 PPC_LFSUX = 0x7c000000,
333 PPC_MFSR = 0x7c000000,
334 PPC_LSWI = 0x7c000000,
335 PPC_SYNC = 0x7c000000,
336 PPC_LFDX = 0x7c000000,
337 PPC_LFDUX = 0x7c000000,
338 PPC_MFSRIN = 0x7c000000,
339 PPC_STSWX = 0x7c000000,
340 PPC_STWBRX = 0x7c000000,
341 PPC_STFSX = 0x7c00052e,
342 PPC_STFSUX = 0x7c000000,
343 PPC_STSWI = 0x7c000000,
344 PPC_STFDX = 0x7c000000,
345 PPC_DCBA = 0x7c000000,
346 PPC_STFDUX = 0x7c000000,
347 PPC_LHBRX = 0x7c000000,
348 PPC_SRAW = 0x7c000630,
349 PPC_SRAD = 0x7c000000,
350 PPC_SRAWI = 0x7c000000,
351 PPC_EIEIO = 0x7c000000,
352 PPC_STHBRX = 0x7c000000,
353 PPC_EXTSH = 0x7c000734,
354 PPC_EXTSB = 0x7c000774,
355 PPC_ICBI = 0x7c000000,
356 //------------
357 PPC_STFIWX = 0x7c0007ae,
358 PPC_EXTSW = 0x7c000000,
359 PPC_DCBZ = 0x7c000000,
360 PPC_LWZ = 0x80000000,
361 PPC_LWZU = 0x84000000,
362 PPC_LBZ = 0x88000000,
363 PPC_LBZU = 0x8c000000,
364 PPC_STW = 0x90000000,
365 PPC_STWU = 0x94000000,
366 PPC_STB = 0x98000000,
367 PPC_STBU = 0x9c000000,
368 PPC_LHZ = 0xa0000000,
369 PPC_LHZU = 0xa4000000,
370 PPC_LHA = 0xa8000000,
371 PPC_LHAU = 0xac000000,
372 PPC_STH = 0xb0000000,
373 PPC_STHU = 0xb4000000,
374 PPC_LMW = 0xb8000000,
375 PPC_STMW = 0xbc000000,
376 PPC_LFS = 0xc0000000,
377 PPC_LFSU = 0xc4000000,
378 PPC_LFD = 0xc8000000,
379 PPC_LFDU = 0xcc000000,
380 PPC_STFS = 0xd0000000,
381 PPC_STFSU = 0xd4000000,
382 PPC_STFD = 0xd8000000,
383 PPC_STFDU = 0xdc000000,
384 PPC_LD = 0xe8000000,
385 PPC_LDU = 0xe8000001,
386 PPC_LWA = 0xe8000002,
387 PPC_FDIVS = 0xec000024,
388 PPC_FSUBS = 0xec000028,
389 PPC_FADDS = 0xec00002a,
390 //------------
391 PPC_FSQRTS = 0xec000000,
392 PPC_FRES = 0xec000000,
393 PPC_FMULS = 0xec000032,
394 PPC_FMSUBS = 0xec000000,
395 PPC_FMADDS = 0xec000000,
396 PPC_FNMSUBS = 0xec000000,
397 PPC_FNMADDS = 0xec000000,
398 PPC_STD = 0xf8000000,
399 PPC_STDU = 0xf8000001,
400 PPC_FCMPU = 0xfc000000,
401 PPC_FRSP = 0xfc000018,
402 PPC_FCTIW = 0xfc000000,
403 PPC_FCTIWZ = 0xfc00001e,
404 PPC_FDIV = 0xfc000000,
405 PPC_FSUB = 0xfc000028,
406 PPC_FADD = 0xfc000000,
407 PPC_FSQRT = 0xfc000000,
408 PPC_FSEL = 0xfc000000,
409 PPC_FMUL = 0xfc000000,
410 PPC_FRSQRTE = 0xfc000000,
411 PPC_FMSUB = 0xfc000000,
412 PPC_FMADD = 0xfc000000,
413 PPC_FNMSUB = 0xfc000000,
414 PPC_FNMADD = 0xfc000000,
415 PPC_FCMPO = 0xfc000000,
416 PPC_MTFSB1 = 0xfc000000,
417 PPC_FNEG = 0xfc000050,
418 PPC_MCRFS = 0xfc000000,
419 PPC_MTFSB0 = 0xfc000000,
420 PPC_FMR = 0xfc000000,
421 PPC_MTFSFI = 0xfc000000,
422 PPC_FNABS = 0xfc000000,
423 PPC_FABS = 0xfc000000,
424 //------------
425 PPC_MFFS = 0xfc000000,
426 PPC_MTFSF = 0xfc000000,
427 PPC_FCTID = 0xfc000000,
428 PPC_FCTIDZ = 0xfc000000,
429 PPC_FCFID = 0xfc000000
430
431 } ppcOpcodes_t;
432
433
434 // the newly generated code
435 static unsigned *buf;
436 static int compiledOfs; // in dwords
437 static int pass;
438
439 // fromt the original bytecode
440 static byte *code;
441 static int pc;
442
443 void AsmCall( void );
444
445 double itofConvert[2];
446
Constant4(void)447 static int Constant4( void ) {
448 int v;
449
450 v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
451 pc += 4;
452 return v;
453 }
454
Constant1(void)455 static int Constant1( void ) {
456 int v;
457
458 v = code[pc];
459 pc += 1;
460 return v;
461 }
462
Emit4(char * opname,int i)463 static void Emit4( char *opname, int i ) {
464 #if DEBUG_VM
465 if(pass == 1)
466 printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
467 #endif
468 buf[ compiledOfs ] = i;
469 compiledOfs++;
470 }
471
Inst(char * opname,int opcode,int destReg,int aReg,int bReg)472 static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
473 unsigned r;
474
475 #if DEBUG_VM
476 if(pass == 1)
477 printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
478 #endif
479 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
480 buf[ compiledOfs ] = r;
481 compiledOfs++;
482 }
483
Inst4(char * opname,int opcode,int destReg,int aReg,int bReg,int cReg)484 static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
485 unsigned r;
486
487 #if DEBUG_VM
488 if(pass == 1)
489 printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
490 #endif
491 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
492 buf[ compiledOfs ] = r;
493 compiledOfs++;
494 }
495
InstImm(char * opname,int opcode,int destReg,int aReg,int immediate)496 static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
497 unsigned r;
498
499 if ( immediate > 32767 || immediate < -32768 ) {
500 Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
501 }
502 #if DEBUG_VM
503 if(pass == 1)
504 printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
505 #endif
506 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
507 buf[ compiledOfs ] = r;
508 compiledOfs++;
509 }
510
InstImmU(char * opname,int opcode,int destReg,int aReg,int immediate)511 static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
512 unsigned r;
513
514 if ( immediate > 0xffff || immediate < 0 ) {
515 Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
516 }
517 #if DEBUG_VM
518 if(pass == 1)
519 printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
520 #endif
521 r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
522 buf[ compiledOfs ] = r;
523 compiledOfs++;
524 }
525
526 static int pop0, pop1, oc0, oc1;
527 static vm_t *tvm;
528 static int instruction;
529 static byte *jused;
530
spillOpStack(int depth)531 static void spillOpStack(int depth)
532 {
533 // Store out each register on the operand stack to it's correct location.
534 int i;
535
536 for(i = 0; i < depth; i++)
537 {
538 assert(opStackRegType[i]);
539 assert(opStackRegType[i] == 1);
540 switch(opStackRegType[i])
541 {
542 case 1: // Integer register
543 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
544 break;
545 case 2: // Float register
546 InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
547 break;
548 }
549 opStackRegType[i] = 0;
550 }
551 }
552
loadOpStack(int depth)553 static void loadOpStack(int depth)
554 {
555 // Back off operand stack pointer and reload all operands.
556 // InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 );
557
558 int i;
559
560 for(i = 0; i < depth; i++)
561 {
562 assert(opStackRegType[i] == 0);
563 // For now we're stuck reloading everything as an integer.
564 opStackLoadInstructionAddr[i] = &buf[compiledOfs];
565 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
566 opStackRegType[i] = 1;
567 }
568 }
569
makeFloat(int depth)570 static void makeFloat(int depth)
571 {
572 //assert(opStackRegType[depth] == 1);
573 if(opStackRegType[depth] == 1)
574 {
575 unsigned instruction;
576 unsigned destReg, aReg, bReg, imm;
577
578 if(opStackLoadInstructionAddr[depth])
579 {
580 // Repatch load instruction to use LFS instead of LWZ
581 instruction = *opStackLoadInstructionAddr[depth];
582 // Figure out if it's LWZ or LWZX
583 if((instruction & 0xfc000000) == PPC_LWZ)
584 {
585 //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
586 //printf("old instruction: %08lx\n",instruction);
587 // Extract registers
588 destReg = (instruction >> 21) & 31;
589 aReg = (instruction >> 16) & 31;
590 imm = instruction & 0xffff;
591
592 // Calculate correct FP register to use.
593 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
594 //printf("old dest: %ld\n",destReg);
595 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
596 instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;
597 //printf("new dest: %ld\n",destReg);
598 //printf("new instruction: %08lx\n",instruction);
599 }
600 else
601 {
602 //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
603 //printf("old instruction: %08lx\n",instruction);
604 // Extract registers
605 destReg = (instruction >> 21) & 31;
606 aReg = (instruction >> 16) & 31;
607 bReg = (instruction >> 11) & 31;
608 // Calculate correct FP register to use.
609 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
610 //printf("old dest: %ld\n",destReg);
611 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
612 instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
613 //printf("new dest: %ld\n",destReg);
614 //printf("new instruction: %08lx\n",instruction);
615 }
616 *opStackLoadInstructionAddr[depth] = instruction;
617 opStackLoadInstructionAddr[depth] = 0;
618 }
619 else
620 {
621 //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth);
622 // It was likely loaded as a constant so we have to save/load it. A more
623 // interesting implementation might be to generate code to do a "PC relative"
624 // load from the VM code region.
625 InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
626 // For XXX make sure we force enough NOPs to get the load into
627 // another dispatch group to avoid pipeline flush.
628 Inst( "ori", PPC_ORI, 0, 0, 0 );
629 Inst( "ori", PPC_ORI, 0, 0, 0 );
630 Inst( "ori", PPC_ORI, 0, 0, 0 );
631 Inst( "ori", PPC_ORI, 0, 0, 0 );
632 InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
633 }
634 opStackRegType[depth] = 2;
635 }
636 }
637
638 // TJW: Unused
639 #if 0
640 static void fltop() {
641 if (rtopped == qfalse) {
642 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
643 }
644 }
645 #endif
646
647 #if 0
648 static void fltopandsecond() {
649 InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
650 InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
651 InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
652 rtopped = qfalse;
653 return;
654 }
655 #endif
656
657 #define assertInteger(depth) assert(opStackRegType[depth] == 1)
658
659 /*
660 =================
661 VM_Compile
662 =================
663 */
VM_Compile(vm_t * vm,vmHeader_t * header)664 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
665 int op;
666 int maxLength;
667 int v;
668 int i;
669 int opStackDepth;
670
671 int mainFunction;
672
673 // set up the into-to-float variables
674 ((int *)itofConvert)[0] = 0x43300000;
675 ((int *)itofConvert)[1] = 0x80000000;
676 ((int *)itofConvert)[2] = 0x43300000;
677
678 // allocate a very large temp buffer, we will shrink it later
679 maxLength = header->codeLength * 8;
680 buf = Z_Malloc( maxLength );
681 jused = Z_Malloc(header->instructionCount + 2);
682 Com_Memset(jused, 0, header->instructionCount+2);
683
684 // compile everything twice, so the second pass will have valid instruction
685 // pointers for branches
686 for ( pass = -1 ; pass < 2 ; pass++ ) {
687
688 // translate all instructions
689 pc = 0;
690 mainFunction = 0;
691 opStackDepth = 0;
692
693 pop0 = 343545;
694 pop1 = 2443545;
695 oc0 = -2343535;
696 oc1 = 24353454;
697 tvm = vm;
698 code = (byte *)header + header->codeOffset;
699 compiledOfs = 0;
700 #ifndef __GNUC__
701 // metrowerks seems to require this header in front of functions
702 Emit4( (int)(buf+2) );
703 Emit4( 0 );
704 #endif
705
706 for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
707 if ( compiledOfs*4 > maxLength - 16 ) {
708 Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
709 }
710
711 op = code[ pc ];
712 if ( !pass ) {
713 vm->instructionPointers[ instruction ] = compiledOfs * 4;
714 }
715 pc++;
716 switch ( op ) {
717 case 0:
718 break;
719 case OP_BREAK:
720 #if DEBUG_VM
721 if(pass == 1)
722 printf("%08lx BREAK\n",instruction);
723 #endif
724 InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
725 InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
726 break;
727 case OP_ENTER:
728 opStackDepth = 0;
729 v = Constant4();
730 #if DEBUG_VM
731 if(pass == 1)
732 printf("%08x ENTER\t%04x\n",instruction,v);
733 #endif
734 opStackRegType[opStackDepth] = 0;
735 mainFunction++;
736 if(mainFunction == 1)
737 {
738 // Main VM entry point is the first thing we compile, so save off operand stack
739 // registers here. This avoids issues with trying to trick the native compiler
740 // into doing it, and properly matches the PowerPC ABI
741 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm
742 for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
743 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
744 }
745 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm
746 break;
747 case OP_CONST:
748 v = Constant4();
749 #if DEBUG_VM
750 if(pass == 1)
751 printf("%08x CONST\t%08x\n",instruction,v);
752 #endif
753 opStackLoadInstructionAddr[opStackDepth] = 0;
754 if ( v < 32768 && v >= -32768 ) {
755 InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
756 } else {
757 InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
758 if ( v & 0xffff ) {
759 InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
760 }
761 }
762 opStackRegType[opStackDepth] = 1;
763 opStackDepth += 1;
764 if (code[pc] == OP_JUMP) {
765 jused[v] = 1;
766 }
767 break;
768 case OP_LOCAL:
769 oc1 = Constant4();
770 #if DEBUG_VM
771 if(pass == 1)
772 printf("%08x LOCAL\t%08x\n",instruction,oc1);
773 #endif
774 if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
775 oc1 &= vm->dataMask;
776 }
777 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
778 opStackRegType[opStackDepth] = 1;
779 opStackLoadInstructionAddr[opStackDepth] = 0;
780 opStackDepth += 1;
781 break;
782 case OP_ARG:
783 v = Constant1();
784 #if DEBUG_VM
785 if(pass == 1)
786 printf("%08x ARG \t%08x\n",instruction,v);
787 #endif
788 InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it
789 if(opStackRegType[opStackDepth-1] == 1)
790 Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
791 else
792 Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
793 opStackRegType[opStackDepth-1] = 0;
794 opStackLoadInstructionAddr[opStackDepth-1] = 0;
795 opStackDepth -= 1;
796
797 break;
798 case OP_CALL:
799 #if DEBUG_VM
800 if(pass == 1)
801 printf("%08x CALL\n",instruction);
802 #endif
803 assertInteger(opStackDepth-1);
804 assert(opStackDepth > 0);
805 Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register
806 InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address
807
808 // Spill operand stack registers.
809 spillOpStack(opStackDepth);
810
811 // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address.
812 // It will be consumed (and R4 decremented) by the AsmCall code.
813 InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
814
815 Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register
816 Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register
817
818 // R4 now points to the top of the operand stack, which has the return value in it. We want to
819 // back off the pointer to point to the base of our local operand stack and then reload the stack.
820
821 InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
822
823 // Reload operand stack.
824 loadOpStack(opStackDepth);
825
826 InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address
827 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
828 Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register
829 break;
830 case OP_PUSH:
831 #if DEBUG_VM
832 if(pass == 1)
833 printf("%08x PUSH\n",instruction);
834 #endif
835 opStackRegType[opStackDepth] = 1; // Garbage int value.
836 opStackDepth += 1;
837 break;
838 case OP_POP:
839 #if DEBUG_VM
840 if(pass == 1)
841 printf("%08x POP\n",instruction);
842 #endif
843 opStackDepth -= 1;
844 opStackRegType[opStackDepth] = 0; // ??
845 opStackLoadInstructionAddr[opStackDepth-1] = 0;
846 break;
847 case OP_LEAVE:
848 #if DEBUG_VM
849 if(pass == 1)
850 printf("%08x LEAVE\n",instruction);
851 #endif
852 assert(opStackDepth == 1);
853 assert(opStackRegType[0] != 0);
854 // Save return value onto top of op stack. We also have to increment R_OPSTACK
855 switch(opStackRegType[0])
856 {
857 case 1: // Integer register
858 InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
859 break;
860 case 2: // Float register
861 InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
862 break;
863 }
864 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
865 if(mainFunction == 1)
866 {
867 for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
868 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4);
869 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );
870 }
871 opStackDepth--;
872 opStackRegType[opStackDepth] = 0;
873 opStackLoadInstructionAddr[opStackDepth] = 0;
874 Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register
875 break;
876 case OP_LOAD4:
877 #if DEBUG_VM
878 if(pass == 1)
879 printf("%08x LOAD4\n",instruction);
880 #endif
881 // We should try to figure out whether to use LWZX or LFSX based
882 // on some kind of code analysis after subsequent passes. I think what
883 // we could do is store the compiled load instruction address along with
884 // the register type. When we hit the first mismatched operator, we go back
885 // and patch the load. Since LCC's operand stack should be at 0 depth by the
886 // time we hit a branch, this should work fairly well. FIXME FIXME FIXME.
887 assertInteger(opStackDepth-1);
888 opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
889 Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
890 opStackRegType[opStackDepth-1] = 1;
891 break;
892 case OP_LOAD2:
893 #if DEBUG_VM
894 if(pass == 1)
895 printf("%08x LOAD2\n",instruction);
896 #endif
897 assertInteger(opStackDepth-1);
898 opStackLoadInstructionAddr[opStackDepth-1] = 0;
899 Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
900 opStackRegType[opStackDepth-1] = 1;
901 break;
902 case OP_LOAD1:
903 #if DEBUG_VM
904 if(pass == 1)
905 printf("%08x LOAD1\n",instruction);
906 #endif
907 assertInteger(opStackDepth-1);
908 opStackLoadInstructionAddr[opStackDepth-1] = 0;
909 Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
910 opStackRegType[opStackDepth-1] = 1;
911 break;
912 case OP_STORE4:
913 #if DEBUG_VM
914 if(pass == 1)
915 printf("%08x STORE4\n",instruction);
916 #endif
917 assertInteger(opStackDepth-2);
918 if(opStackRegType[opStackDepth-1] == 1)
919 Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1],
920 opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
921 else
922 Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1],
923 opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
924 opStackRegType[opStackDepth-1] = 0;
925 opStackRegType[opStackDepth-2] = 0;
926 opStackLoadInstructionAddr[opStackDepth-1] = 0;
927 opStackLoadInstructionAddr[opStackDepth-2] = 0;
928 opStackDepth -= 2;
929 break;
930 case OP_STORE2:
931 #if DEBUG_VM
932 if(pass == 1)
933 printf("%08x STORE2\n",instruction);
934 #endif
935 assertInteger(opStackDepth-1);
936 assertInteger(opStackDepth-2);
937 Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
938 opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
939 opStackRegType[opStackDepth-1] = 0;
940 opStackRegType[opStackDepth-2] = 0;
941 opStackLoadInstructionAddr[opStackDepth-1] = 0;
942 opStackLoadInstructionAddr[opStackDepth-2] = 0;
943 opStackDepth -= 2;
944 break;
945 case OP_STORE1:
946 #if DEBUG_VM
947 if(pass == 1)
948 printf("%08x STORE1\n",instruction);
949 #endif
950 assertInteger(opStackDepth-1);
951 assertInteger(opStackDepth-2);
952 Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
953 opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
954 opStackRegType[opStackDepth-1] = 0;
955 opStackRegType[opStackDepth-2] = 0;
956 opStackLoadInstructionAddr[opStackDepth-1] = 0;
957 opStackLoadInstructionAddr[opStackDepth-2] = 0;
958 opStackDepth -= 2;
959 break;
960
961 case OP_EQ:
962 #if DEBUG_VM
963 if(pass == 1)
964 printf("%08x EQ\n",instruction);
965 #endif
966 assertInteger(opStackDepth-1);
967 assertInteger(opStackDepth-2);
968 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
969 opStackRegType[opStackDepth-1] = 0;
970 opStackRegType[opStackDepth-2] = 0;
971 opStackLoadInstructionAddr[opStackDepth-1] = 0;
972 opStackLoadInstructionAddr[opStackDepth-2] = 0;
973 opStackDepth -= 2;
974 i = Constant4();
975 jused[i] = 1;
976 InstImm( "bc", PPC_BC, 4, 2, 8 );
977 if ( pass==1 ) {
978 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
979 } else {
980 v = 0;
981 }
982 Emit4("b", PPC_B | (v&0x3ffffff) );
983 break;
984 case OP_NE:
985 #if DEBUG_VM
986 if(pass == 1)
987 printf("%08x NE\n",instruction);
988 #endif
989 assertInteger(opStackDepth-1);
990 assertInteger(opStackDepth-2);
991 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
992 opStackRegType[opStackDepth-1] = 0;
993 opStackRegType[opStackDepth-2] = 0;
994 opStackLoadInstructionAddr[opStackDepth-1] = 0;
995 opStackLoadInstructionAddr[opStackDepth-2] = 0;
996 opStackDepth -= 2;
997 i = Constant4();
998 jused[i] = 1;
999 InstImm( "bc", PPC_BC, 12, 2, 8 );
1000 if ( pass==1 ) {
1001 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1002 } else {
1003 v = 0;
1004 }
1005 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1006 // InstImm( "bc", PPC_BC, 4, 2, v );
1007
1008 break;
1009 case OP_LTI:
1010 #if DEBUG_VM
1011 if(pass == 1)
1012 printf("%08x LTI\n",instruction);
1013 #endif
1014 assertInteger(opStackDepth-1);
1015 assertInteger(opStackDepth-2);
1016 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1017 opStackRegType[opStackDepth-1] = 0;
1018 opStackRegType[opStackDepth-2] = 0;
1019 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1020 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1021 opStackDepth -= 2;
1022 i = Constant4();
1023 jused[i] = 1;
1024 InstImm( "bc", PPC_BC, 4, 0, 8 );
1025 if ( pass==1 ) {
1026 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1027 } else {
1028 v = 0;
1029 }
1030 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1031 // InstImm( "bc", PPC_BC, 12, 0, v );
1032 break;
1033 case OP_LEI:
1034 #if DEBUG_VM
1035 if(pass == 1)
1036 printf("%08x LEI\n",instruction);
1037 #endif
1038 assertInteger(opStackDepth-1);
1039 assertInteger(opStackDepth-2);
1040 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1041 opStackRegType[opStackDepth-1] = 0;
1042 opStackRegType[opStackDepth-2] = 0;
1043 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1044 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1045 opStackDepth -= 2;
1046 i = Constant4();
1047 jused[i] = 1;
1048 InstImm( "bc", PPC_BC, 12, 1, 8 );
1049 if ( pass==1 ) {
1050 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1051 } else {
1052 v = 0;
1053 }
1054 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1055 // InstImm( "bc", PPC_BC, 4, 1, v );
1056 break;
1057 case OP_GTI:
1058 #if DEBUG_VM
1059 if(pass == 1)
1060 printf("%08x GTI\n",instruction);
1061 #endif
1062 assertInteger(opStackDepth-1);
1063 assertInteger(opStackDepth-2);
1064 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1065 opStackRegType[opStackDepth-1] = 0;
1066 opStackRegType[opStackDepth-2] = 0;
1067 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1068 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1069 opStackDepth -= 2;
1070 i = Constant4();
1071 jused[i] = 1;
1072 InstImm( "bc", PPC_BC, 4, 1, 8 );
1073 if ( pass==1 ) {
1074 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1075 } else {
1076 v = 0;
1077 }
1078 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1079 // InstImm( "bc", PPC_BC, 12, 1, v );
1080 break;
1081 case OP_GEI:
1082 #if DEBUG_VM
1083 if(pass == 1)
1084 printf("%08x GEI\n",instruction);
1085 #endif
1086 assertInteger(opStackDepth-1);
1087 assertInteger(opStackDepth-2);
1088 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1089 opStackRegType[opStackDepth-1] = 0;
1090 opStackRegType[opStackDepth-2] = 0;
1091 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1092 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1093 opStackDepth -= 2;
1094 i = Constant4();
1095 jused[i] = 1;
1096 InstImm( "bc", PPC_BC, 12, 0, 8 );
1097 if ( pass==1 ) {
1098 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1099 } else {
1100 v = 0;
1101 }
1102 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1103 // InstImm( "bc", PPC_BC, 4, 0, v );
1104 break;
1105 case OP_LTU:
1106 #if DEBUG_VM
1107 if(pass == 1)
1108 printf("%08x LTU\n",instruction);
1109 #endif
1110 assertInteger(opStackDepth-1);
1111 assertInteger(opStackDepth-2);
1112 Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1113 opStackRegType[opStackDepth-1] = 0;
1114 opStackRegType[opStackDepth-2] = 0;
1115 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1116 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1117 opStackDepth -= 2;
1118 i = Constant4();
1119 jused[i] = 1;
1120 InstImm( "bc", PPC_BC, 4, 0, 8 );
1121 if ( pass==1 ) {
1122 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1123 } else {
1124 v = 0;
1125 }
1126 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1127 // InstImm( "bc", PPC_BC, 12, 0, v );
1128 break;
1129 case OP_LEU:
1130 #if DEBUG_VM
1131 if(pass == 1)
1132 printf("%08x LEU\n",instruction);
1133 #endif
1134 assertInteger(opStackDepth-1);
1135 assertInteger(opStackDepth-2);
1136 Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1137 opStackRegType[opStackDepth-1] = 0;
1138 opStackRegType[opStackDepth-2] = 0;
1139 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1140 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1141 opStackDepth -= 2;
1142 i = Constant4();
1143 jused[i] = 1;
1144 InstImm( "bc", PPC_BC, 12, 1, 8 );
1145 if ( pass==1 ) {
1146 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1147 } else {
1148 v = 0;
1149 }
1150 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1151 // InstImm( "bc", PPC_BC, 4, 1, v );
1152 break;
1153 case OP_GTU:
1154 #if DEBUG_VM
1155 if(pass == 1)
1156 printf("%08x GTU\n",instruction);
1157 #endif
1158 assertInteger(opStackDepth-1);
1159 assertInteger(opStackDepth-2);
1160 Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1161 opStackRegType[opStackDepth-1] = 0;
1162 opStackRegType[opStackDepth-2] = 0;
1163 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1164 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1165 opStackDepth -= 2;
1166 i = Constant4();
1167 jused[i] = 1;
1168 InstImm( "bc", PPC_BC, 4, 1, 8 );
1169 if ( pass==1 ) {
1170 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1171 } else {
1172 v = 0;
1173 }
1174 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1175 // InstImm( "bc", PPC_BC, 12, 1, v );
1176 break;
1177 case OP_GEU:
1178 #if DEBUG_VM
1179 if(pass == 1)
1180 printf("%08x GEU\n",instruction);
1181 #endif
1182 assertInteger(opStackDepth-1);
1183 assertInteger(opStackDepth-2);
1184 Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1185 opStackRegType[opStackDepth-1] = 0;
1186 opStackRegType[opStackDepth-2] = 0;
1187 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1188 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1189 opStackDepth -= 2;
1190 i = Constant4();
1191 jused[i] = 1;
1192 InstImm( "bc", PPC_BC, 12, 0, 8 );
1193 if ( pass==1 ) {
1194 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1195 } else {
1196 v = 0;
1197 }
1198 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1199 // InstImm( "bc", PPC_BC, 4, 0, v );
1200 break;
1201
1202 case OP_EQF:
1203 #if DEBUG_VM
1204 if(pass == 1)
1205 printf("%08x EQF\n",instruction);
1206 #endif
1207 makeFloat(opStackDepth-1);
1208 makeFloat(opStackDepth-2);
1209 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1210 opStackRegType[opStackDepth-1] = 0;
1211 opStackRegType[opStackDepth-2] = 0;
1212 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1213 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1214 opStackDepth -= 2;
1215 i = Constant4();
1216 jused[i] = 1;
1217 InstImm( "bc", PPC_BC, 4, 2, 8 );
1218 if ( pass==1 ) {
1219 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1220 } else {
1221 v = 0;
1222 }
1223 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1224 // InstImm( "bc", PPC_BC, 12, 2, v );
1225 break;
1226 case OP_NEF:
1227 #if DEBUG_VM
1228 if(pass == 1)
1229 printf("%08x NEF\n",instruction);
1230 #endif
1231 makeFloat(opStackDepth-1);
1232 makeFloat(opStackDepth-2);
1233 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1234 opStackRegType[opStackDepth-1] = 0;
1235 opStackRegType[opStackDepth-2] = 0;
1236 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1237 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1238 opStackDepth -= 2;
1239 i = Constant4();
1240 jused[i] = 1;
1241 InstImm( "bc", PPC_BC, 12, 2, 8 );
1242 if ( pass==1 ) {
1243 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1244 } else {
1245 v = 0;
1246 }
1247 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1248 // InstImm( "bc", PPC_BC, 4, 2, v );
1249 break;
1250 case OP_LTF:
1251 #if DEBUG_VM
1252 if(pass == 1)
1253 printf("%08x LTF\n",instruction);
1254 #endif
1255 makeFloat(opStackDepth-1);
1256 makeFloat(opStackDepth-2);
1257 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1258 opStackRegType[opStackDepth-1] = 0;
1259 opStackRegType[opStackDepth-2] = 0;
1260 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1261 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1262 opStackDepth -= 2;
1263 i = Constant4();
1264 jused[i] = 1;
1265 InstImm( "bc", PPC_BC, 4, 0, 8 );
1266 if ( pass==1 ) {
1267 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1268 } else {
1269 v = 0;
1270 }
1271 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1272 // InstImm( "bc", PPC_BC, 12, 0, v );
1273 break;
1274 case OP_LEF:
1275 #if DEBUG_VM
1276 if(pass == 1)
1277 printf("%08x LEF\n",instruction);
1278 #endif
1279 makeFloat(opStackDepth-1);
1280 makeFloat(opStackDepth-2);
1281 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1282 opStackRegType[opStackDepth-1] = 0;
1283 opStackRegType[opStackDepth-2] = 0;
1284 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1285 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1286 opStackDepth -= 2;
1287 i = Constant4();
1288 jused[i] = 1;
1289 InstImm( "bc", PPC_BC, 12, 1, 8 );
1290 if ( pass==1 ) {
1291 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1292 } else {
1293 v = 0;
1294 }
1295 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1296 // InstImm( "bc", PPC_BC, 4, 1, v );
1297 break;
1298 case OP_GTF:
1299 #if DEBUG_VM
1300 if(pass == 1)
1301 printf("%08x GTF\n",instruction);
1302 #endif
1303 makeFloat(opStackDepth-1);
1304 makeFloat(opStackDepth-2);
1305 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1306 opStackRegType[opStackDepth-1] = 0;
1307 opStackRegType[opStackDepth-2] = 0;
1308 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1309 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1310 opStackDepth -= 2;
1311 i = Constant4();
1312 jused[i] = 1;
1313 InstImm( "bc", PPC_BC, 4, 1, 8 );
1314 if ( pass==1 ) {
1315 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1316 } else {
1317 v = 0;
1318 }
1319 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1320 // InstImm( "bc", PPC_BC, 12, 1, v );
1321 break;
1322 case OP_GEF:
1323 #if DEBUG_VM
1324 if(pass == 1)
1325 printf("%08x GEF\n",instruction);
1326 #endif
1327 makeFloat(opStackDepth-1);
1328 makeFloat(opStackDepth-2);
1329 Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1330 opStackRegType[opStackDepth-1] = 0;
1331 opStackRegType[opStackDepth-2] = 0;
1332 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1333 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1334 opStackDepth -= 2;
1335 i = Constant4();
1336 jused[i] = 1;
1337 InstImm( "bc", PPC_BC, 12, 0, 8 );
1338 if ( pass==1 ) {
1339 v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1340 } else {
1341 v = 0;
1342 }
1343 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1344 // InstImm( "bc", PPC_BC, 4, 0, v );
1345 break;
1346
1347 case OP_NEGI:
1348 #if DEBUG_VM
1349 if(pass == 1)
1350 printf("%08x NEGI\n",instruction);
1351 #endif
1352 assertInteger(opStackDepth-1);
1353 InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1354 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1355 break;
1356 case OP_ADD:
1357 #if DEBUG_VM
1358 if(pass == 1)
1359 printf("%08x ADD\n",instruction);
1360 #endif
1361 assertInteger(opStackDepth-1);
1362 assertInteger(opStackDepth-2);
1363 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1364 opStackRegType[opStackDepth-1] = 0;
1365 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1366 opStackDepth -= 1;
1367 break;
1368 case OP_SUB:
1369 #if DEBUG_VM
1370 if(pass == 1)
1371 printf("%08x SUB\n",instruction);
1372 #endif
1373 assertInteger(opStackDepth-1);
1374 assertInteger(opStackDepth-2);
1375 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1376 opStackRegType[opStackDepth-1] = 0;
1377 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1378 opStackDepth -= 1;
1379 break;
1380 case OP_DIVI:
1381 #if DEBUG_VM
1382 if(pass == 1)
1383 printf("%08x DIVI\n",instruction);
1384 #endif
1385 assertInteger(opStackDepth-1);
1386 assertInteger(opStackDepth-2);
1387 Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1388 opStackRegType[opStackDepth-1] = 0;
1389 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1390 opStackDepth -= 1;
1391 break;
1392 case OP_DIVU:
1393 #if DEBUG_VM
1394 if(pass == 1)
1395 printf("%08x DIVU\n",instruction);
1396 #endif
1397 assertInteger(opStackDepth-1);
1398 assertInteger(opStackDepth-2);
1399 Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1400 opStackRegType[opStackDepth-1] = 0;
1401 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1402 opStackDepth -= 1;
1403 break;
1404 case OP_MODI:
1405 #if DEBUG_VM
1406 if(pass == 1)
1407 printf("%08x MODI\n",instruction);
1408 #endif
1409 assertInteger(opStackDepth-1);
1410 assertInteger(opStackDepth-2);
1411 Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1412 Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
1413 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
1414 opStackRegType[opStackDepth-1] = 0;
1415 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1416 opStackDepth -= 1;
1417 break;
1418 case OP_MODU:
1419 #if DEBUG_VM
1420 if(pass == 1)
1421 printf("%08x MODU\n",instruction);
1422 #endif
1423 assertInteger(opStackDepth-1);
1424 assertInteger(opStackDepth-2);
1425 Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1426 Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
1427 Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
1428 opStackRegType[opStackDepth-1] = 0;
1429 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1430 opStackDepth -= 1;
1431 break;
1432 case OP_MULI:
1433 case OP_MULU:
1434 #if DEBUG_VM
1435 if(pass == 1)
1436 printf("%08x MULI\n",instruction);
1437 #endif
1438 assertInteger(opStackDepth-1);
1439 assertInteger(opStackDepth-2);
1440 Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1441 opStackRegType[opStackDepth-1] = 0;
1442 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1443 opStackDepth -= 1;
1444 break;
1445 case OP_BAND:
1446 #if DEBUG_VM
1447 if(pass == 1)
1448 printf("%08x BAND\n",instruction);
1449 #endif
1450 assertInteger(opStackDepth-1);
1451 assertInteger(opStackDepth-2);
1452 Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1453 opStackRegType[opStackDepth-1] = 0;
1454 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1455 opStackDepth -= 1;
1456 break;
1457 case OP_BOR:
1458 #if DEBUG_VM
1459 if(pass == 1)
1460 printf("%08x BOR\n",instruction);
1461 #endif
1462 assertInteger(opStackDepth-1);
1463 assertInteger(opStackDepth-2);
1464 Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1465 opStackRegType[opStackDepth-1] = 0;
1466 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1467 opStackDepth -= 1;
1468 break;
1469 case OP_BXOR:
1470 #if DEBUG_VM
1471 if(pass == 1)
1472 printf("%08x BXOR\n",instruction);
1473 #endif
1474 assertInteger(opStackDepth-1);
1475 assertInteger(opStackDepth-2);
1476 Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1477 opStackRegType[opStackDepth-1] = 0;
1478 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1479 opStackDepth -= 1;
1480 break;
1481 case OP_BCOM:
1482 #if DEBUG_VM
1483 if(pass == 1)
1484 printf("%08x BCOM\n",instruction);
1485 #endif
1486 assertInteger(opStackDepth-1);
1487 Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] );
1488 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1489 break;
1490 case OP_LSH:
1491 #if DEBUG_VM
1492 if(pass == 1)
1493 printf("%08x LSH\n",instruction);
1494 #endif
1495 assertInteger(opStackDepth-1);
1496 assertInteger(opStackDepth-2);
1497 Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1498 opStackRegType[opStackDepth-1] = 0;
1499 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1500 opStackDepth -= 1;
1501 break;
1502 case OP_RSHI:
1503 #if DEBUG_VM
1504 if(pass == 1)
1505 printf("%08x RSHI\n",instruction);
1506 #endif
1507 assertInteger(opStackDepth-1);
1508 assertInteger(opStackDepth-2);
1509 Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1510 opStackRegType[opStackDepth-1] = 0;
1511 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1512 opStackDepth -= 1;
1513 break;
1514 case OP_RSHU:
1515 #if DEBUG_VM
1516 if(pass == 1)
1517 printf("%08x RSHU\n",instruction);
1518 #endif
1519 assertInteger(opStackDepth-1);
1520 assertInteger(opStackDepth-2);
1521 Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1522 opStackRegType[opStackDepth-1] = 0;
1523 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1524 opStackDepth -= 1;
1525 break;
1526
1527 case OP_NEGF:
1528 #if DEBUG_VM
1529 if(pass == 1)
1530 printf("%08x NEGF\n",instruction);
1531 #endif
1532 makeFloat(opStackDepth-1);
1533 Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
1534 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1535 break;
1536 case OP_ADDF:
1537 #if DEBUG_VM
1538 if(pass == 1)
1539 printf("%08x ADDF\n",instruction);
1540 #endif
1541 makeFloat(opStackDepth-1);
1542 makeFloat(opStackDepth-2);
1543 Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1544 opStackRegType[opStackDepth-1] = 0;
1545 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1546 opStackDepth -= 1;
1547 break;
1548 case OP_SUBF:
1549 #if DEBUG_VM
1550 if(pass == 1)
1551 printf("%08x SUBF\n",instruction);
1552 #endif
1553 makeFloat(opStackDepth-1);
1554 makeFloat(opStackDepth-2);
1555 Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1556 opStackRegType[opStackDepth-1] = 0;
1557 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1558 opStackDepth -= 1;
1559 break;
1560 case OP_DIVF:
1561 #if DEBUG_VM
1562 if(pass == 1)
1563 printf("%08x DIVF\n",instruction);
1564 #endif
1565 makeFloat(opStackDepth-1);
1566 makeFloat(opStackDepth-2);
1567 Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1568 opStackRegType[opStackDepth-1] = 0;
1569 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1570 opStackDepth -= 1;
1571 break;
1572 case OP_MULF:
1573 #if DEBUG_VM
1574 if(pass == 1)
1575 printf("%08x MULF\n",instruction);
1576 #endif
1577 makeFloat(opStackDepth-1);
1578 makeFloat(opStackDepth-2);
1579 Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] );
1580 opStackRegType[opStackDepth-1] = 0;
1581 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1582 opStackDepth -= 1;
1583 break;
1584
1585 case OP_CVIF:
1586 #if DEBUG_VM
1587 if(pass == 1)
1588 printf("%08x CVIF\n",instruction);
1589 #endif
1590 assertInteger(opStackDepth-1);
1591 //makeInteger(opStackDepth-1);
1592 v = (int)&itofConvert;
1593 InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
1594 InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff );
1595 InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 );
1596 InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 );
1597 InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 );
1598 Inst( "ori", PPC_ORI, 0, 0, 0);
1599 Inst( "ori", PPC_ORI, 0, 0, 0);
1600 Inst( "ori", PPC_ORI, 0, 0, 0);
1601 InstImm( "lfd", PPC_LFD, 13, R_EA, 8 );
1602 Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] );
1603 opStackRegType[opStackDepth-1] = 2;
1604 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1605 // Inst( PPC_FRSP, R_TOP, 0, R_TOP );
1606 break;
1607 case OP_CVFI:
1608 #if DEBUG_VM
1609 if(pass == 1)
1610 printf("%08x CVFI\n",instruction);
1611 #endif
1612 makeFloat(opStackDepth-1);
1613
1614 InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
1615
1616 Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
1617 Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now)
1618 Inst( "ori", PPC_ORI, 0, 0, 0);
1619 Inst( "ori", PPC_ORI, 0, 0, 0);
1620 Inst( "ori", PPC_ORI, 0, 0, 0);
1621 Inst( "ori", PPC_ORI, 0, 0, 0);
1622 InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 );
1623
1624 InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
1625
1626 opStackRegType[opStackDepth-1] = 1;
1627 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1628 break;
1629 case OP_SEX8:
1630 #if DEBUG_VM
1631 if(pass == 1)
1632 printf("%08x SEX8\n",instruction);
1633 #endif
1634 assertInteger(opStackDepth-1);
1635 Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1636 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1637 break;
1638 case OP_SEX16:
1639 #if DEBUG_VM
1640 if(pass == 1)
1641 printf("%08x SEX16\n",instruction);
1642 #endif
1643 assertInteger(opStackDepth-1);
1644 Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1645 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1646 break;
1647
1648 case OP_BLOCK_COPY:
1649 v = Constant4() >> 2;
1650 #if DEBUG_VM
1651 if(pass == 1)
1652 printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2);
1653 #endif
1654 assert(opStackDepth >= 2);
1655 assertInteger(opStackDepth-1);
1656 assertInteger(opStackDepth-2);
1657 InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count
1658 // FIXME: range check
1659 Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register
1660
1661 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
1662 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 );
1663 Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE );
1664 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 );
1665
1666 InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source
1667 InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest
1668 Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop
1669 opStackRegType[opStackDepth-1] = 0;
1670 opStackRegType[opStackDepth-2] = 0;
1671 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1672 opStackLoadInstructionAddr[opStackDepth-2] = 0;
1673 opStackDepth -= 2;
1674 break;
1675
1676 case OP_JUMP:
1677 #if DEBUG_VM
1678 if(pass == 1)
1679 printf("%08x JUMP\n",instruction);
1680 #endif
1681 assert(opStackDepth == 1);
1682 assertInteger(opStackDepth-1);
1683
1684 Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 );
1685 // FIXME: range check
1686 Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS );
1687 Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register
1688 Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register
1689 opStackRegType[opStackDepth-1] = 0;
1690 opStackLoadInstructionAddr[opStackDepth-1] = 0;
1691 opStackDepth -= 1;
1692 break;
1693 default:
1694 Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
1695 }
1696 pop0 = pop1;
1697 pop1 = op;
1698 assert(opStackDepth >= 0);
1699 assert(opStackDepth < OP_STACK_MAX_DEPTH);
1700
1701 //printf("%4d\t%s\n",opStackDepth,opnames[op]);
1702 }
1703
1704 Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
1705
1706 if ( pass == 0 ) {
1707 // copy to an exact size buffer on the hunk
1708 vm->codeLength = compiledOfs * 4;
1709 vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
1710 Com_Memcpy( vm->codeBase, buf, vm->codeLength );
1711
1712 //printf("codeBase: %p\n",vm->codeBase);
1713
1714 Z_Free( buf );
1715
1716 // offset all the instruction pointers for the new location
1717 for ( i = 0 ; i < header->instructionCount ; i++ ) {
1718 vm->instructionPointers[i] += (int)vm->codeBase;
1719 //printf("%08x %08lx\n",i,vm->instructionPointers[i]);
1720 }
1721
1722 // go back over it in place now to fixup reletive jump targets
1723 buf = (unsigned *)vm->codeBase;
1724 } else if ( pass == 1 ) {
1725 // clear the instruction cache for generated code
1726 msync(vm->codeBase, vm->codeLength, MS_INVALIDATE);
1727 }
1728 }
1729 if(0)
1730 {
1731 char buf[256];
1732 printf("wait..\n");
1733 gets(buf);
1734 }
1735 Z_Free( jused );
1736 }
1737
1738 /*
1739 ==============
1740 VM_CallCompiled
1741
1742 This function is called directly by the generated code
1743 ==============
1744 */
VM_CallCompiled(vm_t * vm,int * args)1745 int VM_CallCompiled( vm_t *vm, int *args ) {
1746 int stack[1024];
1747 int programStack;
1748 int stackOnEntry;
1749 byte *image;
1750
1751 currentVM = vm;
1752
1753 //printf("VM_CallCompiled: %p %08lx %08lx %08lx\n",
1754 // vm, args[0],args[1],args[2]);
1755
1756 // interpret the code
1757 vm->currentlyInterpreting = qtrue;
1758
1759 // we might be called recursively, so this might not be the very top
1760 programStack = vm->programStack;
1761 stackOnEntry = programStack;
1762 image = vm->dataBase;
1763
1764 // set up the stack frame
1765 programStack -= 48;
1766
1767 *(int *)&image[ programStack + 44] = args[9];
1768 *(int *)&image[ programStack + 40] = args[8];
1769 *(int *)&image[ programStack + 36] = args[7];
1770 *(int *)&image[ programStack + 32] = args[6];
1771 *(int *)&image[ programStack + 28] = args[5];
1772 *(int *)&image[ programStack + 24] = args[4];
1773 *(int *)&image[ programStack + 20] = args[3];
1774 *(int *)&image[ programStack + 16] = args[2];
1775 *(int *)&image[ programStack + 12] = args[1];
1776 *(int *)&image[ programStack + 8 ] = args[0];
1777 *(int *)&image[ programStack + 4 ] = 0; // return stack
1778 *(int *)&image[ programStack ] = -1; // will terminate the loop on return
1779
1780 // Cheesy... manually save registers used by VM call...
1781 // off we go into generated code...
1782 // the PPC calling standard says the parms will all go into R3 - R11, so
1783 // no special asm code is needed here
1784 #ifdef __GNUC__
1785 ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1786 programStack, (int)&stack,
1787 (int)image, vm->dataMask, (int)&AsmCall,
1788 (int)vm->instructionPointers, vm->instructionPointersLength,
1789 (int)vm );
1790 #else
1791 ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1792 programStack, (int)&stack,
1793 (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */,
1794 (int)vm->instructionPointers, vm->instructionPointersLength,
1795 (int)vm );
1796 #endif
1797 vm->programStack = stackOnEntry;
1798
1799 vm->currentlyInterpreting = qfalse;
1800
1801 return stack[1];
1802 }
1803
1804
1805 /*
1806 ==================
1807 AsmCall
1808
1809 Put this at end of file because gcc messes up debug line numbers
1810 ==================
1811 */
1812 #ifdef __GNUC__
1813
AsmCall(void)1814 void AsmCall( void ) {
1815 asm (
1816 // pop off the destination instruction
1817 " lwz 12,0(4) \n" // RG_TOP, 0(RG_OPSTACK)
1818 " addi 4,4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
1819
1820 // see if it is a system trap
1821 " cmpwi 12,0 \n" // RG_TOP, 0 \n"
1822 " bc 12,0, systemTrap \n"
1823
1824 // calling another VM function, so lookup in instructionPointers
1825 " slwi 12,12,2 \n" // RG_TOP,RG_TOP,2
1826 // FIXME: range check
1827 " lwzx 12, 8, 12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1828 " mtctr 12 \n" // RG_TOP
1829 );
1830
1831 #if defined(MACOS_X) && defined(__OPTIMIZE__)
1832 // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
1833 //#warning Mac OS X optimization on, not popping GCC AsmCall frame
1834 #else
1835 // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
1836 asm (
1837 " lwz 1,0(1) \n" // pop off the GCC AsmCall frame
1838 " lmw 30,-8(1) \n"
1839 );
1840 #endif
1841
1842 asm (
1843 " bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register
1844
1845 // calling a system trap
1846 "systemTrap: \n"
1847 // convert to positive system call number
1848 " subfic 12,12,-1 \n"
1849
1850 // save all our registers, including the current link register
1851 " mflr 13 \n" // RG_SECOND // copy off our link register
1852 " addi 1,1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1853 " stw 3,56(1) \n" // RG_STACK, -36(REAL_STACK)
1854 " stw 4,60(1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1855 " stw 5,64(1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1856 " stw 6,68(1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1857 " stw 7,72(1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1858 " stw 8,76(1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1859 " stw 9,80(1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1860 " stw 10,84(1) \n" // RG_VM, 28(RG_REAL_STACK)
1861 " stw 13,88(1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
1862
1863 // save the vm stack position to allow recursive VM entry
1864 " addi 13,3,-4 \n" // RG_TOP, RG_STACK, -4
1865 " stw 13,0(10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1866
1867 // save the system call number as the 0th parameter
1868 " add 3,3,5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1869 " stwu 12,4(3) \n" // RG_TOP, 4(r3)
1870
1871 // make the system call with the address of all the VM parms as a parameter
1872 // vm->systemCalls( &parms )
1873 " lwz 12,4(10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
1874 " mtctr 12 \n" // RG_TOP
1875 " bcctrl 20,0 \n"
1876 " mr 12,3 \n" // RG_TOP, r3
1877
1878 // pop our saved registers
1879 " lwz 3,56(1) \n" // RG_STACK, 0(RG_REAL_STACK)
1880 " lwz 4,60(1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1881 " lwz 5,64(1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1882 " lwz 6,68(1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1883 " lwz 7,72(1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1884 " lwz 8,76(1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1885 " lwz 9,80(1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1886 " lwz 10,84(1) \n" // RG_VM, 28(RG_REAL_STACK)
1887 " lwz 13,88(1) \n" // RG_SECOND, 32(RG_REAL_STACK)
1888 " addi 1,1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36
1889
1890 // restore the old link register
1891 " mtlr 13 \n" // RG_SECOND
1892
1893 // save off the return value
1894 " stwu 12,4(4) \n" // RG_TOP, 0(RG_OPSTACK)
1895
1896 // GCC adds its own prolog / epliog code
1897 );
1898 }
1899 #else
1900
1901 // codewarrior version
1902
AsmCall(void)1903 void asm AsmCall( void ) {
1904
1905 // pop off the destination instruction
1906
1907 lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK)
1908
1909 addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4
1910
1911
1912
1913 // see if it is a system trap
1914
1915 cmpwi r12,0 // RG_TOP, 0
1916
1917 bc 12,0, systemTrap
1918
1919
1920
1921 // calling another VM function, so lookup in instructionPointers
1922
1923 slwi r12,r12,2 // RG_TOP,RG_TOP,2
1924
1925 // FIXME: range check
1926
1927 lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1928
1929 mtctr r12 // RG_TOP
1930
1931
1932
1933 bcctr 20,0 // when it hits a leave, it will branch to the current link register
1934
1935
1936
1937 // calling a system trap
1938
1939 systemTrap:
1940
1941 // convert to positive system call number
1942
1943 subfic r12,r12,-1
1944
1945
1946
1947 // save all our registers, including the current link register
1948
1949 mflr r13 // RG_SECOND // copy off our link register
1950
1951 addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1952
1953 stw r3,56(r1) // RG_STACK, -36(REAL_STACK)
1954
1955 stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
1956
1957 stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
1958
1959 stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
1960
1961 stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
1962
1963 stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1964
1965 stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1966
1967 stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
1968
1969 stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register
1970
1971
1972
1973 // save the vm stack position to allow recursive VM entry
1974
1975 addi r13,r3,-4 // RG_TOP, RG_STACK, -4
1976
1977 stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1978
1979
1980
1981 // save the system call number as the 0th parameter
1982
1983 add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1984
1985 stwu r12,4(r3) // RG_TOP, 4(r3)
1986
1987
1988
1989 // make the system call with the address of all the VM parms as a parameter
1990
1991 // vm->systemCalls( &parms )
1992
1993 lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
1994
1995
1996
1997 // perform macos cross fragment fixup crap
1998
1999 lwz r9,0(r12)
2000
2001 stw r2,52(r1) // save old TOC
2002
2003 lwz r2,4(r12)
2004
2005
2006
2007 mtctr r9 // RG_TOP
2008
2009 bcctrl 20,0
2010
2011
2012
2013 lwz r2,52(r1) // restore TOC
2014
2015
2016
2017 mr r12,r3 // RG_TOP, r3
2018
2019
2020
2021 // pop our saved registers
2022
2023 lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK)
2024
2025 lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
2026
2027 lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
2028
2029 lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
2030
2031 lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
2032
2033 lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
2034
2035 lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
2036
2037 lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
2038
2039 lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK)
2040
2041 addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36
2042
2043
2044
2045 // restore the old link register
2046
2047 mtlr r13 // RG_SECOND
2048
2049
2050
2051 // save off the return value
2052
2053 stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK)
2054
2055
2056
2057 blr
2058
2059 }
2060
2061
2062
2063
2064 #endif
2065