]> Shamusworld >> Repos - virtualjaguar/blob - src/gpu.cpp
Separated activation of aligned STOREs from aligned LOADs.
[virtualjaguar] / src / gpu.cpp
1 #if 1
2
3 //
4 // GPU Core
5 //
6 // Originally by David Raingeard (Cal2)
7 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
8 // Cleanups, endian wrongness, and bad ASM amelioration by James L. Hammons
9 // (C) 2010 Underground Software
10 //
11 // JLH = James L. Hammons <jlhamm@acm.org>
12 //
13 // Who  When        What
14 // ---  ----------  -------------------------------------------------------------
15 // JLH  01/16/2010  Created this log ;-)
16 // JLH  11/26/2011  Added fixes for LOAD/STORE alignment issues
17
18 //
19 // Note: Endian wrongness probably stems from the MAME origins of this emu and
20 //       the braindead way in which MAME handles memory. :-)
21 //
22 // Problem with not booting the BIOS was the incorrect way that the
23 // SUBC instruction set the carry when the carry was set going in...
24 // Same problem with ADDC...
25 //
26
27 #include "gpu.h"
28
29 #include <stdlib.h>
30 #include <string.h>                                                             // For memset
31 #include "dsp.h"
32 #include "jagdasm.h"
33 #include "jaguar.h"
34 #include "log.h"
35 #include "m68k.h"
36 //#include "memory.h"
37 #include "tom.h"
38
39
40 // Seems alignment in loads & stores was off...
41 #define GPU_CORRECT_ALIGNMENT
42 //#define GPU_CORRECT_ALIGNMENT_STORE
43 //#define GPU_DEBUG
44
45 // For GPU dissasembly...
46
47 #if 1
48 #define GPU_DIS_ABS
49 #define GPU_DIS_ADD
50 #define GPU_DIS_ADDC
51 #define GPU_DIS_ADDQ
52 #define GPU_DIS_ADDQT
53 #define GPU_DIS_AND
54 #define GPU_DIS_BCLR
55 #define GPU_DIS_BSET
56 #define GPU_DIS_BTST
57 #define GPU_DIS_CMP
58 #define GPU_DIS_CMPQ
59 #define GPU_DIS_DIV
60 #define GPU_DIS_IMULT
61 #define GPU_DIS_JUMP
62 #define GPU_DIS_JR
63 #define GPU_DIS_LOAD
64 #define GPU_DIS_LOADB
65 #define GPU_DIS_LOADW
66 #define GPU_DIS_LOAD14I
67 #define GPU_DIS_LOAD14R
68 #define GPU_DIS_LOAD15I
69 #define GPU_DIS_LOAD15R
70 #define GPU_DIS_MOVE
71 #define GPU_DIS_MOVEFA
72 #define GPU_DIS_MOVEI
73 #define GPU_DIS_MOVEPC
74 #define GPU_DIS_MOVETA
75 #define GPU_DIS_MOVEQ
76 #define GPU_DIS_MULT
77 #define GPU_DIS_NEG
78 #define GPU_DIS_NOP
79 #define GPU_DIS_NOT
80 #define GPU_DIS_OR
81 #define GPU_DIS_PACK
82 #define GPU_DIS_ROR
83 #define GPU_DIS_RORQ
84 #define GPU_DIS_SAT8
85 #define GPU_DIS_SH
86 #define GPU_DIS_SHA
87 #define GPU_DIS_SHARQ
88 #define GPU_DIS_SHLQ
89 #define GPU_DIS_SHRQ
90 #define GPU_DIS_STORE
91 #define GPU_DIS_STOREB
92 #define GPU_DIS_STOREW
93 #define GPU_DIS_STORE14I
94 #define GPU_DIS_STORE14R
95 #define GPU_DIS_STORE15I
96 #define GPU_DIS_STORE15R
97 #define GPU_DIS_SUB
98 #define GPU_DIS_SUBC
99 #define GPU_DIS_SUBQ
100 #define GPU_DIS_SUBQT
101 #define GPU_DIS_XOR
102
103 //bool doGPUDis = false;
104 bool doGPUDis = true;
105 #endif
106
107 /*
108 GPU opcodes use (BIOS flying ATARI logo):
109 +                     add 357416
110 +                    addq 538030
111 +                   addqt 6999
112 +                     sub 116663
113 +                    subq 188059
114 +                   subqt 15086
115 +                     neg 36097
116 +                     and 233993
117 +                      or 109332
118 +                     xor 1384
119 +                    btst 111924
120 +                    bset 25029
121 +                    bclr 10551
122 +                    mult 28147
123 +                   imult 69148
124 +                     div 64102
125 +                     abs 159394
126 +                    shlq 194690
127 +                    shrq 292587
128 +                   sharq 192649
129 +                    rorq 58672
130 +                     cmp 244963
131 +                    cmpq 114834
132 +                    move 833472
133 +                   moveq 56427
134 +                  moveta 220814
135 +                  movefa 170678
136 +                   movei 152025
137 +                   loadw 108220
138 +                    load 430936
139 +                  storew 3036
140 +                   store 372490
141 +                 move_pc 2330
142 +                    jump 349134
143 +                      jr 529171
144                     mmult 64904
145 +                     nop 432179
146 */
147
148 // Various bits
149
150 #define CINT0FLAG                       0x0200
151 #define CINT1FLAG                       0x0400
152 #define CINT2FLAG                       0x0800
153 #define CINT3FLAG                       0x1000
154 #define CINT4FLAG                       0x2000
155 #define CINT04FLAGS                     (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
156
157 // GPU_FLAGS bits
158
159 #define ZERO_FLAG               0x0001
160 #define CARRY_FLAG              0x0002
161 #define NEGA_FLAG               0x0004
162 #define IMASK                   0x0008
163 #define INT_ENA0                0x0010
164 #define INT_ENA1                0x0020
165 #define INT_ENA2                0x0040
166 #define INT_ENA3                0x0080
167 #define INT_ENA4                0x0100
168 #define INT_CLR0                0x0200
169 #define INT_CLR1                0x0400
170 #define INT_CLR2                0x0800
171 #define INT_CLR3                0x1000
172 #define INT_CLR4                0x2000
173 #define REGPAGE                 0x4000
174 #define DMAEN                   0x8000
175
176 // External global variables
177
178 extern int start_logging;
179 extern int gpu_start_log;
180
181 // Private function prototypes
182
183 void GPUUpdateRegisterBanks(void);
184 void GPUDumpDisassembly(void);
185 void GPUDumpRegisters(void);
186 void GPUDumpMemory(void);
187
188 static void gpu_opcode_add(void);
189 static void gpu_opcode_addc(void);
190 static void gpu_opcode_addq(void);
191 static void gpu_opcode_addqt(void);
192 static void gpu_opcode_sub(void);
193 static void gpu_opcode_subc(void);
194 static void gpu_opcode_subq(void);
195 static void gpu_opcode_subqt(void);
196 static void gpu_opcode_neg(void);
197 static void gpu_opcode_and(void);
198 static void gpu_opcode_or(void);
199 static void gpu_opcode_xor(void);
200 static void gpu_opcode_not(void);
201 static void gpu_opcode_btst(void);
202 static void gpu_opcode_bset(void);
203 static void gpu_opcode_bclr(void);
204 static void gpu_opcode_mult(void);
205 static void gpu_opcode_imult(void);
206 static void gpu_opcode_imultn(void);
207 static void gpu_opcode_resmac(void);
208 static void gpu_opcode_imacn(void);
209 static void gpu_opcode_div(void);
210 static void gpu_opcode_abs(void);
211 static void gpu_opcode_sh(void);
212 static void gpu_opcode_shlq(void);
213 static void gpu_opcode_shrq(void);
214 static void gpu_opcode_sha(void);
215 static void gpu_opcode_sharq(void);
216 static void gpu_opcode_ror(void);
217 static void gpu_opcode_rorq(void);
218 static void gpu_opcode_cmp(void);
219 static void gpu_opcode_cmpq(void);
220 static void gpu_opcode_sat8(void);
221 static void gpu_opcode_sat16(void);
222 static void gpu_opcode_move(void);
223 static void gpu_opcode_moveq(void);
224 static void gpu_opcode_moveta(void);
225 static void gpu_opcode_movefa(void);
226 static void gpu_opcode_movei(void);
227 static void gpu_opcode_loadb(void);
228 static void gpu_opcode_loadw(void);
229 static void gpu_opcode_load(void);
230 static void gpu_opcode_loadp(void);
231 static void gpu_opcode_load_r14_indexed(void);
232 static void gpu_opcode_load_r15_indexed(void);
233 static void gpu_opcode_storeb(void);
234 static void gpu_opcode_storew(void);
235 static void gpu_opcode_store(void);
236 static void gpu_opcode_storep(void);
237 static void gpu_opcode_store_r14_indexed(void);
238 static void gpu_opcode_store_r15_indexed(void);
239 static void gpu_opcode_move_pc(void);
240 static void gpu_opcode_jump(void);
241 static void gpu_opcode_jr(void);
242 static void gpu_opcode_mmult(void);
243 static void gpu_opcode_mtoi(void);
244 static void gpu_opcode_normi(void);
245 static void gpu_opcode_nop(void);
246 static void gpu_opcode_load_r14_ri(void);
247 static void gpu_opcode_load_r15_ri(void);
248 static void gpu_opcode_store_r14_ri(void);
249 static void gpu_opcode_store_r15_ri(void);
250 static void gpu_opcode_sat24(void);
251 static void gpu_opcode_pack(void);
252
253 // This is wrong, since it doesn't take pipeline effects into account. !!! FIX !!!
254 /*uint8 gpu_opcode_cycles[64] =
255 {
256         3,  3,  3,  3,  3,  3,  3,  3,
257         3,  3,  3,  3,  3,  3,  3,  3,
258         3,  3,  1,  3,  1, 18,  3,  3,
259         3,  3,  3,  3,  3,  3,  3,  3,
260         3,  3,  2,  2,  2,  2,  3,  4,
261         5,  4,  5,  6,  6,  1,  1,  1,
262         1,  2,  2,  2,  1,  1,  9,  3,
263         3,  1,  6,  6,  2,  2,  3,  3
264 };//*/
265 //Here's a QnD kludge...
266 //This is wrong, wrong, WRONG, but it seems to work for the time being...
267 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
268 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
269 /*uint8 gpu_opcode_cycles[64] =
270 {
271         1,  1,  1,  1,  1,  1,  1,  1,
272         1,  1,  1,  1,  1,  1,  1,  1,
273         1,  1,  1,  1,  1,  9,  1,  1,
274         1,  1,  1,  1,  1,  1,  1,  1,
275         1,  1,  1,  1,  1,  1,  1,  2,
276         2,  2,  2,  3,  3,  1,  1,  1,
277         1,  1,  1,  1,  1,  1,  4,  1,
278         1,  1,  3,  3,  1,  1,  1,  1
279 };//*/
280 uint8 gpu_opcode_cycles[64] =
281 {
282         1,  1,  1,  1,  1,  1,  1,  1,
283         1,  1,  1,  1,  1,  1,  1,  1,
284         1,  1,  1,  1,  1,  1,  1,  1,
285         1,  1,  1,  1,  1,  1,  1,  1,
286         1,  1,  1,  1,  1,  1,  1,  1,
287         1,  1,  1,  1,  1,  1,  1,  1,
288         1,  1,  1,  1,  1,  1,  1,  1,
289         1,  1,  1,  1,  1,  1,  1,  1
290 };//*/
291
292 void (*gpu_opcode[64])()=
293 {
294         gpu_opcode_add,                                 gpu_opcode_addc,                                gpu_opcode_addq,                                gpu_opcode_addqt,
295         gpu_opcode_sub,                                 gpu_opcode_subc,                                gpu_opcode_subq,                                gpu_opcode_subqt,
296         gpu_opcode_neg,                                 gpu_opcode_and,                                 gpu_opcode_or,                                  gpu_opcode_xor,
297         gpu_opcode_not,                                 gpu_opcode_btst,                                gpu_opcode_bset,                                gpu_opcode_bclr,
298         gpu_opcode_mult,                                gpu_opcode_imult,                               gpu_opcode_imultn,                              gpu_opcode_resmac,
299         gpu_opcode_imacn,                               gpu_opcode_div,                                 gpu_opcode_abs,                                 gpu_opcode_sh,
300         gpu_opcode_shlq,                                gpu_opcode_shrq,                                gpu_opcode_sha,                                 gpu_opcode_sharq,
301         gpu_opcode_ror,                                 gpu_opcode_rorq,                                gpu_opcode_cmp,                                 gpu_opcode_cmpq,
302         gpu_opcode_sat8,                                gpu_opcode_sat16,                               gpu_opcode_move,                                gpu_opcode_moveq,
303         gpu_opcode_moveta,                              gpu_opcode_movefa,                              gpu_opcode_movei,                               gpu_opcode_loadb,
304         gpu_opcode_loadw,                               gpu_opcode_load,                                gpu_opcode_loadp,                               gpu_opcode_load_r14_indexed,
305         gpu_opcode_load_r15_indexed,    gpu_opcode_storeb,                              gpu_opcode_storew,                              gpu_opcode_store,
306         gpu_opcode_storep,                              gpu_opcode_store_r14_indexed,   gpu_opcode_store_r15_indexed,   gpu_opcode_move_pc,
307         gpu_opcode_jump,                                gpu_opcode_jr,                                  gpu_opcode_mmult,                               gpu_opcode_mtoi,
308         gpu_opcode_normi,                               gpu_opcode_nop,                                 gpu_opcode_load_r14_ri,                 gpu_opcode_load_r15_ri,
309         gpu_opcode_store_r14_ri,                gpu_opcode_store_r15_ri,                gpu_opcode_sat24,                               gpu_opcode_pack,
310 };
311
312 static uint8 gpu_ram_8[0x1000];
313 uint32 gpu_pc;
314 static uint32 gpu_acc;
315 static uint32 gpu_remain;
316 static uint32 gpu_hidata;
317 static uint32 gpu_flags;
318 static uint32 gpu_matrix_control;
319 static uint32 gpu_pointer_to_matrix;
320 static uint32 gpu_data_organization;
321 static uint32 gpu_control;
322 static uint32 gpu_div_control;
323 // There is a distinct advantage to having these separated out--there's no need to clear
324 // a bit before writing a result. I.e., if the result of an operation leaves a zero in
325 // the carry flag, you don't have to zero gpu_flag_c before you can write that zero!
326 static uint8 gpu_flag_z, gpu_flag_n, gpu_flag_c;
327 static uint32 gpu_reg_bank_0[32];
328 static uint32 gpu_reg_bank_1[32];
329 static uint32 * gpu_reg;
330 static uint32 * gpu_alternate_reg;
331
332 static uint32 gpu_instruction;
333 static uint32 gpu_opcode_first_parameter;
334 static uint32 gpu_opcode_second_parameter;
335
336 #define GPU_RUNNING             (gpu_control & 0x01)
337
338 #define RM                              gpu_reg[gpu_opcode_first_parameter]
339 #define RN                              gpu_reg[gpu_opcode_second_parameter]
340 #define ALTERNATE_RM    gpu_alternate_reg[gpu_opcode_first_parameter]
341 #define ALTERNATE_RN    gpu_alternate_reg[gpu_opcode_second_parameter]
342 #define IMM_1                   gpu_opcode_first_parameter
343 #define IMM_2                   gpu_opcode_second_parameter
344
345 #define SET_FLAG_Z(r)   (gpu_flag_z = ((r) == 0));
346 #define SET_FLAG_N(r)   (gpu_flag_n = (((uint32)(r) >> 31) & 0x01));
347
348 #define RESET_FLAG_Z()  gpu_flag_z = 0;
349 #define RESET_FLAG_N()  gpu_flag_n = 0;
350 #define RESET_FLAG_C()  gpu_flag_c = 0;
351
352 #define CLR_Z                           (gpu_flag_z = 0)
353 #define CLR_ZN                          (gpu_flag_z = gpu_flag_n = 0)
354 #define CLR_ZNC                         (gpu_flag_z = gpu_flag_n = gpu_flag_c = 0)
355 #define SET_Z(r)                        (gpu_flag_z = ((r) == 0))
356 #define SET_N(r)                        (gpu_flag_n = (((uint32)(r) >> 31) & 0x01))
357 #define SET_C_ADD(a,b)          (gpu_flag_c = ((uint32)(b) > (uint32)(~(a))))
358 #define SET_C_SUB(a,b)          (gpu_flag_c = ((uint32)(b) > (uint32)(a)))
359 #define SET_ZN(r)                       SET_N(r); SET_Z(r)
360 #define SET_ZNC_ADD(a,b,r)      SET_N(r); SET_Z(r); SET_C_ADD(a,b)
361 #define SET_ZNC_SUB(a,b,r)      SET_N(r); SET_Z(r); SET_C_SUB(a,b)
362
363 uint32 gpu_convert_zero[32] =
364         { 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 };
365
366 uint8 * branch_condition_table = 0;
367 #define BRANCH_CONDITION(x)     branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
368
369 uint32 gpu_opcode_use[64];
370
371 const char * gpu_opcode_str[64]=
372 {
373         "add",                          "addc",                         "addq",                         "addqt",
374         "sub",                          "subc",                         "subq",                         "subqt",
375         "neg",                          "and",                          "or",                           "xor",
376         "not",                          "btst",                         "bset",                         "bclr",
377         "mult",                         "imult",                        "imultn",                       "resmac",
378         "imacn",                        "div",                          "abs",                          "sh",
379         "shlq",                         "shrq",                         "sha",                          "sharq",
380         "ror",                          "rorq",                         "cmp",                          "cmpq",
381         "sat8",                         "sat16",                        "move",                         "moveq",
382         "moveta",                       "movefa",                       "movei",                        "loadb",
383         "loadw",                        "load",                         "loadp",                        "load_r14_indexed",
384         "load_r15_indexed",     "storeb",                       "storew",                       "store",
385         "storep",                       "store_r14_indexed","store_r15_indexed","move_pc",
386         "jump",                         "jr",                           "mmult",                        "mtoi",
387         "normi",                        "nop",                          "load_r14_ri",          "load_r15_ri",
388         "store_r14_ri",         "store_r15_ri",         "sat24",                        "pack",
389 };
390
391 static uint32 gpu_in_exec = 0;
392 static uint32 gpu_releaseTimeSlice_flag = 0;
393
394 void GPUReleaseTimeslice(void)
395 {
396         gpu_releaseTimeSlice_flag = 1;
397 }
398
399 uint32 GPUGetPC(void)
400 {
401         return gpu_pc;
402 }
403
404 void build_branch_condition_table(void)
405 {
406         if (!branch_condition_table)
407         {
408                 branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(branch_condition_table[0]));
409
410                 if (branch_condition_table)
411                 {
412                         for(int i=0; i<8; i++)
413                         {
414                                 for(int j=0; j<32; j++)
415                                 {
416                                         int result = 1;
417                                         if (j & 1)
418                                                 if (i & ZERO_FLAG)
419                                                         result = 0;
420                                         if (j & 2)
421                                                 if (!(i & ZERO_FLAG))
422                                                         result = 0;
423                                         if (j & 4)
424                                                 if (i & (CARRY_FLAG << (j >> 4)))
425                                                         result = 0;
426                                         if (j & 8)
427                                                 if (!(i & (CARRY_FLAG << (j >> 4))))
428                                                         result = 0;
429                                         branch_condition_table[i * 32 + j] = result;
430                                 }
431                         }
432                 }
433         }
434 }
435
436 //
437 // GPU byte access (read)
438 //
439 uint8 GPUReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
440 {
441         if (offset >= 0xF02000 && offset <= 0xF020FF)
442                 WriteLog("GPU: ReadByte--Attempt to read from GPU register file by %s!\n", whoName[who]);
443
444         if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
445                 return gpu_ram_8[offset & 0xFFF];
446         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
447         {
448                 uint32 data = GPUReadLong(offset & 0xFFFFFFFC, who);
449
450                 if ((offset & 0x03) == 0)
451                         return data >> 24;
452                 else if ((offset & 0x03) == 1)
453                         return (data >> 16) & 0xFF;
454                 else if ((offset & 0x03) == 2)
455                         return (data >> 8) & 0xFF;
456                 else if ((offset & 0x03) == 3)
457                         return data & 0xFF;
458         }
459
460         return JaguarReadByte(offset, who);
461 }
462
463 //
464 // GPU word access (read)
465 //
466 uint16 GPUReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
467 {
468         if (offset >= 0xF02000 && offset <= 0xF020FF)
469                 WriteLog("GPU: ReadWord--Attempt to read from GPU register file by %s!\n", whoName[who]);
470
471         if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
472         {
473                 offset &= 0xFFF;
474                 uint16 data = ((uint16)gpu_ram_8[offset] << 8) | (uint16)gpu_ram_8[offset+1];
475                 return data;
476         }
477         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
478         {
479 // This looks and smells wrong...
480 // But it *might* be OK...
481                 if (offset & 0x01)                      // Catch cases 1 & 3... (unaligned read)
482                         return (GPUReadByte(offset, who) << 8) | GPUReadByte(offset+1, who);
483
484                 uint32 data = GPUReadLong(offset & 0xFFFFFFFC, who);
485
486                 if (offset & 0x02)                      // Cases 0 & 2...
487                         return data & 0xFFFF;
488                 else
489                         return data >> 16;
490         }
491
492 //TEMP--Mirror of F03000? No. Writes only...
493 //if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
494 //WriteLog("[GPUR16] --> Possible GPU RAM mirror access by %s!", whoName[who]);
495
496         return JaguarReadWord(offset, who);
497 }
498
499 //
500 // GPU dword access (read)
501 //
502 uint32 GPUReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
503 {
504         if (offset >= 0xF02000 && offset <= 0xF020FF)
505                 WriteLog("GPU: ReadLong--Attempt to read from GPU register file by %s!\n", whoName[who]);
506
507 //      if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
508         if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC))
509         {
510                 offset &= 0xFFF;
511                 return ((uint32)gpu_ram_8[offset] << 24) | ((uint32)gpu_ram_8[offset+1] << 16)
512                         | ((uint32)gpu_ram_8[offset+2] << 8) | (uint32)gpu_ram_8[offset+3];//*/
513 //              return GET32(gpu_ram_8, offset);
514         }
515 //      else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
516         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1C))
517         {
518                 offset &= 0x1F;
519                 switch (offset)
520                 {
521                 case 0x00:
522                         gpu_flag_c = (gpu_flag_c ? 1 : 0);
523                         gpu_flag_z = (gpu_flag_z ? 1 : 0);
524                         gpu_flag_n = (gpu_flag_n ? 1 : 0);
525
526                         gpu_flags = (gpu_flags & 0xFFFFFFF8) | (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z;
527
528                         return gpu_flags & 0xFFFFC1FF;
529                 case 0x04:
530                         return gpu_matrix_control;
531                 case 0x08:
532                         return gpu_pointer_to_matrix;
533                 case 0x0C:
534                         return gpu_data_organization;
535                 case 0x10:
536                         return gpu_pc;
537                 case 0x14:
538                         return gpu_control;
539                 case 0x18:
540                         return gpu_hidata;
541                 case 0x1C:
542                         return gpu_remain;
543                 default:                                                                // unaligned long read
544 #ifdef GPU_DEBUG
545                         WriteLog("GPU: Read32--unaligned 32 bit read at %08X by %s.\n", GPU_CONTROL_RAM_BASE + offset, whoName[who]);
546 #endif  // GPU_DEBUG
547                         return 0;
548                 }
549         }
550 //TEMP--Mirror of F03000? No. Writes only...
551 //if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
552 //      WriteLog("[GPUR32] --> Possible GPU RAM mirror access by %s!\n", whoName[who]);
553 /*if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
554         WriteLog("[GPUR32] --> Reading from Wavetable ROM!\n");//*/
555
556         return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset + 2, who);
557 }
558
559 //
560 // GPU byte access (write)
561 //
562 void GPUWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
563 {
564         if (offset >= 0xF02000 && offset <= 0xF020FF)
565                 WriteLog("GPU: WriteByte--Attempt to write to GPU register file by %s!\n", whoName[who]);
566
567         if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFF))
568         {
569                 gpu_ram_8[offset & 0xFFF] = data;
570
571 //This is the same stupid worthless code that was in the DSP!!! AARRRGGGGHHHHH!!!!!!
572 /*              if (!gpu_in_exec)
573                 {
574                         m68k_end_timeslice();
575                         dsp_releaseTimeslice();
576                 }*/
577                 return;
578         }
579         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1F))
580         {
581                 uint32 reg = offset & 0x1C;
582                 int bytenum = offset & 0x03;
583
584 //This is definitely wrong!
585                 if ((reg >= 0x1C) && (reg <= 0x1F))
586                         gpu_div_control = (gpu_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
587                 else
588                 {
589                         uint32 old_data = GPUReadLong(offset & 0xFFFFFFC, who);
590                         bytenum = 3 - bytenum; // convention motorola !!!
591                         old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
592                         GPUWriteLong(offset & 0xFFFFFFC, old_data, who);
593                 }
594                 return;
595         }
596 //      WriteLog("gpu: writing %.2x at 0x%.8x\n",data,offset);
597         JaguarWriteByte(offset, data, who);
598 }
599
600 //
601 // GPU word access (write)
602 //
603 void GPUWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
604 {
605         if (offset >= 0xF02000 && offset <= 0xF020FF)
606                 WriteLog("GPU: WriteWord--Attempt to write to GPU register file by %s!\n", whoName[who]);
607
608         if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFE))
609         {
610                 gpu_ram_8[offset & 0xFFF] = (data>>8) & 0xFF;
611                 gpu_ram_8[(offset+1) & 0xFFF] = data & 0xFF;//*/
612 /*              offset &= 0xFFF;
613                 SET16(gpu_ram_8, offset, data);//*/
614
615 /*if (offset >= 0xF03214 && offset < 0xF0321F)
616         WriteLog("GPU: Writing WORD (%04X) to GPU RAM (%08X)...\n", data, offset);//*/
617
618
619 //This is the same stupid worthless code that was in the DSP!!! AARRRGGGGHHHHH!!!!!!
620 /*              if (!gpu_in_exec)
621                 {
622                         m68k_end_timeslice();
623                         dsp_releaseTimeslice();
624                 }*/
625                 return;
626         }
627         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1E))
628         {
629                 if (offset & 0x01)              // This is supposed to weed out unaligned writes, but does nothing...
630                 {
631 #ifdef GPU_DEBUG
632                         WriteLog("GPU: Write16--unaligned write @ %08X [%04X]\n", offset, data);
633                         GPUDumpRegisters();
634 #endif  // GPU_DEBUG
635                         return;
636                 }
637 //Dual locations in this range: $1C Divide unit remainder/Divide unit control (R/W)
638 //This just literally sucks.
639                 if ((offset & 0x1C) == 0x1C)
640                 {
641 //This doesn't look right either--handles cases 1, 2, & 3 all the same!
642                         if (offset & 0x02)
643                                 gpu_div_control = (gpu_div_control & 0xFFFF0000) | (data & 0xFFFF);
644                         else
645                                 gpu_div_control = (gpu_div_control & 0x0000FFFF) | ((data & 0xFFFF) << 16);
646                 }
647                 else
648                 {
649 //WriteLog("[GPU W16:%08X,%04X]", offset, data);
650                         uint32 old_data = GPUReadLong(offset & 0xFFFFFFC, who);
651                         if (offset & 0x02)
652                                 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
653                         else
654                                 old_data = (old_data & 0x0000FFFF) | ((data & 0xFFFF) << 16);
655                         GPUWriteLong(offset & 0xFFFFFFC, old_data, who);
656                 }
657                 return;
658         }
659         else if ((offset == GPU_WORK_RAM_BASE + 0x0FFF) || (GPU_CONTROL_RAM_BASE + 0x1F))
660         {
661 #ifdef GPU_DEBUG
662                         WriteLog("GPU: Write16--unaligned write @ %08X by %s [%04X]!\n", offset, whoName[who], data);
663                         GPUDumpRegisters();
664 #endif  // GPU_DEBUG
665                 return;
666         }
667
668         // Have to be careful here--this can cause an infinite loop!
669         JaguarWriteWord(offset, data, who);
670 }
671
672 //
673 // GPU dword access (write)
674 //
675 void GPUWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
676 {
677         if (offset >= 0xF02000 && offset <= 0xF020FF)
678                 WriteLog("GPU: WriteLong--Attempt to write to GPU register file by %s!\n", whoName[who]);
679
680 //      if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
681         if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC))
682         {
683 #ifdef GPU_DEBUG
684                 if (offset & 0x03)
685                 {
686                         WriteLog("GPU: Write32--unaligned write @ %08X [%08X] by %s\n", offset, data, whoName[who]);
687                         GPUDumpRegisters();
688                 }
689 #endif  // GPU_DEBUG
690
691                 offset &= 0xFFF;
692                 SET32(gpu_ram_8, offset, data);
693                 return;
694         }
695 //      else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
696         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1C))
697         {
698                 offset &= 0x1F;
699                 switch (offset)
700                 {
701                 case 0x00:
702                 {
703                         bool IMASKCleared = (gpu_flags & IMASK) && !(data & IMASK);
704                         gpu_flags = data;
705                         gpu_flag_z = gpu_flags & ZERO_FLAG;
706                         gpu_flag_c = (gpu_flags & CARRY_FLAG) >> 1;
707                         gpu_flag_n = (gpu_flags & NEGA_FLAG) >> 2;
708                         GPUUpdateRegisterBanks();
709                         gpu_control &= ~((gpu_flags & CINT04FLAGS) >> 3);       // Interrupt latch clear bits
710 //Writing here is only an interrupt enable--this approach is just plain wrong!
711 //                      GPUHandleIRQs();
712 //This, however, is A-OK! ;-)
713                         if (IMASKCleared)                                               // If IMASK was cleared,
714                                 GPUHandleIRQs();                                        // see if any other interrupts need servicing!
715 #ifdef GPU_DEBUG
716                         if (gpu_flags & (INT_ENA0 | INT_ENA1 | INT_ENA2 | INT_ENA3 | INT_ENA4))
717                                 WriteLog("GPU: Interrupt enable set by %s! Bits: %02X\n", whoName[who], (gpu_flags >> 4) & 0x1F);
718                         WriteLog("GPU: REGPAGE %s...\n", (gpu_flags & REGPAGE ? "set" : "cleared"));
719 #endif  // GPU_DEBUG
720                         break;
721                 }
722                 case 0x04:
723                         gpu_matrix_control = data;
724                         break;
725                 case 0x08:
726                         // This can only point to long aligned addresses
727                         gpu_pointer_to_matrix = data & 0xFFFFFFFC;
728                         break;
729                 case 0x0C:
730                         gpu_data_organization = data;
731                         break;
732                 case 0x10:
733                         gpu_pc = data;
734 #ifdef GPU_DEBUG
735 WriteLog("GPU: %s setting GPU PC to %08X %s\n", whoName[who], gpu_pc, (GPU_RUNNING ? "(GPU is RUNNING!)" : ""));//*/
736 #endif  // GPU_DEBUG
737                         break;
738                 case 0x14:
739                 {
740 //                      uint32 gpu_was_running = GPU_RUNNING;
741                         data &= ~0xF7C0;                // Disable writes to INT_LAT0-4 & TOM version number
742
743                         // check for GPU -> CPU interrupt
744                         if (data & 0x02)
745                         {
746 //WriteLog("GPU->CPU interrupt\n");
747                                 if (TOMIRQEnabled(IRQ_GPU))
748                                 {
749 //This is the programmer's responsibility, to make sure the handler is valid, not ours!
750 //                                      if ((TOMIRQEnabled(IRQ_GPU))// && (JaguarInterruptHandlerIsValid(64)))
751                                         {
752                                                 TOMSetPendingGPUInt();
753                                                 m68k_set_irq(2);                        // Set 68000 IPL 2
754                                                 GPUReleaseTimeslice();
755                                         }
756                                 }
757                                 data &= ~0x02;
758                         }
759
760                         // check for CPU -> GPU interrupt #0
761                         if (data & 0x04)
762                         {
763 //WriteLog("CPU->GPU interrupt\n");
764                                 GPUSetIRQLine(0, ASSERT_LINE);
765                                 m68k_end_timeslice();
766                                 DSPReleaseTimeslice();
767                                 data &= ~0x04;
768                         }
769
770                         // single stepping
771                         if (data & 0x10)
772                         {
773                                 //WriteLog("asked to perform a single step (single step is %senabled)\n",(data&0x8)?"":"not ");
774                         }
775                         gpu_control = (gpu_control & 0xF7C0) | (data & (~0xF7C0));
776
777                         // if gpu wasn't running but is now running, execute a few cycles
778 #ifndef GPU_SINGLE_STEPPING
779 /*                      if (!gpu_was_running && GPU_RUNNING)
780 #ifdef GPU_DEBUG
781                         {
782                                 WriteLog("GPU: Write32--About to do stupid braindead GPU execution for 200 cycles.\n");
783 #endif  // GPU_DEBUG
784                                 GPUExec(200);
785 #ifdef GPU_DEBUG
786                         }
787 #endif  // GPU_DEBUG//*/
788 #else
789                         if (gpu_control & 0x18)
790                                 GPUExec(1);
791 #endif  // #ifndef GPU_SINGLE_STEPPING
792 #ifdef GPU_DEBUG
793 WriteLog("Write to GPU CTRL by %s: %08X ", whoName[who], data);
794 if (GPU_RUNNING)
795         WriteLog(" --> Starting to run at %08X by %s...", gpu_pc, whoName[who]);
796 else
797         WriteLog(" --> Stopped by %s! (GPU_PC: %08X)", whoName[who], gpu_pc);
798 WriteLog("\n");
799 #endif  // GPU_DEBUG
800 //if (GPU_RUNNING)
801 //      GPUDumpDisassembly();
802 /*if (GPU_RUNNING)
803 {
804         if (gpu_pc == 0xF035D8)
805         {
806 //              GPUDumpDisassembly();
807 //              log_done();
808 //              exit(1);
809                 gpu_control &= 0xFFFFFFFE;      // Don't run it and let's see what happens!
810 //Hmm. Seems to lock up when going into the demo...
811 //Try to disable the collision altogether!
812         }
813 }//*/
814 extern int effect_start5;
815 static bool finished = false;
816 //if (GPU_RUNNING && effect_start5 && !finished)
817 if (GPU_RUNNING && effect_start5 && gpu_pc == 0xF035D8)
818 {
819         // Let's do a dump of $6528!
820 /*      uint32 numItems = JaguarReadWord(0x6BD6);
821         WriteLog("\nDump of $6528: %u items.\n\n", numItems);
822         for(int i=0; i<numItems*3*4; i+=3*4)
823         {
824                 WriteLog("\t%04X: %08X %08X %08X -> ", 0x6528+i, JaguarReadLong(0x6528+i),
825                         JaguarReadLong(0x6528+i+4), JaguarReadLong(0x6528+i+8));
826                 uint16 link = JaguarReadWord(0x6528+i+8+2);
827                 for(int j=0; j<40; j+=4)
828                         WriteLog("%08X ", JaguarReadLong(link + j));
829                 WriteLog("\n");
830         }
831         WriteLog("\n");//*/
832         // Let's try a manual blit here...
833 //This isn't working the way it should! !!! FIX !!!
834 //Err, actually, it is.
835 // NOW, it works right! Problem solved!!! It's a blitter bug!
836 /*      uint32 src = 0x4D54, dst = 0xF03000, width = 10 * 4;
837         for(int y=0; y<127; y++)
838         {
839                 for(int x=0; x<2; x++)
840                 {
841                         JaguarWriteLong(dst, JaguarReadLong(src));
842
843                         src += 4;
844                         dst += 4;
845                 }
846                 src += width - (2 * 4);
847         }//*/
848 /*      finished = true;
849         doGPUDis = true;
850         WriteLog("\nGPU: About to execute collision detection code.\n\n");//*/
851
852 /*      WriteLog("\nGPU: About to execute collision detection code. Data @ 4D54:\n\n");
853         int count = 0;
854         for(int i=0x004D54; i<0x004D54+2048; i++)
855         {
856                 WriteLog("%02X ", JaguarReadByte(i));
857                 count++;
858                 if (count == 32)
859                 {
860                         count = 0;
861                         WriteLog("\n");
862                 }
863         }
864         WriteLog("\n\nData @ F03000:\n\n");
865         count = 0;
866         for(int i=0xF03000; i<0xF03200; i++)
867         {
868                 WriteLog("%02X ", JaguarReadByte(i));
869                 count++;
870                 if (count == 32)
871                 {
872                         count = 0;
873                         WriteLog("\n");
874                 }
875         }
876         WriteLog("\n\n");
877         log_done();
878         exit(0);//*/
879 }
880 //if (!GPU_RUNNING)
881 //      doGPUDis = false;
882 /*if (!GPU_RUNNING && finished)
883 {
884         WriteLog("\nGPU: Finished collision detection code. Exiting!\n\n");
885         GPUDumpRegisters();
886         log_done();
887         exit(0);
888 }//*/
889                         // (?) If we're set running by the M68K (or DSP?) then end its timeslice to
890                         // allow the GPU a chance to run...
891                         // Yes! This partially fixed Trevor McFur...
892                         if (GPU_RUNNING)
893                                 m68k_end_timeslice();
894                         break;
895                 }
896                 case 0x18:
897                         gpu_hidata = data;
898                         break;
899                 case 0x1C:
900                         gpu_div_control = data;
901                         break;
902 //              default:   // unaligned long write
903                         //exit(0);
904                         //__asm int 3
905                 }
906                 return;
907         }
908
909 //      JaguarWriteWord(offset, (data >> 16) & 0xFFFF, who);
910 //      JaguarWriteWord(offset+2, data & 0xFFFF, who);
911 // We're a 32-bit processor, we can do a long write...!
912         JaguarWriteLong(offset, data, who);
913 }
914
915 //
916 // Change register banks if necessary
917 //
918 void GPUUpdateRegisterBanks(void)
919 {
920         int bank = (gpu_flags & REGPAGE);               // REGPAGE bit
921
922         if (gpu_flags & IMASK)                                  // IMASK bit
923                 bank = 0;                                                       // IMASK forces main bank to be bank 0
924
925         if (bank)
926                 gpu_reg = gpu_reg_bank_1, gpu_alternate_reg = gpu_reg_bank_0;
927         else
928                 gpu_reg = gpu_reg_bank_0, gpu_alternate_reg = gpu_reg_bank_1;
929 }
930
931 void GPUHandleIRQs(void)
932 {
933         // Bail out if we're already in an interrupt!
934         if (gpu_flags & IMASK)
935                 return;
936
937         // Get the interrupt latch & enable bits
938         uint32 bits = (gpu_control >> 6) & 0x1F, mask = (gpu_flags >> 4) & 0x1F;
939
940         // Bail out if latched interrupts aren't enabled
941         bits &= mask;
942         if (!bits)
943                 return;
944
945         // Determine which interrupt to service
946         uint32 which = 0; //Isn't there a #pragma to disable this warning???
947         if (bits & 0x01)
948                 which = 0;
949         if (bits & 0x02)
950                 which = 1;
951         if (bits & 0x04)
952                 which = 2;
953         if (bits & 0x08)
954                 which = 3;
955         if (bits & 0x10)
956                 which = 4;
957
958         if (start_logging)
959                 WriteLog("GPU: Generating IRQ #%i\n", which);
960
961         // set the interrupt flag
962         gpu_flags |= IMASK;
963         GPUUpdateRegisterBanks();
964
965         // subqt  #4,r31                ; pre-decrement stack pointer
966         // move  pc,r30                 ; address of interrupted code
967         // store  r30,(r31)     ; store return address
968         gpu_reg[31] -= 4;
969         GPUWriteLong(gpu_reg[31], gpu_pc - 2, GPU);
970
971         // movei  #service_address,r30  ; pointer to ISR entry
972         // jump  (r30)                                  ; jump to ISR
973         // nop
974         gpu_pc = gpu_reg[30] = GPU_WORK_RAM_BASE + (which * 0x10);
975 }
976
977 void GPUSetIRQLine(int irqline, int state)
978 {
979         if (start_logging)
980                 WriteLog("GPU: Setting GPU IRQ line #%i\n", irqline);
981
982         uint32 mask = 0x0040 << irqline;
983         gpu_control &= ~mask;                           // Clear the interrupt latch
984
985         if (state)
986         {
987                 gpu_control |= mask;                    // Assert the interrupt latch
988                 GPUHandleIRQs();                                // And handle the interrupt...
989         }
990 }
991
992 //TEMPORARY: Testing only!
993 //#include "gpu2.h"
994 //#include "gpu3.h"
995
996 void GPUInit(void)
997 {
998 //      memory_malloc_secure((void **)&gpu_ram_8, 0x1000, "GPU work RAM");
999 //      memory_malloc_secure((void **)&gpu_reg_bank_0, 32 * sizeof(int32), "GPU bank 0 regs");
1000 //      memory_malloc_secure((void **)&gpu_reg_bank_1, 32 * sizeof(int32), "GPU bank 1 regs");
1001
1002         build_branch_condition_table();
1003
1004         GPUReset();
1005
1006 //TEMPORARY: Testing only!
1007 //      gpu2_init();
1008 //      gpu3_init();
1009 }
1010
1011 void GPUReset(void)
1012 {
1013         // GPU registers (directly visible)
1014         gpu_flags                         = 0x00000000;
1015         gpu_matrix_control    = 0x00000000;
1016         gpu_pointer_to_matrix = 0x00000000;
1017         gpu_data_organization = 0xFFFFFFFF;
1018         gpu_pc                            = 0x00F03000;
1019         gpu_control                       = 0x00002800;                 // Correctly sets this as TOM Rev. 2
1020         gpu_hidata                        = 0x00000000;
1021         gpu_remain                        = 0x00000000;                 // These two registers are RO/WO
1022         gpu_div_control           = 0x00000000;
1023
1024         // GPU internal register
1025         gpu_acc                           = 0x00000000;
1026
1027         gpu_reg = gpu_reg_bank_0;
1028         gpu_alternate_reg = gpu_reg_bank_1;
1029
1030         for(int i=0; i<32; i++)
1031                 gpu_reg[i] = gpu_alternate_reg[i] = 0x00000000;
1032
1033         CLR_ZNC;
1034         memset(gpu_ram_8, 0xFF, 0x1000);
1035         gpu_in_exec = 0;
1036 //not needed    GPUInterruptPending = false;
1037         GPUResetStats();
1038 }
1039
1040 uint32 GPUReadPC(void)
1041 {
1042         return gpu_pc;
1043 }
1044
1045 void GPUResetStats(void)
1046 {
1047         for(uint32 i=0; i<64; i++)
1048                 gpu_opcode_use[i] = 0;
1049         WriteLog("--> GPU stats were reset!\n");
1050 }
1051
1052 void GPUDumpDisassembly(void)
1053 {
1054         char buffer[512];
1055
1056         WriteLog("\n---[GPU code at 00F03000]---------------------------\n");
1057         uint32 j = 0xF03000;
1058         while (j <= 0xF03FFF)
1059         {
1060                 uint32 oldj = j;
1061                 j += dasmjag(JAGUAR_GPU, buffer, j);
1062                 WriteLog("\t%08X: %s\n", oldj, buffer);
1063         }
1064 }
1065
1066 void GPUDumpRegisters(void)
1067 {
1068         WriteLog("\n---[GPU flags: NCZ %d%d%d]-----------------------\n", gpu_flag_n, gpu_flag_c, gpu_flag_z);
1069         WriteLog("\nRegisters bank 0\n");
1070         for(int j=0; j<8; j++)
1071         {
1072                 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1073                                                   (j << 2) + 0, gpu_reg_bank_0[(j << 2) + 0],
1074                                                   (j << 2) + 1, gpu_reg_bank_0[(j << 2) + 1],
1075                                                   (j << 2) + 2, gpu_reg_bank_0[(j << 2) + 2],
1076                                                   (j << 2) + 3, gpu_reg_bank_0[(j << 2) + 3]);
1077         }
1078         WriteLog("Registers bank 1\n");
1079         for(int j=0; j<8; j++)
1080         {
1081                 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1082                                                   (j << 2) + 0, gpu_reg_bank_1[(j << 2) + 0],
1083                                                   (j << 2) + 1, gpu_reg_bank_1[(j << 2) + 1],
1084                                                   (j << 2) + 2, gpu_reg_bank_1[(j << 2) + 2],
1085                                                   (j << 2) + 3, gpu_reg_bank_1[(j << 2) + 3]);
1086         }
1087 }
1088
1089 void GPUDumpMemory(void)
1090 {
1091         WriteLog("\n---[GPU data at 00F03000]---------------------------\n");
1092         for(int i=0; i<0xFFF; i+=4)
1093                 WriteLog("\t%08X: %02X %02X %02X %02X\n", 0xF03000+i, gpu_ram_8[i],
1094                         gpu_ram_8[i+1], gpu_ram_8[i+2], gpu_ram_8[i+3]);
1095 }
1096
1097 void GPUDone(void)
1098 {
1099         WriteLog("GPU: Stopped at PC=%08X (GPU %s running)\n", (unsigned int)gpu_pc, GPU_RUNNING ? "was" : "wasn't");
1100
1101         // Get the interrupt latch & enable bits
1102         uint8 bits = (gpu_control >> 6) & 0x1F, mask = (gpu_flags >> 4) & 0x1F;
1103         WriteLog("GPU: Latch bits = %02X, enable bits = %02X\n", bits, mask);
1104
1105         GPUDumpRegisters();
1106         GPUDumpDisassembly();
1107
1108         WriteLog("\nGPU opcodes use:\n");
1109         for(int i=0; i<64; i++)
1110         {
1111                 if (gpu_opcode_use[i])
1112                         WriteLog("\t%17s %lu\n", gpu_opcode_str[i], gpu_opcode_use[i]);
1113         }
1114         WriteLog("\n");
1115
1116 //      memory_free(gpu_ram_8);
1117 //      memory_free(gpu_reg_bank_0);
1118 //      memory_free(gpu_reg_bank_1);
1119 }
1120
1121 //
1122 // Main GPU execution core
1123 //
1124 static int testCount = 1;
1125 static int len = 0;
1126 static bool tripwire = false;
1127 void GPUExec(int32 cycles)
1128 {
1129         if (!GPU_RUNNING)
1130                 return;
1131
1132 #ifdef GPU_SINGLE_STEPPING
1133         if (gpu_control & 0x18)
1134         {
1135                 cycles = 1;
1136                 gpu_control &= ~0x10;
1137         }
1138 #endif
1139         GPUHandleIRQs();
1140         gpu_releaseTimeSlice_flag = 0;
1141         gpu_in_exec++;
1142
1143         while (cycles > 0 && GPU_RUNNING)
1144         {
1145 if (gpu_ram_8[0x054] == 0x98 && gpu_ram_8[0x055] == 0x0A && gpu_ram_8[0x056] == 0x03
1146         && gpu_ram_8[0x057] == 0x00 && gpu_ram_8[0x058] == 0x00 && gpu_ram_8[0x059] == 0x00)
1147 {
1148         if (gpu_pc == 0xF03000)
1149         {
1150                 extern uint32 starCount;
1151                 starCount = 0;
1152 /*              WriteLog("GPU: Starting starfield generator... Dump of [R03=%08X]:\n", gpu_reg_bank_0[03]);
1153                 uint32 base = gpu_reg_bank_0[3];
1154                 for(uint32 i=0; i<0x100; i+=16)
1155                 {
1156                         WriteLog("%02X: ", i);
1157                         for(uint32 j=0; j<16; j++)
1158                         {
1159                                 WriteLog("%02X ", JaguarReadByte(base + i + j));
1160                         }
1161                         WriteLog("\n");
1162                 }*/
1163         }
1164 //      if (gpu_pc == 0xF03)
1165         {
1166         }
1167 }//*/
1168 /*if (gpu_pc == 0xF03B9E && gpu_reg_bank_0[01] == 0)
1169 {
1170         GPUDumpRegisters();
1171         WriteLog("GPU: Starting disassembly log...\n");
1172         doGPUDis = true;
1173 }//*/
1174 /*if (gpu_pc == 0xF0359A)
1175 {
1176         doGPUDis = true;
1177         GPUDumpRegisters();
1178 }*/
1179 /*              gpu_flag_c = (gpu_flag_c ? 1 : 0);
1180                 gpu_flag_z = (gpu_flag_z ? 1 : 0);
1181                 gpu_flag_n = (gpu_flag_n ? 1 : 0);*/
1182
1183                 uint16 opcode = GPUReadWord(gpu_pc, GPU);
1184                 uint32 index = opcode >> 10;
1185                 gpu_instruction = opcode;                               // Added for GPU #3...
1186                 gpu_opcode_first_parameter = (opcode >> 5) & 0x1F;
1187                 gpu_opcode_second_parameter = opcode & 0x1F;
1188 /*if (gpu_pc == 0xF03BE8)
1189 WriteLog("Start of OP frame write...\n");
1190 if (gpu_pc == 0xF03EEE)
1191 WriteLog("--> Writing BRANCH object ---\n");
1192 if (gpu_pc == 0xF03F62)
1193 WriteLog("--> Writing BITMAP object ***\n");//*/
1194 /*if (gpu_pc == 0xF03546)
1195 {
1196         WriteLog("\n--> GPU PC: F03546\n");
1197         GPUDumpRegisters();
1198         GPUDumpDisassembly();
1199 }//*/
1200 /*if (gpu_pc == 0xF033F6)
1201 {
1202         WriteLog("\n--> GPU PC: F033F6\n");
1203         GPUDumpRegisters();
1204         GPUDumpDisassembly();
1205 }//*/
1206 /*if (gpu_pc == 0xF033CC)
1207 {
1208         WriteLog("\n--> GPU PC: F033CC\n");
1209         GPUDumpRegisters();
1210         GPUDumpDisassembly();
1211 }//*/
1212 /*if (gpu_pc == 0xF033D6)
1213 {
1214         WriteLog("\n--> GPU PC: F033D6 (#%d)\n", testCount++);
1215         GPUDumpRegisters();
1216         GPUDumpMemory();
1217 }//*/
1218 /*if (gpu_pc == 0xF033D8)
1219 {
1220         WriteLog("\n--> GPU PC: F033D8 (#%d)\n", testCount++);
1221         GPUDumpRegisters();
1222         GPUDumpMemory();
1223 }//*/
1224 /*if (gpu_pc == 0xF0358E)
1225 {
1226         WriteLog("\n--> GPU PC: F0358E (#%d)\n", testCount++);
1227         GPUDumpRegisters();
1228         GPUDumpMemory();
1229 }//*/
1230 /*if (gpu_pc == 0xF034CA)
1231 {
1232         WriteLog("\n--> GPU PC: F034CA (#%d)\n", testCount++);
1233         GPUDumpRegisters();
1234 }//*/
1235 /*if (gpu_pc == 0xF034CA)
1236 {
1237         len = gpu_reg[1] + 4;//, r9save = gpu_reg[9];
1238         WriteLog("\nAbout to subtract [#%d] (R14=%08X, R15=%08X, R9=%08X):\n   ", testCount++, gpu_reg[14], gpu_reg[15], gpu_reg[9]);
1239         for(int i=0; i<len; i+=4)
1240                 WriteLog(" %08X", GPUReadLong(gpu_reg[15]+i));
1241         WriteLog("\n   ");
1242         for(int i=0; i<len; i+=4)
1243                 WriteLog(" %08X", GPUReadLong(gpu_reg[14]+i));
1244         WriteLog("\n\n");
1245 }
1246 if (gpu_pc == 0xF034DE)
1247 {
1248         WriteLog("\nSubtracted! (R14=%08X, R15=%08X):\n   ", gpu_reg[14], gpu_reg[15]);
1249         for(int i=0; i<len; i+=4)
1250                 WriteLog(" %08X", GPUReadLong(gpu_reg[15]+i));
1251         WriteLog("\n   ");
1252         for(int i=0; i<len; i+=4)
1253                 WriteLog(" %08X", GPUReadLong(gpu_reg[14]+i));
1254         WriteLog("\n   ");
1255         for(int i=0; i<len; i+=4)
1256                 WriteLog(" --------");
1257         WriteLog("\n   ");
1258         for(int i=0; i<len; i+=4)
1259                 WriteLog(" %08X", GPUReadLong(gpu_reg[9]+4+i));
1260         WriteLog("\n\n");
1261 }//*/
1262 /*if (gpu_pc == 0xF035C8)
1263 {
1264         WriteLog("\n--> GPU PC: F035C8 (#%d)\n", testCount++);
1265         GPUDumpRegisters();
1266         GPUDumpDisassembly();
1267 }//*/
1268
1269 if (gpu_start_log)
1270 {
1271 //      gpu_reset_stats();
1272 static char buffer[512];
1273 dasmjag(JAGUAR_GPU, buffer, gpu_pc);
1274 WriteLog("GPU: [%08X] %s (RM=%08X, RN=%08X) -> ", gpu_pc, buffer, RM, RN);
1275 }//*/
1276 //$E400 -> 1110 01 -> $39 -> 57
1277 //GPU #1
1278                 gpu_pc += 2;
1279                 gpu_opcode[index]();
1280 //GPU #2
1281 //              gpu2_opcode[index]();
1282 //              gpu_pc += 2;
1283 //GPU #3                                (Doesn't show ATARI logo! #1 & #2 do...)
1284 //              gpu_pc += 2;
1285 //              gpu3_opcode[index]();
1286
1287 // BIOS hacking
1288 //GPU: [00F03548] jr      nz,00F03560 (0xd561) (RM=00F03114, RN=00000004) ->     --> JR: Branch taken.
1289 /*static bool firstTime = true;
1290 if (gpu_pc == 0xF03548 && firstTime)
1291 {
1292         gpu_flag_z = 1;
1293 //      firstTime = false;
1294
1295 //static char buffer[512];
1296 //int k=0xF03548;
1297 //while (k<0xF0356C)
1298 //{
1299 //int oldk = k;
1300 //k += dasmjag(JAGUAR_GPU, buffer, k);
1301 //WriteLog("GPU: [%08X] %s\n", oldk, buffer);
1302 //}
1303 //      gpu_start_log = 1;
1304 }//*/
1305 //GPU: [00F0354C] jump    nz,(r29) (0xd3a1) (RM=00F03314, RN=00000004) -> (RM=00F03314, RN=00000004)
1306 /*if (gpu_pc == 0xF0354C)
1307         gpu_flag_z = 0;//, gpu_start_log = 1;//*/
1308
1309                 cycles -= gpu_opcode_cycles[index];
1310                 gpu_opcode_use[index]++;
1311 if (gpu_start_log)
1312         WriteLog("(RM=%08X, RN=%08X)\n", RM, RN);//*/
1313 if ((gpu_pc < 0xF03000 || gpu_pc > 0xF03FFF) && !tripwire)
1314 {
1315         WriteLog("GPU: Executing outside local RAM! GPU_PC: %08X\n", gpu_pc);
1316         tripwire = true;
1317 }
1318         }
1319
1320         gpu_in_exec--;
1321 }
1322
1323 //
1324 // GPU opcodes
1325 //
1326
1327 /*
1328 GPU opcodes use (offset punch--vertically below bad guy):
1329                       add 18686
1330                      addq 32621
1331                       sub 7483
1332                      subq 10252
1333                       and 21229
1334                        or 15003
1335                      btst 1822
1336                      bset 2072
1337                      mult 141
1338                       div 2392
1339                      shlq 13449
1340                      shrq 10297
1341                     sharq 11104
1342                       cmp 6775
1343                      cmpq 5944
1344                      move 31259
1345                     moveq 4473
1346                     movei 23277
1347                     loadb 46
1348                     loadw 4201
1349                      load 28580
1350          load_r14_indexed 1183
1351          load_r15_indexed 1125
1352                    storew 178
1353                     store 10144
1354         store_r14_indexed 320
1355         store_r15_indexed 1
1356                   move_pc 1742
1357                      jump 24467
1358                        jr 18090
1359                       nop 41362
1360 */
1361
1362 static void gpu_opcode_jump(void)
1363 {
1364 #ifdef GPU_DIS_JUMP
1365 const char * condition[32] =
1366 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1367         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1368         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1369         "???", "???", "???", "F" };
1370         if (doGPUDis)
1371                 WriteLog("%06X: JUMP   %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", gpu_pc-2, condition[IMM_2], IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM);
1372 #endif
1373         // normalize flags
1374 /*      gpu_flag_c = (gpu_flag_c ? 1 : 0);
1375         gpu_flag_z = (gpu_flag_z ? 1 : 0);
1376         gpu_flag_n = (gpu_flag_n ? 1 : 0);*/
1377         // KLUDGE: Used by BRANCH_CONDITION
1378         uint32 jaguar_flags = (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z;
1379
1380         if (BRANCH_CONDITION(IMM_2))
1381         {
1382 #ifdef GPU_DIS_JUMP
1383         if (doGPUDis)
1384                 WriteLog("Branched!\n");
1385 #endif
1386 if (gpu_start_log)
1387         WriteLog("    --> JUMP: Branch taken.\n");
1388                 uint32 delayed_pc = RM;
1389                 GPUExec(1);
1390                 gpu_pc = delayed_pc;
1391 /*              uint16 opcode = GPUReadWord(gpu_pc, GPU);
1392                 gpu_opcode_first_parameter = (opcode >> 5) & 0x1F;
1393                 gpu_opcode_second_parameter = opcode & 0x1F;
1394
1395                 gpu_pc = delayed_pc;
1396                 gpu_opcode[opcode>>10]();//*/
1397         }
1398 #ifdef GPU_DIS_JUMP
1399         else
1400                 if (doGPUDis)
1401                         WriteLog("Branch NOT taken.\n");
1402 #endif
1403 }
1404
1405 static void gpu_opcode_jr(void)
1406 {
1407 #ifdef GPU_DIS_JR
1408 const char * condition[32] =
1409 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1410         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1411         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1412         "???", "???", "???", "F" };
1413         if (doGPUDis)
1414                 WriteLog("%06X: JR     %s, %06X [NCZ:%u%u%u] ", gpu_pc-2, condition[IMM_2], gpu_pc+((IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1) * 2), gpu_flag_n, gpu_flag_c, gpu_flag_z);
1415 #endif
1416 /*      if (CONDITION(jaguar.op & 31))
1417         {
1418                 int32 r1 = (INT8)((jaguar.op >> 2) & 0xF8) >> 2;
1419                 uint32 newpc = jaguar.PC + r1;
1420                 CALL_MAME_DEBUG;
1421                 jaguar.op = ROPCODE(jaguar.PC);
1422                 jaguar.PC = newpc;
1423                 (*jaguar.table[jaguar.op >> 10])();
1424
1425                 jaguar_icount -= 3;     // 3 wait states guaranteed
1426         }*/
1427         // normalize flags
1428 /*      gpu_flag_n = (gpu_flag_n ? 1 : 0);
1429         gpu_flag_c = (gpu_flag_c ? 1 : 0);
1430         gpu_flag_z = (gpu_flag_z ? 1 : 0);*/
1431         // KLUDGE: Used by BRANCH_CONDITION
1432         uint32 jaguar_flags = (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z;
1433
1434         if (BRANCH_CONDITION(IMM_2))
1435         {
1436 #ifdef GPU_DIS_JR
1437         if (doGPUDis)
1438                 WriteLog("Branched!\n");
1439 #endif
1440 if (gpu_start_log)
1441         WriteLog("    --> JR: Branch taken.\n");
1442                 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1);             // Sign extend IMM_1
1443                 int32 delayed_pc = gpu_pc + (offset * 2);
1444                 GPUExec(1);
1445                 gpu_pc = delayed_pc;
1446 /*              uint16 opcode = GPUReadWord(gpu_pc, GPU);
1447                 gpu_opcode_first_parameter = (opcode >> 5) & 0x1F;
1448                 gpu_opcode_second_parameter = opcode & 0x1F;
1449
1450                 gpu_pc = delayed_pc;
1451                 gpu_opcode[opcode>>10]();//*/
1452         }
1453 #ifdef GPU_DIS_JR
1454         else
1455                 if (doGPUDis)
1456                         WriteLog("Branch NOT taken.\n");
1457 #endif
1458 }
1459
1460 static void gpu_opcode_add(void)
1461 {
1462 #ifdef GPU_DIS_ADD
1463         if (doGPUDis)
1464                 WriteLog("%06X: ADD    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1465 #endif
1466         uint32 res = RN + RM;
1467         CLR_ZNC; SET_ZNC_ADD(RN, RM, res);
1468         RN = res;
1469 #ifdef GPU_DIS_ADD
1470         if (doGPUDis)
1471                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1472 #endif
1473 }
1474
1475 static void gpu_opcode_addc(void)
1476 {
1477 #ifdef GPU_DIS_ADDC
1478         if (doGPUDis)
1479                 WriteLog("%06X: ADDC   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1480 #endif
1481 /*      int dreg = jaguar.op & 31;
1482         uint32 r1 = jaguar.r[(jaguar.op >> 5) & 31];
1483         uint32 r2 = jaguar.r[dreg];
1484         uint32 res = r2 + r1 + ((jaguar.FLAGS >> 1) & 1);
1485         jaguar.r[dreg] = res;
1486         CLR_ZNC; SET_ZNC_ADD(r2,r1,res);*/
1487
1488         uint32 res = RN + RM + gpu_flag_c;
1489         uint32 carry = gpu_flag_c;
1490 //      SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1491         SET_ZNC_ADD(RN + carry, RM, res);
1492 //      SET_ZNC_ADD(RN, RM + carry, res);
1493         RN = res;
1494 #ifdef GPU_DIS_ADDC
1495         if (doGPUDis)
1496                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1497 #endif
1498 }
1499
1500 static void gpu_opcode_addq(void)
1501 {
1502 #ifdef GPU_DIS_ADDQ
1503         if (doGPUDis)
1504                 WriteLog("%06X: ADDQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1505 #endif
1506         uint32 r1 = gpu_convert_zero[IMM_1];
1507         uint32 res = RN + r1;
1508         CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1509         RN = res;
1510 #ifdef GPU_DIS_ADDQ
1511         if (doGPUDis)
1512                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1513 #endif
1514 }
1515
1516 static void gpu_opcode_addqt(void)
1517 {
1518 #ifdef GPU_DIS_ADDQT
1519         if (doGPUDis)
1520                 WriteLog("%06X: ADDQT  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1521 #endif
1522         RN += gpu_convert_zero[IMM_1];
1523 #ifdef GPU_DIS_ADDQT
1524         if (doGPUDis)
1525                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1526 #endif
1527 }
1528
1529 static void gpu_opcode_sub(void)
1530 {
1531 #ifdef GPU_DIS_SUB
1532         if (doGPUDis)
1533                 WriteLog("%06X: SUB    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1534 #endif
1535         uint32 res = RN - RM;
1536         SET_ZNC_SUB(RN, RM, res);
1537         RN = res;
1538 #ifdef GPU_DIS_SUB
1539         if (doGPUDis)
1540                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1541 #endif
1542 }
1543
1544 static void gpu_opcode_subc(void)
1545 {
1546 #ifdef GPU_DIS_SUBC
1547         if (doGPUDis)
1548                 WriteLog("%06X: SUBC   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1549 #endif
1550         uint32 res = RN - RM - gpu_flag_c;
1551         uint32 borrow = gpu_flag_c;
1552 //      SET_ZNC_SUB(RN, RM, res); //???BUG??? YES!!!
1553 //No matter how you do it, there is a problem. With below, it's 0-0 with carry,
1554 //and the one below it it's FFFFFFFF - FFFFFFFF with carry... !!! FIX !!!
1555 //      SET_ZNC_SUB(RN - borrow, RM, res);
1556         SET_ZNC_SUB(RN, RM + borrow, res);
1557         RN = res;
1558 #ifdef GPU_DIS_SUBC
1559         if (doGPUDis)
1560                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1561 #endif
1562 }
1563 /*
1564 N = 5, M = 3, 3 - 5 = -2, C = 1... Or, in our case:
1565 N = 0, M = 1, 0 - 1 = -1, C = 0!
1566
1567 #define SET_C_SUB(a,b)          (gpu_flag_c = ((uint32)(b) > (uint32)(a)))
1568 #define SET_ZN(r)                       SET_N(r); SET_Z(r)
1569 #define SET_ZNC_ADD(a,b,r)      SET_N(r); SET_Z(r); SET_C_ADD(a,b)
1570 #define SET_ZNC_SUB(a,b,r)      SET_N(r); SET_Z(r); SET_C_SUB(a,b)
1571 */
1572 static void gpu_opcode_subq(void)
1573 {
1574 #ifdef GPU_DIS_SUBQ
1575         if (doGPUDis)
1576                 WriteLog("%06X: SUBQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1577 #endif
1578         uint32 r1 = gpu_convert_zero[IMM_1];
1579         uint32 res = RN - r1;
1580         SET_ZNC_SUB(RN, r1, res);
1581         RN = res;
1582 #ifdef GPU_DIS_SUBQ
1583         if (doGPUDis)
1584                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1585 #endif
1586 }
1587
1588 static void gpu_opcode_subqt(void)
1589 {
1590 #ifdef GPU_DIS_SUBQT
1591         if (doGPUDis)
1592                 WriteLog("%06X: SUBQT  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1593 #endif
1594         RN -= gpu_convert_zero[IMM_1];
1595 #ifdef GPU_DIS_SUBQT
1596         if (doGPUDis)
1597                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1598 #endif
1599 }
1600
1601 static void gpu_opcode_cmp(void)
1602 {
1603 #ifdef GPU_DIS_CMP
1604         if (doGPUDis)
1605                 WriteLog("%06X: CMP    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1606 #endif
1607         uint32 res = RN - RM;
1608         SET_ZNC_SUB(RN, RM, res);
1609 #ifdef GPU_DIS_CMP
1610         if (doGPUDis)
1611                 WriteLog("[NCZ:%u%u%u]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z);
1612 #endif
1613 }
1614
1615 static void gpu_opcode_cmpq(void)
1616 {
1617         static int32 sqtable[32] =
1618                 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 };
1619 #ifdef GPU_DIS_CMPQ
1620         if (doGPUDis)
1621                 WriteLog("%06X: CMPQ   #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, sqtable[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1622 #endif
1623         uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1624         uint32 res = RN - r1;
1625         SET_ZNC_SUB(RN, r1, res);
1626 #ifdef GPU_DIS_CMPQ
1627         if (doGPUDis)
1628                 WriteLog("[NCZ:%u%u%u]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z);
1629 #endif
1630 }
1631
1632 static void gpu_opcode_and(void)
1633 {
1634 #ifdef GPU_DIS_AND
1635         if (doGPUDis)
1636                 WriteLog("%06X: AND    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1637 #endif
1638         RN = RN & RM;
1639         SET_ZN(RN);
1640 #ifdef GPU_DIS_AND
1641         if (doGPUDis)
1642                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1643 #endif
1644 }
1645
1646 static void gpu_opcode_or(void)
1647 {
1648 #ifdef GPU_DIS_OR
1649         if (doGPUDis)
1650                 WriteLog("%06X: OR     R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1651 #endif
1652         RN = RN | RM;
1653         SET_ZN(RN);
1654 #ifdef GPU_DIS_OR
1655         if (doGPUDis)
1656                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1657 #endif
1658 }
1659
1660 static void gpu_opcode_xor(void)
1661 {
1662 #ifdef GPU_DIS_XOR
1663         if (doGPUDis)
1664                 WriteLog("%06X: XOR    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1665 #endif
1666         RN = RN ^ RM;
1667         SET_ZN(RN);
1668 #ifdef GPU_DIS_XOR
1669         if (doGPUDis)
1670                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1671 #endif
1672 }
1673
1674 static void gpu_opcode_not(void)
1675 {
1676 #ifdef GPU_DIS_NOT
1677         if (doGPUDis)
1678                 WriteLog("%06X: NOT    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1679 #endif
1680         RN = ~RN;
1681         SET_ZN(RN);
1682 #ifdef GPU_DIS_NOT
1683         if (doGPUDis)
1684                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1685 #endif
1686 }
1687
1688 static void gpu_opcode_move_pc(void)
1689 {
1690 #ifdef GPU_DIS_MOVEPC
1691         if (doGPUDis)
1692                 WriteLog("%06X: MOVE   PC, R%02u [NCZ:%u%u%u, PC=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_pc-2, IMM_2, RN);
1693 #endif
1694         // Should be previous PC--this might not always be previous instruction!
1695         // Then again, this will point right at the *current* instruction, i.e., MOVE PC,R!
1696         RN = gpu_pc - 2;
1697 #ifdef GPU_DIS_MOVEPC
1698         if (doGPUDis)
1699                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1700 #endif
1701 }
1702
1703 static void gpu_opcode_sat8(void)
1704 {
1705 #ifdef GPU_DIS_SAT8
1706         if (doGPUDis)
1707                 WriteLog("%06X: SAT8   R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1708 #endif
1709         RN = ((int32)RN < 0 ? 0 : (RN > 0xFF ? 0xFF : RN));
1710         SET_ZN(RN);
1711 #ifdef GPU_DIS_SAT8
1712         if (doGPUDis)
1713                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1714 #endif
1715 }
1716
1717 static void gpu_opcode_sat16(void)
1718 {
1719         RN = ((int32)RN < 0 ? 0 : (RN > 0xFFFF ? 0xFFFF : RN));
1720         SET_ZN(RN);
1721 }
1722
1723 static void gpu_opcode_sat24(void)
1724 {
1725         RN = ((int32)RN < 0 ? 0 : (RN > 0xFFFFFF ? 0xFFFFFF : RN));
1726         SET_ZN(RN);
1727 }
1728
1729 static void gpu_opcode_store_r14_indexed(void)
1730 {
1731 #ifdef GPU_DIS_STORE14I
1732         if (doGPUDis)
1733                 WriteLog("%06X: STORE  R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", gpu_pc-2, IMM_2, gpu_convert_zero[IMM_1] << 2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, gpu_convert_zero[IMM_1] << 2, gpu_reg[14]+(gpu_convert_zero[IMM_1] << 2));
1734 #endif
1735 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1736         GPUWriteLong((gpu_reg[14] & 0xFFFFFFFC) + (gpu_convert_zero[IMM_1] << 2), RN, GPU);
1737 #else
1738         GPUWriteLong(gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2), RN, GPU);
1739 #endif
1740 }
1741
1742 static void gpu_opcode_store_r15_indexed(void)
1743 {
1744 #ifdef GPU_DIS_STORE15I
1745         if (doGPUDis)
1746                 WriteLog("%06X: STORE  R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", gpu_pc-2, IMM_2, gpu_convert_zero[IMM_1] << 2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, gpu_convert_zero[IMM_1] << 2, gpu_reg[15]+(gpu_convert_zero[IMM_1] << 2));
1747 #endif
1748 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1749         GPUWriteLong((gpu_reg[15] & 0xFFFFFFFC) + (gpu_convert_zero[IMM_1] << 2), RN, GPU);
1750 #else
1751         GPUWriteLong(gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2), RN, GPU);
1752 #endif
1753 }
1754
1755 static void gpu_opcode_load_r14_ri(void)
1756 {
1757 #ifdef GPU_DIS_LOAD14R
1758         if (doGPUDis)
1759                 WriteLog("%06X: LOAD   (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM+gpu_reg[14], IMM_2, RN);
1760 #endif
1761 #ifdef GPU_CORRECT_ALIGNMENT
1762         RN = GPUReadLong((gpu_reg[14] + RM) & 0xFFFFFFFC, GPU);
1763 #else
1764         RN = GPUReadLong(gpu_reg[14] + RM, GPU);
1765 #endif
1766 #ifdef GPU_DIS_LOAD14R
1767         if (doGPUDis)
1768                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1769 #endif
1770 }
1771
1772 static void gpu_opcode_load_r15_ri(void)
1773 {
1774 #ifdef GPU_DIS_LOAD15R
1775         if (doGPUDis)
1776                 WriteLog("%06X: LOAD   (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM+gpu_reg[15], IMM_2, RN);
1777 #endif
1778 #ifdef GPU_CORRECT_ALIGNMENT
1779         RN = GPUReadLong((gpu_reg[15] + RM) & 0xFFFFFFFC, GPU);
1780 #else
1781         RN = GPUReadLong(gpu_reg[15] + RM, GPU);
1782 #endif
1783 #ifdef GPU_DIS_LOAD15R
1784         if (doGPUDis)
1785                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1786 #endif
1787 }
1788
1789 static void gpu_opcode_store_r14_ri(void)
1790 {
1791 #ifdef GPU_DIS_STORE14R
1792         if (doGPUDis)
1793                 WriteLog("%06X: STORE  R%02u, (R14+R%02u) [NCZ:%u%u%u, R%02u=%08X, R14+R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM+gpu_reg[14]);
1794 #endif
1795 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1796         GPUWriteLong((gpu_reg[14] + RM) & 0xFFFFFFFC, RN, GPU);
1797 #else
1798         GPUWriteLong(gpu_reg[14] + RM, RN, GPU);
1799 #endif
1800 }
1801
1802 static void gpu_opcode_store_r15_ri(void)
1803 {
1804 #ifdef GPU_DIS_STORE15R
1805         if (doGPUDis)
1806                 WriteLog("%06X: STORE  R%02u, (R15+R%02u) [NCZ:%u%u%u, R%02u=%08X, R15+R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM+gpu_reg[15]);
1807 #endif
1808 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1809         GPUWriteLong((gpu_reg[15] + RM) & 0xFFFFFFFC, RN, GPU);
1810 #else
1811         GPUWriteLong(gpu_reg[15] + RM, RN, GPU);
1812 #endif
1813 }
1814
1815 static void gpu_opcode_nop(void)
1816 {
1817 #ifdef GPU_DIS_NOP
1818         if (doGPUDis)
1819                 WriteLog("%06X: NOP    [NCZ:%u%u%u]\n", gpu_pc-2, gpu_flag_n, gpu_flag_c, gpu_flag_z);
1820 #endif
1821 }
1822
1823 static void gpu_opcode_pack(void)
1824 {
1825 #ifdef GPU_DIS_PACK
1826         if (doGPUDis)
1827                 WriteLog("%06X: %s R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, (!IMM_1 ? "PACK  " : "UNPACK"), IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1828 #endif
1829         uint32 val = RN;
1830
1831 //BUG!  if (RM == 0)                            // Pack
1832         if (IMM_1 == 0)                         // Pack
1833                 RN = ((val >> 10) & 0x0000F000) | ((val >> 5) & 0x00000F00) | (val & 0x000000FF);
1834         else                                            // Unpack
1835                 RN = ((val & 0x0000F000) << 10) | ((val & 0x00000F00) << 5) | (val & 0x000000FF);
1836 #ifdef GPU_DIS_PACK
1837         if (doGPUDis)
1838                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1839 #endif
1840 }
1841
1842 static void gpu_opcode_storeb(void)
1843 {
1844 #ifdef GPU_DIS_STOREB
1845         if (doGPUDis)
1846                 WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM);
1847 #endif
1848 //Is this right???
1849 // Would appear to be so...!
1850         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1851                 GPUWriteLong(RM, RN & 0xFF, GPU);
1852         else
1853                 JaguarWriteByte(RM, RN, GPU);
1854 }
1855
1856 static void gpu_opcode_storew(void)
1857 {
1858 #ifdef GPU_DIS_STOREW
1859         if (doGPUDis)
1860                 WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM);
1861 #endif
1862 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1863         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1864                 GPUWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, GPU);
1865         else
1866                 JaguarWriteWord(RM & 0xFFFFFFFE, RN, GPU);
1867 #else
1868         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1869                 GPUWriteLong(RM, RN & 0xFFFF, GPU);
1870         else
1871                 JaguarWriteWord(RM, RN, GPU);
1872 #endif
1873 }
1874
1875 static void gpu_opcode_store(void)
1876 {
1877 #ifdef GPU_DIS_STORE
1878         if (doGPUDis)
1879                 WriteLog("%06X: STORE  R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM);
1880 #endif
1881 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1882         GPUWriteLong(RM & 0xFFFFFFFC, RN, GPU);
1883 #else
1884         GPUWriteLong(RM, RN, GPU);
1885 #endif
1886 }
1887
1888 static void gpu_opcode_storep(void)
1889 {
1890 #ifdef GPU_CORRECT_ALIGNMENT_STORE
1891         GPUWriteLong((RM & 0xFFFFFFF8) + 0, gpu_hidata, GPU);
1892         GPUWriteLong((RM & 0xFFFFFFF8) + 4, RN, GPU);
1893 #else
1894         GPUWriteLong(RM + 0, gpu_hidata, GPU);
1895         GPUWriteLong(RM + 4, RN, GPU);
1896 #endif
1897 }
1898
1899 static void gpu_opcode_loadb(void)
1900 {
1901 #ifdef GPU_DIS_LOADB
1902         if (doGPUDis)
1903                 WriteLog("%06X: LOADB  (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1904 #endif
1905         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1906                 RN = GPUReadLong(RM, GPU) & 0xFF;
1907         else
1908                 RN = JaguarReadByte(RM, GPU);
1909 #ifdef GPU_DIS_LOADB
1910         if (doGPUDis)
1911                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1912 #endif
1913 }
1914
1915 static void gpu_opcode_loadw(void)
1916 {
1917 #ifdef GPU_DIS_LOADW
1918         if (doGPUDis)
1919                 WriteLog("%06X: LOADW  (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1920 #endif
1921 #ifdef GPU_CORRECT_ALIGNMENT
1922         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1923                 RN = GPUReadLong(RM & 0xFFFFFFFE, GPU) & 0xFFFF;
1924         else
1925                 RN = JaguarReadWord(RM & 0xFFFFFFFE, GPU);
1926 #else
1927         if ((RM >= 0xF03000) && (RM <= 0xF03FFF))
1928                 RN = GPUReadLong(RM, GPU) & 0xFFFF;
1929         else
1930                 RN = JaguarReadWord(RM, GPU);
1931 #endif
1932 #ifdef GPU_DIS_LOADW
1933         if (doGPUDis)
1934                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1935 #endif
1936 }
1937
1938 // According to the docs, & "Do The Same", this address is long aligned...
1939 // So let's try it:
1940 // And it works!!! Need to fix all instances...
1941 static void gpu_opcode_load(void)
1942 {
1943 #ifdef GPU_DIS_LOAD
1944         if (doGPUDis)
1945                 WriteLog("%06X: LOAD   (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
1946 #endif
1947 #ifdef GPU_CORRECT_ALIGNMENT
1948         RN = GPUReadLong(RM & 0xFFFFFFFC, GPU);
1949 #else
1950         RN = GPUReadLong(RM, GPU);
1951 #endif
1952 #ifdef GPU_DIS_LOAD
1953         if (doGPUDis)
1954                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1955 #endif
1956 }
1957
1958 static void gpu_opcode_loadp(void)
1959 {
1960 #ifdef GPU_CORRECT_ALIGNMENT
1961         gpu_hidata = GPUReadLong((RM & 0xFFFFFFF8) + 0, GPU);
1962         RN                 = GPUReadLong((RM & 0xFFFFFFF8) + 4, GPU);
1963 #else
1964         gpu_hidata = GPUReadLong(RM + 0, GPU);
1965         RN                 = GPUReadLong(RM + 4, GPU);
1966 #endif
1967 }
1968
1969 static void gpu_opcode_load_r14_indexed(void)
1970 {
1971 #ifdef GPU_DIS_LOAD14I
1972         if (doGPUDis)
1973                 WriteLog("%06X: LOAD   (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1] << 2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_convert_zero[IMM_1] << 2, gpu_reg[14]+(gpu_convert_zero[IMM_1] << 2), IMM_2, RN);
1974 #endif
1975 #ifdef GPU_CORRECT_ALIGNMENT
1976         RN = GPUReadLong((gpu_reg[14] & 0xFFFFFFFC) + (gpu_convert_zero[IMM_1] << 2), GPU);
1977 #else
1978         RN = GPUReadLong(gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2), GPU);
1979 #endif
1980 #ifdef GPU_DIS_LOAD14I
1981         if (doGPUDis)
1982                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
1983 #endif
1984 }
1985
1986 static void gpu_opcode_load_r15_indexed(void)
1987 {
1988 #ifdef GPU_DIS_LOAD15I
1989         if (doGPUDis)
1990                 WriteLog("%06X: LOAD   (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1] << 2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_convert_zero[IMM_1] << 2, gpu_reg[15]+(gpu_convert_zero[IMM_1] << 2), IMM_2, RN);
1991 #endif
1992 #ifdef GPU_CORRECT_ALIGNMENT
1993         RN = GPUReadLong((gpu_reg[15] & 0xFFFFFFFC) + (gpu_convert_zero[IMM_1] << 2), GPU);
1994 #else
1995         RN = GPUReadLong(gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2), GPU);
1996 #endif
1997 #ifdef GPU_DIS_LOAD15I
1998         if (doGPUDis)
1999                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2000 #endif
2001 }
2002
2003 static void gpu_opcode_movei(void)
2004 {
2005 #ifdef GPU_DIS_MOVEI
2006         if (doGPUDis)
2007                 WriteLog("%06X: MOVEI  #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, (uint32)GPUReadWord(gpu_pc) | ((uint32)GPUReadWord(gpu_pc + 2) << 16), IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2008 #endif
2009         // This instruction is followed by 32-bit value in LSW / MSW format...
2010         RN = (uint32)GPUReadWord(gpu_pc, GPU) | ((uint32)GPUReadWord(gpu_pc + 2, GPU) << 16);
2011         gpu_pc += 4;
2012 #ifdef GPU_DIS_MOVEI
2013         if (doGPUDis)
2014                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2015 #endif
2016 }
2017
2018 static void gpu_opcode_moveta(void)
2019 {
2020 #ifdef GPU_DIS_MOVETA
2021         if (doGPUDis)
2022                 WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2023 #endif
2024         ALTERNATE_RN = RM;
2025 #ifdef GPU_DIS_MOVETA
2026         if (doGPUDis)
2027                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2028 #endif
2029 }
2030
2031 static void gpu_opcode_movefa(void)
2032 {
2033 #ifdef GPU_DIS_MOVEFA
2034         if (doGPUDis)
2035                 WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2036 #endif
2037         RN = ALTERNATE_RM;
2038 #ifdef GPU_DIS_MOVEFA
2039         if (doGPUDis)
2040                 WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2041 #endif
2042 }
2043
2044 static void gpu_opcode_move(void)
2045 {
2046 #ifdef GPU_DIS_MOVE
2047         if (doGPUDis)
2048                 WriteLog("%06X: MOVE   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2049 #endif
2050         RN = RM;
2051 #ifdef GPU_DIS_MOVE
2052         if (doGPUDis)
2053                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2054 #endif
2055 }
2056
2057 static void gpu_opcode_moveq(void)
2058 {
2059 #ifdef GPU_DIS_MOVEQ
2060         if (doGPUDis)
2061                 WriteLog("%06X: MOVEQ  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2062 #endif
2063         RN = IMM_1;
2064 #ifdef GPU_DIS_MOVEQ
2065         if (doGPUDis)
2066                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2067 #endif
2068 }
2069
2070 static void gpu_opcode_resmac(void)
2071 {
2072         RN = gpu_acc;
2073 }
2074
2075 static void gpu_opcode_imult(void)
2076 {
2077 #ifdef GPU_DIS_IMULT
2078         if (doGPUDis)
2079                 WriteLog("%06X: IMULT  R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2080 #endif
2081         RN = (int16)RN * (int16)RM;
2082         SET_ZN(RN);
2083 #ifdef GPU_DIS_IMULT
2084         if (doGPUDis)
2085                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2086 #endif
2087 }
2088
2089 static void gpu_opcode_mult(void)
2090 {
2091 #ifdef GPU_DIS_MULT
2092         if (doGPUDis)
2093                 WriteLog("%06X: MULT   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2094 #endif
2095         RN = (uint16)RM * (uint16)RN;
2096         SET_ZN(RN);
2097 #ifdef GPU_DIS_MULT
2098         if (doGPUDis)
2099                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2100 #endif
2101 }
2102
2103 static void gpu_opcode_bclr(void)
2104 {
2105 #ifdef GPU_DIS_BCLR
2106         if (doGPUDis)
2107                 WriteLog("%06X: BCLR   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2108 #endif
2109         uint32 res = RN & ~(1 << IMM_1);
2110         RN = res;
2111         SET_ZN(res);
2112 #ifdef GPU_DIS_BCLR
2113         if (doGPUDis)
2114                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2115 #endif
2116 }
2117
2118 static void gpu_opcode_btst(void)
2119 {
2120 #ifdef GPU_DIS_BTST
2121         if (doGPUDis)
2122                 WriteLog("%06X: BTST   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2123 #endif
2124         gpu_flag_z = (~RN >> IMM_1) & 1;
2125 #ifdef GPU_DIS_BTST
2126         if (doGPUDis)
2127                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2128 #endif
2129 }
2130
2131 static void gpu_opcode_bset(void)
2132 {
2133 #ifdef GPU_DIS_BSET
2134         if (doGPUDis)
2135                 WriteLog("%06X: BSET   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2136 #endif
2137         uint32 res = RN | (1 << IMM_1);
2138         RN = res;
2139         SET_ZN(res);
2140 #ifdef GPU_DIS_BSET
2141         if (doGPUDis)
2142                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2143 #endif
2144 }
2145
2146 static void gpu_opcode_imacn(void)
2147 {
2148         uint32 res = (int16)RM * (int16)(RN);
2149         gpu_acc += res;
2150 }
2151
2152 static void gpu_opcode_mtoi(void)
2153 {
2154         uint32 _RM = RM;
2155         uint32 res = RN = (((int32)_RM >> 8) & 0xFF800000) | (_RM & 0x007FFFFF);
2156         SET_ZN(res);
2157 }
2158
2159 static void gpu_opcode_normi(void)
2160 {
2161         uint32 _RM = RM;
2162         uint32 res = 0;
2163
2164         if (_RM)
2165         {
2166                 while ((_RM & 0xFFC00000) == 0)
2167                 {
2168                         _RM <<= 1;
2169                         res--;
2170                 }
2171                 while ((_RM & 0xFF800000) != 0)
2172                 {
2173                         _RM >>= 1;
2174                         res++;
2175                 }
2176         }
2177         RN = res;
2178         SET_ZN(res);
2179 }
2180
2181 static void gpu_opcode_mmult(void)
2182 {
2183         int count       = gpu_matrix_control & 0x0F;    // Matrix width
2184         uint32 addr = gpu_pointer_to_matrix;            // In the GPU's RAM
2185         int64 accum = 0;
2186         uint32 res;
2187
2188         if (gpu_matrix_control & 0x10)                          // Column stepping
2189         {
2190                 for(int i=0; i<count; i++)
2191                 {
2192                         int16 a;
2193                         if (i & 0x01)
2194                                 a = (int16)((gpu_alternate_reg[IMM_1 + (i >> 1)] >> 16) & 0xFFFF);
2195                         else
2196                                 a = (int16)(gpu_alternate_reg[IMM_1 + (i >> 1)] & 0xFFFF);
2197
2198                         int16 b = ((int16)GPUReadWord(addr + 2, GPU));
2199                         accum += a * b;
2200                         addr += 4 * count;
2201                 }
2202         }
2203         else                                                                            // Row stepping
2204         {
2205                 for(int i=0; i<count; i++)
2206                 {
2207                         int16 a;
2208                         if (i & 0x01)
2209                                 a = (int16)((gpu_alternate_reg[IMM_1 + (i >> 1)] >> 16) & 0xFFFF);
2210                         else
2211                                 a = (int16)(gpu_alternate_reg[IMM_1 + (i >> 1)] & 0xFFFF);
2212
2213                         int16 b = ((int16)GPUReadWord(addr + 2, GPU));
2214                         accum += a * b;
2215                         addr += 4;
2216                 }
2217         }
2218         RN = res = (int32)accum;
2219         // carry flag to do (out of the last add)
2220         SET_ZN(res);
2221 }
2222
2223 static void gpu_opcode_abs(void)
2224 {
2225 #ifdef GPU_DIS_ABS
2226         if (doGPUDis)
2227                 WriteLog("%06X: ABS    R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2228 #endif
2229         gpu_flag_c = RN >> 31;
2230         if (RN == 0x80000000)
2231         //Is 0x80000000 a positive number? If so, then we need to set C to 0 as well!
2232                 gpu_flag_n = 1, gpu_flag_z = 0;
2233         else
2234         {
2235                 if (gpu_flag_c)
2236                         RN = -RN;
2237                 gpu_flag_n = 0; SET_FLAG_Z(RN);
2238         }
2239 #ifdef GPU_DIS_ABS
2240         if (doGPUDis)
2241                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2242 #endif
2243 }
2244
2245 static void gpu_opcode_div(void)        // RN / RM
2246 {
2247 #ifdef GPU_DIS_DIV
2248         if (doGPUDis)
2249                 WriteLog("%06X: DIV    R%02u, R%02u (%s) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, (gpu_div_control & 0x01 ? "16.16" : "32"), gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2250 #endif
2251 // NOTE: remainder is NOT calculated correctly here!
2252 //       The original tried to get it right by checking to see if the
2253 //       remainder was negative, but that's too late...
2254 // The code there should do it now, but I'm not 100% sure...
2255
2256         if (RM)
2257         {
2258                 if (gpu_div_control & 0x01)             // 16.16 division
2259                 {
2260                         RN = ((uint64)RN << 16) / RM;
2261                         gpu_remain = ((uint64)RN << 16) % RM;
2262                 }
2263                 else
2264                 {
2265                         RN = RN / RM;
2266                         gpu_remain = RN % RM;
2267                 }
2268
2269                 if ((gpu_remain - RM) & 0x80000000)     // If the result would have been negative...
2270                         gpu_remain -= RM;                       // Then make it negative!
2271         }
2272         else
2273                 RN = 0xFFFFFFFF;
2274
2275 /*      uint32 _RM=RM;
2276         uint32 _RN=RN;
2277
2278         if (_RM)
2279         {
2280                 if (gpu_div_control & 1)
2281                 {
2282                         gpu_remain = (((uint64)_RN) << 16) % _RM;
2283                         if (gpu_remain&0x80000000)
2284                                 gpu_remain-=_RM;
2285                         RN = (((uint64)_RN) << 16) / _RM;
2286                 }
2287                 else
2288                 {
2289                         gpu_remain = _RN % _RM;
2290                         if (gpu_remain&0x80000000)
2291                                 gpu_remain-=_RM;
2292                         RN/=_RM;
2293                 }
2294         }
2295         else
2296                 RN=0xffffffff;*/
2297 #ifdef GPU_DIS_DIV
2298         if (doGPUDis)
2299                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] Remainder: %08X\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN, gpu_remain);
2300 #endif
2301 }
2302
2303 static void gpu_opcode_imultn(void)
2304 {
2305         uint32 res = (int32)((int16)RN * (int16)RM);
2306         gpu_acc = (int32)res;
2307         SET_FLAG_Z(res);
2308         SET_FLAG_N(res);
2309 }
2310
2311 static void gpu_opcode_neg(void)
2312 {
2313 #ifdef GPU_DIS_NEG
2314         if (doGPUDis)
2315                 WriteLog("%06X: NEG    R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2316 #endif
2317         uint32 res = -RN;
2318         SET_ZNC_SUB(0, RN, res);
2319         RN = res;
2320 #ifdef GPU_DIS_NEG
2321         if (doGPUDis)
2322                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2323 #endif
2324 }
2325
2326 static void gpu_opcode_shlq(void)
2327 {
2328 #ifdef GPU_DIS_SHLQ
2329         if (doGPUDis)
2330                 WriteLog("%06X: SHLQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, 32 - IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2331 #endif
2332 // Was a bug here...
2333 // (Look at Aaron's code: If r1 = 32, then 32 - 32 = 0 which is wrong!)
2334         int32 r1 = 32 - IMM_1;
2335         uint32 res = RN << r1;
2336         SET_ZN(res); gpu_flag_c = (RN >> 31) & 1;
2337         RN = res;
2338 #ifdef GPU_DIS_SHLQ
2339         if (doGPUDis)
2340                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2341 #endif
2342 }
2343
2344 static void gpu_opcode_shrq(void)
2345 {
2346 #ifdef GPU_DIS_SHRQ
2347         if (doGPUDis)
2348                 WriteLog("%06X: SHRQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2349 #endif
2350         int32 r1 = gpu_convert_zero[IMM_1];
2351         uint32 res = RN >> r1;
2352         SET_ZN(res); gpu_flag_c = RN & 1;
2353         RN = res;
2354 #ifdef GPU_DIS_SHRQ
2355         if (doGPUDis)
2356                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2357 #endif
2358 }
2359
2360 static void gpu_opcode_ror(void)
2361 {
2362 #ifdef GPU_DIS_ROR
2363         if (doGPUDis)
2364                 WriteLog("%06X: ROR    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2365 #endif
2366         uint32 r1 = RM & 0x1F;
2367         uint32 res = (RN >> r1) | (RN << (32 - r1));
2368         SET_ZN(res); gpu_flag_c = (RN >> 31) & 1;
2369         RN = res;
2370 #ifdef GPU_DIS_ROR
2371         if (doGPUDis)
2372                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2373 #endif
2374 }
2375
2376 static void gpu_opcode_rorq(void)
2377 {
2378 #ifdef GPU_DIS_RORQ
2379         if (doGPUDis)
2380                 WriteLog("%06X: RORQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2381 #endif
2382         uint32 r1 = gpu_convert_zero[IMM_1 & 0x1F];
2383         uint32 r2 = RN;
2384         uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2385         RN = res;
2386         SET_ZN(res); gpu_flag_c = (r2 >> 31) & 0x01;
2387 #ifdef GPU_DIS_RORQ
2388         if (doGPUDis)
2389                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2390 #endif
2391 }
2392
2393 static void gpu_opcode_sha(void)
2394 {
2395 /*      int dreg = jaguar.op & 31;
2396         int32 r1 = (int32)jaguar.r[(jaguar.op >> 5) & 31];
2397         uint32 r2 = jaguar.r[dreg];
2398         uint32 res;
2399
2400         CLR_ZNC;
2401         if (r1 < 0)
2402         {
2403                 res = (r1 <= -32) ? 0 : (r2 << -r1);
2404                 jaguar.FLAGS |= (r2 >> 30) & 2;
2405         }
2406         else
2407         {
2408                 res = (r1 >= 32) ? ((int32)r2 >> 31) : ((int32)r2 >> r1);
2409                 jaguar.FLAGS |= (r2 << 1) & 2;
2410         }
2411         jaguar.r[dreg] = res;
2412         SET_ZN(res);*/
2413
2414 #ifdef GPU_DIS_SHA
2415         if (doGPUDis)
2416                 WriteLog("%06X: SHA    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2417 #endif
2418         uint32 res;
2419
2420         if ((int32)RM < 0)
2421         {
2422                 res = ((int32)RM <= -32) ? 0 : (RN << -(int32)RM);
2423                 gpu_flag_c = RN >> 31;
2424         }
2425         else
2426         {
2427                 res = ((int32)RM >= 32) ? ((int32)RN >> 31) : ((int32)RN >> (int32)RM);
2428                 gpu_flag_c = RN & 0x01;
2429         }
2430         RN = res;
2431         SET_ZN(res);
2432 #ifdef GPU_DIS_SHA
2433         if (doGPUDis)
2434                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2435 #endif
2436
2437 /*      int32 sRM=(int32)RM;
2438         uint32 _RN=RN;
2439
2440         if (sRM<0)
2441         {
2442                 uint32 shift=-sRM;
2443                 if (shift>=32) shift=32;
2444                 gpu_flag_c=(_RN&0x80000000)>>31;
2445                 while (shift)
2446                 {
2447                         _RN<<=1;
2448                         shift--;
2449                 }
2450         }
2451         else
2452         {
2453                 uint32 shift=sRM;
2454                 if (shift>=32) shift=32;
2455                 gpu_flag_c=_RN&0x1;
2456                 while (shift)
2457                 {
2458                         _RN=((int32)_RN)>>1;
2459                         shift--;
2460                 }
2461         }
2462         RN=_RN;
2463         SET_FLAG_Z(_RN);
2464         SET_FLAG_N(_RN);*/
2465 }
2466
2467 static void gpu_opcode_sharq(void)
2468 {
2469 #ifdef GPU_DIS_SHARQ
2470         if (doGPUDis)
2471                 WriteLog("%06X: SHARQ  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2472 #endif
2473         uint32 res = (int32)RN >> gpu_convert_zero[IMM_1];
2474         SET_ZN(res); gpu_flag_c = RN & 0x01;
2475         RN = res;
2476 #ifdef GPU_DIS_SHARQ
2477         if (doGPUDis)
2478                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN);
2479 #endif
2480 }
2481
2482 static void gpu_opcode_sh(void)
2483 {
2484 #ifdef GPU_DIS_SH
2485         if (doGPUDis)
2486                 WriteLog("%06X: SH     R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2487 #endif
2488         if (RM & 0x80000000)            // Shift left
2489         {
2490                 gpu_flag_c = RN >> 31;
2491                 RN = ((int32)RM <= -32 ? 0 : RN << -(int32)RM);
2492         }
2493         else                                            // Shift right
2494         {
2495                 gpu_flag_c = RN & 0x01;
2496                 RN = (RM >= 32 ? 0 : RN >> RM);
2497         }
2498         SET_ZN(RN);
2499 #ifdef GPU_DIS_SH
2500         if (doGPUDis)
2501                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
2502 #endif
2503 }
2504
2505 //Temporary: Testing only!
2506 //#include "gpu2.cpp"
2507 //#include "gpu3.cpp"
2508
2509 #else
2510
2511 // New thread-safe GPU core
2512
2513 int GPUCore(void * data)
2514 {
2515 }
2516
2517 #endif