~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/qcommon/vm_ppc.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
27
#pragma opt_pointer_analysis off
 
28
 
 
29
 
 
30
typedef enum {
 
31
    R_REAL_STACK = 1,
 
32
        // registers 3-11 are the parameter passing registers
 
33
        
 
34
        // state
 
35
        R_STACK = 3,                    // local
 
36
        R_OPSTACK,                              // global
 
37
 
 
38
        // constants    
 
39
        R_MEMBASE,                      // global
 
40
        R_MEMMASK,
 
41
        R_ASMCALL,                      // global
 
42
    R_INSTRUCTIONS,             // global
 
43
    R_NUM_INSTRUCTIONS, // global
 
44
    R_CVM,                              // currentVM
 
45
    
 
46
        // temps
 
47
        R_TOP = 11,
 
48
        R_SECOND = 12,
 
49
        R_EA = 2                                // effective address calculation
 
50
         
 
51
} regNums_t;
 
52
 
 
53
#define RG_REAL_STACK           r1
 
54
#define RG_STACK                        r3
 
55
#define RG_OPSTACK                      r4
 
56
#define RG_MEMBASE                      r5
 
57
#define RG_MEMMASK                      r6
 
58
#define RG_ASMCALL                      r7
 
59
#define RG_INSTRUCTIONS         r8
 
60
#define RG_NUM_INSTRUCTIONS     r9
 
61
#define RG_CVM                          r10
 
62
#define RG_TOP                          r12
 
63
#define RG_SECOND                       r13
 
64
#define RG_EA                           r14
 
65
 
 
66
// this doesn't have the low order bits set for instructions i'm not using...
 
67
typedef enum {
 
68
        PPC_TDI         = 0x08000000,
 
69
        PPC_TWI         = 0x0c000000,
 
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,
 
78
        PPC_BC          = 0x40000000,
 
79
        PPC_SC          = 0x44000000,
 
80
        PPC_B           = 0x48000000,
 
81
 
 
82
        PPC_MCRF        = 0x4c000000,
 
83
        PPC_BCLR        = 0x4c000020,
 
84
        PPC_RFID        = 0x4c000000,
 
85
        PPC_CRNOR       = 0x4c000000,
 
86
        PPC_RFI         = 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,
 
94
//------------
 
95
        PPC_BCCTR       = 0x4c000420,
 
96
        PPC_RLWIMI      = 0x50000000,
 
97
        PPC_RLWINM      = 0x54000000,
 
98
        PPC_RLWNM       = 0x5c000000,
 
99
        PPC_ORI         = 0x60000000,
 
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,
 
112
        PPC_TW          = 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,
 
128
//------------
 
129
        PPC_DCBST       = 0x7c000000,
 
130
        PPC_LWZUX       = 0x7c00006c,
 
131
        PPC_CNTLZD      = 0x7c000000,
 
132
        PPC_ANDC        = 0x7c000000,
 
133
        PPC_TD          = 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,
 
162
//------------
 
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,
 
189
        PPC_OR          = 0x7c000378,
 
190
        PPC_DIVDU       = 0x7c000000,
 
191
        PPC_DIVWU       = 0x7c000396,
 
192
        PPC_MTSPR       = 0x7c0003a6,
 
193
        PPC_DCBI        = 0x7c000000,
 
194
        PPC_NAND        = 0x7c000000,
 
195
        PPC_DIVD        = 0x7c000000,
 
196
//------------
 
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,
 
230
//------------
 
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,
 
258
        PPC_LD          = 0xe8000000,
 
259
        PPC_LDU         = 0xe8000001,
 
260
        PPC_LWA         = 0xe8000002,
 
261
        PPC_FDIVS       = 0xec000024,
 
262
        PPC_FSUBS       = 0xec000028,
 
263
        PPC_FADDS       = 0xec00002a,
 
264
//------------
 
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,
 
298
//------------
 
299
        PPC_MFFS        = 0xfc000000,
 
300
        PPC_MTFSF       = 0xfc000000,
 
301
        PPC_FCTID       = 0xfc000000,
 
302
        PPC_FCTIDZ      = 0xfc000000,
 
303
        PPC_FCFID       = 0xfc000000
 
304
        
 
305
} ppcOpcodes_t;
 
306
 
 
307
 
 
308
// the newly generated code
 
309
static  unsigned        *buf;
 
310
static  int             compiledOfs;    // in dwords
 
311
 
 
312
// fromt the original bytecode
 
313
static  byte    *code;
 
314
static  int             pc;
 
315
 
 
316
void AsmCall( void );
 
317
 
 
318
double  itofConvert[2];
 
319
 
 
320
static int      Constant4( void ) {
 
321
        int             v;
 
322
 
 
323
        v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
 
324
        pc += 4;
 
325
        return v;
 
326
}
 
327
 
 
328
static int      Constant1( void ) {
 
329
        int             v;
 
330
 
 
331
        v = code[pc];
 
332
        pc += 1;
 
333
        return v;
 
334
}
 
335
 
 
336
static void Emit4( int i ) {
 
337
        buf[ compiledOfs ] = i;
 
338
        compiledOfs++;
 
339
}
 
340
 
 
341
static void Inst( int opcode, int destReg, int aReg, int bReg ) {
 
342
    unsigned            r;
 
343
 
 
344
    r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
 
345
    buf[ compiledOfs ] = r;
 
346
    compiledOfs++;
 
347
}
 
348
 
 
349
static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) {
 
350
    unsigned            r;
 
351
 
 
352
    r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
 
353
    buf[ compiledOfs ] = r;
 
354
    compiledOfs++;
 
355
}
 
356
 
 
357
static void InstImm( int opcode, int destReg, int aReg, int immediate ) {
 
358
        unsigned                r;
 
359
        
 
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 );
 
362
        }
 
363
        r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
 
364
        buf[ compiledOfs ] = r;
 
365
        compiledOfs++;
 
366
}
 
367
 
 
368
static void InstImmU( int opcode, int destReg, int aReg, int immediate ) {
 
369
        unsigned                r;
 
370
        
 
371
        if ( immediate > 0xffff || immediate < 0 ) {
 
372
                Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
 
373
        }
 
374
    r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
 
375
        buf[ compiledOfs ] = r;
 
376
        compiledOfs++;
 
377
}
 
378
 
 
379
static qboolean rtopped;
 
380
static int pop0, pop1, oc0, oc1;
 
381
static vm_t *tvm;
 
382
static int instruction;
 
383
static byte *jused;
 
384
static int pass;
 
385
 
 
386
static void ltop() {
 
387
    if (rtopped == qfalse) {
 
388
        InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 );                // get value from opstack
 
389
    }
 
390
}
 
391
 
 
392
static void ltopandsecond() {
 
393
    if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU |  R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
 
394
        compiledOfs--;
 
395
        if (!pass) {
 
396
            tvm->instructionPointers[instruction] = compiledOfs * 4;
 
397
        }
 
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 ) {
 
401
        compiledOfs--;
 
402
        if (!pass) {
 
403
            tvm->instructionPointers[instruction] = compiledOfs * 4;
 
404
        }
 
405
        InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
 
406
        InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
 
407
    } else {
 
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 );
 
411
    }
 
412
    rtopped = qfalse;
 
413
}
 
414
 
 
415
// TJW: Unused
 
416
#if 0
 
417
static void fltop() {
 
418
    if (rtopped == qfalse) {
 
419
        InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );                // get value from opstack
 
420
    }
 
421
}
 
422
#endif
 
423
 
 
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 );
 
428
    rtopped = qfalse;
 
429
        return;
 
430
}
 
431
 
 
432
/*
 
433
=================
 
434
VM_Compile
 
435
=================
 
436
*/
 
437
void VM_Compile( vm_t *vm, vmHeader_t *header ) {
 
438
        int             op;
 
439
        int             maxLength;
 
440
        int             v;
 
441
        int             i;
 
442
        
 
443
        // set up the into-to-float variables
 
444
        ((int *)itofConvert)[0] = 0x43300000;
 
445
        ((int *)itofConvert)[1] = 0x80000000;
 
446
        ((int *)itofConvert)[2] = 0x43300000;
 
447
 
 
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);
 
453
        
 
454
    // compile everything twice, so the second pass will have valid instruction
 
455
    // pointers for branches
 
456
    for ( pass = -1 ; pass < 2 ; pass++ ) {
 
457
 
 
458
        rtopped = qfalse;
 
459
        // translate all instructions
 
460
        pc = 0;
 
461
        
 
462
        pop0 = 343545;
 
463
        pop1 = 2443545;
 
464
        oc0 = -2343535;
 
465
        oc1 = 24353454;
 
466
        tvm = vm;
 
467
        code = (byte *)header + header->codeOffset;
 
468
        compiledOfs = 0;
 
469
#ifndef __GNUC__
 
470
                // metrowerks seems to require this header in front of functions
 
471
                Emit4( (int)(buf+2) );
 
472
                Emit4( 0 );
 
473
#endif
 
474
 
 
475
                for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
 
476
            if ( compiledOfs*4 > maxLength - 16 ) {
 
477
                Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
 
478
            }
 
479
 
 
480
            op = code[ pc ];
 
481
            if ( !pass ) {
 
482
                vm->instructionPointers[ instruction ] = compiledOfs * 4;
 
483
            }
 
484
            pc++;
 
485
            switch ( op ) {
 
486
            case 0:
 
487
                break;
 
488
            case OP_BREAK:
 
489
                InstImmU( PPC_ADDI, R_TOP, 0, 0 );
 
490
                InstImm( PPC_LWZ, R_TOP, R_TOP, 0 );                    // *(int *)0 to crash to debugger
 
491
                rtopped = qfalse;
 
492
                break;
 
493
            case OP_ENTER:
 
494
                InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() );    // sub R_STACK, R_STACK, imm
 
495
                rtopped = qfalse;
 
496
                break;
 
497
            case OP_CONST:
 
498
                v = Constant4();
 
499
                if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
 
500
                    v &= vm->dataMask;
 
501
                }
 
502
                if ( v < 32768 && v >= -32768 ) {
 
503
                    InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff );
 
504
                } else {
 
505
                    InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff );
 
506
                    if ( v & 0xffff ) {
 
507
                        InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff );
 
508
                    }
 
509
                }
 
510
                if (code[pc] == OP_LOAD4) {
 
511
                    Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE );          // load from memory base
 
512
                    pc++;
 
513
                    instruction++;
 
514
                } else if (code[pc] == OP_LOAD2) {
 
515
                    Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE );          // load from memory base
 
516
                    pc++;
 
517
                    instruction++;
 
518
                } else if (code[pc] == OP_LOAD1) {
 
519
                    Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE );          // load from memory base
 
520
                    pc++;
 
521
                    instruction++;
 
522
                }
 
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
 
528
                    pc++;
 
529
                    instruction++;
 
530
                    rtopped = qfalse;
 
531
                    break;
 
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
 
537
                    pc++;
 
538
                    instruction++;
 
539
                    rtopped = qfalse;
 
540
                    break;
 
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
 
546
                    pc++;
 
547
                    instruction++;
 
548
                    rtopped = qfalse;
 
549
                    break;
 
550
                }
 
551
                if (code[pc] == OP_JUMP) {
 
552
                    jused[v] = 1;
 
553
                }
 
554
                InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
 
555
                rtopped = qtrue;
 
556
                break;
 
557
            case OP_LOCAL:
 
558
                oc0 = oc1;
 
559
                oc1 = Constant4();
 
560
                if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
 
561
                    oc1 &= vm->dataMask;
 
562
                }
 
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
 
566
                    pc++;
 
567
                    instruction++;
 
568
                } else if (code[pc] == OP_LOAD2) {
 
569
                    Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE );          // load from memory base
 
570
                    pc++;
 
571
                    instruction++;
 
572
                } else if (code[pc] == OP_LOAD1) {
 
573
                    Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE );          // load from memory base
 
574
                    pc++;
 
575
                    instruction++;
 
576
                }
 
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
 
582
                    pc++;
 
583
                    instruction++;
 
584
                    rtopped = qfalse;
 
585
                    break;
 
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
 
591
                    pc++;
 
592
                    instruction++;
 
593
                    rtopped = qfalse;
 
594
                    break;
 
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
 
600
                    pc++;
 
601
                    instruction++;
 
602
                    rtopped = qfalse;
 
603
                    break;
 
604
                }
 
605
                InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 );
 
606
                rtopped = qtrue;
 
607
                break;
 
608
            case OP_ARG:
 
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 );
 
613
                rtopped = qfalse;
 
614
                break;
 
615
            case OP_CALL:
 
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
 
618
 
 
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
 
621
 
 
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
 
625
                rtopped = qfalse;
 
626
                break;
 
627
            case OP_PUSH:
 
628
                InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 );
 
629
                rtopped = qfalse;
 
630
                break;
 
631
            case OP_POP:
 
632
                InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
 
633
                rtopped = qfalse;
 
634
                break;
 
635
            case OP_LEAVE:
 
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
 
638
                rtopped = qfalse;
 
639
                break;
 
640
            case OP_LOAD4:
 
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 );
 
645
                rtopped = qtrue;
 
646
                break;
 
647
            case OP_LOAD2:
 
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 );
 
652
                rtopped = qtrue;
 
653
                break;
 
654
            case OP_LOAD1:
 
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 );
 
659
                rtopped = qtrue;
 
660
                break;
 
661
            case OP_STORE4:
 
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
 
665
                rtopped = qfalse;
 
666
                break;
 
667
            case OP_STORE2:
 
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
 
671
                rtopped = qfalse;
 
672
                break;
 
673
            case OP_STORE1:
 
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
 
677
                rtopped = qfalse;
 
678
                break;
 
679
 
 
680
            case OP_EQ:
 
681
                ltopandsecond();                                        // get value from opstack
 
682
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
683
                i = Constant4();
 
684
                                jused[i] = 1;
 
685
                InstImm( PPC_BC, 4, 2, 8 );
 
686
                if ( pass==1 ) {
 
687
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
 
688
                } else {
 
689
                    v = 0;             
 
690
                }
 
691
                Emit4(PPC_B | (v&0x3ffffff) );
 
692
                                rtopped = qfalse;
 
693
                break;
 
694
            case OP_NE:
 
695
                ltopandsecond();                                        // get value from opstack
 
696
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
697
                i = Constant4();
 
698
                                jused[i] = 1;
 
699
                InstImm( PPC_BC, 12, 2, 8 );
 
700
                if ( pass==1 ) {
 
701
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
 
702
                } else {
 
703
                    v = 0;
 
704
                }
 
705
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
706
//                InstImm( PPC_BC, 4, 2, v );
 
707
 
 
708
                                rtopped = qfalse;
 
709
                break;
 
710
            case OP_LTI:
 
711
                ltopandsecond();                                        // get value from opstack
 
712
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
713
                i = Constant4();
 
714
                                jused[i] = 1;
 
715
                InstImm( PPC_BC, 4, 0, 8 );
 
716
                if ( pass==1 ) {
 
717
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
718
                } else {
 
719
                    v = 0;
 
720
                }
 
721
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
722
//                InstImm( PPC_BC, 12, 0, v );
 
723
                                rtopped = qfalse;
 
724
                break;
 
725
            case OP_LEI:
 
726
                ltopandsecond();                                        // get value from opstack
 
727
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
728
                i = Constant4();
 
729
                                jused[i] = 1;
 
730
                InstImm( PPC_BC, 12, 1, 8 );
 
731
                if ( pass==1 ) {
 
732
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
733
                } else {
 
734
                    v = 0;
 
735
                }
 
736
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
737
//                InstImm( PPC_BC, 4, 1, v );
 
738
                                rtopped = qfalse;
 
739
                break;
 
740
            case OP_GTI:
 
741
                ltopandsecond();                // get value from opstack
 
742
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
743
                i = Constant4();
 
744
                                jused[i] = 1;
 
745
                InstImm( PPC_BC, 4, 1, 8 );
 
746
                if ( pass==1 ) {
 
747
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
748
                } else {
 
749
                    v = 0;
 
750
                }
 
751
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
752
//                InstImm( PPC_BC, 12, 1, v );
 
753
                                rtopped = qfalse;
 
754
                break;
 
755
            case OP_GEI:
 
756
                ltopandsecond();                // get value from opstack
 
757
                Inst( PPC_CMP, 0, R_SECOND, R_TOP );
 
758
                i = Constant4();
 
759
                                jused[i] = 1;
 
760
                InstImm( PPC_BC, 12, 0, 8 );
 
761
                if ( pass==1 ) {
 
762
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
763
                } else {
 
764
                    v = 0;
 
765
                }
 
766
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
767
//                InstImm( PPC_BC, 4, 0, v );
 
768
                                rtopped = qfalse;
 
769
                break;
 
770
            case OP_LTU:
 
771
                ltopandsecond();                // get value from opstack
 
772
                Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
 
773
                i = Constant4();
 
774
                jused[i] = 1;
 
775
                InstImm( PPC_BC, 4, 0, 8 );
 
776
                if ( pass==1 ) {
 
777
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
778
                } else {
 
779
                    v = 0;
 
780
                }
 
781
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
782
//                InstImm( PPC_BC, 12, 0, v );
 
783
                rtopped = qfalse;
 
784
                break;
 
785
            case OP_LEU:
 
786
                ltopandsecond();                // get value from opstack
 
787
                Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
 
788
                i = Constant4();
 
789
                jused[i] = 1;
 
790
                InstImm( PPC_BC, 12, 1, 8 );
 
791
                if ( pass==1 ) {
 
792
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
793
                } else {
 
794
                    v = 0;
 
795
                }
 
796
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
797
//                InstImm( PPC_BC, 4, 1, v );
 
798
                rtopped = qfalse;
 
799
                break;
 
800
            case OP_GTU:
 
801
                ltopandsecond();                // get value from opstack
 
802
                Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
 
803
                i = Constant4();
 
804
                jused[i] = 1;
 
805
                InstImm( PPC_BC, 4, 1, 8 );
 
806
                if ( pass==1 ) {
 
807
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
808
                } else {
 
809
                    v = 0;
 
810
                }
 
811
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
812
//                InstImm( PPC_BC, 12, 1, v );
 
813
                rtopped = qfalse;
 
814
                break;
 
815
            case OP_GEU:
 
816
                ltopandsecond();                // get value from opstack
 
817
                Inst( PPC_CMPL, 0, R_SECOND, R_TOP );
 
818
                i = Constant4();
 
819
                jused[i] = 1;
 
820
                InstImm( PPC_BC, 12, 0, 8 );
 
821
                if ( pass==1 ) {
 
822
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
823
                } else {
 
824
                    v = 0;
 
825
                }
 
826
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
827
//                InstImm( PPC_BC, 4, 0, v );
 
828
                rtopped = qfalse;
 
829
                break;
 
830
                
 
831
            case OP_EQF:
 
832
                fltopandsecond();               // get value from opstack
 
833
                Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
 
834
                i = Constant4();
 
835
                jused[i] = 1;
 
836
                InstImm( PPC_BC, 4, 2, 8 );
 
837
                if ( pass==1 ) {
 
838
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
839
                } else {
 
840
                    v = 0;
 
841
                }
 
842
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
843
//                InstImm( PPC_BC, 12, 2, v );
 
844
                rtopped = qfalse;
 
845
                break;                  
 
846
            case OP_NEF:
 
847
                fltopandsecond();               // get value from opstack
 
848
                Inst( PPC_FCMPU, 0, R_TOP, R_SECOND );
 
849
                i = Constant4();
 
850
                jused[i] = 1;
 
851
                InstImm( PPC_BC, 12, 2, 8 );
 
852
                if ( pass==1 ) {
 
853
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
854
                } else {
 
855
                    v = 0;
 
856
                }
 
857
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
858
//                InstImm( PPC_BC, 4, 2, v );
 
859
                rtopped = qfalse;
 
860
                break;                  
 
861
            case OP_LTF:
 
862
                fltopandsecond();               // get value from opstack
 
863
                Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
 
864
                i = Constant4();
 
865
                jused[i] = 1;
 
866
                InstImm( PPC_BC, 4, 0, 8 );
 
867
                if ( pass==1 ) {
 
868
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
869
                } else {
 
870
                    v = 0;
 
871
                }
 
872
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
873
//                InstImm( PPC_BC, 12, 0, v );
 
874
                rtopped = qfalse;
 
875
                break;                  
 
876
            case OP_LEF:
 
877
                fltopandsecond();               // get value from opstack
 
878
                Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
 
879
                i = Constant4();
 
880
                jused[i] = 1;
 
881
                InstImm( PPC_BC, 12, 1, 8 );
 
882
                if ( pass==1 ) {
 
883
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
884
                } else {
 
885
                    v = 0;
 
886
                }
 
887
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
888
//                InstImm( PPC_BC, 4, 1, v );
 
889
                rtopped = qfalse;
 
890
                break;                  
 
891
            case OP_GTF:
 
892
                fltopandsecond();               // get value from opstack
 
893
                Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
 
894
                i = Constant4();
 
895
                jused[i] = 1;
 
896
                InstImm( PPC_BC, 4, 1, 8 );
 
897
                if ( pass==1 ) {
 
898
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
899
                } else {
 
900
                    v = 0;
 
901
                }
 
902
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
903
//                InstImm( PPC_BC, 12, 1, v );
 
904
                rtopped = qfalse;
 
905
                break;                  
 
906
            case OP_GEF:
 
907
                fltopandsecond();               // get value from opstack
 
908
                Inst( PPC_FCMPU, 0, R_SECOND, R_TOP );
 
909
                i = Constant4();
 
910
                jused[i] = 1;
 
911
                InstImm( PPC_BC, 12, 0, 8 );
 
912
                if ( pass==1 ) {
 
913
                    v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
 
914
                } else {
 
915
                    v = 0;
 
916
                }
 
917
                Emit4(PPC_B | (unsigned int)(v&0x3ffffff) );
 
918
//                InstImm( PPC_BC, 4, 0, v );
 
919
                rtopped = qfalse;
 
920
                break;
 
921
 
 
922
            case OP_NEGI:
 
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
 
926
                rtopped = qtrue;
 
927
                break;
 
928
            case OP_ADD:
 
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
 
933
                rtopped = qtrue;
 
934
                break;
 
935
            case OP_SUB:
 
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
 
940
                rtopped = qtrue;
 
941
                break;
 
942
            case OP_DIVI:
 
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
 
947
                rtopped = qtrue;
 
948
                break;
 
949
            case OP_DIVU:
 
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
 
954
                rtopped = qtrue;
 
955
                break;
 
956
            case OP_MODI:
 
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
 
963
                rtopped = qtrue;
 
964
                break;
 
965
            case OP_MODU:
 
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
 
972
                rtopped = qtrue;
 
973
                break;
 
974
            case OP_MULI:
 
975
            case OP_MULU:
 
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
 
980
                rtopped = qtrue;
 
981
                break;
 
982
            case OP_BAND:
 
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
 
987
                rtopped = qtrue;
 
988
                break;
 
989
            case OP_BOR:
 
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
 
994
                rtopped = qtrue;
 
995
                break;
 
996
            case OP_BXOR:
 
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
 
1001
                rtopped = qtrue;
 
1002
                break;
 
1003
            case OP_BCOM:
 
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
 
1007
                rtopped = qtrue;
 
1008
                break;
 
1009
            case OP_LSH:
 
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
 
1014
                rtopped = qtrue;
 
1015
                break;
 
1016
            case OP_RSHI:
 
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
 
1021
                rtopped = qtrue;
 
1022
                break;
 
1023
            case OP_RSHU:
 
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
 
1028
                rtopped = qtrue;
 
1029
                break;
 
1030
 
 
1031
            case OP_NEGF:
 
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
 
1035
                rtopped = qfalse;
 
1036
                break;
 
1037
            case OP_ADDF:
 
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
 
1042
                rtopped = qfalse;
 
1043
                break;
 
1044
            case OP_SUBF:
 
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
 
1049
                rtopped = qfalse;
 
1050
                break;
 
1051
            case OP_DIVF:
 
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
 
1056
                rtopped = qfalse;
 
1057
                break;
 
1058
            case OP_MULF:
 
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
 
1063
                rtopped = qfalse;
 
1064
                break;
 
1065
 
 
1066
            case OP_CVIF:
 
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
 
1078
                rtopped = qfalse;
 
1079
                break;
 
1080
            case OP_CVFI:
 
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
 
1084
                rtopped = qfalse;
 
1085
                break;
 
1086
            case OP_SEX8:
 
1087
                ltop(); // get value from opstack
 
1088
                Inst( PPC_EXTSB, R_TOP, R_TOP, 0 );
 
1089
                InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
 
1090
                rtopped = qtrue;
 
1091
                break;
 
1092
            case OP_SEX16:
 
1093
                ltop(); // get value from opstack
 
1094
                Inst( PPC_EXTSH, R_TOP, R_TOP, 0 );
 
1095
                InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 );
 
1096
                rtopped = qtrue;
 
1097
                break;
 
1098
 
 
1099
            case OP_BLOCK_COPY:
 
1100
                v = Constant4() >> 2;
 
1101
                ltop();         // source
 
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
 
1107
 
 
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 );
 
1112
 
 
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
 
1116
                rtopped = qfalse;
 
1117
                break;
 
1118
 
 
1119
            case OP_JUMP:
 
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
 
1127
                rtopped = qfalse;
 
1128
                break;
 
1129
            default:
 
1130
                Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc );
 
1131
            }
 
1132
            pop0 = pop1;
 
1133
            pop1 = op;
 
1134
        }
 
1135
 
 
1136
        Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 );
 
1137
 
 
1138
        if ( pass == 0 ) {
 
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 );
 
1143
            Z_Free( buf );
 
1144
        
 
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;
 
1148
            }
 
1149
 
 
1150
            // go back over it in place now to fixup reletive jump targets
 
1151
            buf = (unsigned *)vm->codeBase;
 
1152
        }
 
1153
    }
 
1154
    Z_Free( jused );
 
1155
}
 
1156
 
 
1157
/*
 
1158
==============
 
1159
VM_CallCompiled
 
1160
 
 
1161
This function is called directly by the generated code
 
1162
==============
 
1163
*/
 
1164
int     VM_CallCompiled( vm_t *vm, int *args ) {
 
1165
        int             stack[1024];
 
1166
        int             programStack;
 
1167
        int             stackOnEntry;
 
1168
        byte    *image;
 
1169
 
 
1170
        currentVM = vm;
 
1171
 
 
1172
        // interpret the code
 
1173
        vm->currentlyInterpreting = qtrue;
 
1174
 
 
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;
 
1179
        
 
1180
        // set up the stack frame 
 
1181
        programStack -= 48;
 
1182
 
 
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
 
1195
 
 
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
 
1199
#ifdef __GNUC__
 
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,
 
1204
        (int)vm );
 
1205
#else
 
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,
 
1210
        (int)vm );
 
1211
#endif
 
1212
        vm->programStack = stackOnEntry;
 
1213
 
 
1214
    vm->currentlyInterpreting = qfalse;
 
1215
 
 
1216
        return stack[1];
 
1217
}
 
1218
 
 
1219
 
 
1220
/*
 
1221
==================
 
1222
AsmCall
 
1223
 
 
1224
Put this at end of file because gcc messes up debug line numbers 
 
1225
==================
 
1226
*/
 
1227
#ifdef __GNUC__
 
1228
 
 
1229
void AsmCall( void ) {
 
1230
asm (
 
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"
 
1234
 
 
1235
    // see if it is a system trap
 
1236
"    cmpwi      r12,0                   \n"     // RG_TOP, 0 \n"
 
1237
"    bc         12,0, systemTrap        \n"
 
1238
 
 
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
 
1244
);
 
1245
 
 
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
 
1249
#else
 
1250
    // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame
 
1251
    asm (
 
1252
"       lwz             r1,0(r1)        \n"     // pop off the GCC AsmCall frame
 
1253
"       lmw             r30,-8(r1)      \n"
 
1254
);
 
1255
#endif
 
1256
 
 
1257
asm (
 
1258
"           bcctr       20,0            \n" // when it hits a leave, it will branch to the current link register
 
1259
 
 
1260
    // calling a system trap
 
1261
"systemTrap:                            \n"
 
1262
        // convert to positive system call number
 
1263
"       subfic  r12,r12,-1              \n"
 
1264
 
 
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
 
1277
 
 
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)
 
1281
 
 
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)
 
1285
 
 
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
 
1290
"    bcctrl     20,0                    \n"
 
1291
"    mr         r12,r3                  \n"     // RG_TOP, r3
 
1292
 
 
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
 
1304
 
 
1305
    // restore the old link register
 
1306
"    mtlr       r13                     \n"     // RG_SECOND
 
1307
 
 
1308
    // save off the return value
 
1309
"    stwu       r12,4(r4)               \n"     // RG_TOP, 0(RG_OPSTACK)
 
1310
 
 
1311
        // GCC adds its own prolog / epilog code
 
1312
 );
 
1313
}
 
1314
#else
 
1315
 
 
1316
// codewarrior version
 
1317
 
 
1318
void asm AsmCall( void ) {
 
1319
 
 
1320
    // pop off the destination instruction
 
1321
 
 
1322
    lwz         r12,0(r4)       // RG_TOP, 0(RG_OPSTACK)
 
1323
 
 
1324
    addi        r4,r4,-4        // RG_OPSTACK, RG_OPSTACK, -4
 
1325
 
 
1326
 
 
1327
 
 
1328
    // see if it is a system trap
 
1329
 
 
1330
    cmpwi       r12,0           // RG_TOP, 0
 
1331
 
 
1332
    bc          12,0, systemTrap
 
1333
 
 
1334
 
 
1335
 
 
1336
    // calling another VM function, so lookup in instructionPointers
 
1337
 
 
1338
    slwi        r12,r12,2               // RG_TOP,RG_TOP,2
 
1339
 
 
1340
                        // FIXME: range check
 
1341
 
 
1342
    lwzx        r12, r8, r12    // RG_TOP, RG_INSTRUCTIONS(RG_TOP)      
 
1343
 
 
1344
    mtctr       r12                     // RG_TOP
 
1345
 
 
1346
 
 
1347
 
 
1348
    bcctr       20,0            // when it hits a leave, it will branch to the current link register
 
1349
 
 
1350
 
 
1351
 
 
1352
    // calling a system trap
 
1353
 
 
1354
systemTrap:
 
1355
 
 
1356
        // convert to positive system call number
 
1357
 
 
1358
        subfic  r12,r12,-1
 
1359
 
 
1360
 
 
1361
 
 
1362
    // save all our registers, including the current link register
 
1363
 
 
1364
    mflr        r13                     // RG_SECOND            // copy off our link register
 
1365
 
 
1366
        addi    r1,r1,-92       // required 24 byets of linkage, 32 bytes of parameter, plus our saves
 
1367
 
 
1368
    stw         r3,56(r1)       // RG_STACK, -36(REAL_STACK)
 
1369
 
 
1370
    stw         r4,60(r1)       // RG_OPSTACK, 4(RG_REAL_STACK)
 
1371
 
 
1372
    stw         r5,64(r1)       // RG_MEMBASE, 8(RG_REAL_STACK)
 
1373
 
 
1374
    stw         r6,68(r1)       // RG_MEMMASK, 12(RG_REAL_STACK)
 
1375
 
 
1376
    stw         r7,72(r1)       // RG_ASMCALL, 16(RG_REAL_STACK)
 
1377
 
 
1378
    stw         r8,76(r1)       // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
 
1379
 
 
1380
    stw         r9,80(r1)       // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
 
1381
 
 
1382
    stw         r10,84(r1)      // RG_VM, 28(RG_REAL_STACK)
 
1383
 
 
1384
    stw         r13,88(r1)      // RG_SECOND, 32(RG_REAL_STACK) // link register
 
1385
 
 
1386
 
 
1387
 
 
1388
    // save the vm stack position to allow recursive VM entry
 
1389
 
 
1390
    addi        r13,r3,-4       // RG_TOP, RG_STACK, -4
 
1391
 
 
1392
    stw         r13,0(r10)      //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM)
 
1393
 
 
1394
 
 
1395
 
 
1396
    // save the system call number as the 0th parameter
 
1397
 
 
1398
    add         r3,r3,r5        // r3,  RG_STACK, RG_MEMBASE            // r3 is the first parameter to vm->systemCalls
 
1399
 
 
1400
    stwu        r12,4(r3)       // RG_TOP, 4(r3)
 
1401
 
 
1402
 
 
1403
 
 
1404
    // make the system call with the address of all the VM parms as a parameter
 
1405
 
 
1406
    // vm->systemCalls( &parms )
 
1407
 
 
1408
    lwz         r12,4(r10)      // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM)
 
1409
 
 
1410
    
 
1411
 
 
1412
    // perform macos cross fragment fixup crap
 
1413
 
 
1414
    lwz         r9,0(r12)
 
1415
 
 
1416
    stw         r2,52(r1)       // save old TOC
 
1417
 
 
1418
        lwz             r2,4(r12)
 
1419
 
 
1420
            
 
1421
 
 
1422
    mtctr       r9                      // RG_TOP
 
1423
 
 
1424
    bcctrl      20,0
 
1425
 
 
1426
    
 
1427
 
 
1428
    lwz         r2,52(r1)       // restore TOC
 
1429
 
 
1430
    
 
1431
 
 
1432
    mr          r12,r3          // RG_TOP, r3
 
1433
 
 
1434
 
 
1435
 
 
1436
    // pop our saved registers
 
1437
 
 
1438
        lwz             r3,56(r1)       // RG_STACK, 0(RG_REAL_STACK)
 
1439
 
 
1440
        lwz             r4,60(r1)       // RG_OPSTACK, 4(RG_REAL_STACK)
 
1441
 
 
1442
        lwz             r5,64(r1)       // RG_MEMBASE, 8(RG_REAL_STACK)
 
1443
 
 
1444
        lwz             r6,68(r1)       // RG_MEMMASK, 12(RG_REAL_STACK)
 
1445
 
 
1446
        lwz             r7,72(r1)       // RG_ASMCALL, 16(RG_REAL_STACK)
 
1447
 
 
1448
        lwz             r8,76(r1)       // RG_INSTRUCTIONS, 20(RG_REAL_STACK)
 
1449
 
 
1450
        lwz             r9,80(r1)       // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK)
 
1451
 
 
1452
        lwz             r10,84(r1)      // RG_VM, 28(RG_REAL_STACK)
 
1453
 
 
1454
        lwz             r13,88(r1)      // RG_SECOND, 32(RG_REAL_STACK)
 
1455
 
 
1456
    addi        r1,r1,92        // RG_REAL_STACK, RG_REAL_STACK, 36
 
1457
 
 
1458
 
 
1459
 
 
1460
    // restore the old link register
 
1461
 
 
1462
    mtlr        r13                     // RG_SECOND
 
1463
 
 
1464
 
 
1465
 
 
1466
    // save off the return value
 
1467
 
 
1468
    stwu        r12,4(r4)       // RG_TOP, 0(RG_OPSTACK)
 
1469
 
 
1470
 
 
1471
 
 
1472
        blr
 
1473
 
 
1474
}
 
1475
 
 
1476
 
 
1477
 
 
1478
 
 
1479
#endif