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