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