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