drc: rm unneeded writebacks in stubs, as suggested by Ari64
[pcsx_rearmed.git] / libpcsxcore / ppc / pR3000A.c
1 /*  Pcsx - Pc Psx Emulator
2  *  Copyright (C) 1999-2003  Pcsx Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 USA
17  */
18
19 #ifdef _MSC_VER_
20 #pragma warning(disable:4244)
21 #pragma warning(disable:4761)
22 #endif
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <sys/types.h>
27 #include <sys/mman.h>
28
29 #ifndef MAP_ANONYMOUS
30 #define MAP_ANONYMOUS MAP_ANON
31 #endif
32
33 #include "../psxcommon.h"
34 #include "ppc.h"
35 #include "reguse.h"
36 #include "../r3000a.h"
37 #include "../psxhle.h"
38
39 //#define NO_CONSTANT
40
41 u32 *psxRecLUT;
42
43 #undef _Op_
44 #define _Op_     _fOp_(psxRegs.code)
45 #undef _Funct_
46 #define _Funct_  _fFunct_(psxRegs.code)
47 #undef _Rd_
48 #define _Rd_     _fRd_(psxRegs.code)
49 #undef _Rt_
50 #define _Rt_     _fRt_(psxRegs.code)
51 #undef _Rs_
52 #define _Rs_     _fRs_(psxRegs.code)
53 #undef _Sa_
54 #define _Sa_     _fSa_(psxRegs.code)
55 #undef _Im_
56 #define _Im_     _fIm_(psxRegs.code)
57 #undef _Target_
58 #define _Target_ _fTarget_(psxRegs.code)
59
60 #undef _Imm_
61 #define _Imm_    _fImm_(psxRegs.code)
62 #undef _ImmU_
63 #define _ImmU_   _fImmU_(psxRegs.code)
64
65 #undef PC_REC
66 #undef PC_REC8
67 #undef PC_REC16
68 #undef PC_REC32
69 #define PC_REC(x)       (psxRecLUT[x >> 16] + (x & 0xffff))
70 #define PC_REC8(x)      (*(u8 *)PC_REC(x))
71 #define PC_REC16(x) (*(u16*)PC_REC(x))
72 #define PC_REC32(x) (*(u32*)PC_REC(x))
73
74 #define OFFSET(X,Y) ((u32)(Y)-(u32)(X))
75
76 #define RECMEM_SIZE             (12*1024*1024)
77
78 static char *recMem;    /* the recompiled blocks will be here */
79 static char *recRAM;    /* and the ptr to the blocks here */
80 static char *recROM;    /* and here */
81
82 static u32 pc;                  /* recompiler pc */
83 static u32 pcold;               /* recompiler oldpc */
84 static int count;               /* recompiler intruction count */
85 static int branch;              /* set for branch */
86 static u32 target;              /* branch target */
87 static u32 resp;
88
89 u32 cop2readypc = 0;
90 u32 idlecyclecount = 0;
91
92 #define NUM_REGISTERS   34
93 typedef struct {
94         int state;
95         u32 k;
96         int reg;
97 } iRegisters;
98
99 static iRegisters iRegs[34];
100
101 #define ST_UNK      0x00
102 #define ST_CONST    0x01
103 #define ST_MAPPED   0x02
104
105 #ifdef NO_CONSTANT
106 #define IsConst(reg) 0
107 #else
108 #define IsConst(reg)  (iRegs[reg].state & ST_CONST)
109 #endif
110 #define IsMapped(reg) (iRegs[reg].state & ST_MAPPED)
111
112 static void (*recBSC[64])();
113 static void (*recSPC[64])();
114 static void (*recREG[32])();
115 static void (*recCP0[32])();
116 static void (*recCP2[64])();
117 static void (*recCP2BSC[32])();
118
119 #define REG_LO                  32
120 #define REG_HI                  33
121
122 // Hardware register usage
123 #define HWUSAGE_NONE     0x00
124
125 #define HWUSAGE_READ     0x01
126 #define HWUSAGE_WRITE    0x02
127 #define HWUSAGE_CONST    0x04
128 #define HWUSAGE_ARG      0x08   /* used as an argument for a function call */
129
130 #define HWUSAGE_RESERVED 0x10   /* won't get flushed when flushing all regs */
131 #define HWUSAGE_SPECIAL  0x20   /* special purpose register */
132 #define HWUSAGE_HARDWIRED 0x40  /* specific hardware register mapping that is never disposed */
133 #define HWUSAGE_INITED    0x80
134 #define HWUSAGE_PSXREG    0x100
135
136 // Remember to invalidate the special registers if they are modified by compiler
137 enum {
138     ARG1 = 3,
139     ARG2 = 4,
140     ARG3 = 5,
141     PSXREGS,    // ptr
142          PSXMEM,                // ptr
143     CYCLECOUNT, // ptr
144     PSXPC,      // ptr
145     TARGETPTR,  // ptr
146     TARGET,     // ptr
147     RETVAL,
148     REG_RZERO,
149     REG_WZERO
150 };
151
152 typedef struct {
153     int code;
154     u32 k;
155     int usage;
156     int lastUsed;
157     
158     void (*flush)(int hwreg);
159     int private;
160 } HWRegister;
161 static HWRegister HWRegisters[NUM_HW_REGISTERS];
162 static int HWRegUseCount;
163 static int DstCPUReg;
164 static int UniqueRegAlloc;
165
166 static int GetFreeHWReg();
167 static void InvalidateCPURegs();
168 static void DisposeHWReg(int index);
169 static void FlushHWReg(int index);
170 static void FlushAllHWReg();
171 static void MapPsxReg32(int reg);
172 static void FlushPsxReg32(int hwreg);
173 static int UpdateHWRegUsage(int hwreg, int usage);
174 static int GetHWReg32(int reg);
175 static int PutHWReg32(int reg);
176 static int GetSpecialIndexFromHWRegs(int which);
177 static int GetHWRegFromCPUReg(int cpureg);
178 static int MapRegSpecial(int which);
179 static void FlushRegSpecial(int hwreg);
180 static int GetHWRegSpecial(int which);
181 static int PutHWRegSpecial(int which);
182 static void recRecompile();
183 static void recError();
184
185 #pragma mark --- Generic register mapping ---
186
187 static int GetFreeHWReg()
188 {
189         int i, least, index;
190         
191         if (DstCPUReg != -1) {
192                 index = GetHWRegFromCPUReg(DstCPUReg);
193                 DstCPUReg = -1;
194         } else {
195             // LRU algorith with a twist ;)
196             for (i=0; i<NUM_HW_REGISTERS; i++) {
197                     if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) {
198                             break;
199                     }
200             }
201     
202             least = HWRegisters[i].lastUsed; index = i;
203             for (; i<NUM_HW_REGISTERS; i++) {
204                     if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) {
205                             if (HWRegisters[i].usage == HWUSAGE_NONE && HWRegisters[i].code >= 13) {
206                                     index = i;
207                                     break;
208                             }
209                             else if (HWRegisters[i].lastUsed < least) {
210                                     least = HWRegisters[i].lastUsed;
211                                     index = i;
212                             }
213                     }
214             }
215                  
216                  // Cycle the registers
217                  if (HWRegisters[index].usage == HWUSAGE_NONE) {
218                         for (; i<NUM_HW_REGISTERS; i++) {
219                                 if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) {
220                                         if (HWRegisters[i].usage == HWUSAGE_NONE && 
221                                                  HWRegisters[i].code >= 13 && 
222                                                  HWRegisters[i].lastUsed < least) {
223                                                 least = HWRegisters[i].lastUsed;
224                                                 index = i;
225                                                 break;
226                                         }
227                                 }
228                         }
229                  }
230         }
231         
232 /*      if (HWRegisters[index].code < 13 && HWRegisters[index].code > 3) {
233                 SysPrintf("Allocating volatile register %i\n", HWRegisters[index].code);
234         }
235         if (HWRegisters[index].usage != HWUSAGE_NONE) {
236                 SysPrintf("RegUse too big. Flushing %i\n", HWRegisters[index].code);
237         }*/
238         if (HWRegisters[index].usage & (HWUSAGE_RESERVED | HWUSAGE_HARDWIRED)) {
239                 if (HWRegisters[index].usage & HWUSAGE_RESERVED) {
240                         SysPrintf("Error! Trying to map a new register to a reserved register (r%i)", 
241                                                 HWRegisters[index].code);
242                 }
243                 if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) {
244                         SysPrintf("Error! Trying to map a new register to a hardwired register (r%i)", 
245                                                 HWRegisters[index].code);
246                 }
247         }
248         
249         if (HWRegisters[index].lastUsed != 0) {
250                 UniqueRegAlloc = 0;
251         }
252         
253         // Make sure the register is really flushed!
254         FlushHWReg(index);
255         HWRegisters[index].usage = HWUSAGE_NONE;
256         HWRegisters[index].flush = NULL;
257         
258         return index;
259 }
260
261 static void FlushHWReg(int index)
262 {
263         if (index < 0) return;
264         if (HWRegisters[index].usage == HWUSAGE_NONE) return;
265         
266         if (HWRegisters[index].flush) {
267                 HWRegisters[index].usage |= HWUSAGE_RESERVED;
268                 HWRegisters[index].flush(index);
269                 HWRegisters[index].flush = NULL;
270         }
271         
272         if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) {
273                 HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE);
274         } else {
275                 HWRegisters[index].usage = HWUSAGE_NONE;
276         }
277 }
278
279 // get rid of a mapped register without flushing the contents to the memory
280 static void DisposeHWReg(int index)
281 {
282         if (index < 0) return;
283         if (HWRegisters[index].usage == HWUSAGE_NONE) return;
284         
285         HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE);
286         if (HWRegisters[index].usage == HWUSAGE_NONE) {
287                 SysPrintf("Error! not correctly disposing register (r%i)", HWRegisters[index].code);
288         }
289         
290         FlushHWReg(index);
291 }
292
293 // operated on cpu registers
294 __inline static void FlushCPURegRange(int start, int end)
295 {
296         int i;
297         
298         if (end <= 0) end = 31;
299         if (start <= 0) start = 0;
300         
301         for (i=0; i<NUM_HW_REGISTERS; i++) {
302                 if (HWRegisters[i].code >= start && HWRegisters[i].code <= end)
303                         if (HWRegisters[i].flush)
304                                 FlushHWReg(i);
305         }
306
307         for (i=0; i<NUM_HW_REGISTERS; i++) {
308                 if (HWRegisters[i].code >= start && HWRegisters[i].code <= end)
309                         FlushHWReg(i);
310         }
311 }
312
313 static void FlushAllHWReg()
314 {
315         FlushCPURegRange(0,31);
316 }
317
318 static void InvalidateCPURegs()
319 {
320         FlushCPURegRange(0,12);
321 }
322
323 #pragma mark --- Mapping utility functions ---
324
325 static void MoveHWRegToCPUReg(int cpureg, int hwreg)
326 {
327         int dstreg;
328         
329         if (HWRegisters[hwreg].code == cpureg)
330                 return;
331         
332         dstreg = GetHWRegFromCPUReg(cpureg);
333         
334         HWRegisters[dstreg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG);
335         if (HWRegisters[hwreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) {
336                 FlushHWReg(dstreg);
337                 MR(HWRegisters[dstreg].code, HWRegisters[hwreg].code);
338         } else {
339                 if (HWRegisters[dstreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) {
340                         MR(HWRegisters[hwreg].code, HWRegisters[dstreg].code);
341                 }
342                 else if (HWRegisters[dstreg].usage != HWUSAGE_NONE) {
343                         FlushHWReg(dstreg);
344                 }
345         }
346         
347         HWRegisters[dstreg].code = HWRegisters[hwreg].code;
348         HWRegisters[hwreg].code = cpureg;
349 }
350
351 static int UpdateHWRegUsage(int hwreg, int usage)
352 {
353         HWRegisters[hwreg].lastUsed = ++HWRegUseCount;    
354         if (usage & HWUSAGE_WRITE) {
355                 HWRegisters[hwreg].usage &= ~HWUSAGE_CONST;
356         }
357         if (!(usage & HWUSAGE_INITED)) {
358                 HWRegisters[hwreg].usage &= ~HWUSAGE_INITED;
359         }
360         HWRegisters[hwreg].usage |= usage;
361         
362         return HWRegisters[hwreg].code;
363 }
364
365 static int GetHWRegFromCPUReg(int cpureg)
366 {
367         int i;
368         for (i=0; i<NUM_HW_REGISTERS; i++) {
369                 if (HWRegisters[i].code == cpureg) {
370                         return i;
371                 }
372         }
373         
374         SysPrintf("Error! Register location failure (r%i)", cpureg);
375         return 0;
376 }
377
378 // this function operates on cpu registers
379 void SetDstCPUReg(int cpureg)
380 {
381         DstCPUReg = cpureg;
382 }
383
384 static void ReserveArgs(int args)
385 {
386         int index, i;
387         
388         for (i=0; i<args; i++) {
389                 index = GetHWRegFromCPUReg(3+i);
390                 HWRegisters[index].usage |= HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG;
391         }
392 }
393
394 static void ReleaseArgs()
395 {
396         int i;
397         
398         for (i=0; i<NUM_HW_REGISTERS; i++) {
399                 if (HWRegisters[i].usage & HWUSAGE_ARG) {
400                         //HWRegisters[i].usage = HWUSAGE_NONE;
401                         //HWRegisters[i].flush = NULL;
402                         HWRegisters[i].usage &= ~(HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG);
403                         FlushHWReg(i);
404                 }
405         }
406 }
407
408 #pragma mark --- Psx register mapping ---
409
410 static void MapPsxReg32(int reg)
411 {
412     int hwreg = GetFreeHWReg();
413     HWRegisters[hwreg].flush = FlushPsxReg32;
414     HWRegisters[hwreg].private = reg;
415     
416     if (iRegs[reg].reg != -1) {
417         SysPrintf("error: double mapped psx register");
418     }
419     
420     iRegs[reg].reg = hwreg;
421     iRegs[reg].state |= ST_MAPPED;
422 }
423
424 static void FlushPsxReg32(int hwreg)
425 {
426         int reg = HWRegisters[hwreg].private;
427         
428         if (iRegs[reg].reg == -1) {
429                 SysPrintf("error: flushing unmapped psx register");
430         }
431         
432         if (HWRegisters[hwreg].usage & HWUSAGE_WRITE) {
433                 if (branch) {
434                         /*int reguse = nextPsxRegUse(pc-8, reg);
435                         if (reguse == REGUSE_NONE || (reguse & REGUSE_READ))*/ {
436                                 STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS));
437                         }
438                 } else {
439                         int reguse = nextPsxRegUse(pc-4, reg);
440                         if (reguse == REGUSE_NONE || (reguse & REGUSE_READ)) {
441                                 STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS));
442                         }
443                 }
444         }
445         
446         iRegs[reg].reg = -1;
447         iRegs[reg].state = ST_UNK;
448 }
449
450 static int GetHWReg32(int reg)
451 {
452         int usage = HWUSAGE_PSXREG | HWUSAGE_READ;
453         
454         if (reg == 0) {
455                 return GetHWRegSpecial(REG_RZERO);
456         }
457         if (!IsMapped(reg)) {
458                 usage |= HWUSAGE_INITED;
459                 MapPsxReg32(reg);
460                 
461                 HWRegisters[iRegs[reg].reg].usage |= HWUSAGE_RESERVED;
462                 if (IsConst(reg)) {
463                         LIW(HWRegisters[iRegs[reg].reg].code, iRegs[reg].k);
464                         usage |= HWUSAGE_WRITE | HWUSAGE_CONST;
465                         //iRegs[reg].state &= ~ST_CONST;
466                 }
467                 else {
468                         LWZ(HWRegisters[iRegs[reg].reg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS));
469                 }
470                 HWRegisters[iRegs[reg].reg].usage &= ~HWUSAGE_RESERVED;
471         }
472         else if (DstCPUReg != -1) {
473                 int dst = DstCPUReg;
474                 DstCPUReg = -1;
475                 
476                 if (HWRegisters[iRegs[reg].reg].code < 13) {
477                         MoveHWRegToCPUReg(dst, iRegs[reg].reg);
478                 } else {
479                         MR(DstCPUReg, HWRegisters[iRegs[reg].reg].code);
480                 }
481         }
482         
483         DstCPUReg = -1;
484         
485         return UpdateHWRegUsage(iRegs[reg].reg, usage);
486 }
487
488 static int PutHWReg32(int reg)
489 {
490         int usage = HWUSAGE_PSXREG | HWUSAGE_WRITE;
491         if (reg == 0) {
492                 return PutHWRegSpecial(REG_WZERO);
493         }
494         
495         if (DstCPUReg != -1 && IsMapped(reg)) {
496                 if (HWRegisters[iRegs[reg].reg].code != DstCPUReg) {
497                         int tmp = DstCPUReg;
498                         DstCPUReg = -1;
499                         DisposeHWReg(iRegs[reg].reg);
500                         DstCPUReg = tmp;
501                 }
502         }
503         if (!IsMapped(reg)) {
504                 usage |= HWUSAGE_INITED;
505                 MapPsxReg32(reg);
506         }
507         
508         DstCPUReg = -1;
509         iRegs[reg].state &= ~ST_CONST;
510
511         return UpdateHWRegUsage(iRegs[reg].reg, usage);
512 }
513
514 #pragma mark --- Special register mapping ---
515
516 static int GetSpecialIndexFromHWRegs(int which)
517 {
518         int i;
519         for (i=0; i<NUM_HW_REGISTERS; i++) {
520                 if (HWRegisters[i].usage & HWUSAGE_SPECIAL) {
521                         if (HWRegisters[i].private == which) {
522                                 return i;
523                         }
524                 }
525         }
526         return -1;
527 }
528
529 static int MapRegSpecial(int which)
530 {
531         int hwreg = GetFreeHWReg();
532         HWRegisters[hwreg].flush = FlushRegSpecial;
533         HWRegisters[hwreg].private = which;
534         
535         return hwreg;
536 }
537
538 static void FlushRegSpecial(int hwreg)
539 {
540         int which = HWRegisters[hwreg].private;
541         
542         if (!(HWRegisters[hwreg].usage & HWUSAGE_WRITE))
543                 return;
544         
545         switch (which) {
546                 case CYCLECOUNT:
547                         STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.cycle), GetHWRegSpecial(PSXREGS));
548                         break;
549                 case PSXPC:
550                         STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.pc), GetHWRegSpecial(PSXREGS));
551                         break;
552                 case TARGET:
553                         STW(HWRegisters[hwreg].code, 0, GetHWRegSpecial(TARGETPTR));
554                         break;
555         }
556 }
557
558 static int GetHWRegSpecial(int which)
559 {
560         int index = GetSpecialIndexFromHWRegs(which);
561         int usage = HWUSAGE_READ | HWUSAGE_SPECIAL;
562         
563         if (index == -1) {
564                 usage |= HWUSAGE_INITED;
565                 index = MapRegSpecial(which);
566                 
567                 HWRegisters[index].usage |= HWUSAGE_RESERVED;
568                 switch (which) {
569                         case PSXREGS:
570                         case PSXMEM:
571                                 SysPrintf("error! shouldn't be here!\n");
572                                 //HWRegisters[index].flush = NULL;
573                                 //LIW(HWRegisters[index].code, (u32)&psxRegs);
574                                 break;
575                         case TARGETPTR:
576                                 HWRegisters[index].flush = NULL;
577                                 LIW(HWRegisters[index].code, (u32)&target);
578                                 break;
579                         case REG_RZERO:
580                                 HWRegisters[index].flush = NULL;
581                                 LIW(HWRegisters[index].code, 0);
582                                 break;
583                         case RETVAL:
584                                 MoveHWRegToCPUReg(3, index);
585                                 /*reg = GetHWRegFromCPUReg(3);
586                                 HWRegisters[reg].code = HWRegisters[index].code;
587                                 HWRegisters[index].code = 3;*/
588                                 HWRegisters[index].flush = NULL;
589                                 
590                                 usage |= HWUSAGE_RESERVED;
591                                 break;
592
593                         case CYCLECOUNT:
594                                 LWZ(HWRegisters[index].code, OFFSET(&psxRegs, &psxRegs.cycle), GetHWRegSpecial(PSXREGS));
595                                 break;
596                         case PSXPC:
597                                 LWZ(HWRegisters[index].code, OFFSET(&psxRegs, &psxRegs.pc), GetHWRegSpecial(PSXREGS));
598                                 break;
599                         case TARGET:
600                                 LWZ(HWRegisters[index].code, 0, GetHWRegSpecial(TARGETPTR));
601                                 break;
602                         default:
603                                 SysPrintf("Error: Unknown special register in GetHWRegSpecial()\n");
604                                 break;
605                 }
606                 HWRegisters[index].usage &= ~HWUSAGE_RESERVED;
607         }
608         else if (DstCPUReg != -1) {
609                 int dst = DstCPUReg;
610                 DstCPUReg = -1;
611                 
612                 MoveHWRegToCPUReg(dst, index);
613         }
614
615         return UpdateHWRegUsage(index, usage);
616 }
617
618 static int PutHWRegSpecial(int which)
619 {
620         int index = GetSpecialIndexFromHWRegs(which);
621         int usage = HWUSAGE_WRITE | HWUSAGE_SPECIAL;
622         
623         if (DstCPUReg != -1 && index != -1) {
624                 if (HWRegisters[index].code != DstCPUReg) {
625                         int tmp = DstCPUReg;
626                         DstCPUReg = -1;
627                         DisposeHWReg(index);
628                         DstCPUReg = tmp;
629                 }
630         }
631         switch (which) {
632                 case PSXREGS:
633                 case TARGETPTR:
634                         SysPrintf("Error: Read-only special register in PutHWRegSpecial()\n");
635                 case REG_WZERO:
636                         if (index >= 0) {
637                                         if (HWRegisters[index].usage & HWUSAGE_WRITE)
638                                                 break;
639                         }
640                         index = MapRegSpecial(which);
641                         HWRegisters[index].flush = NULL;
642                         break;
643                 default:
644                         if (index == -1) {
645                                 usage |= HWUSAGE_INITED;
646                                 index = MapRegSpecial(which);
647                                 
648                                 HWRegisters[index].usage |= HWUSAGE_RESERVED;
649                                 switch (which) {
650                                         case ARG1:
651                                         case ARG2:
652                                         case ARG3:
653                                                 MoveHWRegToCPUReg(3+(which-ARG1), index);
654                                                 /*reg = GetHWRegFromCPUReg(3+(which-ARG1));
655                                                 
656                                                 if (HWRegisters[reg].usage != HWUSAGE_NONE) {
657                                                         HWRegisters[reg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG);
658                                                         if (HWRegisters[reg].flush != NULL && HWRegisters[reg].usage & (HWUSAGE_WRITE | HWUSAGE_READ)) {
659                                                                 MR(HWRegisters[index].code, HWRegisters[reg].code);
660                                                         } else {
661                                                                 FlushHWReg(reg);
662                                                         }
663                                                 }
664                                                 HWRegisters[reg].code = HWRegisters[index].code;
665                                                 if (!(HWRegisters[index].code >= 3 && HWRegisters[index].code <=31))
666                                                         SysPrintf("Error! Register allocation");
667                                                 HWRegisters[index].code = 3+(which-ARG1);*/
668                                                 HWRegisters[index].flush = NULL;
669                                                 
670                                                 usage |= HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG;
671                                                 break;
672                                 }
673                         }
674                         HWRegisters[index].usage &= ~HWUSAGE_RESERVED;
675                         break;
676         }
677         
678         DstCPUReg = -1;
679
680         return UpdateHWRegUsage(index, usage);
681 }
682
683 #pragma mark --- ---
684
685 static void MapConst(int reg, u32 _const) {
686         if (reg == 0)
687                 return;
688         if (IsConst(reg) && iRegs[reg].k == _const)
689                 return;
690         
691         DisposeHWReg(iRegs[reg].reg);
692         iRegs[reg].k = _const;
693         iRegs[reg].state = ST_CONST;
694 }
695
696 static void MapCopy(int dst, int src)
697 {
698     // do it the lazy way for now
699     MR(PutHWReg32(dst), GetHWReg32(src));
700 }
701
702 static void iFlushReg(u32 nextpc, int reg) {
703         if (!IsMapped(reg) && IsConst(reg)) {
704                 GetHWReg32(reg);
705         }
706         if (IsMapped(reg)) {
707                 if (nextpc) {
708                         int use = nextPsxRegUse(nextpc, reg);
709                         if ((use & REGUSE_RW) == REGUSE_WRITE) {
710                                 DisposeHWReg(iRegs[reg].reg);
711                         } else {
712                                 FlushHWReg(iRegs[reg].reg);
713                         }
714                 } else {
715                         FlushHWReg(iRegs[reg].reg);
716                 }
717         }
718 }
719
720 static void iFlushRegs(u32 nextpc) {
721         int i;
722
723         for (i=1; i<NUM_REGISTERS; i++) {
724                 iFlushReg(nextpc, i);
725         }
726 }
727
728 static void Return()
729 {
730         iFlushRegs(0);
731         FlushAllHWReg();
732         if (((u32)returnPC & 0x1fffffc) == (u32)returnPC) {
733                 BA((u32)returnPC);
734         }
735         else {
736                 LIW(0, (u32)returnPC);
737                 MTLR(0);
738                 BLR();
739         }
740 }
741
742 static void iRet() {
743     /* store cycle */
744     count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
745     ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
746     Return();
747 }
748
749 static int iLoadTest() {
750         u32 tmp;
751
752         // check for load delay
753         tmp = psxRegs.code >> 26;
754         switch (tmp) {
755                 case 0x10: // COP0
756                         switch (_Rs_) {
757                                 case 0x00: // MFC0
758                                 case 0x02: // CFC0
759                                         return 1;
760                         }
761                         break;
762                 case 0x12: // COP2
763                         switch (_Funct_) {
764                                 case 0x00:
765                                         switch (_Rs_) {
766                                                 case 0x00: // MFC2
767                                                 case 0x02: // CFC2
768                                                         return 1;
769                                         }
770                                         break;
771                         }
772                         break;
773                 case 0x32: // LWC2
774                         return 1;
775                 default:
776                         if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
777                                 return 1;
778                         }
779                         break;
780         }
781         return 0;
782 }
783
784 /* set a pending branch */
785 static void SetBranch() {
786         int treg;
787         branch = 1;
788         psxRegs.code = PSXMu32(pc);
789         pc+=4;
790
791         if (iLoadTest() == 1) {
792                 iFlushRegs(0);
793                 LIW(0, psxRegs.code);
794                 STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS));
795                 /* store cycle */
796                 count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
797                 ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
798                 
799                 treg = GetHWRegSpecial(TARGET);
800                 MR(PutHWRegSpecial(ARG2), treg);
801                 DisposeHWReg(GetHWRegFromCPUReg(treg));
802                 LIW(PutHWRegSpecial(ARG1), _Rt_);
803                 LIW(GetHWRegSpecial(PSXPC), pc);
804                 FlushAllHWReg();
805                 CALLFunc((u32)psxDelayTest);
806
807                 Return();
808                 return;
809         }
810
811         recBSC[psxRegs.code>>26]();
812
813         iFlushRegs(0);
814         treg = GetHWRegSpecial(TARGET);
815         MR(PutHWRegSpecial(PSXPC), GetHWRegSpecial(TARGET)); // FIXME: this line should not be needed
816         DisposeHWReg(GetHWRegFromCPUReg(treg));
817         FlushAllHWReg();
818
819         count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
820         ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
821         FlushAllHWReg();
822         CALLFunc((u32)psxBranchTest);
823         
824         // TODO: don't return if target is compiled
825         Return();
826 }
827
828 static void iJump(u32 branchPC) {
829         u32 *b1, *b2;
830         branch = 1;
831         psxRegs.code = PSXMu32(pc);
832         pc+=4;
833
834         if (iLoadTest() == 1) {
835                 iFlushRegs(0);
836                 LIW(0, psxRegs.code);
837                 STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS));
838                 /* store cycle */
839                 count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
840                 ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
841
842                 LIW(PutHWRegSpecial(ARG2), branchPC);
843                 LIW(PutHWRegSpecial(ARG1), _Rt_);
844                 LIW(GetHWRegSpecial(PSXPC), pc);
845                 FlushAllHWReg();
846                 CALLFunc((u32)psxDelayTest);
847                 
848                 Return();
849                 return;
850         }
851
852         recBSC[psxRegs.code>>26]();
853
854         iFlushRegs(branchPC);
855         LIW(PutHWRegSpecial(PSXPC), branchPC);
856         FlushAllHWReg();
857
858         count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
859         //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) {
860         //    LIW(PutHWRegSpecial(CYCLECOUNT), 0);
861         //} else {
862             ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
863         //}
864         FlushAllHWReg();
865         CALLFunc((u32)psxBranchTest);
866
867         if (!Config.HLE && Config.PsxOut &&
868             ((branchPC & 0x1fffff) == 0xa0 ||
869              (branchPC & 0x1fffff) == 0xb0 ||
870              (branchPC & 0x1fffff) == 0xc0))
871           CALLFunc((u32)psxJumpTest);
872
873         // always return for now...
874         //Return();
875                 
876         // maybe just happened an interruption, check so
877         LIW(0, branchPC);
878         CMPLW(GetHWRegSpecial(PSXPC), 0);
879         BNE_L(b1);
880         
881         LIW(3, PC_REC(branchPC));
882         LWZ(3, 0, 3);
883         CMPLWI(3, 0);
884         BNE_L(b2);
885         
886         B_DST(b1);
887         Return();
888         
889         // next bit is already compiled - jump right to it
890         B_DST(b2);
891         MTCTR(3);
892         BCTR();
893 }
894
895 static void iBranch(u32 branchPC, int savectx) {
896         HWRegister HWRegistersS[NUM_HW_REGISTERS];
897         iRegisters iRegsS[NUM_REGISTERS];
898         int HWRegUseCountS = 0;
899         u32 respold=0;
900         u32 *b1, *b2;
901
902         if (savectx) {
903                 respold = resp;
904                 memcpy(iRegsS, iRegs, sizeof(iRegs));
905                 memcpy(HWRegistersS, HWRegisters, sizeof(HWRegisters));
906                 HWRegUseCountS = HWRegUseCount;
907         }
908         
909         branch = 1;
910         psxRegs.code = PSXMu32(pc);
911
912         // the delay test is only made when the branch is taken
913         // savectx == 0 will mean that :)
914         if (savectx == 0 && iLoadTest() == 1) {
915                 iFlushRegs(0);
916                 LIW(0, psxRegs.code);
917                 STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS));
918                 /* store cycle */
919                 count = (idlecyclecount + ((pc+4) - pcold) / 4) * BIAS;
920                 ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
921
922                 LIW(PutHWRegSpecial(ARG2), branchPC);
923                 LIW(PutHWRegSpecial(ARG1), _Rt_);
924                 LIW(GetHWRegSpecial(PSXPC), pc);
925                 FlushAllHWReg();
926                 CALLFunc((u32)psxDelayTest);
927
928                 Return();
929                 return;
930         }
931
932         pc+= 4;
933         recBSC[psxRegs.code>>26]();
934         
935         iFlushRegs(branchPC);
936         LIW(PutHWRegSpecial(PSXPC), branchPC);
937         FlushAllHWReg();
938
939         /* store cycle */
940         count = (idlecyclecount + (pc - pcold) / 4) * BIAS;
941         //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) {
942         //    LIW(PutHWRegSpecial(CYCLECOUNT), 0);
943         //} else {
944             ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
945         //}
946         FlushAllHWReg();
947         CALLFunc((u32)psxBranchTest);
948         
949         // always return for now...
950         //Return();
951
952         LIW(0, branchPC);
953         CMPLW(GetHWRegSpecial(PSXPC), 0);
954         BNE_L(b1);
955         
956         LIW(3, PC_REC(branchPC));
957         LWZ(3, 0, 3);
958         CMPLWI(3, 0);
959         BNE_L(b2);
960         
961         B_DST(b1);
962         Return();
963         
964         B_DST(b2);
965         MTCTR(3);
966         BCTR();
967
968         // maybe just happened an interruption, check so
969 /*      CMP32ItoM((u32)&psxRegs.pc, branchPC);
970         j8Ptr[1] = JE8(0);
971         RET();
972
973         x86SetJ8(j8Ptr[1]);
974         MOV32MtoR(EAX, PC_REC(branchPC));
975         TEST32RtoR(EAX, EAX);
976         j8Ptr[2] = JNE8(0);
977         RET();
978
979         x86SetJ8(j8Ptr[2]);
980         JMP32R(EAX);*/
981
982         pc-= 4;
983         if (savectx) {
984                 resp = respold;
985                 memcpy(iRegs, iRegsS, sizeof(iRegs));
986                 memcpy(HWRegisters, HWRegistersS, sizeof(HWRegisters));
987                 HWRegUseCount = HWRegUseCountS;
988         }
989 }
990
991
992 static void iDumpRegs() {
993         int i, j;
994
995         printf("%lx %lx\n", psxRegs.pc, psxRegs.cycle);
996         for (i=0; i<4; i++) {
997                 for (j=0; j<8; j++)
998                         printf("%lx ", psxRegs.GPR.r[j*i]);
999                 printf("\n");
1000         }
1001 }
1002
1003 void iDumpBlock(char *ptr) {
1004 /*      FILE *f;
1005         u32 i;
1006
1007         SysPrintf("dump1 %x:%x, %x\n", psxRegs.pc, pc, psxCurrentCycle);
1008
1009         for (i = psxRegs.pc; i < pc; i+=4)
1010                 SysPrintf("%s\n", disR3000AF(PSXMu32(i), i));
1011
1012         fflush(stdout);
1013         f = fopen("dump1", "w");
1014         fwrite(ptr, 1, (u32)x86Ptr - (u32)ptr, f);
1015         fclose(f);
1016         system("ndisasmw -u dump1");
1017         fflush(stdout);*/
1018 }
1019
1020 #define REC_FUNC(f) \
1021 void psx##f(); \
1022 static void rec##f() { \
1023         iFlushRegs(0); \
1024         LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \
1025         STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \
1026         LIW(PutHWRegSpecial(PSXPC), (u32)pc); \
1027         FlushAllHWReg(); \
1028         CALLFunc((u32)psx##f); \
1029 /*      branch = 2; */\
1030 }
1031
1032 #define REC_SYS(f) \
1033 void psx##f(); \
1034 static void rec##f() { \
1035         iFlushRegs(0); \
1036         LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \
1037         STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \
1038         LIW(PutHWRegSpecial(PSXPC), (u32)pc); \
1039         FlushAllHWReg(); \
1040         CALLFunc((u32)psx##f); \
1041         branch = 2; \
1042         iRet(); \
1043 }
1044
1045 #define REC_BRANCH(f) \
1046 void psx##f(); \
1047 static void rec##f() { \
1048         iFlushRegs(0); \
1049         LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \
1050         STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \
1051         LIW(PutHWRegSpecial(PSXPC), (u32)pc); \
1052         FlushAllHWReg(); \
1053         CALLFunc((u32)psx##f); \
1054         branch = 2; \
1055         iRet(); \
1056 }
1057
1058 static void freeMem(int all)
1059 {
1060     if (recMem) free(recMem);
1061     if (recRAM) free(recRAM);
1062     if (recROM) free(recROM);
1063     recMem = recRAM = recROM = 0;
1064     
1065     if (all && psxRecLUT) {
1066         free(psxRecLUT); psxRecLUT = NULL;
1067     }
1068 }
1069
1070 static int allocMem() {
1071         int i;
1072
1073         freeMem(0);
1074         
1075         if (psxRecLUT==NULL)
1076                 psxRecLUT = (u32*) malloc(0x010000 * 4);
1077
1078         recMem = (char*) malloc(RECMEM_SIZE);
1079         //recMem = mmap(NULL, RECMEM_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1,  0);
1080         recRAM = (char*) malloc(0x200000);
1081         recROM = (char*) malloc(0x080000);
1082         if (recRAM == NULL || recROM == NULL || recMem == NULL/*(void *)-1*/ || psxRecLUT == NULL) {
1083                 freeMem(1);
1084                 SysMessage("Error allocating memory"); return -1;
1085         }
1086
1087         for (i=0; i<0x80; i++) psxRecLUT[i + 0x0000] = (u32)&recRAM[(i & 0x1f) << 16];
1088         memcpy(psxRecLUT + 0x8000, psxRecLUT, 0x80 * 4);
1089         memcpy(psxRecLUT + 0xa000, psxRecLUT, 0x80 * 4);
1090
1091         for (i=0; i<0x08; i++) psxRecLUT[i + 0xbfc0] = (u32)&recROM[i << 16];
1092         
1093         return 0;
1094 }
1095
1096 static int recInit() {
1097         return allocMem();
1098 }
1099
1100 static void recReset() {
1101         memset(recRAM, 0, 0x200000);
1102         memset(recROM, 0, 0x080000);
1103
1104         ppcInit();
1105         ppcSetPtr((u32 *)recMem);
1106
1107         branch = 0;
1108         memset(iRegs, 0, sizeof(iRegs));
1109         iRegs[0].state = ST_CONST;
1110         iRegs[0].k     = 0;
1111 }
1112
1113 static void recShutdown() {
1114         freeMem(1);
1115         ppcShutdown();
1116 }
1117
1118 static void recError() {
1119         SysReset();
1120         ClosePlugins();
1121         SysMessage("Unrecoverable error while running recompiler\n");
1122         SysRunGui();
1123 }
1124
1125 __inline static void execute() {
1126         void (**recFunc)();
1127         char *p;
1128
1129         p =     (char*)PC_REC(psxRegs.pc);
1130         /*if (p != NULL)*/ recFunc = (void (**)()) (u32)p;
1131         /*else { recError(); return; }*/
1132
1133         if (*recFunc == 0) {
1134                 recRecompile();
1135         }
1136         recRun(*recFunc, (u32)&psxRegs, (u32)&psxM);
1137 }
1138
1139 static void recExecute() {
1140         for (;;) execute();
1141 }
1142
1143 static void recExecuteBlock() {
1144         execute();
1145 }
1146
1147 static void recClear(u32 Addr, u32 Size) {
1148         memset((void*)PC_REC(Addr), 0, Size * 4);
1149 }
1150
1151 static void recNULL() {
1152 //      SysMessage("recUNK: %8.8x\n", psxRegs.code);
1153 }
1154
1155 /*********************************************************
1156 * goes to opcodes tables...                              *
1157 * Format:  table[something....]                          *
1158 *********************************************************/
1159
1160 //REC_SYS(SPECIAL);
1161 static void recSPECIAL() {
1162         recSPC[_Funct_]();
1163 }
1164
1165 static void recREGIMM() {
1166         recREG[_Rt_]();
1167 }
1168
1169 static void recCOP0() {
1170         recCP0[_Rs_]();
1171 }
1172
1173 //REC_SYS(COP2);
1174 static void recCOP2() {
1175         recCP2[_Funct_]();
1176 }
1177
1178 static void recBASIC() {
1179         recCP2BSC[_Rs_]();
1180 }
1181
1182 //end of Tables opcodes...
1183
1184 #pragma mark - Arithmetic with immediate operand -
1185 /*********************************************************
1186 * Arithmetic with immediate operand                      *
1187 * Format:  OP rt, rs, immediate                          *
1188 *********************************************************/
1189
1190 #if 0
1191 /*REC_FUNC(ADDI);
1192 REC_FUNC(ADDIU);
1193 REC_FUNC(ANDI);
1194 REC_FUNC(ORI);
1195 REC_FUNC(XORI);
1196 REC_FUNC(SLTI);
1197 REC_FUNC(SLTIU);*/
1198 #else
1199 static void recADDIU()  {
1200 // Rt = Rs + Im
1201         if (!_Rt_) return;
1202
1203         if (IsConst(_Rs_)) {
1204                 MapConst(_Rt_, iRegs[_Rs_].k + _Imm_);
1205         } else {
1206                 if (_Imm_ == 0) {
1207                         MapCopy(_Rt_, _Rs_);
1208                 } else {
1209                         ADDI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _Imm_);
1210                 }
1211         }
1212 }
1213
1214 static void recADDI()  {
1215 // Rt = Rs + Im
1216         recADDIU();
1217 }
1218
1219 //REC_FUNC(SLTI);
1220 //REC_FUNC(SLTIU);
1221 //CR0:  SIGN      | POSITIVE | ZERO  | SOVERFLOW | SOVERFLOW | OVERFLOW | CARRY
1222 static void recSLTI() {
1223 // Rt = Rs < Im (signed)
1224         if (!_Rt_) return;
1225
1226         if (IsConst(_Rs_)) {
1227                 MapConst(_Rt_, (s32)iRegs[_Rs_].k < _Imm_);
1228         } else {
1229                 if (_Imm_ == 0) {
1230                         SRWI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), 31);
1231                 } else {
1232                         int reg;
1233                         CMPWI(GetHWReg32(_Rs_), _Imm_);
1234                         reg = PutHWReg32(_Rt_);
1235                         LI(reg, 1);
1236                         BLT(1);
1237                         LI(reg, 0);
1238                 }
1239         }
1240 }
1241
1242 static void recSLTIU() {
1243 // Rt = Rs < Im (unsigned)
1244         if (!_Rt_) return;
1245
1246         if (IsConst(_Rs_)) {
1247                 MapConst(_Rt_, iRegs[_Rs_].k < _ImmU_);
1248         } else {
1249                 int reg;
1250                 CMPLWI(GetHWReg32(_Rs_), _Imm_);
1251                 reg = PutHWReg32(_Rt_);
1252                 LI(reg, 1);
1253                 BLT(1);
1254                 LI(reg, 0);
1255         }
1256 }
1257
1258 static void recANDI() {
1259 // Rt = Rs And Im
1260     if (!_Rt_) return;
1261
1262     if (IsConst(_Rs_)) {
1263         MapConst(_Rt_, iRegs[_Rs_].k & _ImmU_);
1264     } else {
1265         ANDI_(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_);
1266     }
1267 }
1268
1269 static void recORI() {
1270 // Rt = Rs Or Im
1271         if (!_Rt_) return;
1272
1273         if (IsConst(_Rs_)) {
1274                 MapConst(_Rt_, iRegs[_Rs_].k | _ImmU_);
1275         } else {
1276                 if (_Imm_ == 0) {
1277                         MapCopy(_Rt_, _Rs_);
1278                 } else {
1279                         ORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_);
1280                 }
1281         }
1282 }
1283
1284 static void recXORI() {
1285 // Rt = Rs Xor Im
1286     if (!_Rt_) return;
1287
1288     if (IsConst(_Rs_)) {
1289         MapConst(_Rt_, iRegs[_Rs_].k ^ _ImmU_);
1290     } else {
1291         XORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_);
1292     }
1293 }
1294 #endif
1295 //end of * Arithmetic with immediate operand  
1296
1297 /*********************************************************
1298 * Load higher 16 bits of the first word in GPR with imm  *
1299 * Format:  OP rt, immediate                              *
1300 *********************************************************/
1301 //REC_FUNC(LUI);
1302 //#if 0*/
1303 static void recLUI()  {
1304 // Rt = Imm << 16
1305         if (!_Rt_) return;
1306
1307         MapConst(_Rt_, psxRegs.code << 16);
1308 }
1309 //#endif
1310 //End of Load Higher .....
1311
1312 #pragma mark - Register arithmetic -
1313 /*********************************************************
1314 * Register arithmetic                                    *
1315 * Format:  OP rd, rs, rt                                 *
1316 *********************************************************/
1317
1318 #if 0
1319 /*REC_FUNC(ADD);
1320 REC_FUNC(ADDU);
1321 REC_FUNC(SUB);
1322 REC_FUNC(SUBU);
1323 REC_FUNC(AND);
1324 REC_FUNC(OR);
1325 REC_FUNC(XOR);
1326 REC_FUNC(NOR);
1327 REC_FUNC(SLT);
1328 REC_FUNC(SLTU);*/
1329 #else
1330 static void recADDU() {
1331 // Rd = Rs + Rt 
1332         if (!_Rd_) return;
1333
1334         if (IsConst(_Rs_) && IsConst(_Rt_)) {
1335                 MapConst(_Rd_, iRegs[_Rs_].k + iRegs[_Rt_].k);
1336         } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
1337                 if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) {
1338                         ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), (s16)iRegs[_Rs_].k);
1339                 } else if ((iRegs[_Rs_].k & 0xffff) == 0) {
1340                         ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k>>16);
1341                 } else {
1342                         ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1343                 }
1344         } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1345                 if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) {
1346                         ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (s16)iRegs[_Rt_].k);
1347                 } else if ((iRegs[_Rt_].k & 0xffff) == 0) {
1348                         ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k>>16);
1349                 } else {
1350                         ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1351                 }
1352         } else {
1353                 ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1354         }
1355 }
1356
1357 static void recADD() {
1358 // Rd = Rs + Rt
1359         recADDU();
1360 }
1361
1362 static void recSUBU() {
1363 // Rd = Rs - Rt
1364     if (!_Rd_) return;
1365
1366     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1367         MapConst(_Rd_, iRegs[_Rs_].k - iRegs[_Rt_].k);
1368     } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1369         if ((s32)(s16)(-iRegs[_Rt_].k) == (s32)(-iRegs[_Rt_].k)) {
1370             ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), -iRegs[_Rt_].k);
1371         } else if (((-iRegs[_Rt_].k) & 0xffff) == 0) {
1372             ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (-iRegs[_Rt_].k)>>16);
1373         } else {
1374             SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1375         }
1376     } else {
1377         SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1378     }
1379 }   
1380
1381 static void recSUB() {
1382 // Rd = Rs - Rt
1383         recSUBU();
1384 }
1385
1386 static void recAND() {
1387 // Rd = Rs And Rt
1388     if (!_Rd_) return;
1389     
1390     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1391         MapConst(_Rd_, iRegs[_Rs_].k & iRegs[_Rt_].k);
1392     } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
1393         // TODO: implement shifted (ANDIS) versions of these
1394         if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
1395             ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
1396         } else {
1397             AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1398         }
1399     } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1400         if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
1401             ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k);
1402         } else {
1403             AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1404         }
1405     } else {
1406         AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1407     }
1408 }   
1409
1410 static void recOR() {
1411 // Rd = Rs Or Rt
1412     if (!_Rd_) return;
1413     
1414     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1415         MapConst(_Rd_, iRegs[_Rs_].k | iRegs[_Rt_].k);
1416     }
1417     else {
1418         if (_Rs_ == _Rt_) {
1419             MapCopy(_Rd_, _Rs_);
1420         }
1421         else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
1422             if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
1423                 ORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
1424             } else {
1425                 OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1426             }
1427         }
1428         else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1429             if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
1430                 ORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k);
1431             } else {
1432                 OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1433             }
1434         } else {
1435             OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1436         }
1437     }
1438 }
1439
1440 static void recXOR() {
1441 // Rd = Rs Xor Rt
1442     if (!_Rd_) return;
1443     
1444     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1445         MapConst(_Rd_, iRegs[_Rs_].k ^ iRegs[_Rt_].k);
1446     } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
1447         if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
1448             XORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
1449         } else {
1450             XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1451         }
1452     } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1453         if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
1454             XORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k);
1455         } else {
1456             XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1457         }
1458     } else {
1459         XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1460     }
1461 }
1462
1463 static void recNOR() {
1464 // Rd = Rs Nor Rt
1465     if (!_Rd_) return;
1466     
1467     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1468         MapConst(_Rd_, ~(iRegs[_Rs_].k | iRegs[_Rt_].k));
1469     } /*else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
1470         if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
1471             NORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
1472         } else {
1473             NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1474         }
1475     } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
1476         if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
1477             NORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k);
1478         } else {
1479             NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1480         }
1481     } */else {
1482         NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1483     }
1484 }
1485
1486 static void recSLT() {
1487 // Rd = Rs < Rt (signed)
1488     if (!_Rd_) return;
1489
1490     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1491         MapConst(_Rd_, (s32)iRegs[_Rs_].k < (s32)iRegs[_Rt_].k);
1492     } else { // TODO: add immidiate cases
1493         int reg;
1494         CMPW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1495         reg = PutHWReg32(_Rd_);
1496         LI(reg, 1);
1497         BLT(1);
1498         LI(reg, 0);
1499     }
1500 }
1501
1502 static void recSLTU() { 
1503 // Rd = Rs < Rt (unsigned)
1504     if (!_Rd_) return;
1505
1506     if (IsConst(_Rs_) && IsConst(_Rt_)) {
1507         MapConst(_Rd_, iRegs[_Rs_].k < iRegs[_Rt_].k);
1508     } else { // TODO: add immidiate cases
1509         SUBFC(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_));
1510         SUBFE(PutHWReg32(_Rd_), GetHWReg32(_Rd_), GetHWReg32(_Rd_));
1511         NEG(PutHWReg32(_Rd_), GetHWReg32(_Rd_));
1512     }
1513 }
1514 #endif
1515 //End of * Register arithmetic
1516
1517 #pragma mark - mult/div & Register trap logic -
1518 /*********************************************************
1519 * Register mult/div & Register trap logic                *
1520 * Format:  OP rs, rt                                     *
1521 *********************************************************/
1522
1523 #if 0
1524 REC_FUNC(MULT);
1525 REC_FUNC(MULTU);
1526 REC_FUNC(DIV);
1527 REC_FUNC(DIVU);
1528 #else
1529
1530 int DoShift(u32 k)
1531 {
1532         u32 i;
1533         for (i=0; i<30; i++) {
1534                 if (k == (1ul << i))
1535                         return i;
1536         }
1537         return -1;
1538 }
1539
1540 //REC_FUNC(MULT);
1541
1542 // FIXME: doesn't work in GT - wrong way marker
1543 static void recMULT() {
1544 // Lo/Hi = Rs * Rt (signed)
1545         s32 k; int r;
1546         int usehi, uselo;
1547         
1548         if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) ||
1549                 (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) {
1550                 MapConst(REG_LO, 0);
1551                 MapConst(REG_HI, 0);
1552                 return;
1553         }
1554         
1555         if (IsConst(_Rs_) && IsConst(_Rt_)) {
1556                 u64 res = (s64)((s64)(s32)iRegs[_Rs_].k * (s64)(s32)iRegs[_Rt_].k);
1557                 MapConst(REG_LO, (res & 0xffffffff));
1558                 MapConst(REG_HI, ((res >> 32) & 0xffffffff));
1559                 return;
1560         }
1561         
1562         if (IsConst(_Rs_)) {
1563                 k = (s32)iRegs[_Rs_].k;
1564                 r = _Rt_;
1565         } else if (IsConst(_Rt_)) {
1566                 k = (s32)iRegs[_Rt_].k;
1567                 r = _Rs_;
1568         } else {
1569                 r = -1;
1570                 k = 0;
1571         }
1572         
1573         // FIXME: this should not be needed!!!
1574 //      uselo = isPsxRegUsed(pc, REG_LO);
1575 //      usehi = isPsxRegUsed(pc, REG_HI);
1576         uselo = 1; //isPsxRegUsed(pc, REG_LO);
1577         usehi = 1; //isPsxRegUsed(pc, REG_HI);
1578
1579
1580         if (r != -1) {
1581                 int shift = DoShift(k);
1582                 if (shift != -1) {
1583                         if (uselo) {
1584                                 SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift)
1585                         }
1586                         if (usehi) {
1587                                 SRAWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift);
1588                         }
1589                 } else {
1590                         //if ((s32)(s16)k == k) {
1591                         //      MULLWI(PutHWReg32(REG_LO), GetHWReg32(r), k);
1592                         //      MULHWI(PutHWReg32(REG_HI), GetHWReg32(r), k);
1593                         //} else
1594                         {
1595                                 if (uselo) {
1596                                         MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1597                                 }
1598                                 if (usehi) {
1599                                         MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1600                                 }
1601                         }
1602                 }
1603         } else {
1604                 if (uselo) {
1605                         MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1606                 }
1607                 if (usehi) {
1608                         MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1609                 }
1610         }
1611 }
1612
1613 static void recMULTU() {
1614 // Lo/Hi = Rs * Rt (unsigned)
1615         u32 k; int r;
1616         int usehi, uselo;
1617         
1618         if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) ||
1619                 (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) {
1620                 MapConst(REG_LO, 0);
1621                 MapConst(REG_HI, 0);
1622                 return;
1623         }
1624         
1625         if (IsConst(_Rs_) && IsConst(_Rt_)) {
1626                 u64 res = (u64)((u64)(u32)iRegs[_Rs_].k * (u64)(u32)iRegs[_Rt_].k);
1627                 MapConst(REG_LO, (res & 0xffffffff));
1628                 MapConst(REG_HI, ((res >> 32) & 0xffffffff));
1629                 return;
1630         }
1631         
1632         if (IsConst(_Rs_)) {
1633                 k = (s32)iRegs[_Rs_].k;
1634                 r = _Rt_;
1635         } else if (IsConst(_Rt_)) {
1636                 k = (s32)iRegs[_Rt_].k;
1637                 r = _Rs_;
1638         } else {
1639                 r = -1;
1640                 k = 0;
1641         }
1642         
1643         uselo = isPsxRegUsed(pc, REG_LO);
1644         usehi = isPsxRegUsed(pc, REG_HI);
1645
1646         if (r != -1) {
1647                 int shift = DoShift(k);
1648                 if (shift != -1) {
1649                         if (uselo) {
1650                                 SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift);
1651                         }
1652                         if (usehi) {
1653                                 SRWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift);
1654                         }
1655                 } else {
1656                         {
1657                                 if (uselo) {
1658                                         MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1659                                 }
1660                                 if (usehi) {
1661                                         MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1662                                 }
1663                         }
1664                 }
1665         } else {
1666                 if (uselo) {
1667                         MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1668                 }
1669                 if (usehi) {
1670                         MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1671                 }
1672         }
1673 }
1674
1675 static void recDIV() {
1676 // Lo/Hi = Rs / Rt (signed)
1677         int usehi;
1678
1679         if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) {
1680                 MapConst(REG_LO, 0);
1681                 MapConst(REG_HI, 0);
1682                 return;
1683         }
1684         if (IsConst(_Rt_) && IsConst(_Rs_)) {
1685                 MapConst(REG_LO, (s32)iRegs[_Rs_].k / (s32)iRegs[_Rt_].k);
1686                 MapConst(REG_HI, (s32)iRegs[_Rs_].k % (s32)iRegs[_Rt_].k);
1687                 return;
1688         }
1689         
1690         usehi = isPsxRegUsed(pc, REG_HI);
1691         
1692         if (IsConst(_Rt_)) {
1693                 int shift = DoShift(iRegs[_Rt_].k);
1694                 if (shift != -1) {
1695                         SRAWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift);
1696                         ADDZE(PutHWReg32(REG_LO), GetHWReg32(REG_LO));
1697                         if (usehi) {
1698                                 RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, 31-shift, 31);
1699                         }
1700                 } else if (iRegs[_Rt_].k == 3) {
1701                         // http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html
1702                         LIS(PutHWReg32(REG_HI), 0x5555);
1703                         ADDI(PutHWReg32(REG_HI), GetHWReg32(REG_HI), 0x5556);
1704                         MULHW(PutHWReg32(REG_LO), GetHWReg32(REG_HI), GetHWReg32(_Rs_));
1705                         SRWI(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 31);
1706                         ADD(PutHWReg32(REG_LO), GetHWReg32(REG_LO), GetHWReg32(REG_HI));
1707                         if (usehi) {
1708                                 MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), 3);
1709                                 SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI));
1710                         }
1711                 } else {
1712                         DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1713                         if (usehi) {
1714                                 if ((iRegs[_Rt_].k & 0x7fff) == iRegs[_Rt_].k) {
1715                                         MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), iRegs[_Rt_].k);
1716                                 } else {
1717                                         MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_));
1718                                 }
1719                                 SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI));
1720                         }
1721                 }
1722         } else {
1723                 DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1724                 if (usehi) {
1725                         MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_));
1726                         SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI));
1727                 }
1728         }
1729 }
1730
1731 static void recDIVU() {
1732 // Lo/Hi = Rs / Rt (unsigned)
1733         int usehi;
1734
1735         if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) {
1736                 MapConst(REG_LO, 0);
1737                 MapConst(REG_HI, 0);
1738                 return;
1739         }
1740         if (IsConst(_Rt_) && IsConst(_Rs_)) {
1741                 MapConst(REG_LO, (u32)iRegs[_Rs_].k / (u32)iRegs[_Rt_].k);
1742                 MapConst(REG_HI, (u32)iRegs[_Rs_].k % (u32)iRegs[_Rt_].k);
1743                 return;
1744         }
1745         
1746         usehi = isPsxRegUsed(pc, REG_HI);
1747
1748         if (IsConst(_Rt_)) {
1749                 int shift = DoShift(iRegs[_Rt_].k);
1750                 if (shift != -1) {
1751                         SRWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift);
1752                         if (usehi) {
1753                                 RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, 31-shift, 31);
1754                         }
1755                 } else {
1756                         DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1757                         if (usehi) {
1758                                 MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO));
1759                                 SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI));
1760                         }
1761                 }
1762         } else {
1763                 DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_));
1764                 if (usehi) {
1765                         MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO));
1766                         SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI));
1767                 }
1768         }
1769 }
1770 #endif
1771 //End of * Register mult/div & Register trap logic  
1772
1773 #pragma mark - memory access -
1774
1775 #if 0
1776 REC_FUNC(LB);
1777 REC_FUNC(LBU);
1778 REC_FUNC(LH);
1779 REC_FUNC(LHU);
1780 REC_FUNC(LW);
1781
1782 REC_FUNC(SB);
1783 REC_FUNC(SH);
1784 REC_FUNC(SW);
1785
1786 REC_FUNC(LWL);
1787 REC_FUNC(LWR);
1788 REC_FUNC(SWL);
1789 REC_FUNC(SWR);
1790 #else
1791 static void preMemRead()
1792 {
1793         int rs;
1794         
1795         ReserveArgs(1);
1796         if (_Rs_ != _Rt_) {
1797                 DisposeHWReg(iRegs[_Rt_].reg);
1798         }
1799         rs = GetHWReg32(_Rs_);
1800         if (rs != 3 || _Imm_ != 0) {
1801                 ADDI(PutHWRegSpecial(ARG1), rs, _Imm_);
1802         }
1803         if (_Rs_ == _Rt_) {
1804                 DisposeHWReg(iRegs[_Rt_].reg);
1805         }
1806         InvalidateCPURegs();
1807         //FlushAllHWReg();
1808 }
1809
1810 static void preMemWrite(int size)
1811 {
1812         int rs;
1813         
1814         ReserveArgs(2);
1815         rs = GetHWReg32(_Rs_);
1816         if (rs != 3 || _Imm_ != 0) {
1817                 ADDI(PutHWRegSpecial(ARG1), rs, _Imm_);
1818         }
1819         if (size == 1) {
1820                 RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 24, 31);
1821                 //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xff);
1822         } else if (size == 2) {
1823                 RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 16, 31);
1824                 //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xffff);
1825         } else {
1826                 MR(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_));
1827         }
1828         
1829         InvalidateCPURegs();
1830         //FlushAllHWReg();
1831 }
1832
1833 static void recLB() {
1834 // Rt = mem[Rs + Im] (signed)
1835         
1836     /*if (IsConst(_Rs_)) {
1837         u32 addr = iRegs[_Rs_].k + _Imm_;
1838         int t = addr >> 16;
1839     
1840         if ((t & 0xfff0)  == 0xbfc0) {
1841             if (!_Rt_) return;
1842             // since bios is readonly it won't change
1843             MapConst(_Rt_, psxRs8(addr));
1844             return;
1845         }
1846         if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
1847             if (!_Rt_) return;
1848                 
1849             addr = (u32)&psxM[addr & 0x1fffff];
1850             LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct?
1851             LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_));
1852             EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_));
1853             return;
1854         }
1855         if (t == 0x1f80 && addr < 0x1f801000) {
1856             if (!_Rt_) return;
1857     
1858             addr = (u32)&psxH[addr & 0xfff];
1859             LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct?
1860             LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_));
1861             EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_));
1862             return;
1863         }
1864     //  SysPrintf("unhandled r8 %x\n", addr);
1865     }*/
1866         
1867         preMemRead();
1868         CALLFunc((u32)psxMemRead8);
1869         if (_Rt_) {
1870                 EXTSB(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL));
1871                 DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL));
1872         }
1873 }
1874
1875 static void recLBU() {
1876 // Rt = mem[Rs + Im] (unsigned)
1877
1878     /*if (IsConst(_Rs_)) {
1879         u32 addr = iRegs[_Rs_].k + _Imm_;
1880         int t = addr >> 16;
1881     
1882         if ((t & 0xfff0)  == 0xbfc0) {
1883             if (!_Rt_) return;
1884             // since bios is readonly it won't change
1885             MapConst(_Rt_, psxRu8(addr));
1886             return;
1887         }
1888         if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
1889             if (!_Rt_) return;
1890                 
1891             addr = (u32)&psxM[addr & 0x1fffff];
1892             LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct?
1893             LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_));
1894             return;
1895         }
1896         if (t == 0x1f80 && addr < 0x1f801000) {
1897             if (!_Rt_) return;
1898     
1899             addr = (u32)&psxH[addr & 0xfff];
1900             LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct?
1901             LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_));
1902             return;
1903         }
1904     //  SysPrintf("unhandled r8 %x\n", addr);
1905     }*/
1906         
1907         preMemRead();
1908         CALLFunc((u32)psxMemRead8);
1909         
1910         if (_Rt_) {
1911                 SetDstCPUReg(3);
1912                 PutHWReg32(_Rt_);
1913         }
1914 }
1915
1916 static void recLH() {
1917 // Rt = mem[Rs + Im] (signed)
1918
1919         if (IsConst(_Rs_)) {
1920                 u32 addr = iRegs[_Rs_].k + _Imm_;
1921                 int t = addr >> 16;
1922         
1923                 if ((t & 0xfff0)  == 0xbfc0) {
1924                         if (!_Rt_) return;
1925                         // since bios is readonly it won't change
1926                         MapConst(_Rt_, psxRs16(addr));
1927                         return;
1928                 }
1929                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
1930                         if (!_Rt_) return;
1931
1932                         LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]);
1933                         LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
1934                         EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_));
1935                         return;
1936                 }
1937                 if (t == 0x1f80 && addr < 0x1f801000) {
1938                         if (!_Rt_) return;
1939
1940                         LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]);
1941                         LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
1942                         EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_));
1943                         return;
1944                 }
1945         //      SysPrintf("unhandled r16 %x\n", addr);
1946         }
1947     
1948         preMemRead();
1949         CALLFunc((u32)psxMemRead16);
1950         if (_Rt_) {
1951                 EXTSH(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL));
1952                 DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL));
1953         }
1954 }
1955
1956 static void recLHU() {
1957 // Rt = mem[Rs + Im] (unsigned)
1958
1959         if (IsConst(_Rs_)) {
1960                 u32 addr = iRegs[_Rs_].k + _Imm_;
1961                 int t = addr >> 16;
1962         
1963                 if ((t & 0xfff0) == 0xbfc0) {
1964                         if (!_Rt_) return;
1965                         // since bios is readonly it won't change
1966                         MapConst(_Rt_, psxRu16(addr));
1967                         return;
1968                 }
1969                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
1970                         if (!_Rt_) return;
1971
1972                         LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]);
1973                         LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
1974                         return;
1975                 }
1976                 if (t == 0x1f80 && addr < 0x1f801000) {
1977                         if (!_Rt_) return;
1978
1979                         LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]);
1980                         LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
1981                         return;
1982                 }
1983                 if (t == 0x1f80) {
1984                         if (addr >= 0x1f801c00 && addr < 0x1f801e00) {
1985                                         if (!_Rt_) return;
1986                                         
1987                                         ReserveArgs(1);
1988                                         LIW(PutHWRegSpecial(ARG1), addr);
1989                                         DisposeHWReg(iRegs[_Rt_].reg);
1990                                         InvalidateCPURegs();
1991                                         CALLFunc((u32)SPU_readRegister);
1992                                         
1993                                         SetDstCPUReg(3);
1994                                         PutHWReg32(_Rt_);
1995                                         return;
1996                         }
1997                         switch (addr) {
1998                                         case 0x1f801100: case 0x1f801110: case 0x1f801120:
1999                                                 if (!_Rt_) return;
2000                                                 
2001                                                 ReserveArgs(1);
2002                                                 LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3);
2003                                                 DisposeHWReg(iRegs[_Rt_].reg);
2004                                                 InvalidateCPURegs();
2005                                                 CALLFunc((u32)psxRcntRcount);
2006                                                 
2007                                                 SetDstCPUReg(3);
2008                                                 PutHWReg32(_Rt_);
2009                                                 return;
2010
2011                                         case 0x1f801104: case 0x1f801114: case 0x1f801124:
2012                                                 if (!_Rt_) return;
2013                                                 
2014                         ReserveArgs(1);
2015                         LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3);
2016                         DisposeHWReg(iRegs[_Rt_].reg);
2017                         InvalidateCPURegs();
2018                         CALLFunc((u32)psxRcntRmode);
2019                         
2020                         SetDstCPUReg(3);
2021                         PutHWReg32(_Rt_);
2022                                                 return;
2023         
2024                                         case 0x1f801108: case 0x1f801118: case 0x1f801128:
2025                                                 if (!_Rt_) return;
2026
2027                         ReserveArgs(1);
2028                         LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3);
2029                         DisposeHWReg(iRegs[_Rt_].reg);
2030                         InvalidateCPURegs();
2031                         CALLFunc((u32)psxRcntRtarget);
2032                         
2033                         SetDstCPUReg(3);
2034                         PutHWReg32(_Rt_);
2035                                                 return;
2036                                         }
2037                 }
2038         //      SysPrintf("unhandled r16u %x\n", addr);
2039         }
2040         
2041         preMemRead();
2042         CALLFunc((u32)psxMemRead16);
2043         if (_Rt_) {
2044                 SetDstCPUReg(3);
2045                 PutHWReg32(_Rt_);
2046         }
2047 }
2048
2049 static void recLW() {
2050 // Rt = mem[Rs + Im] (unsigned)
2051
2052         if (IsConst(_Rs_)) {
2053                 u32 addr = iRegs[_Rs_].k + _Imm_;
2054                 int t = addr >> 16;
2055
2056                 if ((t & 0xfff0) == 0xbfc0) {
2057                         if (!_Rt_) return;
2058                         // since bios is readonly it won't change
2059                         MapConst(_Rt_, psxRu32(addr));
2060                         return;
2061                 }
2062                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2063                         if (!_Rt_) return;
2064
2065                         LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]);
2066                         LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
2067                         return;
2068                 }
2069                 if (t == 0x1f80 && addr < 0x1f801000) {
2070                         if (!_Rt_) return;
2071
2072                         LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]);
2073                         LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
2074                         return;
2075                 }
2076                 if (t == 0x1f80) {
2077                         switch (addr) {
2078                                 case 0x1f801080: case 0x1f801084: case 0x1f801088: 
2079                                 case 0x1f801090: case 0x1f801094: case 0x1f801098: 
2080                                 case 0x1f8010a0: case 0x1f8010a4: case 0x1f8010a8: 
2081                                 case 0x1f8010b0: case 0x1f8010b4: case 0x1f8010b8: 
2082                                 case 0x1f8010c0: case 0x1f8010c4: case 0x1f8010c8: 
2083                                 case 0x1f8010d0: case 0x1f8010d4: case 0x1f8010d8: 
2084                                 case 0x1f8010e0: case 0x1f8010e4: case 0x1f8010e8: 
2085                                 case 0x1f801070: case 0x1f801074:
2086                                 case 0x1f8010f0: case 0x1f8010f4:
2087                                         if (!_Rt_) return;
2088                                         
2089                                         LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xffff]);
2090                                         LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_));
2091                                         return;
2092
2093                                 case 0x1f801810:
2094                                         if (!_Rt_) return;
2095
2096                                         DisposeHWReg(iRegs[_Rt_].reg);
2097                                         InvalidateCPURegs();
2098                                         CALLFunc((u32)GPU_readData);
2099                                         
2100                                         SetDstCPUReg(3);
2101                                         PutHWReg32(_Rt_);
2102                                         return;
2103
2104                                 case 0x1f801814:
2105                                         if (!_Rt_) return;
2106
2107                                         DisposeHWReg(iRegs[_Rt_].reg);
2108                                         InvalidateCPURegs();
2109                                         CALLFunc((u32)GPU_readStatus);
2110                                         
2111                                         SetDstCPUReg(3);
2112                                         PutHWReg32(_Rt_);
2113                                         return;
2114                         }
2115                 }
2116 //              SysPrintf("unhandled r32 %x\n", addr);
2117         }
2118
2119         preMemRead();
2120         CALLFunc((u32)psxMemRead32);
2121         if (_Rt_) {
2122                 SetDstCPUReg(3);
2123                 PutHWReg32(_Rt_);
2124         }
2125 }
2126
2127 REC_FUNC(LWL);
2128 REC_FUNC(LWR);
2129 REC_FUNC(SWL);
2130 REC_FUNC(SWR);
2131 /*extern u32 LWL_MASK[4];
2132 extern u32 LWL_SHIFT[4];
2133
2134 void iLWLk(u32 shift) {
2135         if (IsConst(_Rt_)) {
2136                 MOV32ItoR(ECX, iRegs[_Rt_].k);
2137         } else {
2138                 MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]);
2139         }
2140         AND32ItoR(ECX, LWL_MASK[shift]);
2141         SHL32ItoR(EAX, LWL_SHIFT[shift]);
2142         OR32RtoR (EAX, ECX);
2143 }
2144
2145 void recLWL() {
2146 // Rt = Rt Merge mem[Rs + Im]
2147
2148         if (IsConst(_Rs_)) {
2149                 u32 addr = iRegs[_Rs_].k + _Imm_;
2150                 int t = addr >> 16;
2151
2152                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2153                         MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]);
2154                         iLWLk(addr & 3);
2155
2156                         iRegs[_Rt_].state = ST_UNK;
2157                         MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2158                         return;
2159                 }
2160                 if (t == 0x1f80 && addr < 0x1f801000) {
2161                         MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]);
2162                         iLWLk(addr & 3);
2163
2164                         iRegs[_Rt_].state = ST_UNK;
2165                         MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2166                         return;
2167                 }
2168         }
2169
2170         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2171         else {
2172                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2173                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2174         }
2175         PUSH32R  (EAX);
2176         AND32ItoR(EAX, ~3);
2177         PUSH32R  (EAX);
2178         CALLFunc((u32)psxMemRead32);
2179
2180         if (_Rt_) {
2181                 ADD32ItoR(ESP, 4);
2182                 POP32R   (EDX);
2183                 AND32ItoR(EDX, 0x3); // shift = addr & 3;
2184
2185                 MOV32ItoR(ECX, (u32)LWL_SHIFT);
2186                 MOV32RmStoR(ECX, ECX, EDX, 2);
2187                 SHL32CLtoR(EAX); // mem(EAX) << LWL_SHIFT[shift]
2188
2189                 MOV32ItoR(ECX, (u32)LWL_MASK);
2190                 MOV32RmStoR(ECX, ECX, EDX, 2);
2191                 if (IsConst(_Rt_)) {
2192                         MOV32ItoR(EDX, iRegs[_Rt_].k);
2193                 } else {
2194                         MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]);
2195                 }
2196                 AND32RtoR(EDX, ECX); // _rRt_ & LWL_MASK[shift]
2197
2198                 OR32RtoR(EAX, EDX);
2199
2200                 iRegs[_Rt_].state = ST_UNK;
2201                 MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2202         } else {
2203 //              ADD32ItoR(ESP, 8);
2204                 resp+= 8;
2205         }
2206 }
2207
2208 static void recLWBlock(int count) {
2209         u32 *code = PSXM(pc);
2210         int i, respsave;
2211 // Rt = mem[Rs + Im] (unsigned)
2212
2213 //      iFlushRegs(0);
2214
2215         if (IsConst(_Rs_)) {
2216                 u32 addr = iRegs[_Rs_].k + _Imm_;
2217                 int t = addr >> 16;
2218
2219                 if ((t & 0xfff0) == 0xbfc0) {
2220                         // since bios is readonly it won't change
2221                         for (i=0; i<count; i++, code++, addr+=4) {
2222                                 if (_fRt_(*code)) {
2223                                         MapConst(_fRt_(*code), psxRu32(addr));
2224                                 }
2225                         }
2226                         return;
2227                 }
2228                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2229                         for (i=0; i<count; i++, code++, addr+=4) {
2230                                 if (!_fRt_(*code)) return;
2231                                 iRegs[_fRt_(*code)].state = ST_UNK;
2232
2233                                 MOV32MtoR(EAX, (u32)&psxM[addr & 0x1fffff]);
2234                                 MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX);
2235                         }
2236                         return;
2237                 }
2238                 if (t == 0x1f80 && addr < 0x1f801000) {
2239                         for (i=0; i<count; i++, code++, addr+=4) {
2240                                 if (!_fRt_(*code)) return;
2241                                 iRegs[_fRt_(*code)].state = ST_UNK;
2242
2243                                 MOV32MtoR(EAX, (u32)&psxH[addr & 0xfff]);
2244                                 MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX);
2245                         }
2246                         return;
2247                 }
2248         }
2249
2250         SysPrintf("recLWBlock %d: %d\n", count, IsConst(_Rs_));
2251         iPushOfB();
2252         CALLFunc((u32)psxMemPointer);
2253 //      ADD32ItoR(ESP, 4);
2254         resp+= 4;
2255
2256         respsave = resp; resp = 0;
2257         TEST32RtoR(EAX, EAX);
2258         j32Ptr[4] = JZ32(0);
2259         XOR32RtoR(ECX, ECX);
2260         for (i=0; i<count; i++, code++) {
2261                 if (_fRt_(*code)) {
2262                         iRegs[_fRt_(*code)].state = ST_UNK;
2263                         
2264                         MOV32RmStoR(EDX, EAX, ECX, 2);
2265                         MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EDX);
2266                 }
2267                 if (i != (count-1)) INC32R(ECX);
2268         }
2269         j32Ptr[5] = JMP32(0);
2270         x86SetJ32(j32Ptr[4]);
2271         for (i=0, code = PSXM(pc); i<count; i++, code++) {
2272                 psxRegs.code = *code;
2273                 recLW();
2274         }
2275         ADD32ItoR(ESP, resp);
2276         x86SetJ32(j32Ptr[5]);
2277         resp = respsave;
2278 }
2279
2280 extern u32 LWR_MASK[4];
2281 extern u32 LWR_SHIFT[4];
2282
2283 void iLWRk(u32 shift) {
2284         if (IsConst(_Rt_)) {
2285                 MOV32ItoR(ECX, iRegs[_Rt_].k);
2286         } else {
2287                 MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]);
2288         }
2289         AND32ItoR(ECX, LWR_MASK[shift]);
2290         SHR32ItoR(EAX, LWR_SHIFT[shift]);
2291         OR32RtoR (EAX, ECX);
2292 }
2293
2294 void recLWR() {
2295 // Rt = Rt Merge mem[Rs + Im]
2296
2297         if (IsConst(_Rs_)) {
2298                 u32 addr = iRegs[_Rs_].k + _Imm_;
2299                 int t = addr >> 16;
2300
2301                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2302                         MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]);
2303                         iLWRk(addr & 3);
2304
2305                         iRegs[_Rt_].state = ST_UNK;
2306                         MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2307                         return;
2308                 }
2309                 if (t == 0x1f80 && addr < 0x1f801000) {
2310                         MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]);
2311                         iLWRk(addr & 3);
2312
2313                         iRegs[_Rt_].state = ST_UNK;
2314                         MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2315                         return;
2316                 }
2317         }
2318
2319         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2320         else {
2321                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2322                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2323         }
2324         PUSH32R  (EAX);
2325         AND32ItoR(EAX, ~3);
2326         PUSH32R  (EAX);
2327         CALLFunc((u32)psxMemRead32);
2328
2329         if (_Rt_) {
2330                 ADD32ItoR(ESP, 4);
2331                 POP32R   (EDX);
2332                 AND32ItoR(EDX, 0x3); // shift = addr & 3;
2333
2334                 MOV32ItoR(ECX, (u32)LWR_SHIFT);
2335                 MOV32RmStoR(ECX, ECX, EDX, 2);
2336                 SHR32CLtoR(EAX); // mem(EAX) >> LWR_SHIFT[shift]
2337
2338                 MOV32ItoR(ECX, (u32)LWR_MASK);
2339                 MOV32RmStoR(ECX, ECX, EDX, 2);
2340
2341                 if (IsConst(_Rt_)) {
2342                         MOV32ItoR(EDX, iRegs[_Rt_].k);
2343                 } else {
2344                         MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]);
2345                 }
2346                 AND32RtoR(EDX, ECX); // _rRt_ & LWR_MASK[shift]
2347
2348                 OR32RtoR(EAX, EDX);
2349
2350                 iRegs[_Rt_].state = ST_UNK;
2351                 MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
2352         } else {
2353 //              ADD32ItoR(ESP, 8);
2354                 resp+= 8;
2355         }
2356 }*/
2357
2358 static void recSB() {
2359 // mem[Rs + Im] = Rt
2360
2361         /*if (IsConst(_Rs_)) {
2362                 u32 addr = iRegs[_Rs_].k + _Imm_;
2363                 int t = addr >> 16;
2364
2365                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2366                         if (IsConst(_Rt_)) {
2367                                 MOV8ItoM((u32)&psxM[addr & 0x1fffff], (u8)iRegs[_Rt_].k);
2368                         } else {
2369                                 MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]);
2370                                 MOV8RtoM((u32)&psxM[addr & 0x1fffff], EAX);
2371                         }
2372                         return;
2373                 }
2374                 if (t == 0x1f80 && addr < 0x1f801000) {
2375                         if (IsConst(_Rt_)) {
2376                                 MOV8ItoM((u32)&psxH[addr & 0xfff], (u8)iRegs[_Rt_].k);
2377                         } else {
2378                                 MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]);
2379                                 MOV8RtoM((u32)&psxH[addr & 0xfff], EAX);
2380                         }
2381                         return;
2382                 }
2383 //              SysPrintf("unhandled w8 %x\n", addr);
2384         }*/
2385
2386         preMemWrite(1);
2387         CALLFunc((u32)psxMemWrite8);
2388 }
2389
2390 static void recSH() {
2391 // mem[Rs + Im] = Rt
2392
2393         /*if (IsConst(_Rs_)) {
2394                 u32 addr = iRegs[_Rs_].k + _Imm_;
2395                 int t = addr >> 16;
2396
2397                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2398                         if (IsConst(_Rt_)) {
2399                                 MOV16ItoM((u32)&psxM[addr & 0x1fffff], (u16)iRegs[_Rt_].k);
2400                         } else {
2401                                 MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]);
2402                                 MOV16RtoM((u32)&psxM[addr & 0x1fffff], EAX);
2403                         }
2404                         return;
2405                 }
2406                 if (t == 0x1f80 && addr < 0x1f801000) {
2407                         if (IsConst(_Rt_)) {
2408                                 MOV16ItoM((u32)&psxH[addr & 0xfff], (u16)iRegs[_Rt_].k);
2409                         } else {
2410                                 MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]);
2411                                 MOV16RtoM((u32)&psxH[addr & 0xfff], EAX);
2412                         }
2413                         return;
2414                 }
2415                 if (t == 0x1f80) {
2416                         if (addr >= 0x1f801c00 && addr < 0x1f801e00) {
2417                                 if (IsConst(_Rt_)) {
2418                                         PUSH32I(iRegs[_Rt_].k);
2419                                 } else {
2420                                         PUSH32M((u32)&psxRegs.GPR.r[_Rt_]);
2421                                 }
2422                                 PUSH32I  (addr);
2423                                 CALL32M  ((u32)&SPU_writeRegister);
2424 #ifndef __WIN32__
2425                                 resp+= 8;
2426 #endif
2427                                 return;
2428                         }
2429                 }
2430 //              SysPrintf("unhandled w16 %x\n", addr);
2431         }*/
2432
2433         preMemWrite(2);
2434         CALLFunc((u32)psxMemWrite16);
2435 }
2436
2437 static void recSW() {
2438 // mem[Rs + Im] = Rt
2439         u32 *b1, *b2;
2440 #if 0
2441         if (IsConst(_Rs_)) {
2442                 u32 addr = iRegs[_Rs_].k + _Imm_;
2443                 int t = addr >> 16;
2444
2445                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2446                         LIW(0, addr & 0x1fffff);
2447                         STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0);
2448                         return;
2449                 }
2450                 if (t == 0x1f80 && addr < 0x1f801000) {
2451                         LIW(0, (u32)&psxH[addr & 0xfff]);
2452                         STWBRX(GetHWReg32(_Rt_), 0, 0);
2453                         return;
2454                 }
2455                 if (t == 0x1f80) {
2456                         switch (addr) {
2457                                 case 0x1f801080: case 0x1f801084: 
2458                                 case 0x1f801090: case 0x1f801094: 
2459                                 case 0x1f8010a0: case 0x1f8010a4: 
2460                                 case 0x1f8010b0: case 0x1f8010b4: 
2461                                 case 0x1f8010c0: case 0x1f8010c4: 
2462                                 case 0x1f8010d0: case 0x1f8010d4: 
2463                                 case 0x1f8010e0: case 0x1f8010e4: 
2464                                 case 0x1f801074:
2465                                 case 0x1f8010f0:
2466                                         LIW(0, (u32)&psxH[addr & 0xffff]);
2467                                         STWBRX(GetHWReg32(_Rt_), 0, 0);
2468                                         return;
2469
2470 /*                              case 0x1f801810:
2471                                         if (IsConst(_Rt_)) {
2472                                                 PUSH32I(iRegs[_Rt_].k);
2473                                         } else {
2474                                                 PUSH32M((u32)&psxRegs.GPR.r[_Rt_]);
2475                                         }
2476                                         CALL32M((u32)&GPU_writeData);
2477 #ifndef __WIN32__
2478                                         resp+= 4;
2479 #endif
2480                                         return;
2481
2482                                 case 0x1f801814:
2483                                         if (IsConst(_Rt_)) {
2484                                                 PUSH32I(iRegs[_Rt_].k);
2485                                         } else {
2486                                                 PUSH32M((u32)&psxRegs.GPR.r[_Rt_]);
2487                                         }
2488                                         CALL32M((u32)&GPU_writeStatus);
2489 #ifndef __WIN32__
2490                                         resp+= 4;
2491 #endif*/
2492                         }
2493                 }
2494 //              SysPrintf("unhandled w32 %x\n", addr);
2495         }
2496         
2497 /*      LIS(0, 0x0079 + ((_Imm_ <= 0) ? 1 : 0));
2498         CMPLW(GetHWReg32(_Rs_), 0);
2499         BGE_L(b1);
2500         
2501         //SaveContext();
2502         ADDI(0, GetHWReg32(_Rs_), _Imm_);
2503         RLWINM(0, GetHWReg32(_Rs_), 0, 11, 31);
2504         STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0);
2505         B_L(b2);
2506         
2507         B_DST(b1);*/
2508 #endif
2509         preMemWrite(4);
2510         CALLFunc((u32)psxMemWrite32);
2511         
2512         //B_DST(b2);
2513 }
2514
2515 /*
2516 static void recSWBlock(int count) {
2517         u32 *code;
2518         int i, respsave;
2519 // mem[Rs + Im] = Rt
2520
2521 //      iFlushRegs();
2522
2523         if (IsConst(_Rs_)) {
2524                 u32 addr = iRegs[_Rs_].k + _Imm_;
2525                 int t = addr >> 16;
2526                 code = PSXM(pc);
2527
2528                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2529                         for (i=0; i<count; i++, code++, addr+=4) {
2530                                 if (IsConst(_fRt_(*code))) {
2531                                         MOV32ItoM((u32)&psxM[addr & 0x1fffff], iRegs[_fRt_(*code)].k);
2532                                 } else {
2533                                         MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_fRt_(*code)]);
2534                                         MOV32RtoM((u32)&psxM[addr & 0x1fffff], EAX);
2535                                 }
2536                         }
2537                         return;
2538                 }
2539                 if (t == 0x1f80 && addr < 0x1f801000) {
2540                         for (i=0; i<count; i++, code++, addr+=4) {
2541                                 if (!_fRt_(*code)) return;
2542                                 iRegs[_fRt_(*code)].state = ST_UNK;
2543
2544                                 MOV32MtoR(EAX, (u32)&psxH[addr & 0xfff]);
2545                                 MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX);
2546                         }
2547                         return;
2548                 }
2549         }
2550
2551         SysPrintf("recSWBlock %d: %d\n", count, IsConst(_Rs_));
2552         iPushOfB();
2553         CALLFunc((u32)psxMemPointer);
2554 //      ADD32ItoR(ESP, 4);
2555         resp+= 4;
2556
2557         respsave = resp; resp = 0;
2558         TEST32RtoR(EAX, EAX);
2559         j32Ptr[4] = JZ32(0);
2560         XOR32RtoR(ECX, ECX);
2561         for (i=0, code = PSXM(pc); i<count; i++, code++) {
2562                 if (IsConst(_fRt_(*code))) {
2563                         MOV32ItoR(EDX, iRegs[_fRt_(*code)].k);
2564                 } else {
2565                         MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_fRt_(*code)]);
2566                 }
2567                 MOV32RtoRmS(EAX, ECX, 2, EDX);
2568                 if (i != (count-1)) INC32R(ECX);
2569         }
2570         j32Ptr[5] = JMP32(0);
2571         x86SetJ32(j32Ptr[4]);
2572         for (i=0, code = PSXM(pc); i<count; i++, code++) {
2573                 psxRegs.code = *code;
2574                 recSW();
2575         }
2576         ADD32ItoR(ESP, resp);
2577         x86SetJ32(j32Ptr[5]);
2578         resp = respsave;
2579 }
2580
2581 extern u32 SWL_MASK[4];
2582 extern u32 SWL_SHIFT[4];
2583
2584 void iSWLk(u32 shift) {
2585         if (IsConst(_Rt_)) {
2586                 MOV32ItoR(ECX, iRegs[_Rt_].k);
2587         } else {
2588                 MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]);
2589         }
2590         SHR32ItoR(ECX, SWL_SHIFT[shift]);
2591         AND32ItoR(EAX, SWL_MASK[shift]);
2592         OR32RtoR (EAX, ECX);
2593 }
2594
2595 void recSWL() {
2596 // mem[Rs + Im] = Rt Merge mem[Rs + Im]
2597
2598         if (IsConst(_Rs_)) {
2599                 u32 addr = iRegs[_Rs_].k + _Imm_;
2600                 int t = addr >> 16;
2601
2602                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2603                         MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]);
2604                         iSWLk(addr & 3);
2605                         MOV32RtoM((u32)&psxM[addr & 0x1ffffc], EAX);
2606                         return;
2607                 }
2608                 if (t == 0x1f80 && addr < 0x1f801000) {
2609                         MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]);
2610                         iSWLk(addr & 3);
2611                         MOV32RtoM((u32)&psxH[addr & 0xffc], EAX);
2612                         return;
2613                 }
2614         }
2615
2616         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2617         else {
2618                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2619                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2620         }
2621         PUSH32R  (EAX);
2622         AND32ItoR(EAX, ~3);
2623         PUSH32R  (EAX);
2624
2625         CALLFunc((u32)psxMemRead32);
2626
2627         ADD32ItoR(ESP, 4);
2628         POP32R   (EDX);
2629         AND32ItoR(EDX, 0x3); // shift = addr & 3;
2630
2631         MOV32ItoR(ECX, (u32)SWL_MASK);
2632         MOV32RmStoR(ECX, ECX, EDX, 2);
2633         AND32RtoR(EAX, ECX); // mem & SWL_MASK[shift]
2634
2635         MOV32ItoR(ECX, (u32)SWL_SHIFT);
2636         MOV32RmStoR(ECX, ECX, EDX, 2);
2637         if (IsConst(_Rt_)) {
2638                 MOV32ItoR(EDX, iRegs[_Rt_].k);
2639         } else {
2640                 MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]);
2641         }
2642         SHR32CLtoR(EDX); // _rRt_ >> SWL_SHIFT[shift]
2643
2644         OR32RtoR (EAX, EDX);
2645         PUSH32R  (EAX);
2646
2647         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2648         else {
2649                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2650                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2651         }
2652         AND32ItoR(EAX, ~3);
2653         PUSH32R  (EAX);
2654
2655         CALLFunc((u32)psxMemWrite32);
2656 //      ADD32ItoR(ESP, 8);
2657         resp+= 8;
2658 }
2659
2660 extern u32 SWR_MASK[4];
2661 extern u32 SWR_SHIFT[4];
2662
2663 void iSWRk(u32 shift) {
2664         if (IsConst(_Rt_)) {
2665                 MOV32ItoR(ECX, iRegs[_Rt_].k);
2666         } else {
2667                 MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]);
2668         }
2669         SHL32ItoR(ECX, SWR_SHIFT[shift]);
2670         AND32ItoR(EAX, SWR_MASK[shift]);
2671         OR32RtoR (EAX, ECX);
2672 }
2673
2674 void recSWR() {
2675 // mem[Rs + Im] = Rt Merge mem[Rs + Im]
2676
2677         if (IsConst(_Rs_)) {
2678                 u32 addr = iRegs[_Rs_].k + _Imm_;
2679                 int t = addr >> 16;
2680
2681                 if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) {
2682                         MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]);
2683                         iSWRk(addr & 3);
2684                         MOV32RtoM((u32)&psxM[addr & 0x1ffffc], EAX);
2685                         return;
2686                 }
2687                 if (t == 0x1f80 && addr < 0x1f801000) {
2688                         MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]);
2689                         iSWRk(addr & 3);
2690                         MOV32RtoM((u32)&psxH[addr & 0xffc], EAX);
2691                         return;
2692                 }
2693         }
2694
2695         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2696         else {
2697                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2698                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2699         }
2700         PUSH32R  (EAX);
2701         AND32ItoR(EAX, ~3);
2702         PUSH32R  (EAX);
2703
2704         CALLFunc((u32)psxMemRead32);
2705
2706         ADD32ItoR(ESP, 4);
2707         POP32R   (EDX);
2708         AND32ItoR(EDX, 0x3); // shift = addr & 3;
2709
2710         MOV32ItoR(ECX, (u32)SWR_MASK);
2711         MOV32RmStoR(ECX, ECX, EDX, 2);
2712         AND32RtoR(EAX, ECX); // mem & SWR_MASK[shift]
2713
2714         MOV32ItoR(ECX, (u32)SWR_SHIFT);
2715         MOV32RmStoR(ECX, ECX, EDX, 2);
2716         if (IsConst(_Rt_)) {
2717                 MOV32ItoR(EDX, iRegs[_Rt_].k);
2718         } else {
2719                 MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]);
2720         }
2721         SHL32CLtoR(EDX); // _rRt_ << SWR_SHIFT[shift]
2722
2723         OR32RtoR (EAX, EDX);
2724         PUSH32R  (EAX);
2725
2726         if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_);
2727         else {
2728                 MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]);
2729                 if (_Imm_) ADD32ItoR(EAX, _Imm_);
2730         }
2731         AND32ItoR(EAX, ~3);
2732         PUSH32R  (EAX);
2733
2734         CALLFunc((u32)psxMemWrite32);
2735 //      ADD32ItoR(ESP, 8);
2736         resp+= 8;
2737 }*/
2738 #endif
2739
2740 #if 0
2741 /*REC_FUNC(SLL);
2742 REC_FUNC(SRL);
2743 REC_FUNC(SRA);*/
2744 #else
2745 static void recSLL() {
2746 // Rd = Rt << Sa
2747     if (!_Rd_) return;
2748
2749     if (IsConst(_Rt_)) {
2750         MapConst(_Rd_, iRegs[_Rt_].k << _Sa_);
2751     } else {
2752         SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_);
2753     }
2754 }
2755
2756 static void recSRL() {
2757 // Rd = Rt >> Sa
2758     if (!_Rd_) return;
2759
2760     if (IsConst(_Rt_)) {
2761         MapConst(_Rd_, iRegs[_Rt_].k >> _Sa_);
2762     } else {
2763         SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_);
2764     }
2765 }
2766
2767 static void recSRA() {
2768 // Rd = Rt >> Sa
2769     if (!_Rd_) return;
2770
2771     if (IsConst(_Rt_)) {
2772         MapConst(_Rd_, (s32)iRegs[_Rt_].k >> _Sa_);
2773     } else {
2774         SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_);
2775     }
2776 }
2777 #endif
2778
2779 #pragma mark - shift ops -
2780 #if 0
2781 /*REC_FUNC(SLLV);
2782 REC_FUNC(SRLV);
2783 REC_FUNC(SRAV);*/
2784 #else
2785 static void recSLLV() {
2786 // Rd = Rt << Rs
2787         if (!_Rd_) return;
2788
2789         if (IsConst(_Rt_) && IsConst(_Rs_)) {
2790                 MapConst(_Rd_, iRegs[_Rt_].k << iRegs[_Rs_].k);
2791         } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
2792                 SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
2793         } else {
2794                 SLW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_));
2795         }
2796 }
2797
2798 static void recSRLV() {
2799 // Rd = Rt >> Rs
2800         if (!_Rd_) return;
2801
2802         if (IsConst(_Rt_) && IsConst(_Rs_)) {
2803                 MapConst(_Rd_, iRegs[_Rt_].k >> iRegs[_Rs_].k);
2804         } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
2805                 SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
2806         } else {
2807                 SRW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_));
2808         }
2809 }
2810
2811 static void recSRAV() {
2812 // Rd = Rt >> Rs
2813         if (!_Rd_) return;
2814
2815         if (IsConst(_Rt_) && IsConst(_Rs_)) {
2816                 MapConst(_Rd_, (s32)iRegs[_Rt_].k >> iRegs[_Rs_].k);
2817         } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
2818                 SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k);
2819         } else {
2820                 SRAW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_));
2821         }
2822 }
2823 #endif
2824
2825 //REC_SYS(SYSCALL);
2826 //REC_SYS(BREAK);
2827
2828 //#if 0*/
2829 /*int dump;*/
2830 static void recSYSCALL() {
2831 //      dump=1;
2832         iFlushRegs(0);
2833         
2834         ReserveArgs(2);
2835         LIW(PutHWRegSpecial(PSXPC), pc - 4);
2836         LIW(PutHWRegSpecial(ARG1), 0x20);
2837         LIW(PutHWRegSpecial(ARG2), (branch == 1 ? 1 : 0));
2838         FlushAllHWReg();
2839         CALLFunc ((u32)psxException);
2840
2841         branch = 2;
2842         iRet();
2843 }
2844
2845 static void recBREAK() {
2846 }
2847 //#endif
2848
2849 #if 0
2850 /*REC_FUNC(MFHI);
2851 REC_FUNC(MTHI);
2852 REC_FUNC(MFLO);
2853 REC_FUNC(MTLO);*/
2854 #else
2855 static void recMFHI() {
2856 // Rd = Hi
2857         if (!_Rd_) return;
2858         
2859         if (IsConst(REG_HI)) {
2860                 MapConst(_Rd_, iRegs[REG_HI].k);
2861         } else {
2862                 MapCopy(_Rd_, REG_HI);
2863         }
2864 }
2865
2866 static void recMTHI() {
2867 // Hi = Rs
2868
2869         if (IsConst(_Rs_)) {
2870                 MapConst(REG_HI, iRegs[_Rs_].k);
2871         } else {
2872                 MapCopy(REG_HI, _Rs_);
2873         }
2874 }
2875
2876 static void recMFLO() {
2877 // Rd = Lo
2878         if (!_Rd_) return;
2879
2880         if (IsConst(REG_LO)) {
2881                 MapConst(_Rd_, iRegs[REG_LO].k);
2882         } else {
2883                 MapCopy(_Rd_, REG_LO);
2884         }
2885 }
2886
2887 static void recMTLO() {
2888 // Lo = Rs
2889
2890         if (IsConst(_Rs_)) {
2891                 MapConst(REG_LO, iRegs[_Rs_].k);
2892         } else {
2893                 MapCopy(REG_LO, _Rs_);
2894         }
2895 }
2896 #endif
2897
2898 #pragma mark - branch ops -
2899 #if 0
2900 /*REC_BRANCH(J);
2901 REC_BRANCH(JR);
2902 REC_BRANCH(JAL);
2903 REC_BRANCH(JALR);
2904 REC_BRANCH(BLTZ);
2905 REC_BRANCH(BGTZ);
2906 REC_BRANCH(BLTZAL);
2907 REC_BRANCH(BGEZAL);
2908 REC_BRANCH(BNE);
2909 REC_BRANCH(BEQ);
2910 REC_BRANCH(BLEZ);
2911 REC_BRANCH(BGEZ);*/
2912 #else
2913 static void recBLTZ() {
2914 // Branch if Rs < 0
2915         u32 bpc = _Imm_ * 4 + pc;
2916         u32 *b;
2917
2918         if (IsConst(_Rs_)) {
2919                 if ((s32)iRegs[_Rs_].k < 0) {
2920                         iJump(bpc); return;
2921                 } else {
2922                         iJump(pc+4); return;
2923                 }
2924         }
2925
2926         CMPWI(GetHWReg32(_Rs_), 0);
2927         BLT_L(b);
2928         
2929         iBranch(pc+4, 1);
2930
2931         B_DST(b);
2932         
2933         iBranch(bpc, 0);
2934         pc+=4;
2935 }
2936
2937 static void recBGTZ() {
2938 // Branch if Rs > 0
2939     u32 bpc = _Imm_ * 4 + pc;
2940     u32 *b;
2941
2942     if (IsConst(_Rs_)) {
2943         if ((s32)iRegs[_Rs_].k > 0) {
2944             iJump(bpc); return;
2945         } else {
2946             iJump(pc+4); return;
2947         }
2948     }
2949
2950     CMPWI(GetHWReg32(_Rs_), 0);
2951     BGT_L(b);
2952     
2953     iBranch(pc+4, 1);
2954
2955     B_DST(b);
2956
2957     iBranch(bpc, 0);
2958     pc+=4;
2959 }
2960
2961 static void recBLTZAL() {
2962 // Branch if Rs < 0
2963     u32 bpc = _Imm_ * 4 + pc;
2964     u32 *b;
2965
2966     if (IsConst(_Rs_)) {
2967         if ((s32)iRegs[_Rs_].k < 0) {
2968             MapConst(31, pc + 4);
2969
2970             iJump(bpc); return;
2971         } else {
2972             iJump(pc+4); return;
2973         }
2974     }
2975
2976     CMPWI(GetHWReg32(_Rs_), 0);
2977     BLT_L(b);
2978     
2979     iBranch(pc+4, 1);
2980
2981     B_DST(b);
2982     
2983     MapConst(31, pc + 4);
2984
2985     iBranch(bpc, 0);
2986     pc+=4;
2987 }
2988
2989 static void recBGEZAL() {
2990 // Branch if Rs >= 0
2991     u32 bpc = _Imm_ * 4 + pc;
2992     u32 *b;
2993
2994     if (IsConst(_Rs_)) {
2995         if ((s32)iRegs[_Rs_].k >= 0) {
2996             MapConst(31, pc + 4);
2997
2998             iJump(bpc); return;
2999         } else {
3000             iJump(pc+4); return;
3001         }
3002     }
3003
3004     CMPWI(GetHWReg32(_Rs_), 0);
3005     BGE_L(b);
3006     
3007     iBranch(pc+4, 1);
3008
3009     B_DST(b);
3010     
3011     MapConst(31, pc + 4);
3012
3013     iBranch(bpc, 0);
3014     pc+=4;
3015 }
3016
3017 static void recJ() {
3018 // j target
3019
3020         iJump(_Target_ * 4 + (pc & 0xf0000000));
3021 }
3022
3023 static void recJAL() {
3024 // jal target
3025         MapConst(31, pc + 4);
3026
3027         iJump(_Target_ * 4 + (pc & 0xf0000000));
3028 }
3029
3030 static void recJR() {
3031 // jr Rs
3032
3033         if (IsConst(_Rs_)) {
3034                 iJump(iRegs[_Rs_].k);
3035                 //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k);
3036         } else {
3037                 MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_));
3038                 SetBranch();
3039         }
3040 }
3041
3042 static void recJALR() {
3043 // jalr Rs
3044
3045         if (_Rd_) {
3046                 MapConst(_Rd_, pc + 4);
3047         }
3048         
3049         if (IsConst(_Rs_)) {
3050                 iJump(iRegs[_Rs_].k);
3051                 //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k);
3052         } else {
3053                 MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_));
3054                 SetBranch();
3055         }
3056 }
3057
3058 static void recBEQ() {
3059 // Branch if Rs == Rt
3060         u32 bpc = _Imm_ * 4 + pc;
3061         u32 *b;
3062
3063         if (_Rs_ == _Rt_) {
3064                 iJump(bpc);
3065         }
3066         else {
3067                 if (IsConst(_Rs_) && IsConst(_Rt_)) {
3068                         if (iRegs[_Rs_].k == iRegs[_Rt_].k) {
3069                                 iJump(bpc); return;
3070                         } else {
3071                                 iJump(pc+4); return;
3072                         }
3073                 }
3074                 else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
3075                         if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
3076                                 CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k);
3077                         }
3078                         else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) {
3079                                 CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k);
3080                         }
3081                         else {
3082                                 CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3083                         }
3084                 }
3085                 else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
3086                         if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
3087                                 CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k);
3088                         }
3089                         else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) {
3090                                 CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k);
3091                         }
3092                         else {
3093                                 CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3094                         }
3095                 }
3096                 else {
3097                         CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3098                 }
3099                 
3100                 BEQ_L(b);
3101                 
3102                 iBranch(pc+4, 1);
3103         
3104                 B_DST(b);
3105                 
3106                 iBranch(bpc, 0);
3107                 pc+=4;
3108         }
3109 }
3110
3111 static void recBNE() {
3112 // Branch if Rs != Rt
3113         u32 bpc = _Imm_ * 4 + pc;
3114         u32 *b;
3115
3116         if (_Rs_ == _Rt_) {
3117                 iJump(pc+4);
3118         }
3119         else {
3120                 if (IsConst(_Rs_) && IsConst(_Rt_)) {
3121                         if (iRegs[_Rs_].k != iRegs[_Rt_].k) {
3122                                 iJump(bpc); return;
3123                         } else {
3124                                 iJump(pc+4); return;
3125                         }
3126                 }
3127                 else if (IsConst(_Rs_) && !IsMapped(_Rs_)) {
3128                         if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) {
3129                                 CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k);
3130                         }
3131                         else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) {
3132                                 CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k);
3133                         }
3134                         else {
3135                                 CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3136                         }
3137                 }
3138                 else if (IsConst(_Rt_) && !IsMapped(_Rt_)) {
3139                         if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) {
3140                                 CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k);
3141                         }
3142                         else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) {
3143                                 CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k);
3144                         }
3145                         else {
3146                                 CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3147                         }
3148                 }
3149                 else {
3150                         CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_));
3151                 }
3152                 
3153                 BNE_L(b);
3154                 
3155                 iBranch(pc+4, 1);
3156         
3157                 B_DST(b);
3158                 
3159                 iBranch(bpc, 0);
3160                 pc+=4;
3161         }
3162 }
3163
3164 static void recBLEZ() {
3165 // Branch if Rs <= 0
3166         u32 bpc = _Imm_ * 4 + pc;
3167         u32 *b;
3168
3169         if (IsConst(_Rs_)) {
3170                 if ((s32)iRegs[_Rs_].k <= 0) {
3171                         iJump(bpc); return;
3172                 } else {
3173                         iJump(pc+4); return;
3174                 }
3175         }
3176
3177         CMPWI(GetHWReg32(_Rs_), 0);
3178         BLE_L(b);
3179         
3180         iBranch(pc+4, 1);
3181
3182         B_DST(b);
3183         
3184         iBranch(bpc, 0);
3185         pc+=4;
3186 }
3187
3188 static void recBGEZ() {
3189 // Branch if Rs >= 0
3190         u32 bpc = _Imm_ * 4 + pc;
3191         u32 *b;
3192
3193         if (IsConst(_Rs_)) {
3194                 if ((s32)iRegs[_Rs_].k >= 0) {
3195                         iJump(bpc); return;
3196                 } else {
3197                         iJump(pc+4); return;
3198                 }
3199         }
3200
3201         CMPWI(GetHWReg32(_Rs_), 0);
3202         BGE_L(b);
3203         
3204         iBranch(pc+4, 1);
3205
3206         B_DST(b);
3207         
3208         iBranch(bpc, 0);
3209         pc+=4;
3210 }
3211 #endif
3212
3213 #if 1
3214 //REC_FUNC(MFC0);
3215 //REC_SYS(MTC0);
3216 //REC_FUNC(CFC0);
3217 //REC_SYS(CTC0);
3218 REC_FUNC(RFE);
3219 //#else
3220 static void recMFC0() {
3221 // Rt = Cop0->Rd
3222         if (!_Rt_) return;
3223         
3224         LWZ(PutHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS));
3225 }
3226
3227 static void recCFC0() {
3228 // Rt = Cop0->Rd
3229
3230         recMFC0();
3231 }
3232
3233 static void recMTC0() {
3234 // Cop0->Rd = Rt
3235
3236         /*if (IsConst(_Rt_)) {
3237                 switch (_Rd_) {
3238                         case 12:
3239                                 MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k);
3240                                 break;
3241                         case 13:
3242                                 MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k & ~(0xfc00));
3243                                 break;
3244                         default:
3245                                 MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k);
3246                                 break;
3247                 }
3248         } else*/ {
3249                 switch (_Rd_) {
3250                         case 13:
3251                                 RLWINM(0,GetHWReg32(_Rt_),0,22,15); // & ~(0xfc00)
3252                                 STW(0, OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS));
3253                                 break;
3254                         default:
3255                                 STW(GetHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS));
3256                                 break;
3257                 }
3258         }
3259
3260         if (_Rd_ == 12 || _Rd_ == 13) {
3261                 iFlushRegs(0);
3262                 LIW(PutHWRegSpecial(PSXPC), (u32)pc);
3263                 FlushAllHWReg();
3264                 CALLFunc((u32)psxTestSWInts);
3265                 if(_Rd_ == 12) {
3266                   LWZ(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS));
3267                   ORIS(0, 0, 0x8000);
3268                   STW(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS));
3269                 }
3270                 branch = 2;
3271                 iRet();
3272         }
3273 }
3274
3275 static void recCTC0() {
3276 // Cop0->Rd = Rt
3277
3278         recMTC0();
3279 }
3280 #else
3281 static void recRFE() {
3282         // TODO: implement multiple temp registers or cop0 registers
3283         RLWINM(t1,Status,0,0,27);
3284         RLWINM(Status,Status,30,28,31);
3285         OR(Status,t1,Status);
3286         
3287         MOV32MtoR(EAX, (u32)&psxRegs.CP0.n.Status);
3288         MOV32RtoR(ECX, EAX);
3289         AND32ItoR(EAX, 0xfffffff0);
3290         AND32ItoR(ECX, 0x3c);
3291         SHR32ItoR(ECX, 2);
3292         OR32RtoR (EAX, ECX);
3293         MOV32RtoM((u32)&psxRegs.CP0.n.Status, EAX);
3294         CALLFunc((u32)psxExceptionTest);
3295 }
3296 #endif
3297
3298 #if 0
3299 #define CP2_FUNC(f) \
3300 void gte##f(); \
3301 static void rec##f() { \
3302         iFlushRegs(0); \
3303         LIW(0, (u32)psxRegs.code); \
3304         STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \
3305         FlushAllHWReg(); \
3306         CALLFunc ((u32)gte##f); \
3307 }
3308 CP2_FUNC(LWC2);
3309 CP2_FUNC(SWC2);
3310
3311 #else
3312 #include "pGte.h"
3313 #endif
3314 //
3315
3316 static void recHLE() {
3317         iFlushRegs(0);
3318         FlushAllHWReg();
3319         
3320         if ((psxRegs.code & 0x3ffffff) == (psxRegs.code & 0x7)) {
3321                 CALLFunc((u32)psxHLEt[psxRegs.code & 0x7]);
3322         } else {
3323                 // somebody else must have written to current opcode for this to happen!!!!
3324                 CALLFunc((u32)psxHLEt[0]); // call dummy function
3325         }
3326         
3327         count = (idlecyclecount + (pc - pcold) / 4 + 20) * BIAS;
3328         ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count);
3329         FlushAllHWReg();
3330         CALLFunc((u32)psxBranchTest);
3331         Return();
3332         
3333         branch = 2;
3334 }
3335
3336 //
3337
3338 static void (*recBSC[64])() = {
3339         recSPECIAL, recREGIMM, recJ   , recJAL  , recBEQ , recBNE , recBLEZ, recBGTZ,
3340         recADDI   , recADDIU , recSLTI, recSLTIU, recANDI, recORI , recXORI, recLUI ,
3341         recCOP0   , recNULL  , recCOP2, recNULL , recNULL, recNULL, recNULL, recNULL,
3342         recNULL   , recNULL  , recNULL, recNULL , recNULL, recNULL, recNULL, recNULL,
3343         recLB     , recLH    , recLWL , recLW   , recLBU , recLHU , recLWR , recNULL,
3344         recSB     , recSH    , recSWL , recSW   , recNULL, recNULL, recSWR , recNULL,
3345         recNULL   , recNULL  , recLWC2, recNULL , recNULL, recNULL, recNULL, recNULL,
3346         recNULL   , recNULL  , recSWC2, recHLE  , recNULL, recNULL, recNULL, recNULL
3347 };
3348
3349 static void (*recSPC[64])() = {
3350         recSLL , recNULL, recSRL , recSRA , recSLLV   , recNULL , recSRLV, recSRAV,
3351         recJR  , recJALR, recNULL, recNULL, recSYSCALL, recBREAK, recNULL, recNULL,
3352         recMFHI, recMTHI, recMFLO, recMTLO, recNULL   , recNULL , recNULL, recNULL,
3353         recMULT, recMULTU, recDIV, recDIVU, recNULL   , recNULL , recNULL, recNULL,
3354         recADD , recADDU, recSUB , recSUBU, recAND    , recOR   , recXOR , recNOR ,
3355         recNULL, recNULL, recSLT , recSLTU, recNULL   , recNULL , recNULL, recNULL,
3356         recNULL, recNULL, recNULL, recNULL, recNULL   , recNULL , recNULL, recNULL,
3357         recNULL, recNULL, recNULL, recNULL, recNULL   , recNULL , recNULL, recNULL
3358 };
3359
3360 static void (*recREG[32])() = {
3361         recBLTZ  , recBGEZ  , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3362         recNULL  , recNULL  , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3363         recBLTZAL, recBGEZAL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3364         recNULL  , recNULL  , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL
3365 };
3366
3367 static void (*recCP0[32])() = {
3368         recMFC0, recNULL, recCFC0, recNULL, recMTC0, recNULL, recCTC0, recNULL,
3369         recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3370         recRFE , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3371         recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL
3372 };
3373
3374 static void (*recCP2[64])() = {
3375         recBASIC, recRTPS , recNULL , recNULL, recNULL, recNULL , recNCLIP, recNULL, // 00
3376         recNULL , recNULL , recNULL , recNULL, recOP  , recNULL , recNULL , recNULL, // 08
3377         recDPCS , recINTPL, recMVMVA, recNCDS, recCDP , recNULL , recNCDT , recNULL, // 10
3378         recNULL , recNULL , recNULL , recNCCS, recCC  , recNULL , recNCS  , recNULL, // 18
3379         recNCT  , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 20
3380         recSQR  , recDCPL , recDPCT , recNULL, recNULL, recAVSZ3, recAVSZ4, recNULL, // 28 
3381         recRTPT , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 30
3382         recNULL , recNULL , recNULL , recNULL, recNULL, recGPF  , recGPL  , recNCCT  // 38
3383 };
3384
3385 static void (*recCP2BSC[32])() = {
3386         recMFC2, recNULL, recCFC2, recNULL, recMTC2, recNULL, recCTC2, recNULL,
3387         recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3388         recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL,
3389         recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL
3390 };
3391
3392 static void recRecompile() {
3393         //static int recCount = 0;
3394         char *p;
3395         u32 *ptr;
3396         int i;
3397         
3398         cop2readypc = 0;
3399         idlecyclecount = 0;
3400
3401         // initialize state variables
3402         UniqueRegAlloc = 1;
3403         HWRegUseCount = 0;
3404         DstCPUReg = -1;
3405         memset(HWRegisters, 0, sizeof(HWRegisters));
3406         for (i=0; i<NUM_HW_REGISTERS; i++)
3407                 HWRegisters[i].code = cpuHWRegisters[NUM_HW_REGISTERS-i-1];
3408         
3409         // reserve the special psxReg register
3410         HWRegisters[0].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED;
3411         HWRegisters[0].private = PSXREGS;
3412         HWRegisters[0].k = (u32)&psxRegs;
3413
3414         HWRegisters[1].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED;
3415         HWRegisters[1].private = PSXMEM;
3416         HWRegisters[1].k = (u32)&psxM;
3417
3418         // reserve the special psxRegs.cycle register
3419         //HWRegisters[1].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED;
3420         //HWRegisters[1].private = CYCLECOUNT;
3421         
3422         //memset(iRegs, 0, sizeof(iRegs));
3423         for (i=0; i<NUM_REGISTERS; i++) {
3424                 iRegs[i].state = ST_UNK;
3425                 iRegs[i].reg = -1;
3426         }
3427         iRegs[0].k = 0;
3428         iRegs[0].state = ST_CONST;
3429         
3430         /* if ppcPtr reached the mem limit reset whole mem */
3431         if (((u32)ppcPtr - (u32)recMem) >= (RECMEM_SIZE - 0x10000))
3432                 recReset();
3433
3434         ppcAlign(/*32*/4);
3435         ptr = ppcPtr;
3436         
3437         // give us write access
3438         //mprotect(recMem, RECMEM_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE);
3439         
3440         // tell the LUT where to find us
3441         PC_REC32(psxRegs.pc) = (u32)ppcPtr;
3442
3443         pcold = pc = psxRegs.pc;
3444         
3445         //SysPrintf("RecCount: %i\n", recCount++);
3446         
3447         for (count=0; count<500;) {
3448                 p = (char *)PSXM(pc);
3449                 if (p == NULL) recError();
3450                 psxRegs.code = SWAP32(*(u32 *)p);
3451 /*
3452                 if ((psxRegs.code >> 26) == 0x23) { // LW
3453                         int i;
3454                         u32 code;
3455
3456                         for (i=1;; i++) {
3457                                 p = (char *)PSXM(pc+i*4);
3458                                 if (p == NULL) recError();
3459                                 code = *(u32 *)p;
3460
3461                                 if ((code >> 26) != 0x23 ||
3462                                         _fRs_(code)  != _Rs_ ||
3463                                         _fImm_(code) != (_Imm_+i*4))
3464                                         break;
3465                         }
3466                         if (i > 1) {
3467                                 recLWBlock(i);
3468                                 pc = pc + i*4; continue;
3469                         }
3470                 }
3471
3472                 if ((psxRegs.code >> 26) == 0x2b) { // SW
3473                         int i;
3474                         u32 code;
3475
3476                         for (i=1;; i++) {
3477                                 p = (char *)PSXM(pc+i*4);
3478                                 if (p == NULL) recError();
3479                                 code = *(u32 *)p;
3480
3481                                 if ((code >> 26) != 0x2b ||
3482                                         _fRs_(code)  != _Rs_ ||
3483                                         _fImm_(code) != (_Imm_+i*4))
3484                                         break;
3485                         }
3486                         if (i > 1) {
3487                                 recSWBlock(i);
3488                                 pc = pc + i*4; continue;
3489                         }
3490                 }*/
3491
3492                 pc+=4; count++;
3493 //              iFlushRegs(0); // test
3494                 recBSC[psxRegs.code>>26]();
3495
3496                 if (branch) {
3497                         branch = 0;
3498                         //if (dump) iDumpBlock(ptr);
3499                         goto done;
3500                 }
3501         }
3502
3503         iFlushRegs(pc);
3504         
3505         LIW(PutHWRegSpecial(PSXPC), pc);
3506
3507         iRet();
3508
3509 done:;
3510 #if 0
3511         MakeDataExecutable(ptr, ((u8*)ppcPtr)-((u8*)ptr));
3512 #else
3513         u32 a = (u32)(u8*)ptr;
3514         while(a < (u32)(u8*)ppcPtr) {
3515           __asm__ __volatile__("icbi 0,%0" : : "r" (a));
3516           __asm__ __volatile__("dcbst 0,%0" : : "r" (a));
3517           a += 4;
3518         }
3519         __asm__ __volatile__("sync");
3520         __asm__ __volatile__("isync");
3521 #endif
3522         
3523 #if 1
3524         sprintf((char *)ppcPtr, "PC=%08x", pcold);
3525         ppcPtr += strlen((char *)ppcPtr);
3526 #endif
3527
3528         //mprotect(recMem, RECMEM_SIZE, PROT_EXEC|PROT_READ/*|PROT_WRITE*/);
3529 }
3530
3531
3532 R3000Acpu psxRec = {
3533         recInit,
3534         recReset,
3535         recExecute,
3536         recExecuteBlock,
3537         recClear,
3538         recShutdown
3539 };
3540