/[pearpc]/src/cpu/cpu_jitc_x86/ppc_alu.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/cpu/cpu_jitc_x86/ppc_alu.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (12 years, 2 months ago) by dpavlin
File size: 69455 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * ppc_alu.cc
4 *
5 * Copyright (C) 2003-2005 Sebastian Biallas (sb@biallas.net)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "debug/tracers.h"
22 #include "ppc_alu.h"
23 #include "ppc_dec.h"
24 #include "ppc_exc.h"
25 #include "ppc_cpu.h"
26 #include "ppc_opc.h"
27 #include "ppc_tools.h"
28
29 #include "jitc.h"
30 #include "jitc_asm.h"
31 #include "jitc_debug.h"
32 #include "x86asm.h"
33
34 static inline uint32 ppc_mask(int MB, int ME)
35 {
36 uint32 mask;
37 if (MB <= ME) {
38 if (ME-MB == 31) {
39 mask = 0xffffffff;
40 } else {
41 mask = ((1<<(ME-MB+1))-1)<<(31-ME);
42 }
43 } else {
44 mask = ppc_word_rotl((1<<(32-MB+ME+1))-1, 31-ME);
45 }
46 return mask;
47 }
48
49 static JITCFlow ppc_opc_gen_ori_oris_xori_xoris(X86ALUopc opc, uint32 imm, int rS, int rA)
50 {
51 if (imm) {
52 jitcClobberCarryAndFlags();
53 if (rA == rS) {
54 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
55 asmALURegImm(opc, a, imm);
56 } else {
57 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
58 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
59 asmALURegReg(X86_MOV, a, s);
60 asmALURegImm(opc, a, imm);
61 }
62 } else {
63 if (rA == rS) {
64 /* nop */
65 } else {
66 /* mov */
67 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
68 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
69 asmALURegReg(X86_MOV, a, s);
70 }
71 }
72 return flowContinue;
73 }
74
75 /*
76 * addx Add
77 * .422
78 */
79 void ppc_opc_addx()
80 {
81 int rD, rA, rB;
82 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
83 gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB];
84 if (gCPU.current_opc & PPC_OPC_Rc) {
85 // update cr0 flags
86 ppc_update_cr0(gCPU.gpr[rD]);
87 }
88 }
89 static JITCFlow ppc_opc_gen_add()
90 {
91 int rD, rA, rB;
92 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
93 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
94 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
95 if (rD == rA) {
96 // add rA, rA, rB
97 jitcClobberCarryAndFlags();
98 asmALURegReg(X86_ADD, a, b);
99 jitcDirtyRegister(a);
100 } else if (rD == rB) {
101 // add rB, rA, rB
102 jitcClobberCarryAndFlags();
103 asmALURegReg(X86_ADD, b, a);
104 jitcDirtyRegister(b);
105 } else {
106 // add rD, rA, rB
107 NativeReg result = jitcMapClientRegisterDirty(PPC_GPR(rD));
108 // lea result, [a+1*b+0]
109 byte modrm[6];
110 asmLEA(result, modrm, x86_mem_sib_r(modrm, a, 1, b, 0));
111 // result already is dirty
112 }
113 return flowContinue;
114 }
115 static JITCFlow ppc_opc_gen_addp()
116 {
117 int rD, rA, rB;
118 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
119 jitcClobberCarry();
120 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
121 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
122 if (rD == rA) {
123 // add r1, r1, r2
124 asmALURegReg(X86_ADD, a, b);
125 jitcDirtyRegister(a);
126 } else if (rD == rB) {
127 // add r1, r2, r1
128 asmALURegReg(X86_ADD, b, a);
129 jitcDirtyRegister(b);
130 } else {
131 // add r3, r1, r2
132 NativeReg result = jitcMapClientRegisterDirty(PPC_GPR(rD));
133 // lea doesn't update the flags
134 asmALURegReg(X86_MOV, result, a);
135 asmALURegReg(X86_ADD, result, b);
136 }
137 jitcMapFlagsDirty();
138 return flowContinue;
139 }
140 JITCFlow ppc_opc_gen_addx()
141 {
142 if (gJITC.current_opc & PPC_OPC_Rc) {
143 return ppc_opc_gen_addp();
144 } else {
145 return ppc_opc_gen_add();
146 }
147 }
148 /*
149 * addox Add with Overflow
150 * .422
151 */
152 void ppc_opc_addox()
153 {
154 int rD, rA, rB;
155 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
156 gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB];
157 if (gCPU.current_opc & PPC_OPC_Rc) {
158 // update cr0 flags
159 ppc_update_cr0(gCPU.gpr[rD]);
160 }
161 // update XER flags
162 PPC_ALU_ERR("addox unimplemented\n");
163 }
164 /*
165 * addcx Add Carrying
166 * .423
167 */
168 void ppc_opc_addcx()
169 {
170 int rD, rA, rB;
171 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
172 uint32 a = gCPU.gpr[rA];
173 gCPU.gpr[rD] = a + gCPU.gpr[rB];
174 gCPU.xer_ca = (gCPU.gpr[rD] < a);
175 if (gCPU.current_opc & PPC_OPC_Rc) {
176 // update cr0 flags
177 ppc_update_cr0(gCPU.gpr[rD]);
178 }
179 }
180 JITCFlow ppc_opc_gen_addcx()
181 {
182 int rD, rA, rB;
183 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
184 if (!(gJITC.current_opc & PPC_OPC_Rc)) jitcClobberFlags();
185 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
186 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
187 if (rD == rA) {
188 // add r1, r1, r2
189 asmALURegReg(X86_ADD, a, b);
190 jitcDirtyRegister(a);
191 } else if (rD == rB) {
192 // add r1, r2, r1
193 asmALURegReg(X86_ADD, b, a);
194 jitcDirtyRegister(b);
195 } else {
196 // add r3, r1, r2
197 NativeReg result = jitcMapClientRegisterDirty(PPC_GPR(rD));
198 // lea doesn't update the carry
199 asmALURegReg(X86_MOV, result, a);
200 asmALURegReg(X86_ADD, result, b);
201 }
202 jitcMapCarryDirty();
203 if (gJITC.current_opc & PPC_OPC_Rc) jitcMapFlagsDirty();
204 return flowContinue;
205 }
206 /*
207 * addcox Add Carrying with Overflow
208 * .423
209 */
210 void ppc_opc_addcox()
211 {
212 int rD, rA, rB;
213 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
214 uint32 a = gCPU.gpr[rA];
215 gCPU.gpr[rD] = a + gCPU.gpr[rB];
216 gCPU.xer_ca = (gCPU.gpr[rD] < a);
217 if (gCPU.current_opc & PPC_OPC_Rc) {
218 // update cr0 flags
219 ppc_update_cr0(gCPU.gpr[rD]);
220 }
221 // update XER flags
222 PPC_ALU_ERR("addcox unimplemented\n");
223 }
224 /*
225 * addex Add Extended
226 * .424
227 */
228 void ppc_opc_addex()
229 {
230 int rD, rA, rB;
231 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
232 uint32 a = gCPU.gpr[rA];
233 uint32 b = gCPU.gpr[rB];
234 uint32 ca = gCPU.xer_ca;
235 gCPU.gpr[rD] = a + b + ca;
236 gCPU.xer_ca = ppc_carry_3(a, b, ca);
237 if (gCPU.current_opc & PPC_OPC_Rc) {
238 // update cr0 flags
239 ppc_update_cr0(gCPU.gpr[rD]);
240 }
241 }
242 JITCFlow ppc_opc_gen_addex()
243 {
244 int rD, rA, rB;
245 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
246 if (!(gJITC.current_opc & PPC_OPC_Rc)) jitcClobberFlags();
247 jitcGetClientCarry();
248 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
249 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
250 if (rD == rA) {
251 // add r1, r1, r2
252 asmALURegReg(X86_ADC, a, b);
253 jitcDirtyRegister(a);
254 } else if (rD == rB) {
255 // add r1, r2, r1
256 asmALURegReg(X86_ADC, b, a);
257 jitcDirtyRegister(b);
258 } else {
259 // add r3, r1, r2
260 NativeReg result = jitcMapClientRegisterDirty(PPC_GPR(rD));
261 // lea doesn't update the carry
262 asmALURegReg(X86_MOV, result, a);
263 asmALURegReg(X86_ADC, result, b);
264 }
265 jitcMapCarryDirty();
266 if (gJITC.current_opc & PPC_OPC_Rc) jitcMapFlagsDirty();
267 return flowContinue;
268 }
269 /*
270 * addeox Add Extended with Overflow
271 * .424
272 */
273 void ppc_opc_addeox()
274 {
275 int rD, rA, rB;
276 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
277 uint32 a = gCPU.gpr[rA];
278 uint32 b = gCPU.gpr[rB];
279 uint32 ca = gCPU.xer_ca;
280 gCPU.gpr[rD] = a + b + ca;
281 gCPU.xer_ca = ppc_carry_3(a, b, ca);
282 if (gCPU.current_opc & PPC_OPC_Rc) {
283 // update cr0 flags
284 ppc_update_cr0(gCPU.gpr[rD]);
285 }
286 // update XER flags
287 PPC_ALU_ERR("addeox unimplemented\n");
288 }
289 /*
290 * addi Add Immediate
291 * .425
292 */
293 void ppc_opc_addi()
294 {
295 int rD, rA;
296 uint32 imm;
297 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
298 gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm;
299 }
300 JITCFlow ppc_opc_gen_addi_addis(int rD, int rA, uint32 imm)
301 {
302 if (rA == 0) {
303 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
304 if (imm == 0 && !jitcFlagsMapped() && !jitcCarryMapped()) {
305 jitcClobberCarryAndFlags();
306 asmALURegReg(X86_XOR, d, d);
307 } else {
308 asmMOVRegImm_NoFlags(d, imm);
309 }
310 } else {
311 if (rD == rA) {
312 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
313 if (!imm) {
314 // empty
315 } else if (imm == 1) {
316 // inc / dec doesn't clobber carry
317 jitcClobberFlags();
318 asmINCReg(a);
319 } else if (imm == 0xffffffff) {
320 jitcClobberFlags();
321 asmDECReg(a);
322 } else {
323 if (jitcFlagsMapped() || jitcCarryMapped()) {
324 // lea rA, [rB+imm]
325 byte modrm[6];
326 asmLEA(a, modrm, x86_mem_r(modrm, a, imm));
327 } else {
328 jitcClobberCarryAndFlags();
329 asmALURegImm(X86_ADD, a, imm);
330 }
331 }
332 } else {
333 if (imm) {
334 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
335 // lea d, [a+imm]
336 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
337 byte modrm[6];
338 asmLEA(d, modrm, x86_mem_r(modrm, a, imm));
339 } else {
340 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
341 // mov d, a
342 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
343 asmALURegReg(X86_MOV, d, a);
344 }
345 }
346 }
347 return flowContinue;
348 }
349 JITCFlow ppc_opc_gen_addi()
350 {
351 int rD, rA;
352 uint32 imm;
353 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, rD, rA, imm);
354 return ppc_opc_gen_addi_addis(rD, rA, imm);
355 }
356 /*
357 * addic Add Immediate Carrying
358 * .426
359 */
360 void ppc_opc_addic()
361 {
362 int rD, rA;
363 uint32 imm;
364 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
365 uint32 a = gCPU.gpr[rA];
366 gCPU.gpr[rD] = a + imm;
367 gCPU.xer_ca = (gCPU.gpr[rD] < a);
368 }
369 JITCFlow ppc_opc_gen_addic()
370 {
371 int rD, rA;
372 uint32 imm;
373 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, rD, rA, imm);
374 jitcClobberFlags();
375 if (rD == rA) {
376 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
377 asmALURegImm(X86_ADD, a, imm);
378 } else {
379 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
380 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
381 asmALURegReg(X86_MOV, d, a);
382 asmALURegImm(X86_ADD, d, imm);
383 }
384 jitcMapCarryDirty();
385 return flowContinue;
386 }
387 /*
388 * addic. Add Immediate Carrying and Record
389 * .427
390 */
391 void ppc_opc_addic_()
392 {
393 int rD, rA;
394 uint32 imm;
395 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
396 uint32 a = gCPU.gpr[rA];
397 gCPU.gpr[rD] = a + imm;
398 gCPU.xer_ca = (gCPU.gpr[rD] < a);
399 // update cr0 flags
400 ppc_update_cr0(gCPU.gpr[rD]);
401 }
402 JITCFlow ppc_opc_gen_addic_()
403 {
404 int rD, rA;
405 uint32 imm;
406 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, rD, rA, imm);
407 if (rD == rA) {
408 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
409 asmALURegImm(X86_ADD, a, imm);
410 } else {
411 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
412 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
413 asmALURegReg(X86_MOV, d, a);
414 asmALURegImm(X86_ADD, d, imm);
415 }
416 jitcMapCarryDirty();
417 jitcMapFlagsDirty();
418 return flowContinue;
419 }
420 /*
421 * addis Add Immediate Shifted
422 * .428
423 */
424 void ppc_opc_addis()
425 {
426 int rD, rA;
427 uint32 imm;
428 PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rD, rA, imm);
429 gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm;
430 }
431 JITCFlow ppc_opc_gen_addis()
432 {
433 int rD, rA;
434 uint32 imm;
435 PPC_OPC_TEMPL_D_Shift16(gJITC.current_opc, rD, rA, imm);
436 return ppc_opc_gen_addi_addis(rD, rA, imm);
437 }
438 /*
439 * addmex Add to Minus One Extended
440 * .429
441 */
442 void ppc_opc_addmex()
443 {
444 int rD, rA, rB;
445 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
446 PPC_OPC_ASSERT(rB == 0);
447 uint32 a = gCPU.gpr[rA];
448 uint32 ca = gCPU.xer_ca;
449 gCPU.gpr[rD] = a + ca + 0xffffffff;
450 gCPU.xer_ca = a || ca;
451 if (gCPU.current_opc & PPC_OPC_Rc) {
452 // update cr0 flags
453 ppc_update_cr0(gCPU.gpr[rD]);
454 }
455 }
456 JITCFlow ppc_opc_gen_addmex()
457 {
458 ppc_opc_gen_interpret(ppc_opc_addmex);
459 return flowEndBlock;
460
461 }
462 /*
463 * addmeox Add to Minus One Extended with Overflow
464 * .429
465 */
466 void ppc_opc_addmeox()
467 {
468 int rD, rA, rB;
469 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
470 PPC_OPC_ASSERT(rB == 0);
471 uint32 a = gCPU.gpr[rA];
472 uint32 ca = (gCPU.xer_ca);
473 gCPU.gpr[rD] = a + ca + 0xffffffff;
474 gCPU.xer_ca = (a || ca);
475 if (gCPU.current_opc & PPC_OPC_Rc) {
476 // update cr0 flags
477 ppc_update_cr0(gCPU.gpr[rD]);
478 }
479 // update XER flags
480 PPC_ALU_ERR("addmeox unimplemented\n");
481 }
482 /*
483 * addzex Add to Zero Extended
484 * .430
485 */
486 void ppc_opc_addzex()
487 {
488 int rD, rA, rB;
489 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
490 PPC_OPC_ASSERT(rB == 0);
491 uint32 a = gCPU.gpr[rA];
492 uint32 ca = gCPU.xer_ca;
493 gCPU.gpr[rD] = a + ca;
494 gCPU.xer_ca = ((a == 0xffffffff) && ca);
495 if (gCPU.current_opc & PPC_OPC_Rc) {
496 // update cr0 flags
497 ppc_update_cr0(gCPU.gpr[rD]);
498 }
499 }
500 JITCFlow ppc_opc_gen_addzex()
501 {
502 int rD, rA, rB;
503 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
504 if (!(gJITC.current_opc & PPC_OPC_Rc)) jitcClobberFlags();
505 jitcGetClientCarry();
506 NativeReg d;
507 if (rA == rD) {
508 d = jitcGetClientRegisterDirty(PPC_GPR(rD));
509 } else {
510 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
511 d = jitcMapClientRegisterDirty(PPC_GPR(rD));
512 asmALURegReg(X86_MOV, d, a);
513 }
514 asmALURegImm(X86_ADC, d, 0);
515 jitcMapCarryDirty();
516 if (gJITC.current_opc & PPC_OPC_Rc) jitcMapFlagsDirty();
517 return flowContinue;
518 }
519 /*
520 * addzeox Add to Zero Extended with Overflow
521 * .430
522 */
523 void ppc_opc_addzeox()
524 {
525 int rD, rA, rB;
526 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
527 PPC_OPC_ASSERT(rB == 0);
528 uint32 a = gCPU.gpr[rA];
529 uint32 ca = gCPU.xer_ca;
530 gCPU.gpr[rD] = a + ca;
531 gCPU.xer_ca = ((a == 0xffffffff) && ca);
532 if (gCPU.current_opc & PPC_OPC_Rc) {
533 // update cr0 flags
534 ppc_update_cr0(gCPU.gpr[rD]);
535 }
536 // update XER flags
537 PPC_ALU_ERR("addzeox unimplemented\n");
538 }
539
540 /*
541 * andx AND
542 * .431
543 */
544 void ppc_opc_andx()
545 {
546 int rS, rA, rB;
547 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
548 gCPU.gpr[rA] = gCPU.gpr[rS] & gCPU.gpr[rB];
549 if (gCPU.current_opc & PPC_OPC_Rc) {
550 // update cr0 flags
551 ppc_update_cr0(gCPU.gpr[rA]);
552 }
553 }
554 JITCFlow ppc_opc_gen_andx()
555 {
556 int rS, rA, rB;
557 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
558 if (gJITC.current_opc & PPC_OPC_Rc) {
559 jitcClobberCarry();
560 } else {
561 jitcClobberCarryAndFlags();
562 }
563 if (rA == rS) {
564 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
565 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
566 asmALURegReg(X86_AND, a, b);
567 } else if (rA == rB) {
568 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
569 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
570 asmALURegReg(X86_AND, a, s);
571 } else {
572 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
573 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
574 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
575 asmALURegReg(X86_MOV, a, s);
576 asmALURegReg(X86_AND, a, b);
577 }
578 if (gJITC.current_opc & PPC_OPC_Rc) {
579 jitcMapFlagsDirty();
580 }
581 return flowContinue;
582 }
583 /*
584 * andcx AND with Complement
585 * .432
586 */
587 void ppc_opc_andcx()
588 {
589 int rS, rA, rB;
590 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
591 gCPU.gpr[rA] = gCPU.gpr[rS] & ~gCPU.gpr[rB];
592 if (gCPU.current_opc & PPC_OPC_Rc) {
593 // update cr0 flags
594 ppc_update_cr0(gCPU.gpr[rA]);
595 }
596 }
597 JITCFlow ppc_opc_gen_andcx()
598 {
599 int rS, rA, rB;
600 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
601 if (gJITC.current_opc & PPC_OPC_Rc) {
602 jitcClobberCarry();
603 } else {
604 jitcClobberCarryAndFlags();
605 }
606 if (rA == rS) {
607 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
608 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
609 NativeReg tmp = jitcAllocRegister();
610 asmALURegReg(X86_MOV, tmp, b);
611 asmALUReg(X86_NOT, tmp);
612 asmALURegReg(X86_AND, a, tmp);
613 } else if (rA == rB) {
614 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
615 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
616 asmALUReg(X86_NOT, a);
617 asmALURegReg(X86_AND, a, s);
618 } else {
619 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
620 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
621 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
622 asmALURegReg(X86_MOV, a, b);
623 asmALUReg(X86_NOT, a);
624 asmALURegReg(X86_AND, a, s);
625 }
626 if (gJITC.current_opc & PPC_OPC_Rc) {
627 jitcMapFlagsDirty();
628 }
629 return flowContinue;
630 }
631 /*
632 * andi. AND Immediate
633 * .433
634 */
635 void ppc_opc_andi_()
636 {
637 int rS, rA;
638 uint32 imm;
639 PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
640 gCPU.gpr[rA] = gCPU.gpr[rS] & imm;
641 // update cr0 flags
642 ppc_update_cr0(gCPU.gpr[rA]);
643 }
644 JITCFlow ppc_opc_gen_andi_()
645 {
646 int rS, rA;
647 uint32 imm;
648 PPC_OPC_TEMPL_D_UImm(gJITC.current_opc, rS, rA, imm);
649 jitcClobberCarry();
650 if (rS == rA) {
651 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
652 asmALURegImm(X86_AND, a, imm);
653 } else {
654 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
655 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
656 asmALURegReg(X86_MOV, a, s);
657 asmALURegImm(X86_AND, a, imm);
658 }
659 jitcMapFlagsDirty();
660 return flowContinue;
661 }
662 /*
663 * andis. AND Immediate Shifted
664 * .434
665 */
666 void ppc_opc_andis_()
667 {
668 int rS, rA;
669 uint32 imm;
670 PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
671 gCPU.gpr[rA] = gCPU.gpr[rS] & imm;
672 // update cr0 flags
673 ppc_update_cr0(gCPU.gpr[rA]);
674 }
675 JITCFlow ppc_opc_gen_andis_()
676 {
677 int rS, rA;
678 uint32 imm;
679 PPC_OPC_TEMPL_D_Shift16(gJITC.current_opc, rS, rA, imm);
680 jitcClobberCarry();
681 if (rS == rA) {
682 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
683 asmALURegImm(X86_AND, a, imm);
684 } else {
685 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
686 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
687 asmALURegReg(X86_MOV, a, s);
688 asmALURegImm(X86_AND, a, imm);
689 }
690 jitcMapFlagsDirty();
691 return flowContinue;
692 }
693
694 /*
695 * cmp Compare
696 * .442
697 */
698 static uint32 ppc_cmp_and_mask[8] = {
699 0xfffffff0,
700 0xffffff0f,
701 0xfffff0ff,
702 0xffff0fff,
703 0xfff0ffff,
704 0xff0fffff,
705 0xf0ffffff,
706 0x0fffffff,
707 };
708
709 void ppc_opc_cmp()
710 {
711 uint32 cr;
712 int rA, rB;
713 PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB);
714 cr >>= 2;
715 sint32 a = gCPU.gpr[rA];
716 sint32 b = gCPU.gpr[rB];
717 uint32 c;
718 if (a < b) {
719 c = 8;
720 } else if (a > b) {
721 c = 4;
722 } else {
723 c = 2;
724 }
725 if (gCPU.xer & XER_SO) c |= 1;
726 cr = 7-cr;
727 gCPU.cr &= ppc_cmp_and_mask[cr];
728 gCPU.cr |= c<<(cr*4);
729 }
730 JITCFlow ppc_opc_gen_cmp()
731 {
732 uint32 cr;
733 int rA, rB;
734 PPC_OPC_TEMPL_X(gJITC.current_opc, cr, rA, rB);
735 cr >>= 2;
736 jitcClobberCarryAndFlags();
737 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
738 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
739 asmALURegReg(X86_CMP, a, b);
740 #if 0
741 if (cr == 0) {
742 asmCALL((NativeAddress)ppc_flush_flags_signed_0_asm);
743 } else {
744 jitcClobberRegister(EAX | NATIVE_REG);
745 asmMOVRegImm_NoFlags(EAX, (7-cr)/2);
746 asmCALL((cr & 1) ? (NativeAddress)ppc_flush_flags_signed_odd_asm : (NativeAddress)ppc_flush_flags_signed_even_asm);
747 }
748 #else
749 if (cr & 1) {
750 jitcFlushFlagsAfterCMP_L((7-cr)/2);
751 } else {
752 jitcFlushFlagsAfterCMP_U((7-cr)/2);
753 }
754 #endif
755 return flowContinue;
756 }
757 /*
758 * cmpi Compare Immediate
759 * .443
760 */
761 void ppc_opc_cmpi()
762 {
763 uint32 cr;
764 int rA;
765 uint32 imm;
766 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, cr, rA, imm);
767 cr >>= 2;
768 sint32 a = gCPU.gpr[rA];
769 sint32 b = imm;
770 uint32 c;
771 if (a < b) {
772 c = 8;
773 } else if (a > b) {
774 c = 4;
775 } else {
776 c = 2;
777 }
778 if (gCPU.xer & XER_SO) c |= 1;
779 cr = 7-cr;
780 gCPU.cr &= ppc_cmp_and_mask[cr];
781 gCPU.cr |= c<<(cr*4);
782 }
783 JITCFlow ppc_opc_gen_cmpi()
784 {
785 uint32 cr;
786 int rA;
787 uint32 imm;
788 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, cr, rA, imm);
789 cr >>= 2;
790 jitcClobberCarryAndFlags();
791 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
792 asmALURegImm(X86_CMP, a, imm);
793 #if 0
794 if (cr == 0) {
795 asmCALL((NativeAddress)ppc_flush_flags_signed_0_asm);
796 } else {
797 jitcClobberRegister(EAX | NATIVE_REG);
798 asmMOVRegImm_NoFlags(EAX, (7-cr)/2);
799 asmCALL((cr & 1) ? (NativeAddress)ppc_flush_flags_signed_odd_asm : (NativeAddress)ppc_flush_flags_signed_even_asm);
800 }
801 #else
802 if (cr & 1) {
803 jitcFlushFlagsAfterCMP_L((7-cr)/2);
804 } else {
805 jitcFlushFlagsAfterCMP_U((7-cr)/2);
806 }
807 #endif
808 return flowContinue;
809 }
810 /*
811 * cmpl Compare Logical
812 * .444
813 */
814 void ppc_opc_cmpl()
815 {
816 uint32 cr;
817 int rA, rB;
818 PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB);
819 cr >>= 2;
820 uint32 a = gCPU.gpr[rA];
821 uint32 b = gCPU.gpr[rB];
822 uint32 c;
823 if (a < b) {
824 c = 8;
825 } else if (a > b) {
826 c = 4;
827 } else {
828 c = 2;
829 }
830 if (gCPU.xer & XER_SO) c |= 1;
831 cr = 7-cr;
832 gCPU.cr &= ppc_cmp_and_mask[cr];
833 gCPU.cr |= c<<(cr*4);
834 }
835 JITCFlow ppc_opc_gen_cmpl()
836 {
837 uint32 cr;
838 int rA, rB;
839 PPC_OPC_TEMPL_X(gJITC.current_opc, cr, rA, rB);
840 cr >>= 2;
841 jitcClobberCarryAndFlags();
842 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
843 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
844 asmALURegReg(X86_CMP, a, b);
845 #if 0
846 if (cr == 0) {
847 asmCALL((NativeAddress)ppc_flush_flags_unsigned_0_asm);
848 } else {
849 jitcClobberRegister(EAX | NATIVE_REG);
850 asmMOVRegImm_NoFlags(EAX, (7-cr)/2);
851 asmCALL((cr & 1) ? (NativeAddress)ppc_flush_flags_unsigned_odd_asm : (NativeAddress)ppc_flush_flags_unsigned_even_asm);
852 }
853 #else
854 if (cr & 1) {
855 jitcFlushFlagsAfterCMPL_L((7-cr)/2);
856 } else {
857 jitcFlushFlagsAfterCMPL_U((7-cr)/2);
858 }
859 #endif
860 return flowContinue;
861 }
862 /*
863 * cmpli Compare Logical Immediate
864 * .445
865 */
866 void ppc_opc_cmpli()
867 {
868 uint32 cr;
869 int rA;
870 uint32 imm;
871 PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, cr, rA, imm);
872 cr >>= 2;
873 uint32 a = gCPU.gpr[rA];
874 uint32 b = imm;
875 uint32 c;
876 if (a < b) {
877 c = 8;
878 } else if (a > b) {
879 c = 4;
880 } else {
881 c = 2;
882 }
883 if (gCPU.xer & XER_SO) c |= 1;
884 cr = 7-cr;
885 gCPU.cr &= ppc_cmp_and_mask[cr];
886 gCPU.cr |= c<<(cr*4);
887 }
888 JITCFlow ppc_opc_gen_cmpli()
889 {
890 uint32 cr;
891 int rA;
892 uint32 imm;
893 PPC_OPC_TEMPL_D_UImm(gJITC.current_opc, cr, rA, imm);
894 cr >>= 2;
895 jitcClobberCarryAndFlags();
896 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
897 asmALURegImm(X86_CMP, a, imm);
898 #if 0
899 if (cr == 0) {
900 asmCALL((NativeAddress)ppc_flush_flags_unsigned_0_asm);
901 } else {
902 jitcClobberRegister(EAX | NATIVE_REG);
903 asmMOVRegImm_NoFlags(EAX, (7-cr)/2);
904 asmCALL((cr & 1) ? (NativeAddress)ppc_flush_flags_unsigned_odd_asm : (NativeAddress)ppc_flush_flags_unsigned_even_asm);
905 }
906 #else
907 if (cr & 1) {
908 jitcFlushFlagsAfterCMPL_L((7-cr)/2);
909 } else {
910 jitcFlushFlagsAfterCMPL_U((7-cr)/2);
911 }
912 #endif
913 return flowContinue;
914 }
915
916 /*
917 * cntlzwx Count Leading Zeros Word
918 * .447
919 */
920 void ppc_opc_cntlzwx()
921 {
922 int rS, rA, rB;
923 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
924 PPC_OPC_ASSERT(rB==0);
925 uint32 n=0;
926 uint32 x=0x80000000;
927 uint32 v=gCPU.gpr[rS];
928 while (!(v & x)) {
929 n++;
930 if (n==32) break;
931 x>>=1;
932 }
933 gCPU.gpr[rA] = n;
934 if (gCPU.current_opc & PPC_OPC_Rc) {
935 // update cr0 flags
936 ppc_update_cr0(gCPU.gpr[rA]);
937 }
938 }
939 JITCFlow ppc_opc_gen_cntlzwx()
940 {
941 int rS, rA, rB;
942 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
943 jitcClobberCarryAndFlags();
944 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
945 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
946 NativeReg z = jitcAllocRegister();
947 asmALURegImm(X86_MOV, z, 0xffffffff);
948 asmBSxRegReg(X86_BSR, a, s);
949 asmCMOVRegReg(X86_Z, a, z);
950 asmALUReg(X86_NEG, a);
951 asmALURegImm(X86_ADD, a, 31);
952 if (gJITC.current_opc & PPC_OPC_Rc) {
953 jitcMapFlagsDirty();
954 }
955 return flowContinue;
956 }
957
958 /*
959 * crand Condition Register AND
960 * .448
961 */
962 void ppc_opc_crand()
963 {
964 int crD, crA, crB;
965 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
966 if ((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB)))) {
967 gCPU.cr |= (1<<(31-crD));
968 } else {
969 gCPU.cr &= ~(1<<(31-crD));
970 }
971 }
972 JITCFlow ppc_opc_gen_crand()
973 {
974 int crD, crA, crB;
975 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
976 jitcClobberCarryAndFlags();
977 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
978 NativeAddress nocrA = asmJxxFixup(X86_Z);
979 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
980 NativeAddress nocrB = asmJxxFixup(X86_Z);
981 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
982 NativeAddress end1 = asmJMPFixup();
983 asmResolveFixup(nocrB, asmHERE());
984 asmResolveFixup(nocrA, asmHERE());
985 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
986 asmResolveFixup(end1, asmHERE());
987 return flowContinue;
988 }
989 /*
990 * crandc Condition Register AND with Complement
991 * .449
992 */
993 void ppc_opc_crandc()
994 {
995 int crD, crA, crB;
996 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
997 if ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB)))) {
998 gCPU.cr |= (1<<(31-crD));
999 } else {
1000 gCPU.cr &= ~(1<<(31-crD));
1001 }
1002 }
1003 JITCFlow ppc_opc_gen_crandc()
1004 {
1005 int crD, crA, crB;
1006 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1007 jitcClobberCarryAndFlags();
1008 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
1009 NativeAddress nocrA = asmJxxFixup(X86_Z);
1010 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1011 NativeAddress nocrB = asmJxxFixup(X86_NZ);
1012 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1013 NativeAddress end1 = asmJMPFixup();
1014 asmResolveFixup(nocrB, asmHERE());
1015 asmResolveFixup(nocrA, asmHERE());
1016 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1017 asmResolveFixup(end1, asmHERE());
1018 return flowContinue;
1019 }
1020 /*
1021 * creqv Condition Register Equivalent
1022 * .450
1023 */
1024 void ppc_opc_creqv()
1025 {
1026 int crD, crA, crB;
1027 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1028 if (((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))
1029 || (!(gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) {
1030 gCPU.cr |= (1<<(31-crD));
1031 } else {
1032 gCPU.cr &= ~(1<<(31-crD));
1033 }
1034 }
1035 JITCFlow ppc_opc_gen_creqv()
1036 {
1037 int crD, crA, crB;
1038 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1039 jitcClobberCarryAndFlags();
1040 if (crA == crB) {
1041 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1042 } else {
1043 // crD = crA ? (crB ? 1 : 0) : (crB ? 0 : 1)
1044 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
1045 NativeAddress nocrA = asmJxxFixup(X86_Z);
1046 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1047 NativeAddress nocrB1 = asmJxxFixup(X86_Z);
1048 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1049 NativeAddress end1 = asmJMPFixup();
1050 asmResolveFixup(nocrB1, asmHERE());
1051 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1052 NativeAddress end2 = asmJMPFixup();
1053 asmResolveFixup(nocrA, asmHERE());
1054 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1055 NativeAddress nocrB2 = asmJxxFixup(X86_Z);
1056 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1057 NativeAddress end3 = asmJMPFixup();
1058 asmResolveFixup(nocrB2, asmHERE());
1059 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1060 asmResolveFixup(end1, asmHERE());
1061 asmResolveFixup(end2, asmHERE());
1062 asmResolveFixup(end3, asmHERE());
1063 }
1064 return flowContinue;
1065 }
1066 /*
1067 * crnand Condition Register NAND
1068 * .451
1069 */
1070 void ppc_opc_crnand()
1071 {
1072 int crD, crA, crB;
1073 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1074 if (!((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))) {
1075 gCPU.cr |= (1<<(31-crD));
1076 } else {
1077 gCPU.cr &= ~(1<<(31-crD));
1078 }
1079 }
1080 JITCFlow ppc_opc_gen_crnand()
1081 {
1082 int crD, crA, crB;
1083 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1084 jitcClobberCarryAndFlags();
1085 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
1086 NativeAddress nocrA = asmJxxFixup(X86_Z);
1087 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1088 NativeAddress nocrB = asmJxxFixup(X86_Z);
1089 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1090 NativeAddress end1 = asmJMPFixup();
1091 asmResolveFixup(nocrB, asmHERE());
1092 asmResolveFixup(nocrA, asmHERE());
1093 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1094 asmResolveFixup(end1, asmHERE());
1095 return flowContinue;
1096 }
1097 /*
1098 * crnor Condition Register NOR
1099 * .452
1100 */
1101 void ppc_opc_crnor()
1102 {
1103 int crD, crA, crB;
1104 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1105 uint32 t = (1<<(31-crA)) | (1<<(31-crB));
1106 if (!(gCPU.cr & t)) {
1107 gCPU.cr |= (1<<(31-crD));
1108 } else {
1109 gCPU.cr &= ~(1<<(31-crD));
1110 }
1111 }
1112 JITCFlow ppc_opc_gen_crnor()
1113 {
1114 int crD, crA, crB;
1115 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1116 jitcClobberCarryAndFlags();
1117 asmTESTDMemImm((uint32)&gCPU.cr, (1<<(31-crA)) | (1<<(31-crB)));
1118 NativeAddress notset = asmJxxFixup(X86_Z);
1119 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1120 NativeAddress end1 = asmJMPFixup();
1121 asmResolveFixup(notset, asmHERE());
1122 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1123 asmResolveFixup(end1, asmHERE());
1124 return flowContinue;
1125 }
1126 /*
1127 * cror Condition Register OR
1128 * .453
1129 */
1130 void ppc_opc_cror()
1131 {
1132 int crD, crA, crB;
1133 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1134 uint32 t = (1<<(31-crA)) | (1<<(31-crB));
1135 if (gCPU.cr & t) {
1136 gCPU.cr |= (1<<(31-crD));
1137 } else {
1138 gCPU.cr &= ~(1<<(31-crD));
1139 }
1140 }
1141 JITCFlow ppc_opc_gen_cror()
1142 {
1143 int crD, crA, crB;
1144 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1145 jitcClobberCarryAndFlags();
1146 asmTESTDMemImm((uint32)&gCPU.cr, (1<<(31-crA)) | (1<<(31-crB)));
1147 NativeAddress notset = asmJxxFixup(X86_Z);
1148 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1149 NativeAddress end1 = asmJMPFixup();
1150 asmResolveFixup(notset, asmHERE());
1151 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1152 asmResolveFixup(end1, asmHERE());
1153 return flowContinue;
1154 }
1155 /*
1156 * crorc Condition Register OR with Complement
1157 * .454
1158 */
1159 void ppc_opc_crorc()
1160 {
1161 int crD, crA, crB;
1162 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1163 if ((gCPU.cr & (1<<(31-crA))) || !(gCPU.cr & (1<<(31-crB)))) {
1164 gCPU.cr |= (1<<(31-crD));
1165 } else {
1166 gCPU.cr &= ~(1<<(31-crD));
1167 }
1168 }
1169
1170 JITCFlow ppc_opc_gen_crorc()
1171 {
1172 int crD, crA, crB;
1173 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1174 jitcClobberCarryAndFlags();
1175 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
1176 NativeAddress crAset = asmJxxFixup(X86_NZ);
1177 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1178 NativeAddress nocrB = asmJxxFixup(X86_Z);
1179 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1180 NativeAddress end1 = asmJMPFixup();
1181 asmResolveFixup(nocrB, asmHERE());
1182 asmResolveFixup(crAset, asmHERE());
1183 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1184 asmResolveFixup(end1, asmHERE());
1185 return flowContinue;
1186 }
1187 /*
1188 * crxor Condition Register XOR
1189 * .448
1190 */
1191 void ppc_opc_crxor()
1192 {
1193 int crD, crA, crB;
1194 PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
1195 if ((!(gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))
1196 || ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) {
1197 gCPU.cr |= (1<<(31-crD));
1198 } else {
1199 gCPU.cr &= ~(1<<(31-crD));
1200 }
1201 }
1202 JITCFlow ppc_opc_gen_crxor()
1203 {
1204 int crD, crA, crB;
1205 PPC_OPC_TEMPL_X(gJITC.current_opc, crD, crA, crB);
1206 jitcClobberCarryAndFlags();
1207 if (crA == crB) {
1208 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1209 } else {
1210 // crD = crA ? (crB ? 0 : 1) : (crB ? 1 : 0)
1211 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crA));
1212 NativeAddress nocrA = asmJxxFixup(X86_Z);
1213 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1214 NativeAddress nocrB1 = asmJxxFixup(X86_Z);
1215 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1216 NativeAddress end1 = asmJMPFixup();
1217 asmResolveFixup(nocrB1, asmHERE());
1218 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1219 NativeAddress end2 = asmJMPFixup();
1220 asmResolveFixup(nocrA, asmHERE());
1221 asmTESTDMemImm((uint32)&gCPU.cr, 1<<(31-crB));
1222 NativeAddress nocrB2 = asmJxxFixup(X86_Z);
1223 asmORDMemImm((uint32)&gCPU.cr, 1<<(31-crD));
1224 NativeAddress end3 = asmJMPFixup();
1225 asmResolveFixup(nocrB2, asmHERE());
1226 asmANDDMemImm((uint32)&gCPU.cr, ~(1<<(31-crD)));
1227 asmResolveFixup(end1, asmHERE());
1228 asmResolveFixup(end2, asmHERE());
1229 asmResolveFixup(end3, asmHERE());
1230 }
1231 return flowContinue;
1232 }
1233
1234 /*
1235 * divwx Divide Word
1236 * .470
1237 */
1238 void ppc_opc_divwx()
1239 {
1240 int rD, rA, rB;
1241 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1242 if (!gCPU.gpr[rB]) {
1243 PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc);
1244 SINGLESTEP("");
1245 } else {
1246 sint32 a = gCPU.gpr[rA];
1247 sint32 b = gCPU.gpr[rB];
1248 gCPU.gpr[rD] = a / b;
1249 }
1250 if (gCPU.current_opc & PPC_OPC_Rc) {
1251 // update cr0 flags
1252 ppc_update_cr0(gCPU.gpr[rD]);
1253 }
1254 }
1255 JITCFlow ppc_opc_gen_divwx()
1256 {
1257 int rD, rA, rB;
1258 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1259 jitcClobberCarryAndFlags();
1260 jitcAllocRegister(NATIVE_REG | EDX);
1261 jitcGetClientRegister(PPC_GPR(rA), NATIVE_REG | EAX);
1262 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1263 jitcClobberRegister(NATIVE_REG | EAX);
1264 asmSimple(X86_CDQ);
1265 asmALURegReg(X86_TEST, EAX, EAX);
1266 NativeAddress na = asmJxxFixup(X86_Z);
1267 asmALUReg(X86_IDIV, b);
1268 asmResolveFixup(na, asmHERE());
1269 jitcMapClientRegisterDirty(PPC_GPR(rD), NATIVE_REG | EAX);
1270 if (gJITC.current_opc & PPC_OPC_Rc) {
1271 asmALURegReg(X86_TEST, EAX, EAX);
1272 jitcMapFlagsDirty();
1273 }
1274 return flowContinue;
1275 }
1276 /*
1277 * divwox Divide Word with Overflow
1278 * .470
1279 */
1280 void ppc_opc_divwox()
1281 {
1282 int rD, rA, rB;
1283 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1284 if (!gCPU.gpr[rB]) {
1285 PPC_ALU_WARN("division by zero\n");
1286 } else {
1287 sint32 a = gCPU.gpr[rA];
1288 sint32 b = gCPU.gpr[rB];
1289 gCPU.gpr[rD] = a / b;
1290 }
1291 if (gCPU.current_opc & PPC_OPC_Rc) {
1292 // update cr0 flags
1293 ppc_update_cr0(gCPU.gpr[rD]);
1294 }
1295 // update XER flags
1296 PPC_ALU_ERR("divwox unimplemented\n");
1297 }
1298 /*
1299 * divwux Divide Word Unsigned
1300 * .472
1301 */
1302 void ppc_opc_divwux()
1303 {
1304 int rD, rA, rB;
1305 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1306 if (!gCPU.gpr[rB]) {
1307 PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc);
1308 SINGLESTEP("");
1309 } else {
1310 gCPU.gpr[rD] = gCPU.gpr[rA] / gCPU.gpr[rB];
1311 }
1312 if (gCPU.current_opc & PPC_OPC_Rc) {
1313 // update cr0 flags
1314 ppc_update_cr0(gCPU.gpr[rD]);
1315 }
1316 }
1317 JITCFlow ppc_opc_gen_divwux()
1318 {
1319 int rD, rA, rB;
1320 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1321 jitcClobberCarryAndFlags();
1322 jitcAllocRegister(NATIVE_REG | EDX);
1323 jitcGetClientRegister(PPC_GPR(rA), NATIVE_REG | EAX);
1324 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1325 jitcClobberRegister(NATIVE_REG | EAX);
1326 asmALURegReg(X86_XOR, EDX, EDX);
1327 asmALURegReg(X86_TEST, EAX, EAX);
1328 NativeAddress na = asmJxxFixup(X86_Z);
1329 asmALUReg(X86_DIV, b);
1330 asmResolveFixup(na, asmHERE());
1331 jitcMapClientRegisterDirty(PPC_GPR(rD), NATIVE_REG | EAX);
1332 if (gJITC.current_opc & PPC_OPC_Rc) {
1333 asmALURegReg(X86_TEST, EAX, EAX);
1334 jitcMapFlagsDirty();
1335 }
1336 return flowContinue;
1337 }
1338 /*
1339 * divwuox Divide Word Unsigned with Overflow
1340 * .472
1341 */
1342 void ppc_opc_divwuox()
1343 {
1344 int rD, rA, rB;
1345 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1346 if (!gCPU.gpr[rB]) {
1347 PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc);
1348 } else {
1349 gCPU.gpr[rD] = gCPU.gpr[rA] / gCPU.gpr[rB];
1350 }
1351 if (gCPU.current_opc & PPC_OPC_Rc) {
1352 // update cr0 flags
1353 ppc_update_cr0(gCPU.gpr[rD]);
1354 }
1355 // update XER flags
1356 PPC_ALU_ERR("divwuox unimplemented\n");
1357 }
1358
1359 /*
1360 * eqvx Equivalent
1361 * .480
1362 */
1363 void ppc_opc_eqvx()
1364 {
1365 int rS, rA, rB;
1366 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1367 gCPU.gpr[rA] = ~(gCPU.gpr[rS] ^ gCPU.gpr[rB]);
1368 if (gCPU.current_opc & PPC_OPC_Rc) {
1369 // update cr0 flags
1370 ppc_update_cr0(gCPU.gpr[rA]);
1371 }
1372 }
1373 JITCFlow ppc_opc_gen_eqvx()
1374 {
1375 int rS, rA, rB;
1376 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1377 if (gJITC.current_opc & PPC_OPC_Rc) {
1378 jitcClobberCarry();
1379 } else {
1380 jitcClobberCarryAndFlags();
1381 }
1382 NativeReg a;
1383 if (rA == rS) {
1384 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1385 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1386 asmALURegReg(X86_XOR, a, b);
1387 } else if (rA == rB) {
1388 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1389 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1390 asmALURegReg(X86_XOR, a, s);
1391 } else {
1392 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1393 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1394 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1395 asmALURegReg(X86_MOV, a, s);
1396 asmALURegReg(X86_XOR, a, b);
1397 }
1398 asmALUReg(X86_NOT, a);
1399 if (gJITC.current_opc & PPC_OPC_Rc) {
1400 // "NOT" doesn't update the flags
1401 asmALURegReg(X86_TEST, a, a);
1402 jitcMapFlagsDirty();
1403 }
1404 return flowContinue;
1405 }
1406
1407 /*
1408 * extsbx Extend Sign Byte
1409 * .481
1410 */
1411 void ppc_opc_extsbx()
1412 {
1413 int rS, rA, rB;
1414 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1415 PPC_OPC_ASSERT(rB==0);
1416 gCPU.gpr[rA] = gCPU.gpr[rS];
1417 if (gCPU.gpr[rA] & 0x80) {
1418 gCPU.gpr[rA] |= 0xffffff00;
1419 } else {
1420 gCPU.gpr[rA] &= ~0xffffff00;
1421 }
1422 if (gCPU.current_opc & PPC_OPC_Rc) {
1423 // update cr0 flags
1424 ppc_update_cr0(gCPU.gpr[rA]);
1425 }
1426 }
1427 JITCFlow ppc_opc_gen_extsbx()
1428 {
1429 int rS, rA, rB;
1430 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1431 NativeReg8 s = (NativeReg8)jitcGetClientRegister(PPC_GPR(rS), NATIVE_REG_8);
1432 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1433 asmMOVxxRegReg8(X86_MOVSX, a, s);
1434 if (gJITC.current_opc & PPC_OPC_Rc) {
1435 jitcClobberCarry();
1436 asmALURegReg(X86_TEST, a, a);
1437 jitcMapFlagsDirty();
1438 }
1439 return flowContinue;
1440 }
1441 /*
1442 * extshx Extend Sign Half Word
1443 * .482
1444 */
1445 void ppc_opc_extshx()
1446 {
1447 int rS, rA, rB;
1448 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1449 PPC_OPC_ASSERT(rB==0);
1450 gCPU.gpr[rA] = gCPU.gpr[rS];
1451 if (gCPU.gpr[rA] & 0x8000) {
1452 gCPU.gpr[rA] |= 0xffff0000;
1453 } else {
1454 gCPU.gpr[rA] &= ~0xffff0000;
1455 }
1456 if (gCPU.current_opc & PPC_OPC_Rc) {
1457 // update cr0 flags
1458 ppc_update_cr0(gCPU.gpr[rA]);
1459 }
1460 }
1461 JITCFlow ppc_opc_gen_extshx()
1462 {
1463 int rS, rA, rB;
1464 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1465 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1466 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1467 asmMOVxxRegReg16(X86_MOVSX, a, s);
1468 if (gJITC.current_opc & PPC_OPC_Rc) {
1469 jitcClobberCarry();
1470 asmALURegReg(X86_TEST, a, a);
1471 jitcMapFlagsDirty();
1472 }
1473 return flowContinue;
1474 }
1475
1476 /*
1477 * mulhwx Multiply High Word
1478 * .595
1479 */
1480 void ppc_opc_mulhwx()
1481 {
1482 int rD, rA, rB;
1483 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1484 sint64 a = (sint32)gCPU.gpr[rA];
1485 sint64 b = (sint32)gCPU.gpr[rB];
1486 sint64 c = a*b;
1487 gCPU.gpr[rD] = ((uint64)c)>>32;
1488 if (gCPU.current_opc & PPC_OPC_Rc) {
1489 // update cr0 flags
1490 ppc_update_cr0(gCPU.gpr[rD]);
1491 // PPC_ALU_WARN("mulhw. correct?\n");
1492 }
1493 }
1494 JITCFlow ppc_opc_gen_mulhwx()
1495 {
1496 int rD, rA, rB;
1497 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1498 jitcClobberCarryAndFlags();
1499 NativeReg a, b;
1500 if (jitcGetClientRegisterMapping(PPC_GPR(rB)) == EAX) {
1501 // swapped by incident
1502 a = EAX;
1503 b = jitcGetClientRegister(PPC_GPR(rA));
1504 } else {
1505 a = jitcGetClientRegister(PPC_GPR(rA), NATIVE_REG | EAX);
1506 b = jitcGetClientRegister(PPC_GPR(rB));
1507 }
1508 jitcClobberRegister(NATIVE_REG | EAX);
1509 jitcClobberRegister(NATIVE_REG | EDX);
1510 asmALUReg(X86_IMUL, b);
1511 jitcMapClientRegisterDirty(PPC_GPR(rD), NATIVE_REG | EDX);
1512 if (gJITC.current_opc & PPC_OPC_Rc) {
1513 asmALURegReg(X86_TEST, EDX, EDX);
1514 jitcMapFlagsDirty();
1515 }
1516 return flowContinue;
1517 }
1518 /*
1519 * mulhwux Multiply High Word Unsigned
1520 * .596
1521 */
1522 void ppc_opc_mulhwux()
1523 {
1524 int rD, rA, rB;
1525 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1526 uint64 a = gCPU.gpr[rA];
1527 uint64 b = gCPU.gpr[rB];
1528 uint64 c = a*b;
1529 gCPU.gpr[rD] = c>>32;
1530 if (gCPU.current_opc & PPC_OPC_Rc) {
1531 // update cr0 flags
1532 ppc_update_cr0(gCPU.gpr[rD]);
1533 }
1534 }
1535 JITCFlow ppc_opc_gen_mulhwux()
1536 {
1537 int rD, rA, rB;
1538 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1539 jitcClobberCarryAndFlags();
1540 NativeReg a, b;
1541 if (jitcGetClientRegisterMapping(PPC_GPR(rB)) == EAX) {
1542 // swapped by incident
1543 a = EAX;
1544 b = jitcGetClientRegister(PPC_GPR(rA));
1545 } else {
1546 a = jitcGetClientRegister(PPC_GPR(rA), NATIVE_REG | EAX);
1547 b = jitcGetClientRegister(PPC_GPR(rB));
1548 }
1549 jitcClobberRegister(NATIVE_REG | EAX);
1550 jitcClobberRegister(NATIVE_REG | EDX);
1551 asmALUReg(X86_MUL, b);
1552 jitcMapClientRegisterDirty(PPC_GPR(rD), NATIVE_REG | EDX);
1553 if (gJITC.current_opc & PPC_OPC_Rc) {
1554 asmALURegReg(X86_TEST, EDX, EDX);
1555 jitcMapFlagsDirty();
1556 }
1557 return flowContinue;
1558 }
1559 /*
1560 * mulli Multiply Low Immediate
1561 * .598
1562 */
1563 void ppc_opc_mulli()
1564 {
1565 int rD, rA;
1566 uint32 imm;
1567 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1568 // FIXME: signed / unsigned correct?
1569 gCPU.gpr[rD] = gCPU.gpr[rA] * imm;
1570 }
1571 JITCFlow ppc_opc_gen_mulli()
1572 {
1573 int rD, rA;
1574 uint32 imm;
1575 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, rD, rA, imm);
1576 jitcClobberCarryAndFlags();
1577 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
1578 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
1579 asmIMULRegRegImm(d, a, imm);
1580 return flowContinue;
1581 }
1582 /*
1583 * mullwx Multiply Low Word
1584 * .599
1585 */
1586 void ppc_opc_mullwx()
1587 {
1588 int rD, rA, rB;
1589 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1590 gCPU.gpr[rD] = gCPU.gpr[rA] * gCPU.gpr[rB];
1591 if (gCPU.current_opc & PPC_OPC_Rc) {
1592 // update cr0 flags
1593 ppc_update_cr0(gCPU.gpr[rD]);
1594 }
1595 if (gCPU.current_opc & PPC_OPC_OE) {
1596 // update XER flags
1597 PPC_ALU_ERR("mullwox unimplemented\n");
1598 }
1599 }
1600 JITCFlow ppc_opc_gen_mullwx()
1601 {
1602 int rD, rA, rB;
1603 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1604 if (gJITC.current_opc & PPC_OPC_Rc) {
1605 jitcClobberCarry();
1606 } else {
1607 jitcClobberCarryAndFlags();
1608 }
1609 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
1610 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1611 NativeReg d;
1612 if (rA == rD) {
1613 d = a;
1614 jitcDirtyRegister(a);
1615 } else if (rB == rD) {
1616 d = b;
1617 jitcDirtyRegister(b);
1618 b = a;
1619 } else {
1620 d = jitcMapClientRegisterDirty(PPC_GPR(rD));
1621 asmALURegReg(X86_MOV, d, a);
1622 }
1623 // now: d *= b
1624 asmIMULRegReg(d, b);
1625 if (gJITC.current_opc & PPC_OPC_Rc) {
1626 asmALURegReg(X86_OR, d, d);
1627 jitcMapFlagsDirty();
1628 }
1629 return flowContinue;
1630 }
1631
1632 /*
1633 * nandx NAND
1634 * .600
1635 */
1636 void ppc_opc_nandx()
1637 {
1638 int rS, rA, rB;
1639 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1640 gCPU.gpr[rA] = ~(gCPU.gpr[rS] & gCPU.gpr[rB]);
1641 if (gCPU.current_opc & PPC_OPC_Rc) {
1642 // update cr0 flags
1643 ppc_update_cr0(gCPU.gpr[rA]);
1644 }
1645 }
1646 JITCFlow ppc_opc_gen_nandx()
1647 {
1648 int rS, rA, rB;
1649 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1650 if (gJITC.current_opc & PPC_OPC_Rc) {
1651 jitcClobberCarry();
1652 } else {
1653 jitcClobberCarryAndFlags();
1654 }
1655 NativeReg a;
1656 if (rS == rB) {
1657 if (rA == rS) {
1658 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1659 } else {
1660 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1661 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1662 asmALURegReg(X86_MOV, a, s);
1663 }
1664 } else if (rA == rS) {
1665 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1666 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1667 asmALURegReg(X86_AND, a, b);
1668 } else if (rA == rB) {
1669 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1670 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1671 asmALURegReg(X86_AND, a, s);
1672 } else {
1673 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1674 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1675 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1676 asmALURegReg(X86_MOV, a, s);
1677 asmALURegReg(X86_AND, a, b);
1678 }
1679 asmALUReg(X86_NOT, a);
1680 if (gJITC.current_opc & PPC_OPC_Rc) {
1681 // "NOT" doesn't update the flags
1682 asmALURegReg(X86_TEST, a, a);
1683 jitcMapFlagsDirty();
1684 }
1685 return flowContinue;
1686 }
1687
1688 /*
1689 * negx Negate
1690 * .601
1691 */
1692 void ppc_opc_negx()
1693 {
1694 int rD, rA, rB;
1695 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1696 PPC_OPC_ASSERT(rB == 0);
1697 gCPU.gpr[rD] = -gCPU.gpr[rA];
1698 if (gCPU.current_opc & PPC_OPC_Rc) {
1699 // update cr0 flags
1700 ppc_update_cr0(gCPU.gpr[rD]);
1701 }
1702 }
1703 JITCFlow ppc_opc_gen_negx()
1704 {
1705 int rD, rA, rB;
1706 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
1707 if (gJITC.current_opc & PPC_OPC_Rc) {
1708 jitcClobberCarry();
1709 } else {
1710 jitcClobberCarryAndFlags();
1711 }
1712 if (rA == rD) {
1713 NativeReg d = jitcGetClientRegisterDirty(PPC_GPR(rD));
1714 asmALUReg(X86_NEG, d);
1715 } else {
1716 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
1717 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
1718 asmALURegReg(X86_MOV, d, a);
1719 asmALUReg(X86_NEG, d);
1720 }
1721 if (gJITC.current_opc & PPC_OPC_Rc) {
1722 jitcMapFlagsDirty();
1723 }
1724 return flowContinue;
1725 }
1726 /*
1727 * negox Negate with Overflow
1728 * .601
1729 */
1730 void ppc_opc_negox()
1731 {
1732 int rD, rA, rB;
1733 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
1734 PPC_OPC_ASSERT(rB == 0);
1735 gCPU.gpr[rD] = -gCPU.gpr[rA];
1736 if (gCPU.current_opc & PPC_OPC_Rc) {
1737 // update cr0 flags
1738 ppc_update_cr0(gCPU.gpr[rD]);
1739 }
1740 // update XER flags
1741 PPC_ALU_ERR("negox unimplemented\n");
1742 }
1743 /*
1744 * norx NOR
1745 * .602
1746 */
1747 void ppc_opc_norx()
1748 {
1749 int rS, rA, rB;
1750 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1751 gCPU.gpr[rA] = ~(gCPU.gpr[rS] | gCPU.gpr[rB]);
1752 if (gCPU.current_opc & PPC_OPC_Rc) {
1753 // update cr0 flags
1754 ppc_update_cr0(gCPU.gpr[rA]);
1755 }
1756 }
1757 JITCFlow ppc_opc_gen_norx()
1758 {
1759 int rS, rA, rB;
1760 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1761 NativeReg a;
1762 if (rS == rB) {
1763 // norx rA, rS, rS == not rA, rS
1764 // not doen't clobber the flags
1765 if (gJITC.current_opc & PPC_OPC_Rc) {
1766 jitcClobberCarry();
1767 }
1768 if (rA == rS) {
1769 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1770 } else {
1771 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1772 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1773 asmALURegReg(X86_MOV, a, s);
1774 }
1775 } else {
1776 if (gJITC.current_opc & PPC_OPC_Rc) {
1777 jitcClobberCarry();
1778 } else {
1779 jitcClobberCarryAndFlags();
1780 }
1781 if (rA == rS) {
1782 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1783 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1784 asmALURegReg(X86_OR, a, b);
1785 } else if (rA == rB) {
1786 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1787 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1788 asmALURegReg(X86_OR, a, s);
1789 } else {
1790 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1791 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1792 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1793 asmALURegReg(X86_MOV, a, s);
1794 asmALURegReg(X86_OR, a, b);
1795 }
1796 }
1797 asmALUReg(X86_NOT, a);
1798 if (gJITC.current_opc & PPC_OPC_Rc) {
1799 // "NOT" doesn't update the flags
1800 asmALURegReg(X86_TEST, a, a);
1801 jitcMapFlagsDirty();
1802 }
1803 return flowContinue;
1804 }
1805
1806 /*
1807 * orx OR
1808 * .603
1809 */
1810 void ppc_opc_orx()
1811 {
1812 int rS, rA, rB;
1813 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1814 gCPU.gpr[rA] = gCPU.gpr[rS] | gCPU.gpr[rB];
1815 if (gCPU.current_opc & PPC_OPC_Rc) {
1816 // update cr0 flags
1817 ppc_update_cr0(gCPU.gpr[rA]);
1818 }
1819 }
1820 JITCFlow ppc_opc_gen_or()
1821 {
1822 int rS, rA, rB;
1823 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1824 if (rS == rB) {
1825 if (rS == rA) {
1826 /* nop */
1827 } else {
1828 /* mr rA, rS*/
1829 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1830 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1831 asmALURegReg(X86_MOV, a, s);
1832 }
1833 } else {
1834 if (rA == rS) {
1835 // or a, a, b
1836 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1837 jitcClobberCarryAndFlags();
1838 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1839 asmALURegReg(X86_OR, a, b);
1840 } else if (rA == rB) {
1841 // or a, s, a
1842 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1843 jitcClobberCarryAndFlags();
1844 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1845 asmALURegReg(X86_OR, a, s);
1846 } else {
1847 // or a, s, b
1848 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1849 jitcClobberCarryAndFlags();
1850 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1851 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1852 asmALURegReg(X86_MOV, a, s);
1853 asmALURegReg(X86_OR, a, b);
1854 }
1855 }
1856 return flowContinue;
1857 }
1858 JITCFlow ppc_opc_gen_orp()
1859 {
1860 int rS, rA, rB;
1861 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1862 jitcClobberCarry();
1863 if (rS == rB) {
1864 if (rS == rA) {
1865 /* mr. rA, rA */
1866 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
1867 asmALURegReg(X86_TEST, a, a);
1868 } else {
1869 /* mr. rA, rS*/
1870 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1871 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1872 asmALURegReg(X86_MOV, a, s);
1873 asmALURegReg(X86_TEST, a, a);
1874 }
1875 } else {
1876 if (rA == rS) {
1877 // or a, a, b
1878 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1879 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1880 asmALURegReg(X86_OR, a, b);
1881 } else if (rA == rB) {
1882 // or a, s, a
1883 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1884 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1885 asmALURegReg(X86_OR, a, s);
1886 } else {
1887 // or a, s, b
1888 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1889 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1890 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1891 asmALURegReg(X86_MOV, a, s);
1892 asmALURegReg(X86_OR, a, b);
1893 }
1894 }
1895 jitcMapFlagsDirty();
1896 return flowContinue;
1897 }
1898 JITCFlow ppc_opc_gen_orx()
1899 {
1900 if (gJITC.current_opc & PPC_OPC_Rc) {
1901 return ppc_opc_gen_orp();
1902 } else {
1903 return ppc_opc_gen_or();
1904 }
1905 }
1906 /*
1907 * orcx OR with Complement
1908 * .604
1909 */
1910 void ppc_opc_orcx()
1911 {
1912 int rS, rA, rB;
1913 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1914 gCPU.gpr[rA] = gCPU.gpr[rS] | ~gCPU.gpr[rB];
1915 if (gCPU.current_opc & PPC_OPC_Rc) {
1916 // update cr0 flags
1917 ppc_update_cr0(gCPU.gpr[rA]);
1918 }
1919 }
1920 JITCFlow ppc_opc_gen_orcx()
1921 {
1922 int rS, rA, rB;
1923 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
1924 if (gJITC.current_opc & PPC_OPC_Rc) {
1925 jitcClobberCarry();
1926 } else {
1927 jitcClobberCarryAndFlags();
1928 }
1929 if (rA == rS) {
1930 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1931 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1932 NativeReg tmp = jitcAllocRegister();
1933 asmALURegReg(X86_MOV, tmp, b);
1934 asmALUReg(X86_NOT, tmp);
1935 asmALURegReg(X86_OR, a, tmp);
1936 } else if (rA == rB) {
1937 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
1938 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1939 asmALUReg(X86_NOT, a);
1940 asmALURegReg(X86_OR, a, s);
1941 } else {
1942 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
1943 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
1944 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
1945 asmALURegReg(X86_MOV, a, b);
1946 asmALUReg(X86_NOT, a);
1947 asmALURegReg(X86_OR, a, s);
1948 }
1949 if (gJITC.current_opc & PPC_OPC_Rc) {
1950 jitcMapFlagsDirty();
1951 }
1952 return flowContinue;
1953 }
1954 /*
1955 * ori OR Immediate
1956 * .605
1957 */
1958 void ppc_opc_ori()
1959 {
1960 int rS, rA;
1961 uint32 imm;
1962 PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
1963 gCPU.gpr[rA] = gCPU.gpr[rS] | imm;
1964 }
1965 JITCFlow ppc_opc_gen_ori()
1966 {
1967 int rS, rA;
1968 uint32 imm;
1969 PPC_OPC_TEMPL_D_UImm(gJITC.current_opc, rS, rA, imm);
1970 return ppc_opc_gen_ori_oris_xori_xoris(X86_OR, imm, rS, rA);
1971 }
1972 /*
1973 * oris OR Immediate Shifted
1974 * .606
1975 */
1976 void ppc_opc_oris()
1977 {
1978 int rS, rA;
1979 uint32 imm;
1980 PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
1981 gCPU.gpr[rA] = gCPU.gpr[rS] | imm;
1982 }
1983 JITCFlow ppc_opc_gen_oris()
1984 {
1985 int rS, rA;
1986 uint32 imm;
1987 PPC_OPC_TEMPL_D_Shift16(gJITC.current_opc, rS, rA, imm);
1988 return ppc_opc_gen_ori_oris_xori_xoris(X86_OR, imm, rS, rA);
1989 }
1990 /*
1991 * rlwimix Rotate Left Word Immediate then Mask Insert
1992 * .617
1993 */
1994 void ppc_opc_rlwimix()
1995 {
1996 int rS, rA, SH, MB, ME;
1997 PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, SH, MB, ME);
1998 uint32 v = ppc_word_rotl(gCPU.gpr[rS], SH);
1999 uint32 mask = ppc_mask(MB, ME);
2000 gCPU.gpr[rA] = (v & mask) | (gCPU.gpr[rA] & ~mask);
2001 if (gCPU.current_opc & PPC_OPC_Rc) {
2002 // update cr0 flags
2003 ppc_update_cr0(gCPU.gpr[rA]);
2004 }
2005 }
2006 static void ppc_opc_gen_rotl_and(NativeReg r, int SH, uint32 mask)
2007 {
2008 SH &= 0x1f;
2009 if (SH) {
2010 if (mask & ((1<<SH)-1)) {
2011 if (mask & ~((1<<SH)-1)) {
2012 if (SH == 31) {
2013 asmShiftRegImm(X86_ROR, r, 1);
2014 } else {
2015 asmShiftRegImm(X86_ROL, r, SH);
2016 }
2017 } else {
2018 asmShiftRegImm(X86_SHR, r, 32-SH);
2019 }
2020 } else {
2021 asmShiftRegImm(X86_SHL, r, SH);
2022 }
2023 }
2024 }
2025 JITCFlow ppc_opc_gen_rlwimix()
2026 {
2027 int rS, rA, SH, MB, ME;
2028 PPC_OPC_TEMPL_M(gJITC.current_opc, rS, rA, SH, MB, ME);
2029 if (gJITC.current_opc & PPC_OPC_Rc) {
2030 jitcClobberCarry();
2031 } else {
2032 jitcClobberCarryAndFlags();
2033 }
2034 uint32 mask = ppc_mask(MB, ME);
2035 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2036 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2037 NativeReg tmp = jitcAllocRegister();
2038 asmALURegReg(X86_MOV, tmp, s);
2039 ppc_opc_gen_rotl_and(tmp, SH, mask);
2040 asmALURegImm(X86_AND, a, ~mask);
2041 asmALURegImm(X86_AND, tmp, mask);
2042 asmALURegReg(X86_OR, a, tmp);
2043 if (gJITC.current_opc & PPC_OPC_Rc) {
2044 jitcMapFlagsDirty();
2045 }
2046 return flowContinue;
2047 }
2048 /*
2049 * rlwinmx Rotate Left Word Immediate then AND with Mask
2050 * .618
2051 */
2052 void ppc_opc_rlwinmx()
2053 {
2054 int rS, rA, SH;
2055 uint32 MB, ME;
2056 PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, SH, MB, ME);
2057 uint32 v = ppc_word_rotl(gCPU.gpr[rS], SH);
2058 uint32 mask = ppc_mask(MB, ME);
2059 gCPU.gpr[rA] = v & mask;
2060 if (gCPU.current_opc & PPC_OPC_Rc) {
2061 // update cr0 flags
2062 ppc_update_cr0(gCPU.gpr[rA]);
2063 }
2064 }
2065 JITCFlow ppc_opc_gen_rlwinmx()
2066 {
2067 int rS, rA, SH;
2068 uint32 MB, ME;
2069 PPC_OPC_TEMPL_M(gJITC.current_opc, rS, rA, SH, MB, ME);
2070 if (gJITC.current_opc & PPC_OPC_Rc) {
2071 jitcClobberCarry();
2072 } else {
2073 jitcClobberCarryAndFlags();
2074 }
2075 NativeReg a;
2076 if (rS == rA) {
2077 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2078 } else {
2079 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2080 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2081 asmALURegReg(X86_MOV, a, s);
2082 }
2083 uint32 mask = ppc_mask(MB, ME);
2084 ppc_opc_gen_rotl_and(a, SH, mask);
2085 asmALURegImm(X86_AND, a, mask);
2086 if (gJITC.current_opc & PPC_OPC_Rc) {
2087 /*
2088 * Important side-node:
2089 * ROL doesn't update the flags, so beware if you want to
2090 * get rid of the above AND
2091 */
2092 jitcMapFlagsDirty();
2093 }
2094 return flowContinue;
2095 }
2096 /*
2097 * rlwnmx Rotate Left Word then AND with Mask
2098 * .620
2099 */
2100 void ppc_opc_rlwnmx()
2101 {
2102 int rS, rA, rB, MB, ME;
2103 PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, rB, MB, ME);
2104 uint32 v = ppc_word_rotl(gCPU.gpr[rS], gCPU.gpr[rB]);
2105 uint32 mask = ppc_mask(MB, ME);
2106 gCPU.gpr[rA] = v & mask;
2107 if (gCPU.current_opc & PPC_OPC_Rc) {
2108 // update cr0 flags
2109 ppc_update_cr0(gCPU.gpr[rA]);
2110 }
2111 }
2112 JITCFlow ppc_opc_gen_rlwnmx()
2113 {
2114 int rS, rA, rB, MB, ME;
2115 PPC_OPC_TEMPL_M(gJITC.current_opc, rS, rA, rB, MB, ME);
2116 if (gJITC.current_opc & PPC_OPC_Rc) {
2117 jitcClobberCarry();
2118 } else {
2119 jitcClobberCarryAndFlags();
2120 }
2121 NativeReg a;
2122 jitcGetClientRegister(PPC_GPR(rB), NATIVE_REG | ECX);
2123 if (rS == rA) {
2124 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2125 } else {
2126 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2127 if (rA == rB) {
2128 a = jitcAllocRegister();
2129 } else {
2130 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2131 }
2132 asmALURegReg(X86_MOV, a, s);
2133 }
2134 asmShiftRegCL(X86_ROL, a);
2135 if (rA != rS && rA == rB) {
2136 jitcMapClientRegisterDirty(PPC_GPR(rA), NATIVE_REG | a);
2137 }
2138 uint32 mask = ppc_mask(MB, ME);
2139 asmALURegImm(X86_AND, a, mask);
2140 if (gJITC.current_opc & PPC_OPC_Rc) {
2141 /*
2142 * Important side-node:
2143 * ROL doesn't update the flags, so beware if you want to
2144 * get rid of the above AND
2145 */
2146 jitcMapFlagsDirty();
2147 }
2148 return flowContinue;
2149 }
2150
2151 /*
2152 * slwx Shift Left Word
2153 * .625
2154 */
2155 void ppc_opc_slwx()
2156 {
2157 int rS, rA, rB;
2158 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2159 uint32 s = gCPU.gpr[rB] & 0x3f;
2160 if (s > 31) {
2161 gCPU.gpr[rA] = 0;
2162 } else {
2163 gCPU.gpr[rA] = gCPU.gpr[rS] << s;
2164 }
2165 if (gCPU.current_opc & PPC_OPC_Rc) {
2166 // update cr0 flags
2167 ppc_update_cr0(gCPU.gpr[rA]);
2168 }
2169 }
2170 JITCFlow ppc_opc_gen_slwx()
2171 {
2172 int rS, rA, rB;
2173 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
2174 if (gJITC.current_opc & PPC_OPC_Rc) {
2175 jitcClobberCarry();
2176 } else {
2177 jitcClobberCarryAndFlags();
2178 }
2179 NativeReg a;
2180 NativeReg b = jitcGetClientRegister(PPC_GPR(rB), NATIVE_REG | ECX);
2181 asmALURegImm(X86_TEST, b, 0x20);
2182 if (rA == rS) {
2183 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2184 } else {
2185 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2186 if (rA == rB) {
2187 a = jitcAllocRegister();
2188 } else {
2189 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2190 }
2191 asmALURegReg(X86_MOV, a, s);
2192 }
2193 NativeAddress fixup = asmJxxFixup(X86_Z);
2194 asmALURegImm(X86_MOV, a, 0);
2195 asmResolveFixup(fixup, asmHERE());
2196 asmShiftRegCL(X86_SHL, a);
2197 if (rA != rS && rA == rB) {
2198 jitcMapClientRegisterDirty(PPC_GPR(rA), NATIVE_REG | a);
2199 }
2200 if (gJITC.current_opc & PPC_OPC_Rc) {
2201 /*
2202 * Welcome to the wonderful world of braindead
2203 * processor design.
2204 * (shl x, cl doesn't update the flags in case of cl==0)
2205 */
2206 asmALURegReg(X86_TEST, a, a);
2207 jitcMapFlagsDirty();
2208 }
2209 return flowContinue;
2210 }
2211 /*
2212 * srawx Shift Right Algebraic Word
2213 * .628
2214 */
2215 void ppc_opc_srawx()
2216 {
2217 int rS, rA, rB;
2218 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2219 uint32 SH = gCPU.gpr[rB] & 0x3f;
2220 gCPU.gpr[rA] = gCPU.gpr[rS];
2221 gCPU.xer_ca = 0;
2222 if (gCPU.gpr[rA] & 0x80000000) {
2223 uint32 ca = 0;
2224 for (uint i=0; i < SH; i++) {
2225 if (gCPU.gpr[rA] & 1) ca = 1;
2226 gCPU.gpr[rA] >>= 1;
2227 gCPU.gpr[rA] |= 0x80000000;
2228 }
2229 if (ca) gCPU.xer_ca = 1;
2230 } else {
2231 if (SH > 31) {
2232 gCPU.gpr[rA] = 0;
2233 } else {
2234 gCPU.gpr[rA] >>= SH;
2235 }
2236 }
2237 if (gCPU.current_opc & PPC_OPC_Rc) {
2238 // update cr0 flags
2239 ppc_update_cr0(gCPU.gpr[rA]);
2240 }
2241 }
2242 JITCFlow ppc_opc_gen_srawx()
2243 {
2244 #if 0
2245 int rS, rA, rB;
2246 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
2247 if (!(gJITC.current_opc & PPC_OPC_Rc)) {
2248 jitcClobberFlags();
2249 }
2250 NativeReg a = REG_NO;
2251 jitcGetClientRegister(PPC_GPR(rB), NATIVE_REG | ECX);
2252 byte modrm[6];
2253 asmALURegImm(X86_TEST, ECX, 0x20);
2254 NativeAddress ecx_gt_1f = asmJxxFixup(X86_NZ);
2255
2256 // 0 <= SH <= 31
2257 NativeReg t;
2258 if (rS != rA) {
2259 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2260 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2261 asmALURegReg(X86_MOV, a, s);
2262 t = jitcAllocRegister();
2263 asmALURegReg(X86_MOV, t, s);
2264 } else {
2265 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2266 t = jitcAllocRegister();
2267 asmALURegReg(X86_MOV, t, a);
2268 }
2269 asmShiftRegImm(X86_SAR, t, 31);
2270 asmALURegReg(X86_AND, t, a);
2271 asmShiftRegCL(X86_SAR, a);
2272 static int test_values[] = {
2273 0x00000000, 0x00000001, 0x00000003, 0x00000007,
2274 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
2275 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
2276 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
2277 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
2278 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
2279 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
2280 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
2281 };
2282 asmALURegMem(X86_TEST, t, modrm, x86_mem_sib(modrm, REG_NO, 4, ECX, (uint32)&test_values));
2283 asmSETMem(X86_NZ, modrm, x86_mem(modrm, REG_NO, (uint32)&gCPU.xer_ca));
2284 if (gJITC.current_opc & PPC_OPC_Rc) {
2285 asmALURegReg(X86_TEST, a, a);
2286 }
2287 NativeAddress end = asmJMPFixup();
2288
2289
2290 asmResolveFixup(ecx_gt_1f, asmHERE());
2291 // SH > 31
2292 if (rS != rA) {
2293 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2294 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2295 asmALURegReg(X86_MOV, a, s);
2296 } else {
2297 a = jitcGetClientRegister(PPC_GPR(rA));
2298 }
2299 asmShiftRegImm(X86_SAR, a, 31);
2300 asmShiftRegImm(X86_SAR, a, 1);
2301 jitcMapCarryDirty();
2302 asmResolveFixup(end, asmHERE());
2303
2304 if (gJITC.current_opc & PPC_OPC_Rc) {
2305 jitcMapFlagsDirty();
2306 }
2307
2308 return flowContinue;
2309 #endif
2310 ppc_opc_gen_interpret(ppc_opc_srawx);
2311 return flowEndBlock;
2312 }
2313 /*
2314 * srawix Shift Right Algebraic Word Immediate
2315 * .629
2316 */
2317 void ppc_opc_srawix()
2318 {
2319 int rS, rA;
2320 uint32 SH;
2321 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, SH);
2322 gCPU.gpr[rA] = gCPU.gpr[rS];
2323 gCPU.xer_ca = 0;
2324 if (gCPU.gpr[rA] & 0x80000000) {
2325 uint32 ca = 0;
2326 for (uint i=0; i < SH; i++) {
2327 if (gCPU.gpr[rA] & 1) ca = 1;
2328 gCPU.gpr[rA] >>= 1;
2329 gCPU.gpr[rA] |= 0x80000000;
2330 }
2331 if (ca) gCPU.xer_ca = 1;
2332 } else {
2333 gCPU.gpr[rA] >>= SH;
2334 }
2335 if (gCPU.current_opc & PPC_OPC_Rc) {
2336 // update cr0 flags
2337 ppc_update_cr0(gCPU.gpr[rA]);
2338 }
2339 }
2340 JITCFlow ppc_opc_gen_srawix()
2341 {
2342 int rS, rA;
2343 uint32 SH;
2344 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, SH);
2345 if (!(gJITC.current_opc & PPC_OPC_Rc)) {
2346 jitcClobberFlags();
2347 }
2348 NativeReg a = REG_NO;
2349 if (SH) {
2350 NativeReg t;
2351 if (rS != rA) {
2352 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2353 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2354 asmALURegReg(X86_MOV, a, s);
2355 t = jitcAllocRegister();
2356 asmALURegReg(X86_MOV, t, s);
2357 } else {
2358 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2359 t = jitcAllocRegister();
2360 asmALURegReg(X86_MOV, t, a);
2361 }
2362 asmShiftRegImm(X86_SAR, t, 31);
2363 asmALURegReg(X86_AND, t, a);
2364 asmShiftRegImm(X86_SAR, a, SH);
2365 asmALURegImm(X86_TEST, t, (1<<SH)-1);
2366 byte modrm[6];
2367 asmSETMem(X86_NZ, modrm, x86_mem(modrm, REG_NO, (uint32)&gCPU.xer_ca));
2368 } else {
2369 if (rS != rA) {
2370 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2371 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2372 asmALURegReg(X86_MOV, a, s);
2373 } else if (gJITC.current_opc & PPC_OPC_Rc) {
2374 a = jitcGetClientRegister(PPC_GPR(rA));
2375 }
2376 byte modrm[6];
2377 asmALUMemImm8(X86_MOV, modrm, x86_mem(modrm, REG_NO, (uint32)&gCPU.xer_ca), 0);
2378 }
2379 if (gJITC.current_opc & PPC_OPC_Rc) {
2380 asmALURegReg(X86_TEST, a, a);
2381 jitcMapFlagsDirty();
2382 }
2383 return flowContinue;
2384 }
2385 /*
2386 * srwx Shift Right Word
2387 * .631
2388 */
2389 void ppc_opc_srwx()
2390 {
2391 int rS, rA, rB;
2392 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2393 uint32 v = gCPU.gpr[rB] & 0x3f;
2394 if (v > 31) {
2395 gCPU.gpr[rA] = 0;
2396 } else {
2397 gCPU.gpr[rA] = gCPU.gpr[rS] >> v;
2398 }
2399 if (gCPU.current_opc & PPC_OPC_Rc) {
2400 // update cr0 flags
2401 ppc_update_cr0(gCPU.gpr[rA]);
2402 }
2403 }
2404 JITCFlow ppc_opc_gen_srwx()
2405 {
2406 int rS, rA, rB;
2407 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
2408 if (gJITC.current_opc & PPC_OPC_Rc) {
2409 jitcClobberCarry();
2410 } else {
2411 jitcClobberCarryAndFlags();
2412 }
2413 NativeReg a;
2414 NativeReg b = jitcGetClientRegister(PPC_GPR(rB), NATIVE_REG | ECX);
2415 asmALURegImm(X86_TEST, b, 0x20);
2416 if (rA == rS) {
2417 a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2418 } else {
2419 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2420 if (rA == rB) {
2421 a = jitcAllocRegister();
2422 } else {
2423 a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2424 }
2425 asmALURegReg(X86_MOV, a, s);
2426 }
2427 NativeAddress fixup = asmJxxFixup(X86_Z);
2428 asmALURegImm(X86_MOV, a, 0);
2429 asmResolveFixup(fixup, asmHERE());
2430 asmShiftRegCL(X86_SHR, a);
2431 if (rA != rS && rA == rB) {
2432 jitcMapClientRegisterDirty(PPC_GPR(rA), NATIVE_REG | a);
2433 }
2434 if (gJITC.current_opc & PPC_OPC_Rc) {
2435 /*
2436 * Welcome to the wonderful world of braindead
2437 * processor design.
2438 * (shr x, cl doesn't update the flags in case of cl==0)
2439 */
2440 asmALURegReg(X86_TEST, a, a);
2441 jitcMapFlagsDirty();
2442 }
2443 return flowContinue;
2444 /* ppc_opc_gen_interpret(ppc_opc_srwx);
2445 return flowEndBlock;*/
2446 }
2447
2448 /*
2449 * subfx Subtract From
2450 * .666
2451 */
2452 void ppc_opc_subfx()
2453 {
2454 int rD, rA, rB;
2455 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2456 gCPU.gpr[rD] = ~gCPU.gpr[rA] + gCPU.gpr[rB] + 1;
2457 if (gCPU.current_opc & PPC_OPC_Rc) {
2458 // update cr0 flags
2459 ppc_update_cr0(gCPU.gpr[rD]);
2460 }
2461 }
2462 JITCFlow ppc_opc_gen_subfx()
2463 {
2464 int rD, rA, rB;
2465 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
2466 if (gJITC.current_opc & PPC_OPC_Rc) {
2467 jitcClobberCarry();
2468 } else {
2469 jitcClobberCarryAndFlags();
2470 }
2471 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
2472 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
2473 if (rD == rA) {
2474 if (rD == rB) {
2475 asmALURegImm(X86_MOV, a, 0);
2476 } else {
2477 // subf rA, rA, rB (a = b - a)
2478 asmALUReg(X86_NEG, a);
2479 asmALURegReg(X86_ADD, a, b);
2480 }
2481 jitcDirtyRegister(a);
2482 } else if (rD == rB) {
2483 // subf rB, rA, rB (b = b - a)
2484 asmALURegReg(X86_SUB, b, a);
2485 jitcDirtyRegister(b);
2486 } else {
2487 // subf rD, rA, rB (d = b - a)
2488 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
2489 asmALURegReg(X86_MOV, d, b);
2490 asmALURegReg(X86_SUB, d, a);
2491 }
2492 if (gJITC.current_opc & PPC_OPC_Rc) {
2493 jitcMapFlagsDirty();
2494 }
2495 return flowContinue;
2496 }
2497 /*
2498 * subfox Subtract From with Overflow
2499 * .666
2500 */
2501 void ppc_opc_subfox()
2502 {
2503 int rD, rA, rB;
2504 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2505 gCPU.gpr[rD] = ~gCPU.gpr[rA] + gCPU.gpr[rB] + 1;
2506 if (gCPU.current_opc & PPC_OPC_Rc) {
2507 // update cr0 flags
2508 ppc_update_cr0(gCPU.gpr[rD]);
2509 }
2510 // update XER flags
2511 PPC_ALU_ERR("subfox unimplemented\n");
2512 }
2513 /*
2514 * subfcx Subtract From Carrying
2515 * .667
2516 */
2517 void ppc_opc_subfcx()
2518 {
2519 int rD, rA, rB;
2520 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2521 uint32 a = gCPU.gpr[rA];
2522 uint32 b = gCPU.gpr[rB];
2523 gCPU.gpr[rD] = ~a + b + 1;
2524 gCPU.xer_ca = ppc_carry_3(~a, b, 1);
2525 if (gCPU.current_opc & PPC_OPC_Rc) {
2526 // update cr0 flags
2527 ppc_update_cr0(gCPU.gpr[rD]);
2528 }
2529 }
2530 JITCFlow ppc_opc_gen_subfcx()
2531 {
2532 int rD, rA, rB;
2533 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
2534 if (!(gJITC.current_opc & PPC_OPC_Rc)) {
2535 jitcClobberFlags();
2536 }
2537 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
2538 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
2539 if (rA != rD) {
2540 if (rD == rB) {
2541 // b = b - a
2542 asmALURegReg(X86_SUB, b, a);
2543 jitcDirtyRegister(b);
2544 } else {
2545 // d = b - a
2546 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
2547 asmALURegReg(X86_MOV, d, b);
2548 asmALURegReg(X86_SUB, d, a);
2549 }
2550 } else {
2551 // a = b - a
2552 NativeReg tmp = jitcAllocRegister();
2553 asmALURegReg(X86_MOV, tmp, b);
2554 asmALURegReg(X86_SUB, tmp, a);
2555 jitcMapClientRegisterDirty(PPC_GPR(rA), NATIVE_REG | tmp);
2556 }
2557 asmSimple(X86_CMC);
2558 jitcMapCarryDirty();
2559 if (gJITC.current_opc & PPC_OPC_Rc) {
2560 jitcMapFlagsDirty();
2561 }
2562 return flowContinue;
2563 }
2564 /*
2565 * subfcox Subtract From Carrying with Overflow
2566 * .667
2567 */
2568 void ppc_opc_subfcox()
2569 {
2570 int rD, rA, rB;
2571 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2572 uint32 a = gCPU.gpr[rA];
2573 uint32 b = gCPU.gpr[rB];
2574 gCPU.gpr[rD] = ~a + b + 1;
2575 gCPU.xer_ca = ppc_carry_3(~a, b, 1);
2576 if (gCPU.current_opc & PPC_OPC_Rc) {
2577 // update cr0 flags
2578 ppc_update_cr0(gCPU.gpr[rD]);
2579 }
2580 // update XER flags
2581 PPC_ALU_ERR("subfcox unimplemented\n");
2582 }
2583 /*
2584 * subfex Subtract From Extended
2585 * .668
2586 */
2587 void ppc_opc_subfex()
2588 {
2589 int rD, rA, rB;
2590 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2591 uint32 a = gCPU.gpr[rA];
2592 uint32 b = gCPU.gpr[rB];
2593 uint32 ca = (gCPU.xer_ca);
2594 gCPU.gpr[rD] = ~a + b + ca;
2595 gCPU.xer_ca = ppc_carry_3(~a, b, ca);
2596 if (gCPU.current_opc & PPC_OPC_Rc) {
2597 // update cr0 flags
2598 ppc_update_cr0(gCPU.gpr[rD]);
2599 }
2600 }
2601 JITCFlow ppc_opc_gen_subfex()
2602 {
2603 int rD, rA, rB;
2604 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
2605 if (!(gJITC.current_opc & PPC_OPC_Rc)) {
2606 jitcClobberFlags();
2607 }
2608 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
2609 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
2610 jitcGetClientCarry();
2611 asmSimple(X86_CMC);
2612 if (rA != rD) {
2613 if (rD == rB) {
2614 // b = b - a
2615 asmALURegReg(X86_SBB, b, a);
2616 jitcDirtyRegister(b);
2617 } else {
2618 // d = b - a
2619 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
2620 asmALURegReg(X86_MOV, d, b);
2621 asmALURegReg(X86_SBB, d, a);
2622 }
2623 } else {
2624 // a = b - a
2625 NativeReg tmp = jitcAllocRegister();
2626 asmALURegReg(X86_MOV, tmp, b);
2627 asmALURegReg(X86_SBB, tmp, a);
2628 jitcMapClientRegisterDirty(PPC_GPR(rA), NATIVE_REG | tmp);
2629 }
2630 asmSimple(X86_CMC);
2631 jitcMapCarryDirty();
2632 if (gJITC.current_opc & PPC_OPC_Rc) {
2633 jitcMapFlagsDirty();
2634 }
2635 return flowContinue;
2636 }
2637 /*
2638 * subfeox Subtract From Extended with Overflow
2639 * .668
2640 */
2641 void ppc_opc_subfeox()
2642 {
2643 int rD, rA, rB;
2644 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2645 uint32 a = gCPU.gpr[rA];
2646 uint32 b = gCPU.gpr[rB];
2647 uint32 ca = gCPU.xer_ca;
2648 gCPU.gpr[rD] = ~a + b + ca;
2649 gCPU.xer_ca = (ppc_carry_3(~a, b, ca));
2650 if (gCPU.current_opc & PPC_OPC_Rc) {
2651 // update cr0 flags
2652 ppc_update_cr0(gCPU.gpr[rD]);
2653 }
2654 // update XER flags
2655 PPC_ALU_ERR("subfeox unimplemented\n");
2656 }
2657 /*
2658 * subfic Subtract From Immediate Carrying
2659 * .669
2660 */
2661 void ppc_opc_subfic()
2662 {
2663 int rD, rA;
2664 uint32 imm;
2665 PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
2666 uint32 a = gCPU.gpr[rA];
2667 gCPU.gpr[rD] = ~a + imm + 1;
2668 gCPU.xer_ca = (ppc_carry_3(~a, imm, 1));
2669 }
2670 JITCFlow ppc_opc_gen_subfic()
2671 {
2672 int rD, rA;
2673 uint32 imm;
2674 PPC_OPC_TEMPL_D_SImm(gJITC.current_opc, rD, rA, imm);
2675 jitcClobberFlags();
2676 NativeReg d;
2677 if (rA == rD) {
2678 d = jitcGetClientRegisterDirty(PPC_GPR(rD));
2679 } else {
2680 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
2681 d = jitcMapClientRegisterDirty(PPC_GPR(rD));
2682 asmALURegReg(X86_MOV, d, a);
2683 }
2684 asmALUReg(X86_NOT, d);
2685 if (imm == 0xffffffff) {
2686 asmSimple(X86_STC);
2687 } else {
2688 asmALURegImm(X86_ADD, d, imm+1);
2689 }
2690 jitcMapCarryDirty();
2691 return flowContinue;
2692 }
2693 /*
2694 * subfmex Subtract From Minus One Extended
2695 * .670
2696 */
2697 void ppc_opc_subfmex()
2698 {
2699 int rD, rA, rB;
2700 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2701 PPC_OPC_ASSERT(rB == 0);
2702 uint32 a = gCPU.gpr[rA];
2703 uint32 ca = gCPU.xer_ca;
2704 gCPU.gpr[rD] = ~a + ca + 0xffffffff;
2705 gCPU.xer_ca = ((a!=0xffffffff) || ca);
2706 if (gCPU.current_opc & PPC_OPC_Rc) {
2707 // update cr0 flags
2708 ppc_update_cr0(gCPU.gpr[rD]);
2709 }
2710 }
2711 JITCFlow ppc_opc_gen_subfmex()
2712 {
2713 ppc_opc_gen_interpret(ppc_opc_subfmex);
2714 return flowEndBlock;
2715 }
2716 /*
2717 * subfmeox Subtract From Minus One Extended with Overflow
2718 * .670
2719 */
2720 void ppc_opc_subfmeox()
2721 {
2722 int rD, rA, rB;
2723 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2724 PPC_OPC_ASSERT(rB == 0);
2725 uint32 a = gCPU.gpr[rA];
2726 uint32 ca = gCPU.xer_ca;
2727 gCPU.gpr[rD] = ~a + ca + 0xffffffff;
2728 gCPU.xer_ca = ((a!=0xffffffff) || ca);
2729 if (gCPU.current_opc & PPC_OPC_Rc) {
2730 // update cr0 flags
2731 ppc_update_cr0(gCPU.gpr[rD]);
2732 }
2733 // update XER flags
2734 PPC_ALU_ERR("subfmeox unimplemented\n");
2735 }
2736 /*
2737 * subfzex Subtract From Zero Extended
2738 * .671
2739 */
2740 void ppc_opc_subfzex()
2741 {
2742 int rD, rA, rB;
2743 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2744 PPC_OPC_ASSERT(rB == 0);
2745 uint32 a = gCPU.gpr[rA];
2746 uint32 ca = gCPU.xer_ca;
2747 gCPU.gpr[rD] = ~a + ca;
2748 gCPU.xer_ca = (!a && ca);
2749 if (gCPU.current_opc & PPC_OPC_Rc) {
2750 // update cr0 flags
2751 ppc_update_cr0(gCPU.gpr[rD]);
2752 }
2753 }
2754 JITCFlow ppc_opc_gen_subfzex()
2755 {
2756 int rD, rA, rB;
2757 PPC_OPC_TEMPL_XO(gJITC.current_opc, rD, rA, rB);
2758 if (!(gJITC.current_opc & PPC_OPC_Rc)) {
2759 jitcClobberFlags();
2760 }
2761 NativeReg a = jitcGetClientRegister(PPC_GPR(rA));
2762 if (rD != rA) {
2763 NativeReg d = jitcMapClientRegisterDirty(PPC_GPR(rD));
2764 asmALURegReg(X86_MOV, d, a);
2765 a = d;
2766 }
2767 jitcGetClientCarry();
2768 asmALUReg(X86_NOT, a);
2769 asmALURegImm(X86_ADC, a, 0);
2770 jitcDirtyRegister(a);
2771 jitcMapCarryDirty();
2772 if (gJITC.current_opc & PPC_OPC_Rc) {
2773 jitcMapFlagsDirty();
2774 }
2775 return flowContinue;
2776 }
2777 /*
2778 * subfzeox Subtract From Zero Extended with Overflow
2779 * .671
2780 */
2781 void ppc_opc_subfzeox()
2782 {
2783 int rD, rA, rB;
2784 PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
2785 PPC_OPC_ASSERT(rB == 0);
2786 uint32 a = gCPU.gpr[rA];
2787 uint32 ca = gCPU.xer_ca;
2788 gCPU.gpr[rD] = ~a + ca;
2789 gCPU.xer_ca = (!a && ca);
2790 if (gCPU.current_opc & PPC_OPC_Rc) {
2791 // update cr0 flags
2792 ppc_update_cr0(gCPU.gpr[rD]);
2793 }
2794 // update XER flags
2795 PPC_ALU_ERR("subfzeox unimplemented\n");
2796 }
2797
2798 /*
2799 * xorx XOR
2800 * .680
2801 */
2802 void ppc_opc_xorx()
2803 {
2804 int rS, rA, rB;
2805 PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2806 gCPU.gpr[rA] = gCPU.gpr[rS] ^ gCPU.gpr[rB];
2807 if (gCPU.current_opc & PPC_OPC_Rc) {
2808 // update cr0 flags
2809 ppc_update_cr0(gCPU.gpr[rA]);
2810 }
2811 }
2812 JITCFlow ppc_opc_gen_xorx()
2813 {
2814 int rS, rA, rB;
2815 PPC_OPC_TEMPL_X(gJITC.current_opc, rS, rA, rB);
2816 if (gJITC.current_opc & PPC_OPC_Rc) {
2817 jitcClobberCarry();
2818 } else {
2819 jitcClobberCarryAndFlags();
2820 }
2821 if (rA == rS) {
2822 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2823 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
2824 asmALURegReg(X86_XOR, a, b);
2825 } else if (rA == rB) {
2826 NativeReg a = jitcGetClientRegisterDirty(PPC_GPR(rA));
2827 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2828 asmALURegReg(X86_XOR, a, s);
2829 } else {
2830 NativeReg s = jitcGetClientRegister(PPC_GPR(rS));
2831 NativeReg b = jitcGetClientRegister(PPC_GPR(rB));
2832 NativeReg a = jitcMapClientRegisterDirty(PPC_GPR(rA));
2833 asmALURegReg(X86_MOV, a, s);
2834 asmALURegReg(X86_XOR, a, b);
2835 }
2836 if (gJITC.current_opc & PPC_OPC_Rc) {
2837 jitcMapFlagsDirty();
2838 }
2839 return flowContinue;
2840 }
2841 /*
2842 * xori XOR Immediate
2843 * .681
2844 */
2845 void ppc_opc_xori()
2846 {
2847 int rS, rA;
2848 uint32 imm;
2849 PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
2850 gCPU.gpr[rA] = gCPU.gpr[rS] ^ imm;
2851 }
2852 JITCFlow ppc_opc_gen_xori()
2853 {
2854 int rS, rA;
2855 uint32 imm;
2856 PPC_OPC_TEMPL_D_UImm(gJITC.current_opc, rS, rA, imm);
2857 return ppc_opc_gen_ori_oris_xori_xoris(X86_XOR, imm, rS, rA);
2858 }
2859 /*
2860 * xoris XOR Immediate Shifted
2861 * .682
2862 */
2863 void ppc_opc_xoris()
2864 {
2865 int rS, rA;
2866 uint32 imm;
2867 PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
2868 gCPU.gpr[rA] = gCPU.gpr[rS] ^ imm;
2869 }
2870 JITCFlow ppc_opc_gen_xoris()
2871 {
2872 int rS, rA;
2873 uint32 imm;
2874 PPC_OPC_TEMPL_D_Shift16(gJITC.current_opc, rS, rA, imm);
2875 return ppc_opc_gen_ori_oris_xori_xoris(X86_XOR, imm, rS, rA);
2876 }

  ViewVC Help
Powered by ViewVC 1.1.26