2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
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.
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.
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
===========================================================================
23
// ppc dynamic compiler
28
#include <CoreServices/CoreServices.h>
34
static char *opnames[256] = {
125
// registers 3-11 are the parameter passing registers
128
R_STACK = 3, // local
135
R_INSTRUCTIONS, // global
136
R_NUM_INSTRUCTIONS, // global
142
R_EA = 2 // effective address calculation
146
#define RG_REAL_STACK r1
148
#define RG_OPSTACK r4
149
#define RG_MEMBASE r5
150
#define RG_MEMMASK r6
151
#define RG_ASMCALL r7
152
#define RG_INSTRUCTIONS r8
153
#define RG_NUM_INSTRUCTIONS r9
156
#define RG_SECOND r13
159
// The deepest value I saw in the Quake3 games was 9.
160
#define OP_STACK_MAX_DEPTH 16
162
// These are all volatile and thus must be saved upon entry to the VM code.
163
// NOTE: These are General Purpose Registers (GPR) numbers like the
164
// R_ definitions in the regNums_t enum above (31 is the max)
165
static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
173
static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
175
// We use different registers for the floating point
176
// operand stack (these are volatile in the PPC ABI)
177
// NOTE: these are Floating Point Register (FPR) numbers, not
178
// General Purpose Register (GPR) numbers
179
static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
187
static int opStackRegType[OP_STACK_MAX_DEPTH] =
195
// this doesn't have the low order bits set for instructions i'm not using...
197
PPC_TDI = 0x08000000,
198
PPC_TWI = 0x0c000000,
199
PPC_MULLI = 0x1c000000,
200
PPC_SUBFIC = 0x20000000,
201
PPC_CMPI = 0x28000000,
202
PPC_CMPLI = 0x2c000000,
203
PPC_ADDIC = 0x30000000,
204
PPC_ADDIC_ = 0x34000000,
205
PPC_ADDI = 0x38000000,
206
PPC_ADDIS = 0x3c000000,
211
PPC_MCRF = 0x4c000000,
212
PPC_BCLR = 0x4c000020,
213
PPC_RFID = 0x4c000000,
214
PPC_CRNOR = 0x4c000000,
215
PPC_RFI = 0x4c000000,
216
PPC_CRANDC = 0x4c000000,
217
PPC_ISYNC = 0x4c000000,
218
PPC_CRXOR = 0x4c000000,
219
PPC_CRNAND = 0x4c000000,
220
PPC_CREQV = 0x4c000000,
221
PPC_CRORC = 0x4c000000,
222
PPC_CROR = 0x4c000000,
224
PPC_BCCTR = 0x4c000420,
225
PPC_RLWIMI = 0x50000000,
226
PPC_RLWINM = 0x54000000,
227
PPC_RLWNM = 0x5c000000,
228
PPC_ORI = 0x60000000,
229
PPC_ORIS = 0x64000000,
230
PPC_XORI = 0x68000000,
231
PPC_XORIS = 0x6c000000,
232
PPC_ANDI_ = 0x70000000,
233
PPC_ANDIS_ = 0x74000000,
234
PPC_RLDICL = 0x78000000,
235
PPC_RLDICR = 0x78000000,
236
PPC_RLDIC = 0x78000000,
237
PPC_RLDIMI = 0x78000000,
238
PPC_RLDCL = 0x78000000,
239
PPC_RLDCR = 0x78000000,
240
PPC_CMP = 0x7c000000,
242
PPC_SUBFC = 0x7c000010,
243
PPC_MULHDU = 0x7c000000,
244
PPC_ADDC = 0x7c000014,
245
PPC_MULHWU = 0x7c000000,
246
PPC_MFCR = 0x7c000000,
247
PPC_LWAR = 0x7c000000,
248
PPC_LDX = 0x7c000000,
249
PPC_LWZX = 0x7c00002e,
250
PPC_SLW = 0x7c000030,
251
PPC_CNTLZW = 0x7c000000,
252
PPC_SLD = 0x7c000000,
253
PPC_AND = 0x7c000038,
254
PPC_CMPL = 0x7c000040,
255
PPC_SUBF = 0x7c000050,
256
PPC_LDUX = 0x7c000000,
258
PPC_DCBST = 0x7c000000,
259
PPC_LWZUX = 0x7c00006c,
260
PPC_CNTLZD = 0x7c000000,
261
PPC_ANDC = 0x7c000000,
263
PPC_MULHD = 0x7c000000,
264
PPC_MULHW = 0x7c000000,
265
PPC_MTSRD = 0x7c000000,
266
PPC_MFMSR = 0x7c000000,
267
PPC_LDARX = 0x7c000000,
268
PPC_DCBF = 0x7c000000,
269
PPC_LBZX = 0x7c0000ae,
270
PPC_NEG = 0x7c000000,
271
PPC_MTSRDIN = 0x7c000000,
272
PPC_LBZUX = 0x7c000000,
273
PPC_NOR = 0x7c0000f8,
274
PPC_SUBFE = 0x7c000000,
275
PPC_ADDE = 0x7c000000,
276
PPC_MTCRF = 0x7c000000,
277
PPC_MTMSR = 0x7c000000,
278
PPC_STDX = 0x7c000000,
279
PPC_STWCX_ = 0x7c000000,
280
PPC_STWX = 0x7c00012e,
281
PPC_MTMSRD = 0x7c000000,
282
PPC_STDUX = 0x7c000000,
283
PPC_STWUX = 0x7c00016e,
284
PPC_SUBFZE = 0x7c000000,
285
PPC_ADDZE = 0x7c000000,
286
PPC_MTSR = 0x7c000000,
287
PPC_STDCX_ = 0x7c000000,
288
PPC_STBX = 0x7c0001ae,
289
PPC_SUBFME = 0x7c000000,
290
PPC_MULLD = 0x7c000000,
292
PPC_ADDME = 0x7c000000,
293
PPC_MULLW = 0x7c0001d6,
294
PPC_MTSRIN = 0x7c000000,
295
PPC_DCBTST = 0x7c000000,
296
PPC_STBUX = 0x7c000000,
297
PPC_ADD = 0x7c000214,
298
PPC_DCBT = 0x7c000000,
299
PPC_LHZX = 0x7c00022e,
300
PPC_EQV = 0x7c000000,
301
PPC_TLBIE = 0x7c000000,
302
PPC_ECIWX = 0x7c000000,
303
PPC_LHZUX = 0x7c000000,
304
PPC_XOR = 0x7c000278,
305
PPC_MFSPR = 0x7c0002a6,
306
PPC_LWAX = 0x7c000000,
307
PPC_LHAX = 0x7c000000,
308
PPC_TLBIA = 0x7c000000,
309
PPC_MFTB = 0x7c000000,
310
PPC_LWAUX = 0x7c000000,
311
PPC_LHAUX = 0x7c000000,
312
PPC_STHX = 0x7c00032e,
313
PPC_ORC = 0x7c000338,
314
PPC_SRADI = 0x7c000000,
315
PPC_SLBIE = 0x7c000000,
316
PPC_ECOWX = 0x7c000000,
317
PPC_STHUX = 0x7c000000,
319
PPC_DIVDU = 0x7c000000,
320
PPC_DIVWU = 0x7c000396,
321
PPC_MTSPR = 0x7c0003a6,
322
PPC_DCBI = 0x7c000000,
323
PPC_NAND = 0x7c000000,
324
PPC_DIVD = 0x7c000000,
326
PPC_DIVW = 0x7c0003d6,
327
PPC_SLBIA = 0x7c000000,
328
PPC_MCRXR = 0x7c000000,
329
PPC_LSWX = 0x7c000000,
330
PPC_LWBRX = 0x7c000000,
331
PPC_LFSX = 0x7c00042e,
332
PPC_SRW = 0x7c000430,
333
PPC_SRD = 0x7c000000,
334
PPC_TLBSYNC = 0x7c000000,
335
PPC_LFSUX = 0x7c000000,
336
PPC_MFSR = 0x7c000000,
337
PPC_LSWI = 0x7c000000,
338
PPC_SYNC = 0x7c000000,
339
PPC_LFDX = 0x7c000000,
340
PPC_LFDUX = 0x7c000000,
341
PPC_MFSRIN = 0x7c000000,
342
PPC_STSWX = 0x7c000000,
343
PPC_STWBRX = 0x7c000000,
344
PPC_STFSX = 0x7c00052e,
345
PPC_STFSUX = 0x7c000000,
346
PPC_STSWI = 0x7c000000,
347
PPC_STFDX = 0x7c000000,
348
PPC_DCBA = 0x7c000000,
349
PPC_STFDUX = 0x7c000000,
350
PPC_LHBRX = 0x7c000000,
351
PPC_SRAW = 0x7c000630,
352
PPC_SRAD = 0x7c000000,
353
PPC_SRAWI = 0x7c000000,
354
PPC_EIEIO = 0x7c000000,
355
PPC_STHBRX = 0x7c000000,
356
PPC_EXTSH = 0x7c000734,
357
PPC_EXTSB = 0x7c000774,
358
PPC_ICBI = 0x7c000000,
360
PPC_STFIWX = 0x7c0007ae,
361
PPC_EXTSW = 0x7c000000,
362
PPC_DCBZ = 0x7c000000,
363
PPC_LWZ = 0x80000000,
364
PPC_LWZU = 0x84000000,
365
PPC_LBZ = 0x88000000,
366
PPC_LBZU = 0x8c000000,
367
PPC_STW = 0x90000000,
368
PPC_STWU = 0x94000000,
369
PPC_STB = 0x98000000,
370
PPC_STBU = 0x9c000000,
371
PPC_LHZ = 0xa0000000,
372
PPC_LHZU = 0xa4000000,
373
PPC_LHA = 0xa8000000,
374
PPC_LHAU = 0xac000000,
375
PPC_STH = 0xb0000000,
376
PPC_STHU = 0xb4000000,
377
PPC_LMW = 0xb8000000,
378
PPC_STMW = 0xbc000000,
379
PPC_LFS = 0xc0000000,
380
PPC_LFSU = 0xc4000000,
381
PPC_LFD = 0xc8000000,
382
PPC_LFDU = 0xcc000000,
383
PPC_STFS = 0xd0000000,
384
PPC_STFSU = 0xd4000000,
385
PPC_STFD = 0xd8000000,
386
PPC_STFDU = 0xdc000000,
388
PPC_LDU = 0xe8000001,
389
PPC_LWA = 0xe8000002,
390
PPC_FDIVS = 0xec000024,
391
PPC_FSUBS = 0xec000028,
392
PPC_FADDS = 0xec00002a,
394
PPC_FSQRTS = 0xec000000,
395
PPC_FRES = 0xec000000,
396
PPC_FMULS = 0xec000032,
397
PPC_FMSUBS = 0xec000000,
398
PPC_FMADDS = 0xec000000,
399
PPC_FNMSUBS = 0xec000000,
400
PPC_FNMADDS = 0xec000000,
401
PPC_STD = 0xf8000000,
402
PPC_STDU = 0xf8000001,
403
PPC_FCMPU = 0xfc000000,
404
PPC_FRSP = 0xfc000018,
405
PPC_FCTIW = 0xfc000000,
406
PPC_FCTIWZ = 0xfc00001e,
407
PPC_FDIV = 0xfc000000,
408
PPC_FSUB = 0xfc000028,
409
PPC_FADD = 0xfc000000,
410
PPC_FSQRT = 0xfc000000,
411
PPC_FSEL = 0xfc000000,
412
PPC_FMUL = 0xfc000000,
413
PPC_FRSQRTE = 0xfc000000,
414
PPC_FMSUB = 0xfc000000,
415
PPC_FMADD = 0xfc000000,
416
PPC_FNMSUB = 0xfc000000,
417
PPC_FNMADD = 0xfc000000,
418
PPC_FCMPO = 0xfc000000,
419
PPC_MTFSB1 = 0xfc000000,
420
PPC_FNEG = 0xfc000050,
421
PPC_MCRFS = 0xfc000000,
422
PPC_MTFSB0 = 0xfc000000,
423
PPC_FMR = 0xfc000000,
424
PPC_MTFSFI = 0xfc000000,
425
PPC_FNABS = 0xfc000000,
426
PPC_FABS = 0xfc000000,
428
PPC_MFFS = 0xfc000000,
429
PPC_MTFSF = 0xfc000000,
430
PPC_FCTID = 0xfc000000,
431
PPC_FCTIDZ = 0xfc000000,
432
PPC_FCFID = 0xfc000000
437
// the newly generated code
438
static unsigned *buf;
439
static int compiledOfs; // in dwords
442
// fromt the original bytecode
446
void AsmCall( void );
448
double itofConvert[2];
450
static int Constant4( void ) {
453
v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
458
static int Constant1( void ) {
466
static void Emit4( char *opname, int i ) {
469
printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
471
buf[ compiledOfs ] = i;
475
static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
480
printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
482
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
483
buf[ compiledOfs ] = r;
487
static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
492
printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
494
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
495
buf[ compiledOfs ] = r;
499
static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
502
if ( immediate > 32767 || immediate < -32768 ) {
503
Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
507
printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
509
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
510
buf[ compiledOfs ] = r;
514
static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
517
if ( immediate > 0xffff || immediate < 0 ) {
518
Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
522
printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
524
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
525
buf[ compiledOfs ] = r;
529
static int pop0, pop1, oc0, oc1;
531
static int instruction;
534
static void spillOpStack(int depth)
536
// Store out each register on the operand stack to it's correct location.
539
for(i = 0; i < depth; i++)
541
assert(opStackRegType[i]);
542
assert(opStackRegType[i] == 1);
543
switch(opStackRegType[i])
545
case 1: // Integer register
546
InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
548
case 2: // Float register
549
InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
552
opStackRegType[i] = 0;
556
static void loadOpStack(int depth)
558
// Back off operand stack pointer and reload all operands.
559
// InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 );
563
for(i = 0; i < depth; i++)
565
assert(opStackRegType[i] == 0);
566
// For now we're stuck reloading everything as an integer.
567
opStackLoadInstructionAddr[i] = &buf[compiledOfs];
568
InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
569
opStackRegType[i] = 1;
573
static void makeFloat(int depth)
575
//assert(opStackRegType[depth] == 1);
576
if(opStackRegType[depth] == 1)
578
unsigned instruction;
579
unsigned destReg, aReg, bReg, imm;
581
if(opStackLoadInstructionAddr[depth])
583
// Repatch load instruction to use LFS instead of LWZ
584
instruction = *opStackLoadInstructionAddr[depth];
585
// Figure out if it's LWZ or LWZX
586
if((instruction & 0xfc000000) == PPC_LWZ)
588
//printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
589
//printf("old instruction: %08lx\n",instruction);
591
destReg = (instruction >> 21) & 31;
592
aReg = (instruction >> 16) & 31;
593
imm = instruction & 0xffff;
595
// Calculate correct FP register to use.
596
// THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
597
//printf("old dest: %ld\n",destReg);
598
destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
599
instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;
600
//printf("new dest: %ld\n",destReg);
601
//printf("new instruction: %08lx\n",instruction);
605
//printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
606
//printf("old instruction: %08lx\n",instruction);
608
destReg = (instruction >> 21) & 31;
609
aReg = (instruction >> 16) & 31;
610
bReg = (instruction >> 11) & 31;
611
// Calculate correct FP register to use.
612
// THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
613
//printf("old dest: %ld\n",destReg);
614
destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
615
instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
616
//printf("new dest: %ld\n",destReg);
617
//printf("new instruction: %08lx\n",instruction);
619
*opStackLoadInstructionAddr[depth] = instruction;
620
opStackLoadInstructionAddr[depth] = 0;
624
//printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth);
625
// It was likely loaded as a constant so we have to save/load it. A more
626
// interesting implementation might be to generate code to do a "PC relative"
627
// load from the VM code region.
628
InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
629
// For XXX make sure we force enough NOPs to get the load into
630
// another dispatch group to avoid pipeline flush.
631
Inst( "ori", PPC_ORI, 0, 0, 0 );
632
Inst( "ori", PPC_ORI, 0, 0, 0 );
633
Inst( "ori", PPC_ORI, 0, 0, 0 );
634
Inst( "ori", PPC_ORI, 0, 0, 0 );
635
InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
637
opStackRegType[depth] = 2;
643
static void fltop() {
644
if (rtopped == qfalse) {
645
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
651
static void fltopandsecond() {
652
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
653
InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
654
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
660
#define assertInteger(depth) assert(opStackRegType[depth] == 1)
667
void VM_Compile( vm_t *vm, vmHeader_t *header ) {
676
// set up the into-to-float variables
677
((int *)itofConvert)[0] = 0x43300000;
678
((int *)itofConvert)[1] = 0x80000000;
679
((int *)itofConvert)[2] = 0x43300000;
681
// allocate a very large temp buffer, we will shrink it later
682
maxLength = header->codeLength * 8;
683
buf = Z_Malloc( maxLength );
684
jused = Z_Malloc(header->instructionCount + 2);
685
Com_Memset(jused, 0, header->instructionCount+2);
687
// compile everything twice, so the second pass will have valid instruction
688
// pointers for branches
689
for ( pass = -1 ; pass < 2 ; pass++ ) {
691
// translate all instructions
701
code = (byte *)header + header->codeOffset;
704
// metrowerks seems to require this header in front of functions
705
Emit4( (int)(buf+2) );
709
for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
710
if ( compiledOfs*4 > maxLength - 16 ) {
711
Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
716
vm->instructionPointers[ instruction ] = compiledOfs * 4;
725
printf("%08lx BREAK\n",instruction);
727
InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
728
InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
735
printf("%08x ENTER\t%04x\n",instruction,v);
737
opStackRegType[opStackDepth] = 0;
739
if(mainFunction == 1)
741
// Main VM entry point is the first thing we compile, so save off operand stack
742
// registers here. This avoids issues with trying to trick the native compiler
743
// into doing it, and properly matches the PowerPC ABI
744
InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm
745
for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
746
InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
748
InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm
754
printf("%08x CONST\t%08x\n",instruction,v);
756
opStackLoadInstructionAddr[opStackDepth] = 0;
757
if ( v < 32768 && v >= -32768 ) {
758
InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
760
InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
762
InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
765
opStackRegType[opStackDepth] = 1;
767
if (code[pc] == OP_JUMP) {
775
printf("%08x LOCAL\t%08x\n",instruction,oc1);
777
if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
780
InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
781
opStackRegType[opStackDepth] = 1;
782
opStackLoadInstructionAddr[opStackDepth] = 0;
789
printf("%08x ARG \t%08x\n",instruction,v);
791
InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it
792
if(opStackRegType[opStackDepth-1] == 1)
793
Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
795
Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
796
opStackRegType[opStackDepth-1] = 0;
797
opStackLoadInstructionAddr[opStackDepth-1] = 0;
804
printf("%08x CALL\n",instruction);
806
assertInteger(opStackDepth-1);
807
assert(opStackDepth > 0);
808
Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register
809
InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address
811
// Spill operand stack registers.
812
spillOpStack(opStackDepth);
814
// We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address.
815
// It will be consumed (and R4 decremented) by the AsmCall code.
816
InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
818
Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register
819
Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register
821
// R4 now points to the top of the operand stack, which has the return value in it. We want to
822
// back off the pointer to point to the base of our local operand stack and then reload the stack.
824
InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
826
// Reload operand stack.
827
loadOpStack(opStackDepth);
829
InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address
830
InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
831
Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register
836
printf("%08x PUSH\n",instruction);
838
opStackRegType[opStackDepth] = 1; // Garbage int value.
844
printf("%08x POP\n",instruction);
847
opStackRegType[opStackDepth] = 0; // ??
848
opStackLoadInstructionAddr[opStackDepth-1] = 0;
853
printf("%08x LEAVE\n",instruction);
855
assert(opStackDepth == 1);
856
assert(opStackRegType[0] != 0);
857
// Save return value onto top of op stack. We also have to increment R_OPSTACK
858
switch(opStackRegType[0])
860
case 1: // Integer register
861
InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
863
case 2: // Float register
864
InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
867
InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
868
if(mainFunction == 1)
870
for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
871
InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4);
872
InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );
875
opStackRegType[opStackDepth] = 0;
876
opStackLoadInstructionAddr[opStackDepth] = 0;
877
Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register
882
printf("%08x LOAD4\n",instruction);
884
// We should try to figure out whether to use LWZX or LFSX based
885
// on some kind of code analysis after subsequent passes. I think what
886
// we could do is store the compiled load instruction address along with
887
// the register type. When we hit the first mismatched operator, we go back
888
// and patch the load. Since LCC's operand stack should be at 0 depth by the
889
// time we hit a branch, this should work fairly well. FIXME FIXME FIXME.
890
assertInteger(opStackDepth-1);
891
opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
892
Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
893
opStackRegType[opStackDepth-1] = 1;
898
printf("%08x LOAD2\n",instruction);
900
assertInteger(opStackDepth-1);
901
opStackLoadInstructionAddr[opStackDepth-1] = 0;
902
Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
903
opStackRegType[opStackDepth-1] = 1;
908
printf("%08x LOAD1\n",instruction);
910
assertInteger(opStackDepth-1);
911
opStackLoadInstructionAddr[opStackDepth-1] = 0;
912
Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
913
opStackRegType[opStackDepth-1] = 1;
918
printf("%08x STORE4\n",instruction);
920
assertInteger(opStackDepth-2);
921
if(opStackRegType[opStackDepth-1] == 1)
922
Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1],
923
opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
925
Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1],
926
opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
927
opStackRegType[opStackDepth-1] = 0;
928
opStackRegType[opStackDepth-2] = 0;
929
opStackLoadInstructionAddr[opStackDepth-1] = 0;
930
opStackLoadInstructionAddr[opStackDepth-2] = 0;
936
printf("%08x STORE2\n",instruction);
938
assertInteger(opStackDepth-1);
939
assertInteger(opStackDepth-2);
940
Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
941
opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
942
opStackRegType[opStackDepth-1] = 0;
943
opStackRegType[opStackDepth-2] = 0;
944
opStackLoadInstructionAddr[opStackDepth-1] = 0;
945
opStackLoadInstructionAddr[opStackDepth-2] = 0;
951
printf("%08x STORE1\n",instruction);
953
assertInteger(opStackDepth-1);
954
assertInteger(opStackDepth-2);
955
Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
956
opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base
957
opStackRegType[opStackDepth-1] = 0;
958
opStackRegType[opStackDepth-2] = 0;
959
opStackLoadInstructionAddr[opStackDepth-1] = 0;
960
opStackLoadInstructionAddr[opStackDepth-2] = 0;
967
printf("%08x EQ\n",instruction);
969
assertInteger(opStackDepth-1);
970
assertInteger(opStackDepth-2);
971
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
972
opStackRegType[opStackDepth-1] = 0;
973
opStackRegType[opStackDepth-2] = 0;
974
opStackLoadInstructionAddr[opStackDepth-1] = 0;
975
opStackLoadInstructionAddr[opStackDepth-2] = 0;
979
InstImm( "bc", PPC_BC, 4, 2, 8 );
981
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
985
Emit4("b", PPC_B | (v&0x3ffffff) );
990
printf("%08x NE\n",instruction);
992
assertInteger(opStackDepth-1);
993
assertInteger(opStackDepth-2);
994
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
995
opStackRegType[opStackDepth-1] = 0;
996
opStackRegType[opStackDepth-2] = 0;
997
opStackLoadInstructionAddr[opStackDepth-1] = 0;
998
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1002
InstImm( "bc", PPC_BC, 12, 2, 8 );
1004
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1008
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1009
// InstImm( "bc", PPC_BC, 4, 2, v );
1015
printf("%08x LTI\n",instruction);
1017
assertInteger(opStackDepth-1);
1018
assertInteger(opStackDepth-2);
1019
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1020
opStackRegType[opStackDepth-1] = 0;
1021
opStackRegType[opStackDepth-2] = 0;
1022
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1023
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1027
InstImm( "bc", PPC_BC, 4, 0, 8 );
1029
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1033
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1034
// InstImm( "bc", PPC_BC, 12, 0, v );
1039
printf("%08x LEI\n",instruction);
1041
assertInteger(opStackDepth-1);
1042
assertInteger(opStackDepth-2);
1043
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1044
opStackRegType[opStackDepth-1] = 0;
1045
opStackRegType[opStackDepth-2] = 0;
1046
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1047
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1051
InstImm( "bc", PPC_BC, 12, 1, 8 );
1053
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1057
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1058
// InstImm( "bc", PPC_BC, 4, 1, v );
1063
printf("%08x GTI\n",instruction);
1065
assertInteger(opStackDepth-1);
1066
assertInteger(opStackDepth-2);
1067
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1068
opStackRegType[opStackDepth-1] = 0;
1069
opStackRegType[opStackDepth-2] = 0;
1070
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1071
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1075
InstImm( "bc", PPC_BC, 4, 1, 8 );
1077
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1081
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1082
// InstImm( "bc", PPC_BC, 12, 1, v );
1087
printf("%08x GEI\n",instruction);
1089
assertInteger(opStackDepth-1);
1090
assertInteger(opStackDepth-2);
1091
Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1092
opStackRegType[opStackDepth-1] = 0;
1093
opStackRegType[opStackDepth-2] = 0;
1094
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1095
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1099
InstImm( "bc", PPC_BC, 12, 0, 8 );
1101
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1105
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1106
// InstImm( "bc", PPC_BC, 4, 0, v );
1111
printf("%08x LTU\n",instruction);
1113
assertInteger(opStackDepth-1);
1114
assertInteger(opStackDepth-2);
1115
Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1116
opStackRegType[opStackDepth-1] = 0;
1117
opStackRegType[opStackDepth-2] = 0;
1118
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1119
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1123
InstImm( "bc", PPC_BC, 4, 0, 8 );
1125
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1129
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1130
// InstImm( "bc", PPC_BC, 12, 0, v );
1135
printf("%08x LEU\n",instruction);
1137
assertInteger(opStackDepth-1);
1138
assertInteger(opStackDepth-2);
1139
Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1140
opStackRegType[opStackDepth-1] = 0;
1141
opStackRegType[opStackDepth-2] = 0;
1142
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1143
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1147
InstImm( "bc", PPC_BC, 12, 1, 8 );
1149
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1153
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1154
// InstImm( "bc", PPC_BC, 4, 1, v );
1159
printf("%08x GTU\n",instruction);
1161
assertInteger(opStackDepth-1);
1162
assertInteger(opStackDepth-2);
1163
Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1164
opStackRegType[opStackDepth-1] = 0;
1165
opStackRegType[opStackDepth-2] = 0;
1166
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1167
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1171
InstImm( "bc", PPC_BC, 4, 1, 8 );
1173
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1177
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1178
// InstImm( "bc", PPC_BC, 12, 1, v );
1183
printf("%08x GEU\n",instruction);
1185
assertInteger(opStackDepth-1);
1186
assertInteger(opStackDepth-2);
1187
Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1188
opStackRegType[opStackDepth-1] = 0;
1189
opStackRegType[opStackDepth-2] = 0;
1190
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1191
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1195
InstImm( "bc", PPC_BC, 12, 0, 8 );
1197
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1201
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1202
// InstImm( "bc", PPC_BC, 4, 0, v );
1208
printf("%08x EQF\n",instruction);
1210
makeFloat(opStackDepth-1);
1211
makeFloat(opStackDepth-2);
1212
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1213
opStackRegType[opStackDepth-1] = 0;
1214
opStackRegType[opStackDepth-2] = 0;
1215
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1216
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1220
InstImm( "bc", PPC_BC, 4, 2, 8 );
1222
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1226
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1227
// InstImm( "bc", PPC_BC, 12, 2, v );
1232
printf("%08x NEF\n",instruction);
1234
makeFloat(opStackDepth-1);
1235
makeFloat(opStackDepth-2);
1236
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1237
opStackRegType[opStackDepth-1] = 0;
1238
opStackRegType[opStackDepth-2] = 0;
1239
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1240
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1244
InstImm( "bc", PPC_BC, 12, 2, 8 );
1246
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1250
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1251
// InstImm( "bc", PPC_BC, 4, 2, v );
1256
printf("%08x LTF\n",instruction);
1258
makeFloat(opStackDepth-1);
1259
makeFloat(opStackDepth-2);
1260
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1261
opStackRegType[opStackDepth-1] = 0;
1262
opStackRegType[opStackDepth-2] = 0;
1263
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1264
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1268
InstImm( "bc", PPC_BC, 4, 0, 8 );
1270
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1274
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1275
// InstImm( "bc", PPC_BC, 12, 0, v );
1280
printf("%08x LEF\n",instruction);
1282
makeFloat(opStackDepth-1);
1283
makeFloat(opStackDepth-2);
1284
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1285
opStackRegType[opStackDepth-1] = 0;
1286
opStackRegType[opStackDepth-2] = 0;
1287
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1288
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1292
InstImm( "bc", PPC_BC, 12, 1, 8 );
1294
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1298
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1299
// InstImm( "bc", PPC_BC, 4, 1, v );
1304
printf("%08x GTF\n",instruction);
1306
makeFloat(opStackDepth-1);
1307
makeFloat(opStackDepth-2);
1308
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1309
opStackRegType[opStackDepth-1] = 0;
1310
opStackRegType[opStackDepth-2] = 0;
1311
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1312
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1316
InstImm( "bc", PPC_BC, 4, 1, 8 );
1318
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1322
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1323
// InstImm( "bc", PPC_BC, 12, 1, v );
1328
printf("%08x GEF\n",instruction);
1330
makeFloat(opStackDepth-1);
1331
makeFloat(opStackDepth-2);
1332
Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1333
opStackRegType[opStackDepth-1] = 0;
1334
opStackRegType[opStackDepth-2] = 0;
1335
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1336
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1340
InstImm( "bc", PPC_BC, 12, 0, 8 );
1342
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
1346
Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
1347
// InstImm( "bc", PPC_BC, 4, 0, v );
1353
printf("%08x NEGI\n",instruction);
1355
assertInteger(opStackDepth-1);
1356
InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1357
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1362
printf("%08x ADD\n",instruction);
1364
assertInteger(opStackDepth-1);
1365
assertInteger(opStackDepth-2);
1366
Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1367
opStackRegType[opStackDepth-1] = 0;
1368
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1374
printf("%08x SUB\n",instruction);
1376
assertInteger(opStackDepth-1);
1377
assertInteger(opStackDepth-2);
1378
Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1379
opStackRegType[opStackDepth-1] = 0;
1380
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1386
printf("%08x DIVI\n",instruction);
1388
assertInteger(opStackDepth-1);
1389
assertInteger(opStackDepth-2);
1390
Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1391
opStackRegType[opStackDepth-1] = 0;
1392
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1398
printf("%08x DIVU\n",instruction);
1400
assertInteger(opStackDepth-1);
1401
assertInteger(opStackDepth-2);
1402
Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1403
opStackRegType[opStackDepth-1] = 0;
1404
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1410
printf("%08x MODI\n",instruction);
1412
assertInteger(opStackDepth-1);
1413
assertInteger(opStackDepth-2);
1414
Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1415
Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
1416
Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
1417
opStackRegType[opStackDepth-1] = 0;
1418
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1424
printf("%08x MODU\n",instruction);
1426
assertInteger(opStackDepth-1);
1427
assertInteger(opStackDepth-2);
1428
Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1429
Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA );
1430
Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] );
1431
opStackRegType[opStackDepth-1] = 0;
1432
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1439
printf("%08x MULI\n",instruction);
1441
assertInteger(opStackDepth-1);
1442
assertInteger(opStackDepth-2);
1443
Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] );
1444
opStackRegType[opStackDepth-1] = 0;
1445
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1451
printf("%08x BAND\n",instruction);
1453
assertInteger(opStackDepth-1);
1454
assertInteger(opStackDepth-2);
1455
Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1456
opStackRegType[opStackDepth-1] = 0;
1457
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1463
printf("%08x BOR\n",instruction);
1465
assertInteger(opStackDepth-1);
1466
assertInteger(opStackDepth-2);
1467
Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1468
opStackRegType[opStackDepth-1] = 0;
1469
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1475
printf("%08x BXOR\n",instruction);
1477
assertInteger(opStackDepth-1);
1478
assertInteger(opStackDepth-2);
1479
Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1480
opStackRegType[opStackDepth-1] = 0;
1481
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1487
printf("%08x BCOM\n",instruction);
1489
assertInteger(opStackDepth-1);
1490
Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] );
1491
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1496
printf("%08x LSH\n",instruction);
1498
assertInteger(opStackDepth-1);
1499
assertInteger(opStackDepth-2);
1500
Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1501
opStackRegType[opStackDepth-1] = 0;
1502
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1508
printf("%08x RSHI\n",instruction);
1510
assertInteger(opStackDepth-1);
1511
assertInteger(opStackDepth-2);
1512
Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1513
opStackRegType[opStackDepth-1] = 0;
1514
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1520
printf("%08x RSHU\n",instruction);
1522
assertInteger(opStackDepth-1);
1523
assertInteger(opStackDepth-2);
1524
Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
1525
opStackRegType[opStackDepth-1] = 0;
1526
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1533
printf("%08x NEGF\n",instruction);
1535
makeFloat(opStackDepth-1);
1536
Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
1537
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1542
printf("%08x ADDF\n",instruction);
1544
makeFloat(opStackDepth-1);
1545
makeFloat(opStackDepth-2);
1546
Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1547
opStackRegType[opStackDepth-1] = 0;
1548
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1554
printf("%08x SUBF\n",instruction);
1556
makeFloat(opStackDepth-1);
1557
makeFloat(opStackDepth-2);
1558
Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1559
opStackRegType[opStackDepth-1] = 0;
1560
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1566
printf("%08x DIVF\n",instruction);
1568
makeFloat(opStackDepth-1);
1569
makeFloat(opStackDepth-2);
1570
Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] );
1571
opStackRegType[opStackDepth-1] = 0;
1572
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1578
printf("%08x MULF\n",instruction);
1580
makeFloat(opStackDepth-1);
1581
makeFloat(opStackDepth-2);
1582
Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] );
1583
opStackRegType[opStackDepth-1] = 0;
1584
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1591
printf("%08x CVIF\n",instruction);
1593
assertInteger(opStackDepth-1);
1594
//makeInteger(opStackDepth-1);
1595
v = (int)&itofConvert;
1596
InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
1597
InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff );
1598
InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 );
1599
InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 );
1600
InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 );
1601
Inst( "ori", PPC_ORI, 0, 0, 0);
1602
Inst( "ori", PPC_ORI, 0, 0, 0);
1603
Inst( "ori", PPC_ORI, 0, 0, 0);
1604
InstImm( "lfd", PPC_LFD, 13, R_EA, 8 );
1605
Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] );
1606
opStackRegType[opStackDepth-1] = 2;
1607
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1608
// Inst( PPC_FRSP, R_TOP, 0, R_TOP );
1613
printf("%08x CVFI\n",instruction);
1615
makeFloat(opStackDepth-1);
1617
InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
1619
Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] );
1620
Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now)
1621
Inst( "ori", PPC_ORI, 0, 0, 0);
1622
Inst( "ori", PPC_ORI, 0, 0, 0);
1623
Inst( "ori", PPC_ORI, 0, 0, 0);
1624
Inst( "ori", PPC_ORI, 0, 0, 0);
1625
InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 );
1627
InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
1629
opStackRegType[opStackDepth-1] = 1;
1630
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1635
printf("%08x SEX8\n",instruction);
1637
assertInteger(opStackDepth-1);
1638
Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1639
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1644
printf("%08x SEX16\n",instruction);
1646
assertInteger(opStackDepth-1);
1647
Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 );
1648
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1652
v = Constant4() >> 2;
1655
printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2);
1657
assert(opStackDepth >= 2);
1658
assertInteger(opStackDepth-1);
1659
assertInteger(opStackDepth-2);
1660
InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count
1661
// FIXME: range check
1662
Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register
1664
Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );
1665
InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 );
1666
Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE );
1667
InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 );
1669
InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source
1670
InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest
1671
Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop
1672
opStackRegType[opStackDepth-1] = 0;
1673
opStackRegType[opStackDepth-2] = 0;
1674
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1675
opStackLoadInstructionAddr[opStackDepth-2] = 0;
1682
printf("%08x JUMP\n",instruction);
1684
assert(opStackDepth == 1);
1685
assertInteger(opStackDepth-1);
1687
Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 );
1688
// FIXME: range check
1689
Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS );
1690
Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register
1691
Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register
1692
opStackRegType[opStackDepth-1] = 0;
1693
opStackLoadInstructionAddr[opStackDepth-1] = 0;
1697
Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
1701
assert(opStackDepth >= 0);
1702
assert(opStackDepth < OP_STACK_MAX_DEPTH);
1704
//printf("%4d\t%s\n",opStackDepth,opnames[op]);
1707
Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
1710
// copy to an exact size buffer on the hunk
1711
vm->codeLength = compiledOfs * 4;
1712
vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
1713
Com_Memcpy( vm->codeBase, buf, vm->codeLength );
1715
//printf("codeBase: %p\n",vm->codeBase);
1719
// offset all the instruction pointers for the new location
1720
for ( i = 0 ; i < header->instructionCount ; i++ ) {
1721
vm->instructionPointers[i] += (int)vm->codeBase;
1722
//printf("%08x %08lx\n",i,vm->instructionPointers[i]);
1725
// go back over it in place now to fixup reletive jump targets
1726
buf = (unsigned *)vm->codeBase;
1727
} else if ( pass == 1 ) {
1729
// On Mac OS X, the following library routine clears the instruction cache for generated code
1730
MakeDataExecutable(vm->codeBase, vm->codeLength);
1732
#warning Need to clear the instruction cache for generated code
1749
This function is called directly by the generated code
1752
int VM_CallCompiled( vm_t *vm, int *args ) {
1760
//printf("VM_CallCompiled: %p %08lx %08lx %08lx\n",
1761
// vm, args[0],args[1],args[2]);
1763
// interpret the code
1764
vm->currentlyInterpreting = qtrue;
1766
// we might be called recursively, so this might not be the very top
1767
programStack = vm->programStack;
1768
stackOnEntry = programStack;
1769
image = vm->dataBase;
1771
// set up the stack frame
1774
*(int *)&image[ programStack + 44] = args[9];
1775
*(int *)&image[ programStack + 40] = args[8];
1776
*(int *)&image[ programStack + 36] = args[7];
1777
*(int *)&image[ programStack + 32] = args[6];
1778
*(int *)&image[ programStack + 28] = args[5];
1779
*(int *)&image[ programStack + 24] = args[4];
1780
*(int *)&image[ programStack + 20] = args[3];
1781
*(int *)&image[ programStack + 16] = args[2];
1782
*(int *)&image[ programStack + 12] = args[1];
1783
*(int *)&image[ programStack + 8 ] = args[0];
1784
*(int *)&image[ programStack + 4 ] = 0; // return stack
1785
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
1787
// Cheesy... manually save registers used by VM call...
1788
// off we go into generated code...
1789
// the PPC calling standard says the parms will all go into R3 - R11, so
1790
// no special asm code is needed here
1792
((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1793
programStack, (int)&stack,
1794
(int)image, vm->dataMask, (int)&AsmCall,
1795
(int)vm->instructionPointers, vm->instructionPointersLength,
1798
((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1799
programStack, (int)&stack,
1800
(int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */,
1801
(int)vm->instructionPointers, vm->instructionPointersLength,
1804
vm->programStack = stackOnEntry;
1806
vm->currentlyInterpreting = qfalse;
1816
Put this at end of file because gcc messes up debug line numbers
1821
void AsmCall( void ) {
1823
// pop off the destination instruction
1824
" lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK)
1825
" addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
1827
// see if it is a system trap
1828
" cmpwi r12,0 \n" // RG_TOP, 0 \n"
1829
" bc 12,0, systemTrap \n"
1831
// calling another VM function, so lookup in instructionPointers
1832
" slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2
1833
// FIXME: range check
1834
" lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1835
" mtctr r12 \n" // RG_TOP
1838
#if defined(MACOS_X) && defined(__OPTIMIZE__)
1839
// On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
1840
//#warning Mac OS X optimization on, not popping GCC AsmCall frame
1842
// Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
1844
" lwz r1,0(r1) \n" // pop off the GCC AsmCall frame
1845
" lmw r30,-8(r1) \n"
1850
" bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register
1852
// calling a system trap
1854
// convert to positive system call number
1855
" subfic r12,r12,-1 \n"
1857
// save all our registers, including the current link register
1858
" mflr r13 \n" // RG_SECOND // copy off our link register
1859
" addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1860
" stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK)
1861
" stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1862
" stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1863
" stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1864
" stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1865
" stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1866
" stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1867
" stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
1868
" stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
1870
// save the vm stack position to allow recursive VM entry
1871
" addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4
1872
" stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1874
// save the system call number as the 0th parameter
1875
" add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1876
" stwu r12,4(r3) \n" // RG_TOP, 4(r3)
1878
// make the system call with the address of all the VM parms as a parameter
1879
// vm->systemCalls( &parms )
1880
" lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
1881
" mtctr r12 \n" // RG_TOP
1883
" mr r12,r3 \n" // RG_TOP, r3
1885
// pop our saved registers
1886
" lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK)
1887
" lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1888
" lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1889
" lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1890
" lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1891
" lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1892
" lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1893
" lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
1894
" lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK)
1895
" addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36
1897
// restore the old link register
1898
" mtlr r13 \n" // RG_SECOND
1900
// save off the return value
1901
" stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK)
1903
// GCC adds its own prolog / epliog code
1908
// codewarrior version
1910
void asm AsmCall( void ) {
1912
// pop off the destination instruction
1914
lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK)
1916
addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4
1920
// see if it is a system trap
1922
cmpwi r12,0 // RG_TOP, 0
1928
// calling another VM function, so lookup in instructionPointers
1930
slwi r12,r12,2 // RG_TOP,RG_TOP,2
1932
// FIXME: range check
1934
lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1940
bcctr 20,0 // when it hits a leave, it will branch to the current link register
1944
// calling a system trap
1948
// convert to positive system call number
1954
// save all our registers, including the current link register
1956
mflr r13 // RG_SECOND // copy off our link register
1958
addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1960
stw r3,56(r1) // RG_STACK, -36(REAL_STACK)
1962
stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
1964
stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
1966
stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
1968
stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
1970
stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1972
stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1974
stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
1976
stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register
1980
// save the vm stack position to allow recursive VM entry
1982
addi r13,r3,-4 // RG_TOP, RG_STACK, -4
1984
stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1988
// save the system call number as the 0th parameter
1990
add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1992
stwu r12,4(r3) // RG_TOP, 4(r3)
1996
// make the system call with the address of all the VM parms as a parameter
1998
// vm->systemCalls( &parms )
2000
lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
2004
// perform macos cross fragment fixup crap
2008
stw r2,52(r1) // save old TOC
2020
lwz r2,52(r1) // restore TOC
2024
mr r12,r3 // RG_TOP, r3
2028
// pop our saved registers
2030
lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK)
2032
lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
2034
lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
2036
lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
2038
lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
2040
lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
2042
lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
2044
lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
2046
lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK)
2048
addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36
2052
// restore the old link register
2054
mtlr r13 // RG_SECOND
2058
// save off the return value
2060
stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK)