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
27
#pragma opt_pointer_analysis off
32
// registers 3-11 are the parameter passing registers
42
R_INSTRUCTIONS, // global
43
R_NUM_INSTRUCTIONS, // global
49
R_EA = 2 // effective address calculation
53
#define RG_REAL_STACK r1
59
#define RG_INSTRUCTIONS r8
60
#define RG_NUM_INSTRUCTIONS r9
66
// this doesn't have the low order bits set for instructions i'm not using...
70
PPC_MULLI = 0x1c000000,
71
PPC_SUBFIC = 0x20000000,
72
PPC_CMPI = 0x28000000,
73
PPC_CMPLI = 0x2c000000,
74
PPC_ADDIC = 0x30000000,
75
PPC_ADDIC_ = 0x34000000,
76
PPC_ADDI = 0x38000000,
77
PPC_ADDIS = 0x3c000000,
82
PPC_MCRF = 0x4c000000,
83
PPC_BCLR = 0x4c000020,
84
PPC_RFID = 0x4c000000,
85
PPC_CRNOR = 0x4c000000,
87
PPC_CRANDC = 0x4c000000,
88
PPC_ISYNC = 0x4c000000,
89
PPC_CRXOR = 0x4c000000,
90
PPC_CRNAND = 0x4c000000,
91
PPC_CREQV = 0x4c000000,
92
PPC_CRORC = 0x4c000000,
93
PPC_CROR = 0x4c000000,
95
PPC_BCCTR = 0x4c000420,
96
PPC_RLWIMI = 0x50000000,
97
PPC_RLWINM = 0x54000000,
98
PPC_RLWNM = 0x5c000000,
100
PPC_ORIS = 0x64000000,
101
PPC_XORI = 0x68000000,
102
PPC_XORIS = 0x6c000000,
103
PPC_ANDI_ = 0x70000000,
104
PPC_ANDIS_ = 0x74000000,
105
PPC_RLDICL = 0x78000000,
106
PPC_RLDICR = 0x78000000,
107
PPC_RLDIC = 0x78000000,
108
PPC_RLDIMI = 0x78000000,
109
PPC_RLDCL = 0x78000000,
110
PPC_RLDCR = 0x78000000,
111
PPC_CMP = 0x7c000000,
113
PPC_SUBFC = 0x7c000010,
114
PPC_MULHDU = 0x7c000000,
115
PPC_ADDC = 0x7c000014,
116
PPC_MULHWU = 0x7c000000,
117
PPC_MFCR = 0x7c000000,
118
PPC_LWAR = 0x7c000000,
119
PPC_LDX = 0x7c000000,
120
PPC_LWZX = 0x7c00002e,
121
PPC_SLW = 0x7c000030,
122
PPC_CNTLZW = 0x7c000000,
123
PPC_SLD = 0x7c000000,
124
PPC_AND = 0x7c000038,
125
PPC_CMPL = 0x7c000040,
126
PPC_SUBF = 0x7c000050,
127
PPC_LDUX = 0x7c000000,
129
PPC_DCBST = 0x7c000000,
130
PPC_LWZUX = 0x7c00006c,
131
PPC_CNTLZD = 0x7c000000,
132
PPC_ANDC = 0x7c000000,
134
PPC_MULHD = 0x7c000000,
135
PPC_MULHW = 0x7c000000,
136
PPC_MTSRD = 0x7c000000,
137
PPC_MFMSR = 0x7c000000,
138
PPC_LDARX = 0x7c000000,
139
PPC_DCBF = 0x7c000000,
140
PPC_LBZX = 0x7c0000ae,
141
PPC_NEG = 0x7c000000,
142
PPC_MTSRDIN = 0x7c000000,
143
PPC_LBZUX = 0x7c000000,
144
PPC_NOR = 0x7c0000f8,
145
PPC_SUBFE = 0x7c000000,
146
PPC_ADDE = 0x7c000000,
147
PPC_MTCRF = 0x7c000000,
148
PPC_MTMSR = 0x7c000000,
149
PPC_STDX = 0x7c000000,
150
PPC_STWCX_ = 0x7c000000,
151
PPC_STWX = 0x7c00012e,
152
PPC_MTMSRD = 0x7c000000,
153
PPC_STDUX = 0x7c000000,
154
PPC_STWUX = 0x7c00016e,
155
PPC_SUBFZE = 0x7c000000,
156
PPC_ADDZE = 0x7c000000,
157
PPC_MTSR = 0x7c000000,
158
PPC_STDCX_ = 0x7c000000,
159
PPC_STBX = 0x7c0001ae,
160
PPC_SUBFME = 0x7c000000,
161
PPC_MULLD = 0x7c000000,
163
PPC_ADDME = 0x7c000000,
164
PPC_MULLW = 0x7c0001d6,
165
PPC_MTSRIN = 0x7c000000,
166
PPC_DCBTST = 0x7c000000,
167
PPC_STBUX = 0x7c000000,
168
PPC_ADD = 0x7c000214,
169
PPC_DCBT = 0x7c000000,
170
PPC_LHZX = 0x7c00022e,
171
PPC_EQV = 0x7c000000,
172
PPC_TLBIE = 0x7c000000,
173
PPC_ECIWX = 0x7c000000,
174
PPC_LHZUX = 0x7c000000,
175
PPC_XOR = 0x7c000278,
176
PPC_MFSPR = 0x7c0002a6,
177
PPC_LWAX = 0x7c000000,
178
PPC_LHAX = 0x7c000000,
179
PPC_TLBIA = 0x7c000000,
180
PPC_MFTB = 0x7c000000,
181
PPC_LWAUX = 0x7c000000,
182
PPC_LHAUX = 0x7c000000,
183
PPC_STHX = 0x7c00032e,
184
PPC_ORC = 0x7c000338,
185
PPC_SRADI = 0x7c000000,
186
PPC_SLBIE = 0x7c000000,
187
PPC_ECOWX = 0x7c000000,
188
PPC_STHUX = 0x7c000000,
190
PPC_DIVDU = 0x7c000000,
191
PPC_DIVWU = 0x7c000396,
192
PPC_MTSPR = 0x7c0003a6,
193
PPC_DCBI = 0x7c000000,
194
PPC_NAND = 0x7c000000,
195
PPC_DIVD = 0x7c000000,
197
PPC_DIVW = 0x7c0003d6,
198
PPC_SLBIA = 0x7c000000,
199
PPC_MCRXR = 0x7c000000,
200
PPC_LSWX = 0x7c000000,
201
PPC_LWBRX = 0x7c000000,
202
PPC_LFSX = 0x7c000000,
203
PPC_SRW = 0x7c000430,
204
PPC_SRD = 0x7c000000,
205
PPC_TLBSYNC = 0x7c000000,
206
PPC_LFSUX = 0x7c000000,
207
PPC_MFSR = 0x7c000000,
208
PPC_LSWI = 0x7c000000,
209
PPC_SYNC = 0x7c000000,
210
PPC_LFDX = 0x7c000000,
211
PPC_LFDUX = 0x7c000000,
212
PPC_MFSRIN = 0x7c000000,
213
PPC_STSWX = 0x7c000000,
214
PPC_STWBRX = 0x7c000000,
215
PPC_STFSX = 0x7c000000,
216
PPC_STFSUX = 0x7c000000,
217
PPC_STSWI = 0x7c000000,
218
PPC_STFDX = 0x7c000000,
219
PPC_DCBA = 0x7c000000,
220
PPC_STFDUX = 0x7c000000,
221
PPC_LHBRX = 0x7c000000,
222
PPC_SRAW = 0x7c000630,
223
PPC_SRAD = 0x7c000000,
224
PPC_SRAWI = 0x7c000000,
225
PPC_EIEIO = 0x7c000000,
226
PPC_STHBRX = 0x7c000000,
227
PPC_EXTSH = 0x7c000734,
228
PPC_EXTSB = 0x7c000774,
229
PPC_ICBI = 0x7c000000,
231
PPC_STFIWX = 0x7c0007ae,
232
PPC_EXTSW = 0x7c000000,
233
PPC_DCBZ = 0x7c000000,
234
PPC_LWZ = 0x80000000,
235
PPC_LWZU = 0x84000000,
236
PPC_LBZ = 0x88000000,
237
PPC_LBZU = 0x8c000000,
238
PPC_STW = 0x90000000,
239
PPC_STWU = 0x94000000,
240
PPC_STB = 0x98000000,
241
PPC_STBU = 0x9c000000,
242
PPC_LHZ = 0xa0000000,
243
PPC_LHZU = 0xa4000000,
244
PPC_LHA = 0xa8000000,
245
PPC_LHAU = 0xac000000,
246
PPC_STH = 0xb0000000,
247
PPC_STHU = 0xb4000000,
248
PPC_LMW = 0xb8000000,
249
PPC_STMW = 0xbc000000,
250
PPC_LFS = 0xc0000000,
251
PPC_LFSU = 0xc4000000,
252
PPC_LFD = 0xc8000000,
253
PPC_LFDU = 0xcc000000,
254
PPC_STFS = 0xd0000000,
255
PPC_STFSU = 0xd4000000,
256
PPC_STFD = 0xd8000000,
257
PPC_STFDU = 0xdc000000,
259
PPC_LDU = 0xe8000001,
260
PPC_LWA = 0xe8000002,
261
PPC_FDIVS = 0xec000024,
262
PPC_FSUBS = 0xec000028,
263
PPC_FADDS = 0xec00002a,
265
PPC_FSQRTS = 0xec000000,
266
PPC_FRES = 0xec000000,
267
PPC_FMULS = 0xec000032,
268
PPC_FMSUBS = 0xec000000,
269
PPC_FMADDS = 0xec000000,
270
PPC_FNMSUBS = 0xec000000,
271
PPC_FNMADDS = 0xec000000,
272
PPC_STD = 0xf8000000,
273
PPC_STDU = 0xf8000001,
274
PPC_FCMPU = 0xfc000000,
275
PPC_FRSP = 0xfc000018,
276
PPC_FCTIW = 0xfc000000,
277
PPC_FCTIWZ = 0xfc00001e,
278
PPC_FDIV = 0xfc000000,
279
PPC_FSUB = 0xfc000028,
280
PPC_FADD = 0xfc000000,
281
PPC_FSQRT = 0xfc000000,
282
PPC_FSEL = 0xfc000000,
283
PPC_FMUL = 0xfc000000,
284
PPC_FRSQRTE = 0xfc000000,
285
PPC_FMSUB = 0xfc000000,
286
PPC_FMADD = 0xfc000000,
287
PPC_FNMSUB = 0xfc000000,
288
PPC_FNMADD = 0xfc000000,
289
PPC_FCMPO = 0xfc000000,
290
PPC_MTFSB1 = 0xfc000000,
291
PPC_FNEG = 0xfc000050,
292
PPC_MCRFS = 0xfc000000,
293
PPC_MTFSB0 = 0xfc000000,
294
PPC_FMR = 0xfc000000,
295
PPC_MTFSFI = 0xfc000000,
296
PPC_FNABS = 0xfc000000,
297
PPC_FABS = 0xfc000000,
299
PPC_MFFS = 0xfc000000,
300
PPC_MTFSF = 0xfc000000,
301
PPC_FCTID = 0xfc000000,
302
PPC_FCTIDZ = 0xfc000000,
303
PPC_FCFID = 0xfc000000
308
// the newly generated code
309
static unsigned *buf;
310
static int compiledOfs; // in dwords
312
// fromt the original bytecode
316
void AsmCall( void );
318
double itofConvert[2];
320
static int Constant4( void ) {
323
v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
328
static int Constant1( void ) {
336
static void Emit4( int i ) {
337
buf[ compiledOfs ] = i;
341
static void Inst( int opcode, int destReg, int aReg, int bReg ) {
344
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
345
buf[ compiledOfs ] = r;
349
static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) {
352
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
353
buf[ compiledOfs ] = r;
357
static void InstImm( int opcode, int destReg, int aReg, int immediate ) {
360
if ( immediate > 32767 || immediate < -32768 ) {
361
Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
363
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
364
buf[ compiledOfs ] = r;
368
static void InstImmU( int opcode, int destReg, int aReg, int immediate ) {
371
if ( immediate > 0xffff || immediate < 0 ) {
372
Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
374
r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
375
buf[ compiledOfs ] = r;
379
static qboolean rtopped;
380
static int pop0, pop1, oc0, oc1;
382
static int instruction;
387
if (rtopped == qfalse) {
388
InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
392
static void ltopandsecond() {
393
if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
396
tvm->instructionPointers[instruction] = compiledOfs * 4;
398
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
399
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
400
} else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) {
403
tvm->instructionPointers[instruction] = compiledOfs * 4;
405
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
406
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
408
ltop(); // get value from opstack
409
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
410
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
417
static void fltop() {
418
if (rtopped == qfalse) {
419
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
424
static void fltopandsecond() {
425
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
426
InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
427
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
437
void VM_Compile( vm_t *vm, vmHeader_t *header ) {
443
// set up the into-to-float variables
444
((int *)itofConvert)[0] = 0x43300000;
445
((int *)itofConvert)[1] = 0x80000000;
446
((int *)itofConvert)[2] = 0x43300000;
448
// allocate a very large temp buffer, we will shrink it later
449
maxLength = header->codeLength * 8;
450
buf = Z_Malloc( maxLength );
451
jused = Z_Malloc(header->instructionCount + 2);
452
Com_Memset(jused, 0, header->instructionCount+2);
454
// compile everything twice, so the second pass will have valid instruction
455
// pointers for branches
456
for ( pass = -1 ; pass < 2 ; pass++ ) {
459
// translate all instructions
467
code = (byte *)header + header->codeOffset;
470
// metrowerks seems to require this header in front of functions
471
Emit4( (int)(buf+2) );
475
for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
476
if ( compiledOfs*4 > maxLength - 16 ) {
477
Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
482
vm->instructionPointers[ instruction ] = compiledOfs * 4;
489
InstImmU( PPC_ADDI, R_TOP, 0, 0 );
490
InstImm( PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger
494
InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() ); // sub R_STACK, R_STACK, imm
499
if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
502
if ( v < 32768 && v >= -32768 ) {
503
InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff );
505
InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff );
507
InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff );
510
if (code[pc] == OP_LOAD4) {
511
Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
514
} else if (code[pc] == OP_LOAD2) {
515
Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
518
} else if (code[pc] == OP_LOAD1) {
519
Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
523
if (code[pc] == OP_STORE4) {
524
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
525
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
526
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
527
Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
532
} else if (code[pc] == OP_STORE2) {
533
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
534
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
535
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
536
Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
541
} else if (code[pc] == OP_STORE1) {
542
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
543
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
544
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
545
Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
551
if (code[pc] == OP_JUMP) {
554
InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
560
if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
563
InstImm( PPC_ADDI, R_TOP, R_STACK, oc1 );
564
if (code[pc] == OP_LOAD4) {
565
Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
568
} else if (code[pc] == OP_LOAD2) {
569
Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
572
} else if (code[pc] == OP_LOAD1) {
573
Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
577
if (code[pc] == OP_STORE4) {
578
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
579
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
580
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
581
Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
586
} else if (code[pc] == OP_STORE2) {
587
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
588
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
589
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
590
Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
595
} else if (code[pc] == OP_STORE1) {
596
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
597
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
598
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
599
Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
605
InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
609
ltop(); // get value from opstack
610
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
611
InstImm( PPC_ADDI, R_EA, R_STACK, Constant1() ); // location to put it
612
Inst( PPC_STWX, R_TOP, R_EA, R_MEMBASE );
616
Inst( PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register
617
InstImm( PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address
619
Inst( PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register
620
Inst( PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register
622
InstImm( PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address
623
InstImm( PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
624
Inst( PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register
628
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 );
632
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
636
InstImm( PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
637
Inst( PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register
641
ltop(); // get value from opstack
642
//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
643
Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
644
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
648
ltop(); // get value from opstack
649
//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
650
Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
651
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
655
ltop(); // get value from opstack
656
//Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it
657
Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base
658
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
662
ltopandsecond(); // get value from opstack
663
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
664
Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
668
ltopandsecond(); // get value from opstack
669
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
670
Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
674
ltopandsecond(); // get value from opstack
675
//Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it
676
Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base
681
ltopandsecond(); // get value from opstack
682
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
685
InstImm( PPC_BC, 4, 2, 8 );
687
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
691
Emit4(PPC_B | (v&0x3ffffff) );
695
ltopandsecond(); // get value from opstack
696
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
699
InstImm( PPC_BC, 12, 2, 8 );
701
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
705
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
706
// InstImm( PPC_BC, 4, 2, v );
711
ltopandsecond(); // get value from opstack
712
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
715
InstImm( PPC_BC, 4, 0, 8 );
717
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
721
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
722
// InstImm( PPC_BC, 12, 0, v );
726
ltopandsecond(); // get value from opstack
727
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
730
InstImm( PPC_BC, 12, 1, 8 );
732
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
736
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
737
// InstImm( PPC_BC, 4, 1, v );
741
ltopandsecond(); // get value from opstack
742
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
745
InstImm( PPC_BC, 4, 1, 8 );
747
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
751
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
752
// InstImm( PPC_BC, 12, 1, v );
756
ltopandsecond(); // get value from opstack
757
Inst( PPC_CMP, 0, R_SECOND, R_TOP );
760
InstImm( PPC_BC, 12, 0, 8 );
762
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
766
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
767
// InstImm( PPC_BC, 4, 0, v );
771
ltopandsecond(); // get value from opstack
772
Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
775
InstImm( PPC_BC, 4, 0, 8 );
777
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
781
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
782
// InstImm( PPC_BC, 12, 0, v );
786
ltopandsecond(); // get value from opstack
787
Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
790
InstImm( PPC_BC, 12, 1, 8 );
792
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
796
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
797
// InstImm( PPC_BC, 4, 1, v );
801
ltopandsecond(); // get value from opstack
802
Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
805
InstImm( PPC_BC, 4, 1, 8 );
807
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
811
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
812
// InstImm( PPC_BC, 12, 1, v );
816
ltopandsecond(); // get value from opstack
817
Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
820
InstImm( PPC_BC, 12, 0, 8 );
822
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
826
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
827
// InstImm( PPC_BC, 4, 0, v );
832
fltopandsecond(); // get value from opstack
833
Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
836
InstImm( PPC_BC, 4, 2, 8 );
838
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
842
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
843
// InstImm( PPC_BC, 12, 2, v );
847
fltopandsecond(); // get value from opstack
848
Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
851
InstImm( PPC_BC, 12, 2, 8 );
853
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
857
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
858
// InstImm( PPC_BC, 4, 2, v );
862
fltopandsecond(); // get value from opstack
863
Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
866
InstImm( PPC_BC, 4, 0, 8 );
868
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
872
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
873
// InstImm( PPC_BC, 12, 0, v );
877
fltopandsecond(); // get value from opstack
878
Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
881
InstImm( PPC_BC, 12, 1, 8 );
883
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
887
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
888
// InstImm( PPC_BC, 4, 1, v );
892
fltopandsecond(); // get value from opstack
893
Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
896
InstImm( PPC_BC, 4, 1, 8 );
898
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
902
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
903
// InstImm( PPC_BC, 12, 1, v );
907
fltopandsecond(); // get value from opstack
908
Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
911
InstImm( PPC_BC, 12, 0, 8 );
913
v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
917
Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
918
// InstImm( PPC_BC, 4, 0, v );
923
ltop(); // get value from opstack
924
InstImm( PPC_SUBFIC, R_TOP, R_TOP, 0 );
925
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
929
ltop(); // get value from opstack
930
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
931
Inst( PPC_ADD, R_TOP, R_TOP, R_SECOND );
932
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
936
ltop(); // get value from opstack
937
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
938
Inst( PPC_SUBF, R_TOP, R_TOP, R_SECOND );
939
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
943
ltop(); // get value from opstack
944
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
945
Inst( PPC_DIVW, R_TOP, R_SECOND, R_TOP );
946
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
950
ltop(); // get value from opstack
951
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
952
Inst( PPC_DIVWU, R_TOP, R_SECOND, R_TOP );
953
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
957
ltop(); // get value from opstack
958
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
959
Inst( PPC_DIVW, R_EA, R_SECOND, R_TOP );
960
Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
961
Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
962
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
966
ltop(); // get value from opstack
967
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
968
Inst( PPC_DIVWU, R_EA, R_SECOND, R_TOP );
969
Inst( PPC_MULLW, R_EA, R_TOP, R_EA );
970
Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND );
971
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
976
ltop(); // get value from opstack
977
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
978
Inst( PPC_MULLW, R_TOP, R_SECOND, R_TOP );
979
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
983
ltop(); // get value from opstack
984
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
985
Inst( PPC_AND, R_SECOND, R_TOP, R_TOP );
986
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
990
ltop(); // get value from opstack
991
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
992
Inst( PPC_OR, R_SECOND, R_TOP, R_TOP );
993
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
997
ltop(); // get value from opstack
998
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
999
Inst( PPC_XOR, R_SECOND, R_TOP, R_TOP );
1000
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1004
ltop(); // get value from opstack
1005
Inst( PPC_NOR, R_TOP, R_TOP, R_TOP );
1006
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1010
ltop(); // get value from opstack
1011
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1012
Inst( PPC_SLW, R_SECOND, R_TOP, R_TOP );
1013
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1017
ltop(); // get value from opstack
1018
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1019
Inst( PPC_SRAW, R_SECOND, R_TOP, R_TOP );
1020
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1024
ltop(); // get value from opstack
1025
InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1026
Inst( PPC_SRW, R_SECOND, R_TOP, R_TOP );
1027
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1032
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1033
Inst( PPC_FNEG, R_TOP, 0, R_TOP );
1034
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1038
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1039
InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1040
Inst( PPC_FADDS, R_TOP, R_SECOND, R_TOP );
1041
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1045
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1046
InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1047
Inst( PPC_FSUBS, R_TOP, R_SECOND, R_TOP );
1048
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1052
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1053
InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1054
Inst( PPC_FDIVS, R_TOP, R_SECOND, R_TOP );
1055
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1059
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1060
InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack
1061
Inst4( PPC_FMULS, R_TOP, R_SECOND, 0, R_TOP );
1062
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1067
v = (int)&itofConvert;
1068
InstImmU( PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff );
1069
InstImmU( PPC_ORI, R_EA, R_EA, v & 0xffff );
1070
InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1071
InstImmU( PPC_XORIS, R_TOP, R_TOP, 0x8000 );
1072
InstImm( PPC_STW, R_TOP, R_EA, 12 );
1073
InstImm( PPC_LFD, R_TOP, R_EA, 0 );
1074
InstImm( PPC_LFD, R_SECOND, R_EA, 8 );
1075
Inst( PPC_FSUB, R_TOP, R_SECOND, R_TOP );
1076
// Inst( PPC_FRSP, R_TOP, 0, R_TOP );
1077
InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack
1081
InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack
1082
Inst( PPC_FCTIWZ, R_TOP, 0, R_TOP );
1083
Inst( PPC_STFIWX, R_TOP, 0, R_OPSTACK ); // save value to opstack
1087
ltop(); // get value from opstack
1088
Inst( PPC_EXTSB, R_TOP, R_TOP, 0 );
1089
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
1093
ltop(); // get value from opstack
1094
Inst( PPC_EXTSH, R_TOP, R_TOP, 0 );
1095
InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
1100
v = Constant4() >> 2;
1102
InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // dest
1103
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
1104
InstImmU( PPC_ADDI, R_EA, 0, v ); // count
1105
// FIXME: range check
1106
Inst( PPC_MTSPR, R_EA, 9, 0 ); // move to count register
1108
Inst( PPC_ADD, R_TOP, R_TOP, R_MEMBASE );
1109
InstImm( PPC_ADDI, R_TOP, R_TOP, -4 );
1110
Inst( PPC_ADD, R_SECOND, R_SECOND, R_MEMBASE );
1111
InstImm( PPC_ADDI, R_SECOND, R_SECOND, -4 );
1113
InstImm( PPC_LWZU, R_EA, R_TOP, 4 ); // source
1114
InstImm( PPC_STWU, R_EA, R_SECOND, 4 ); // dest
1115
Inst( PPC_BC | 0xfff8 , 16, 0, 0 ); // loop
1120
ltop(); // get value from opstack
1121
InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
1122
Inst( PPC_RLWINM | ( 29 << 1 ), R_TOP, R_TOP, 2 );
1123
// FIXME: range check
1124
Inst( PPC_LWZX, R_TOP, R_TOP, R_INSTRUCTIONS );
1125
Inst( PPC_MTSPR, R_TOP, 9, 0 ); // move to count register
1126
Inst( PPC_BCCTR, 20, 0, 0 ); // jump to the count register
1130
Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
1136
Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
1139
// copy to an exact size buffer on the hunk
1140
vm->codeLength = compiledOfs * 4;
1141
vm->codeBase = Hunk_Alloc( vm->codeLength, h_low );
1142
Com_Memcpy( vm->codeBase, buf, vm->codeLength );
1145
// offset all the instruction pointers for the new location
1146
for ( i = 0 ; i < header->instructionCount ; i++ ) {
1147
vm->instructionPointers[i] += (int)vm->codeBase;
1150
// go back over it in place now to fixup reletive jump targets
1151
buf = (unsigned *)vm->codeBase;
1161
This function is called directly by the generated code
1164
int VM_CallCompiled( vm_t *vm, int *args ) {
1172
// interpret the code
1173
vm->currentlyInterpreting = qtrue;
1175
// we might be called recursively, so this might not be the very top
1176
programStack = vm->programStack;
1177
stackOnEntry = programStack;
1178
image = vm->dataBase;
1180
// set up the stack frame
1183
*(int *)&image[ programStack + 44] = args[9];
1184
*(int *)&image[ programStack + 40] = args[8];
1185
*(int *)&image[ programStack + 36] = args[7];
1186
*(int *)&image[ programStack + 32] = args[6];
1187
*(int *)&image[ programStack + 28] = args[5];
1188
*(int *)&image[ programStack + 24] = args[4];
1189
*(int *)&image[ programStack + 20] = args[3];
1190
*(int *)&image[ programStack + 16] = args[2];
1191
*(int *)&image[ programStack + 12] = args[1];
1192
*(int *)&image[ programStack + 8 ] = args[0];
1193
*(int *)&image[ programStack + 4 ] = 0; // return stack
1194
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
1196
// off we go into generated code...
1197
// the PPC calling standard says the parms will all go into R3 - R11, so
1198
// no special asm code is needed here
1200
((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1201
programStack, (int)&stack,
1202
(int)image, vm->dataMask, (int)&AsmCall,
1203
(int)vm->instructionPointers, vm->instructionPointersLength,
1206
((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))(
1207
programStack, (int)&stack,
1208
(int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */,
1209
(int)vm->instructionPointers, vm->instructionPointersLength,
1212
vm->programStack = stackOnEntry;
1214
vm->currentlyInterpreting = qfalse;
1224
Put this at end of file because gcc messes up debug line numbers
1229
void AsmCall( void ) {
1231
// pop off the destination instruction
1232
" lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK)
1233
" addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n"
1235
// see if it is a system trap
1236
" cmpwi r12,0 \n" // RG_TOP, 0 \n"
1237
" bc 12,0, systemTrap \n"
1239
// calling another VM function, so lookup in instructionPointers
1240
" slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2
1241
// FIXME: range check
1242
" lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1243
" mtctr r12 \n" // RG_TOP
1246
#if defined(MACOS_X) && defined(__OPTIMIZE__)
1247
// On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder.
1248
#warning Mac OS X optimization on, not popping GCC AsmCall frame
1250
// Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
1252
" lwz r1,0(r1) \n" // pop off the GCC AsmCall frame
1253
" lmw r30,-8(r1) \n"
1258
" bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register
1260
// calling a system trap
1262
// convert to positive system call number
1263
" subfic r12,r12,-1 \n"
1265
// save all our registers, including the current link register
1266
" mflr r13 \n" // RG_SECOND // copy off our link register
1267
" addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1268
" stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK)
1269
" stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1270
" stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1271
" stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1272
" stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1273
" stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1274
" stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1275
" stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
1276
" stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register
1278
// save the vm stack position to allow recursive VM entry
1279
" addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4
1280
" stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1282
// save the system call number as the 0th parameter
1283
" add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1284
" stwu r12,4(r3) \n" // RG_TOP, 4(r3)
1286
// make the system call with the address of all the VM parms as a parameter
1287
// vm->systemCalls( &parms )
1288
" lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
1289
" mtctr r12 \n" // RG_TOP
1291
" mr r12,r3 \n" // RG_TOP, r3
1293
// pop our saved registers
1294
" lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK)
1295
" lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK)
1296
" lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK)
1297
" lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK)
1298
" lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK)
1299
" lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1300
" lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1301
" lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK)
1302
" lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK)
1303
" addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36
1305
// restore the old link register
1306
" mtlr r13 \n" // RG_SECOND
1308
// save off the return value
1309
" stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK)
1311
// GCC adds its own prolog / epilog code
1316
// codewarrior version
1318
void asm AsmCall( void ) {
1320
// pop off the destination instruction
1322
lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK)
1324
addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4
1328
// see if it is a system trap
1330
cmpwi r12,0 // RG_TOP, 0
1336
// calling another VM function, so lookup in instructionPointers
1338
slwi r12,r12,2 // RG_TOP,RG_TOP,2
1340
// FIXME: range check
1342
lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP)
1348
bcctr 20,0 // when it hits a leave, it will branch to the current link register
1352
// calling a system trap
1356
// convert to positive system call number
1362
// save all our registers, including the current link register
1364
mflr r13 // RG_SECOND // copy off our link register
1366
addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves
1368
stw r3,56(r1) // RG_STACK, -36(REAL_STACK)
1370
stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
1372
stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
1374
stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
1376
stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
1378
stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1380
stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1382
stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
1384
stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register
1388
// save the vm stack position to allow recursive VM entry
1390
addi r13,r3,-4 // RG_TOP, RG_STACK, -4
1392
stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
1396
// save the system call number as the 0th parameter
1398
add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls
1400
stwu r12,4(r3) // RG_TOP, 4(r3)
1404
// make the system call with the address of all the VM parms as a parameter
1406
// vm->systemCalls( &parms )
1408
lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
1412
// perform macos cross fragment fixup crap
1416
stw r2,52(r1) // save old TOC
1428
lwz r2,52(r1) // restore TOC
1432
mr r12,r3 // RG_TOP, r3
1436
// pop our saved registers
1438
lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK)
1440
lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK)
1442
lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK)
1444
lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK)
1446
lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK)
1448
lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
1450
lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
1452
lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK)
1454
lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK)
1456
addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36
1460
// restore the old link register
1462
mtlr r13 // RG_SECOND
1466
// save off the return value
1468
stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK)