]> Shamusworld >> Repos - virtualjaguar/blob - src/jaguar.cpp
Added Memory Track support. One small step towards full CD-ROM support.
[virtualjaguar] / src / jaguar.cpp
1 //
2 // JAGUAR.CPP
3 //
4 // Originally by David Raingeard (Cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
6 // Cleanups and endian wrongness amelioration by James Hammons
7 // Note: Endian wrongness probably stems from the MAME origins of this emu and
8 //       the braindead way in which MAME handled memory when this was written. :-)
9 //
10 // JLH = James Hammons
11 //
12 // WHO  WHEN        WHAT
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  11/25/2009  Major rewrite of memory subsystem and handlers
15 //
16
17 #include "jaguar.h"
18
19 #include <time.h>
20 #include <SDL.h>
21 #include "SDL_opengl.h"
22 #include "blitter.h"
23 #include "cdrom.h"
24 #include "dac.h"
25 #include "dsp.h"
26 #include "eeprom.h"
27 #include "event.h"
28 #include "foooked.h"
29 #include "gpu.h"
30 #include "jerry.h"
31 #include "joystick.h"
32 #include "log.h"
33 #include "m68000/m68kinterface.h"
34 //#include "memory.h"
35 #include "memtrack.h"
36 #include "mmu.h"
37 #include "settings.h"
38 #include "tom.h"
39
40 #define CPU_DEBUG
41 //Do this in makefile??? Yes! Could, but it's easier to define here...
42 //#define LOG_UNMAPPED_MEMORY_ACCESSES
43 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
44 //#define ABORT_ON_ILLEGAL_INSTRUCTIONS
45 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
46 #define CPU_DEBUG_MEMORY
47 //#define LOG_CD_BIOS_CALLS
48 #define CPU_DEBUG_TRACING
49 #define ALPINE_FUNCTIONS
50
51 // Private function prototypes
52
53 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
54 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
55 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
56 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
57 void M68K_show_context(void);
58
59 // External variables
60
61 #ifdef CPU_DEBUG_MEMORY
62 extern bool startMemLog;                                                        // Set by "e" key
63 extern int effect_start;
64 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
65 #endif
66
67 // Really, need to include memory.h for this, but it might interfere with some stuff...
68 extern uint8_t jagMemSpace[];
69
70 // Internal variables
71
72 uint32_t jaguar_active_memory_dumps = 0;
73
74 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
75 bool jaguarCartInserted = false;
76 bool lowerField = false;
77
78 #ifdef CPU_DEBUG_MEMORY
79 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
80 uint8_t readMem[0x400000];
81 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
82 #endif
83
84 uint32_t pcQueue[0x400];
85 uint32_t a0Queue[0x400];
86 uint32_t a1Queue[0x400];
87 uint32_t a2Queue[0x400];
88 uint32_t a3Queue[0x400];
89 uint32_t a4Queue[0x400];
90 uint32_t a5Queue[0x400];
91 uint32_t a6Queue[0x400];
92 uint32_t a7Queue[0x400];
93 uint32_t d0Queue[0x400];
94 uint32_t d1Queue[0x400];
95 uint32_t d2Queue[0x400];
96 uint32_t d3Queue[0x400];
97 uint32_t d4Queue[0x400];
98 uint32_t d5Queue[0x400];
99 uint32_t d6Queue[0x400];
100 uint32_t d7Queue[0x400];
101 uint32_t srQueue[0x400];
102 uint32_t pcQPtr = 0;
103 bool startM68KTracing = false;
104
105 // Breakpoint on memory access vars (exported)
106 bool bpmActive = false;
107 uint32_t bpmAddress1;
108
109
110 //
111 // Callback function to detect illegal instructions
112 //
113 void GPUDumpDisassembly(void);
114 void GPUDumpRegisters(void);
115 static bool start = false;
116
117 void M68KInstructionHook(void)
118 {
119         uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
120 // Temp, for comparing...
121 {
122 /*      static char buffer[2048];//, mem[64];
123         m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
124         printf("%08X: %s\n", m68kPC, buffer);//*/
125 }
126 //JaguarDasm(m68kPC, 1);
127 //Testing Hover Strike...
128 #if 0
129 //Dasm(regs.pc, 1);
130 static int hitCount = 0;
131 static int inRoutine = 0;
132 static int instSeen;
133
134 //if (regs.pc == 0x80340A)
135 if (m68kPC == 0x803416)
136 {
137         hitCount++;
138         inRoutine = 1;
139         instSeen = 0;
140         printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
141 }
142 else if (m68kPC == 0x803422)
143 {
144         inRoutine = 0;
145         printf("(%i instructions)\n", instSeen);
146 }
147
148 if (inRoutine)
149         instSeen++;
150 #endif
151
152 // For code tracing...
153 #ifdef CPU_DEBUG_TRACING
154         if (startM68KTracing)
155         {
156                 static char buffer[2048];
157
158                 m68k_disassemble(buffer, m68kPC, 0);
159                 WriteLog("%06X: %s\n", m68kPC, buffer);
160         }
161 #endif
162
163 // For tracebacks...
164 // Ideally, we'd save all the registers as well...
165         pcQueue[pcQPtr] = m68kPC;
166         a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
167         a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
168         a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
169         a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
170         a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
171         a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
172         a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
173         a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
174         d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
175         d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
176         d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
177         d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
178         d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
179         d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
180         d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
181         d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
182         srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR);
183         pcQPtr++;
184         pcQPtr &= 0x3FF;
185
186         if (m68kPC & 0x01)              // Oops! We're fetching an odd address!
187         {
188                 WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
189
190                 static char buffer[2048];
191                 for(int i=0; i<0x400; i++)
192                 {
193 //                      WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
194                         WriteLog("[A0=%08X, A1=%08X, A2=%08X, A3=%08X, A4=%08X, A5=%08X, A6=%08X, A7=%08X, D0=%08X, D1=%08X, D2=%08X, D3=%08X, D4=%08X, D5=%08X, D6=%08X, D7=%08X, SR=%04X]\n", a0Queue[(pcQPtr + i) & 0x3FF], a1Queue[(pcQPtr + i) & 0x3FF], a2Queue[(pcQPtr + i) & 0x3FF], a3Queue[(pcQPtr + i) & 0x3FF], a4Queue[(pcQPtr + i) & 0x3FF], a5Queue[(pcQPtr + i) & 0x3FF], a6Queue[(pcQPtr + i) & 0x3FF], a7Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF], d1Queue[(pcQPtr + i) & 0x3FF], d2Queue[(pcQPtr + i) & 0x3FF], d3Queue[(pcQPtr + i) & 0x3FF], d4Queue[(pcQPtr + i) & 0x3FF], d5Queue[(pcQPtr + i) & 0x3FF], d6Queue[(pcQPtr + i) & 0x3FF], d7Queue[(pcQPtr + i) & 0x3FF], srQueue[(pcQPtr + i) & 0x3FF]);
195                         m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
196                         WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
197                 }
198                 WriteLog("\n");
199
200                 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
201                 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
202                 for(int i=0; i<10; i++)
203                         WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
204                 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
205                 M68K_show_context();
206                 LogDone();
207                 exit(0);
208         }
209
210         // Disassemble everything
211 /*      {
212                 static char buffer[2048];
213                 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
214                 WriteLog("%08X: %s", m68kPC, buffer);
215                 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
216                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
217                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
218         }//*/
219 /*      if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
220         {
221                 static char buffer[2048];
222                 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
223                 WriteLog("%08X: %s", m68kPC, buffer);
224                 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
225                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
226                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
227         }//*/
228 /*      if (m68kPC == 0x8D0E48 && effect_start5)
229         {
230                 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
231                 GPUDumpRegisters();
232                 GPUDumpDisassembly();
233                 log_done();
234                 exit(0);
235         }//*/
236 /*      uint16_t opcode = JaguarReadWord(m68kPC);
237         if (opcode == 0x4E75)   // RTS
238         {
239                 if (startMemLog)
240 //                      WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
241                 {
242                         uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
243                         bool found = false;
244                         if (raPtr != 0xFFFFFFFF)
245                         {
246                                 for(uint32_t i=0; i<=raPtr; i++)
247                                 {
248                                         if (returnAddr[i] == addr)
249                                         {
250                                                 found = true;
251                                                 break;
252                                         }
253                                 }
254                         }
255
256                         if (!found)
257                                 returnAddr[++raPtr] = addr;
258                 }
259         }//*/
260
261 //Flip Out! debugging...
262 //805F46, 806486
263 /*
264 00805FDC: movea.l #$9c6f8, A0           D0=00100010, A0=00100000
265 00805FE2: move.w  #$10, (A0)+           D0=00100010, A0=0009C6F8
266 00805FE6: cmpa.l  #$c96f8, A0           D0=00100010, A0=0009C6FA
267 00805FEC: bne     805fe2                D0=00100010, A0=0009C6FA
268
269 0080603A: move.l  #$11ed7c, $100.w              D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
270
271 0012314C: move.l  (A0)+, (A1)+          D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
272 0012314E: cmpa.l  #$f04000, A1          D0=61700080, A0=00124178, D1=00000000, A1=00F04000
273 00123154: blt     12314c                D0=61700080, A0=00124178, D1=00000000, A1=00F04000
274 00123156: move.l  #$0, $f035d0.l                D0=61700080, A0=00124178, D1=00000000, A1=00F04000
275 00123160: move.l  #$f03000, $f02110.l           D0=61700080, A0=00124178, D1=00000000, A1=00F04000
276 0012316A: move.l  #$1, $f02114.l                D0=61700080, A0=00124178, D1=00000000, A1=00F04000
277 00123174: rts           D0=61700080, A0=00124178, D1=00000000, A1=00F04000
278 */
279 /*      static char buffer[2048];
280 //if (m68kPC > 0x805F48) start = true;
281 //if (m68kPC > 0x806486) start = true;
282 //if (m68kPC == 0x805FEE) start = true;
283 //if (m68kPC == 0x80600C)// start = true;
284 if (m68kPC == 0x802058) start = true;
285 //{
286 //      GPUDumpRegisters();
287 //      GPUDumpDisassembly();
288 //
289 //      M68K_show_context();
290 //      log_done();
291 //      exit(0);
292 //}
293         if (start)
294         {
295         m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
296         WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1));
297         }//*/
298
299 /*      if (m68kPC == 0x803F16)
300         {
301                 WriteLog("M68K: Registers found at $803F16:\n");
302                 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
303                 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
304                         WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
305                 WriteLog("\n");
306                 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
307                         WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
308         }*/
309 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
310 // !!! Investigate !!!
311 /*extern bool doDSPDis;
312         static bool disgo = false;
313         if (m68kPC == 0x50222)
314         {
315                 // CD BIOS hacking
316 //              WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
317 //              DSPWriteLong(0xF1B000, 0x12345678, M68K);
318 //              disgo = true;
319         }
320         if (m68kPC == 0x5000)
321 //              doDSPDis = true;
322                 disgo = true;
323         if (disgo)
324         {
325                 static char buffer[2048];
326                 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
327                 WriteLog("%08X: %s", m68kPC, buffer);
328                 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
329                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
330                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
331         }//*/
332 /*      if (m68kPC == 0x82E1A)
333         {
334                 static char buffer[2048];
335                 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
336                 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
337                 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
338                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
339                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
340         }//*/
341 /*      if (m68kPC == 0x82E58)
342                 WriteLog("--> [Routine end]\n");
343         if (m68kPC == 0x80004)
344         {
345                 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
346 //              m68k_set_reg(M68K_REG_D2, 0x12345678);
347         }//*/
348
349 #ifdef LOG_CD_BIOS_CALLS
350 /*
351 CD_init::       -> $3000
352 BIOS_VER::      -> $3004
353 CD_mode::       -> $3006
354 CD_ack::        -> $300C
355 CD_jeri::       -> $3012
356 CD_spin::       -> $3018
357 CD_stop::       -> $301E
358 CD_mute::       -> $3024
359 CD_umute::      -> $302A
360 CD_paus::       -> $3030
361 CD_upaus::      -> $3036
362 CD_read::       -> $303C
363 CD_uread::      -> $3042
364 CD_setup::      -> $3048
365 CD_ptr::        -> $304E
366 CD_osamp::      -> $3054
367 CD_getoc::      -> $305A
368 CD_initm::      -> $3060
369 CD_initf::      -> $3066
370 CD_switch::     -> $306C
371 */
372         if (m68kPC == 0x3000)
373                 WriteLog("M68K: CD_init\n");
374         else if (m68kPC == 0x3006 + (6 * 0))
375                 WriteLog("M68K: CD_mode\n");
376         else if (m68kPC == 0x3006 + (6 * 1))
377                 WriteLog("M68K: CD_ack\n");
378         else if (m68kPC == 0x3006 + (6 * 2))
379                 WriteLog("M68K: CD_jeri\n");
380         else if (m68kPC == 0x3006 + (6 * 3))
381                 WriteLog("M68K: CD_spin\n");
382         else if (m68kPC == 0x3006 + (6 * 4))
383                 WriteLog("M68K: CD_stop\n");
384         else if (m68kPC == 0x3006 + (6 * 5))
385                 WriteLog("M68K: CD_mute\n");
386         else if (m68kPC == 0x3006 + (6 * 6))
387                 WriteLog("M68K: CD_umute\n");
388         else if (m68kPC == 0x3006 + (6 * 7))
389                 WriteLog("M68K: CD_paus\n");
390         else if (m68kPC == 0x3006 + (6 * 8))
391                 WriteLog("M68K: CD_upaus\n");
392         else if (m68kPC == 0x3006 + (6 * 9))
393                 WriteLog("M68K: CD_read\n");
394         else if (m68kPC == 0x3006 + (6 * 10))
395                 WriteLog("M68K: CD_uread\n");
396         else if (m68kPC == 0x3006 + (6 * 11))
397                 WriteLog("M68K: CD_setup\n");
398         else if (m68kPC == 0x3006 + (6 * 12))
399                 WriteLog("M68K: CD_ptr\n");
400         else if (m68kPC == 0x3006 + (6 * 13))
401                 WriteLog("M68K: CD_osamp\n");
402         else if (m68kPC == 0x3006 + (6 * 14))
403                 WriteLog("M68K: CD_getoc\n");
404         else if (m68kPC == 0x3006 + (6 * 15))
405                 WriteLog("M68K: CD_initm\n");
406         else if (m68kPC == 0x3006 + (6 * 16))
407                 WriteLog("M68K: CD_initf\n");
408         else if (m68kPC == 0x3006 + (6 * 17))
409                 WriteLog("M68K: CD_switch\n");
410
411         if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
412                 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
413                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
414                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
415 #endif
416
417 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
418         if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
419         {
420 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
421                 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
422                 {
423                         // This is a kludge to let homebrew programs work properly (i.e., let the other processors
424                         // keep going even when the 68K dumped back to the debugger or what have you).
425 //dis no wok right!
426 //                      m68k_set_reg(M68K_REG_PC, m68kPC - 2);
427 // Try setting the vector to the illegal instruction...
428 //This doesn't work right either! Do something else! Quick!
429 //                      SET32(jaguar_mainRam, 0x10, m68kPC);
430
431                         return;
432                 }
433 #endif
434
435                 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
436                 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
437                 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
438                 uint32_t address = topOfStack - (4 * 4 * 3);
439
440                 for(int i=0; i<10; i++)
441                 {
442                         WriteLog("%06X:", address);
443
444                         for(int j=0; j<4; j++)
445                         {
446                                 WriteLog(" %08X", JaguarReadLong(address));
447                                 address += 4;
448                         }
449
450                         WriteLog("\n");
451                 }
452
453                 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
454                 M68K_show_context();
455
456 //temp
457 //      WriteLog("\n\n68K disasm\n\n");
458 //      jaguar_dasm(0x802000, 0x50C);
459 //      WriteLog("\n\n");
460 //endoftemp
461
462                 LogDone();
463                 exit(0);
464         }//*/
465 #endif
466 }
467
468 #if 0
469 Now here be dragons...
470 Here is how memory ranges are defined in the CoJag driver.
471 Note that we only have to be concerned with 3 entities read/writing anything:
472 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
473 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
474 things that are entirely internal to those modules. This way we should be able to get a handle on all
475 this crap which is currently scattered over Hell's Half Acre(tm).
476
477 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
478 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
479
480 /*************************************
481  *
482  *  Main CPU memory handlers
483  *
484  *************************************/
485
486 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
487         AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
488         AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
489         AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
490         AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
491         AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
492         AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
493         AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
494         AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
495         AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide",  ide_controller32_r, ide_controller32_w)
496         AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
497         AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
498         AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
499         AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
500         AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
501         AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
502         AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
503         AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r)                  // GPI03
504 //  AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w)  // GPI04
505         AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r)                   // GPI05
506         AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
507         AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
508         AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
509 ADDRESS_MAP_END
510
511 /*************************************
512  *
513  *  GPU memory handlers
514  *
515  *************************************/
516
517 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
518         AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
519         AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
520         AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
521         AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
522         AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
523         AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
524         AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
525         AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
526         AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
527         AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
528 ADDRESS_MAP_END
529
530 /*************************************
531  *
532  *  DSP memory handlers
533  *
534  *************************************/
535
536 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
537         AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
538         AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
539         AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
540         AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
541         AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
542         AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
543         AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
544         AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
545 ADDRESS_MAP_END
546 */
547 #endif
548
549 //#define EXPERIMENTAL_MEMORY_HANDLING
550 // Experimental memory mappage...
551 // Dunno if this is a good approach or not, but it seems to make better
552 // sense to have all this crap in one spot intstead of scattered all over
553 // the place the way it is now.
554 #ifdef EXPERIMENTAL_MEMORY_HANDLING
555 // Needed defines...
556 #define NEW_TIMER_SYSTEM
557
558 /*
559 uint8_t jaguarMainRAM[0x400000];                                                // 68K CPU RAM
560 uint8_t jaguarMainROM[0x600000];                                                // 68K CPU ROM
561 uint8_t jaguarBootROM[0x040000];                                                // 68K CPU BIOS ROM--uses only half of this!
562 uint8_t jaguarCDBootROM[0x040000];                                      // 68K CPU CD BIOS ROM
563 bool BIOSLoaded = false;
564 bool CDBIOSLoaded = false;
565
566 uint8_t cdRAM[0x100];
567 uint8_t tomRAM[0x4000];
568 uint8_t jerryRAM[0x10000];
569 static uint16_t eeprom_ram[64];
570
571 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
572 */
573
574 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
575
576 // M68K Memory map/handlers
577 uint32_t        {
578         { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
579         { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
580 // Note that this is really memory mapped I/O region...
581 //      { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
582         { 0xDFFF00, 0xDFFF03, MM_IO,  cdBUTCH }, // base of Butch == interrupt control register, R/W
583         { 0xDFFF04, 0xDFFF07, MM_IO,  cdDSCNTRL }, // DSA control register, R/W
584         { 0xDFFF0A, 0xDFFF0B, MM_IO,  cdDS_DATA }, // DSA TX/RX data, R/W
585         { 0xDFFF10, 0xDFFF13, MM_IO,  cdI2CNTRL }, // i2s bus control register, R/W
586         { 0xDFFF14, 0xDFFF17, MM_IO,  cdSBCNTRL }, // CD subcode control register, R/W
587         { 0xDFFF18, 0xDFFF1B, MM_IO,  cdSUBDATA }, // Subcode data register A
588         { 0xDFFF1C, 0xDFFF1F, MM_IO,  cdSUBDATB }, // Subcode data register B
589         { 0xDFFF20, 0xDFFF23, MM_IO,  cdSB_TIME }, // Subcode time and compare enable (D24)
590         { 0xDFFF24, 0xDFFF27, MM_IO,  cdFIFO_DATA }, // i2s FIFO data
591         { 0xDFFF28, 0xDFFF2B, MM_IO,  cdI2SDAT2 }, // i2s FIFO data (old)
592         { 0xDFFF2C, 0xDFFF2F, MM_IO,  cdUNKNOWN }, // Seems to be some sort of I2S interface
593
594         { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
595
596 //      { 0xF00000, 0xF0FFFF, MM_IO,  TOM_REGS_RW },
597         { 0xF00050, 0xF00051, MM_IO,  tomTimerPrescaler },
598         { 0xF00052, 0xF00053, MM_IO,  tomTimerDivider },
599         { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
600         { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
601         //What about LBUF writes???
602         { 0xF02100, 0xF0211F, MM_IO,  GPUWriteByte }, // GPU CONTROL
603         { 0xF02200, 0xF0229F, MM_IO,  BlitterWriteByte }, // BLITTER
604         { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
605
606         { 0xF10000, 0xF1FFFF, MM_IO,  JERRY_REGS_RW },
607
608 /*
609         EEPROM:
610         { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
611         { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
612         { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
613
614         JOYSTICK:
615         { 0xF14000, 0xF14003, MM_IO,  joystickFoo }
616         0 = pad0/1 button values (4 bits each), RO(?)
617         1 = pad0/1 index value (4 bits each), WO
618         2 = unused, RO
619         3 = NTSC/PAL, certain button states, RO
620
621 JOYSTICK    $F14000               Read/Write
622             15.....8  7......0
623 Read        fedcba98  7654321q    f-1    Signals J15 to J1
624                                   q      Cartridge EEPROM  output data
625 Write       exxxxxxm  76543210    e      1 = enable  J7-J0 outputs
626                                          0 = disable J7-J0 outputs
627                                   x      don't care
628                                   m      Audio mute
629                                          0 = Audio muted (reset state)
630                                          1 = Audio enabled
631                                   7-4    J7-J4 outputs (port 2)
632                                   3-0    J3-J0 outputs (port 1)
633 JOYBUTS     $F14002               Read Only
634             15.....8  7......0
635 Read        xxxxxxxx  rrdv3210    x      don't care
636                                   r      Reserved
637                                   d      Reserved
638                                   v      1 = NTSC Video hardware
639                                          0 = PAL  Video hardware
640                                   3-2    Button inputs B3 & B2 (port 2)
641                                   1-0    Button inputs B1 & B0 (port 1)
642
643 J4 J5 J6 J7  Port 2    B2     B3    J12  J13   J14  J15
644 J3 J2 J1 J0  Port 1    B0     B1    J8   J9    J10  J11
645  0  0  0  0
646  0  0  0  1
647  0  0  1  0
648  0  0  1  1
649  0  1  0  0
650  0  1  0  1
651  0  1  1  0
652  0  1  1  1  Row 3     C3   Option  #     9     6     3
653  1  0  0  0
654  1  0  0  1
655  1  0  1  0
656  1  0  1  1  Row 2     C2      C    0     8     5     2
657  1  1  0  0
658  1  1  0  1  Row 1     C1      B    *     7     4     1
659  1  1  1  0  Row 0   Pause     A    Up  Down  Left  Right
660  1  1  1  1
661
662 0 bit read in any position means that button is pressed.
663 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
664 */
665 };
666
667 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
668 {
669         // Not sure, but I think the system only has 24 address bits...
670         address &= 0x00FFFFFF;
671
672         // RAM                  ($000000 - $3FFFFF)             4M
673         if (address <= 0x3FFFFF)
674                 jaguarMainRAM[address] = byte;
675         // hole                 ($400000 - $7FFFFF)             4M
676         else if (address <= 0x7FFFFF)
677                 ;       // Do nothing
678         // GAME ROM             ($800000 - $DFFEFF)             6M - 256 bytes
679         else if (address <= 0xDFFEFF)
680                 ;       // Do nothing
681         // CDROM                ($DFFF00 - $DFFFFF)             256 bytes
682         else if (address <= 0xDFFFFF)
683         {
684                 cdRAM[address & 0xFF] = byte;
685 #ifdef CDROM_LOG
686                 if ((address & 0xFF) < 12 * 4)
687                         WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
688                 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
689 #endif
690         }
691         // BIOS ROM             ($E00000 - $E3FFFF)             256K
692         else if (address <= 0xE3FFFF)
693                 ;       // Do nothing
694         // hole                 ($E40000 - $EFFFFF)             768K
695         else if (address <= 0xEFFFFF)
696                 ;       // Do nothing
697         // TOM                  ($F00000 - $F0FFFF)             64K
698         else if (address <= 0xF0FFFF)
699 //              ;       // Do nothing
700         {
701                 if (address == 0xF00050)
702                 {
703                         tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
704                         TOMResetPIT();
705                         return;
706                 }
707                 else if (address == 0xF00051)
708                 {
709                         tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
710                         TOMResetPIT();
711                         return;
712                 }
713                 else if (address == 0xF00052)
714                 {
715                         tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
716                         TOMResetPIT();
717                         return;
718                 }
719                 else if (address == 0xF00053)
720                 {
721                         tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
722                         TOMResetPIT();
723                         return;
724                 }
725                 else if (address >= 0xF00400 && address <= 0xF007FF)    // CLUT (A & B)
726                 {
727                         // Writing to one CLUT writes to the other
728                         address &= 0x5FF;               // Mask out $F00600 (restrict to $F00400-5FF)
729                         tomRAM[address] = tomRAM[address + 0x200] = byte;
730                         return;
731                 }
732                 //What about LBUF writes???
733                 else if ((address >= 0xF02100) && (address <= 0xF0211F))        // GPU CONTROL
734                 {
735                         GPUWriteByte(address, byte, who);
736                         return;
737                 }
738                 else if ((address >= 0xF02200) && (address <= 0xF0229F))        // BLITTER
739                 {
740                         BlitterWriteByte(address, byte, who);
741                         return;
742                 }
743                 else if ((address >= 0xF03000) && (address <= 0xF03FFF))        // GPU RAM
744                 {
745                         GPUWriteByte(address, byte, who);
746                         return;
747                 }
748
749                 tomRAM[address & 0x3FFF] = byte;
750         }
751         // JERRY                ($F10000 - $F1FFFF)             64K
752         else if (address <= 0xF1FFFF)
753 //              ;       // Do nothing
754         {
755 #ifdef JERRY_DEBUG
756                 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
757 #endif
758                 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
759                 {
760                         DSPWriteByte(address, byte, who);
761                         return;
762                 }
763                 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
764                 {
765                         DSPWriteByte(address, byte, who);
766                         return;
767                 }
768                 // SCLK ($F1A150--8 bits wide)
769 //NOTE: This should be taken care of in DAC...
770                 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
771                 {
772 //              WriteLog("JERRY: Writing %02X to SCLK...\n", data);
773                         if ((address & 0x03) == 2)
774                                 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
775                         else
776                                 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
777
778                         JERRYI2SInterruptTimer = -1;
779 #ifndef NEW_TIMER_SYSTEM
780                         jerry_i2s_exec(0);
781 #else
782                         RemoveCallback(JERRYI2SCallback);
783                         JERRYI2SCallback();
784 #endif
785 //                      return;
786                 }
787                 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
788                 else if (address >= 0xF1A148 && address <= 0xF1A157)
789                 {
790                         DACWriteByte(address, byte, who);
791                         return;
792                 }
793                 else if (address >= 0xF10000 && address <= 0xF10007)
794                 {
795 #ifndef NEW_TIMER_SYSTEM
796                         switch (address & 0x07)
797                         {
798                         case 0:
799                                 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
800                                 JERRYResetPIT1();
801                                 break;
802                         case 1:
803                                 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
804                                 JERRYResetPIT1();
805                                 break;
806                         case 2:
807                                 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
808                                 JERRYResetPIT1();
809                                 break;
810                         case 3:
811                                 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
812                                 JERRYResetPIT1();
813                                 break;
814                         case 4:
815                                 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
816                                 JERRYResetPIT2();
817                                 break;
818                         case 5:
819                                 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
820                                 JERRYResetPIT2();
821                                 break;
822                         case 6:
823                                 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
824                                 JERRYResetPIT2();
825                                 break;
826                         case 7:
827                                 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
828                                 JERRYResetPIT2();
829                         }
830 #else
831 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
832 #endif
833                         return;
834                 }
835 /*      else if ((offset >= 0xF10010) && (offset <= 0xF10015))
836         {
837                 clock_byte_write(offset, byte);
838                 return;
839         }//*/
840         // JERRY -> 68K interrupt enables/latches (need to be handled!)
841                 else if (address >= 0xF10020 && address <= 0xF10023)
842                 {
843 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
844                 }
845 /*      else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
846         {
847                 anajoy_byte_write(offset, byte);
848                 return;
849         }*/
850                 else if ((address >= 0xF14000) && (address <= 0xF14003))
851                 {
852                         JoystickWriteByte(address, byte);
853                         EepromWriteByte(address, byte);
854                         return;
855                 }
856                 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
857                 {
858                         EepromWriteByte(address, byte);
859                         return;
860                 }
861 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
862                 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
863                         return;
864
865                 jerryRAM[address & 0xFFFF] = byte;
866         }
867         // hole                 ($F20000 - $FFFFFF)             1M - 128K
868         else
869                 ;       // Do nothing
870 }
871
872
873 void WriteWord(uint32_t adddress, uint16_t word)
874 {
875 }
876
877
878 void WriteDWord(uint32_t adddress, uint32_t dword)
879 {
880 }
881
882
883 uint8_t ReadByte(uint32_t adddress)
884 {
885 }
886
887
888 uint16_t ReadWord(uint32_t adddress)
889 {
890 }
891
892
893 uint32_t ReadDWord(uint32_t adddress)
894 {
895 }
896 #endif
897
898
899 void ShowM68KContext(void)
900 {
901         printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
902
903         for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
904         {
905                 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
906
907                 if (i == M68K_REG_D3 || i == M68K_REG_D7)
908                         printf("\n");
909         }
910
911         for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
912         {
913                 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
914
915                 if (i == M68K_REG_A3 || i == M68K_REG_A7)
916                         printf("\n");
917         }
918
919         uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
920         uint32_t disPC = currpc - 30;
921         char buffer[128];
922
923         do
924         {
925                 uint32_t oldpc = disPC;
926                 disPC += m68k_disassemble(buffer, disPC, 0);
927                 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
928         }
929         while (disPC < (currpc + 10));
930 }
931
932
933 //
934 // Custom UAE 68000 read/write/IRQ functions
935 //
936
937 #if 0
938 IRQs:
939 =-=-=
940
941       IPL         Name           Vector            Control
942    ---------+---------------+---------------+---------------
943        2      VBLANK IRQ         $100         INT1 bit #0 
944        2      GPU IRQ            $100         INT1 bit #1
945        2      HBLANK IRQ         $100         INT1 bit #2
946        2      Timer IRQ          $100         INT1 bit #3
947
948    Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
949          and are therefore indistinguishable.
950
951    A typical way to install a LEVEL2 handler for the 68000 would be 
952    something like this, you gotta supply "last_line" and "handler".
953    Note that the interrupt is auto vectored thru $100 (not $68)
954
955
956    V_AUTO   = $100
957    VI       = $F004E
958    INT1     = $F00E0
959    INT2     = $F00E2
960    
961    IRQS_HANDLED=$909                ;; VBLANK and TIMER
962
963          move.w   #$2700,sr         ;; no IRQs please
964          move.l   #handler,V_AUTO   ;; install our routine
965
966          move.w   #last_line,VI     ;; scanline where IRQ should occur
967                                     ;; should be 'odd' BTW
968          move.w   #IRQS_HANDLE&$FF,INT1  ;; enable VBLANK + TIMER
969          move.w   #$2100,sr         ;; enable IRQs on the 68K
970          ...
971
972 handler:
973          move.w   d0,-(a7)
974          move.w   INT1,d0
975          btst.b   #0,d0
976          bne.b    .no_blank
977
978          ...
979
980 .no_blank:
981          btst.b   #3,d0
982          beq.b    .no_timer
983       
984          ...
985
986 .no_timer:
987          move.w   #IRQS_HANDLED,INT1      ; clear latch, keep IRQ alive
988          move.w   #0,INT2                 ; let GPU run again
989          move.w   (a7)+,d0
990          rte
991
992    As you can see, if you have multiple INT1 interrupts coming in,
993    you need to check the lower byte of INT1, to see which interrupt
994    happened.
995 #endif
996 int irq_ack_handler(int level)
997 {
998 #ifdef CPU_DEBUG_TRACING
999         if (startM68KTracing)
1000         {
1001                 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1002         }
1003 #endif
1004
1005         // Tracing the IPL lines on the Jaguar schematic yields the following:
1006         // IPL1 is connected to INTL on TOM (OUT to 68K)
1007         // IPL0-2 are also tied to Vcc via 4.7K resistors!
1008         // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
1009         // There doesn't seem to be any other path to IPL0 or 2 on the schematic,
1010         // which means that *all* IRQs to the 68K are routed thru TOM at level 2.
1011         // Which means they're all maskable.
1012
1013         // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work
1014         // OK...
1015         // They aren't, and this causes problems with a, err, specific ROM. :-D
1016
1017         if (level == 2)
1018         {
1019                 m68k_set_irq(0);                                                // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1020                 return 64;                                                              // Set user interrupt #0
1021         }
1022
1023         return M68K_INT_ACK_AUTOVECTOR;
1024 }
1025
1026
1027 //#define USE_NEW_MMU
1028
1029 unsigned int m68k_read_memory_8(unsigned int address)
1030 {
1031 #ifdef ALPINE_FUNCTIONS
1032         // Check if breakpoint on memory is active, and deal with it
1033         if (bpmActive && address == bpmAddress1)
1034                 M68KDebugHalt();
1035 #endif
1036
1037         // Musashi does this automagically for you, UAE core does not :-P
1038         address &= 0x00FFFFFF;
1039 #ifdef CPU_DEBUG_MEMORY
1040         // Note that the Jaguar only has 2M of RAM, not 4!
1041         if ((address >= 0x000000) && (address <= 0x1FFFFF))
1042         {
1043                 if (startMemLog)
1044                         readMem[address] = 1;
1045         }
1046 #endif
1047 //WriteLog("[RM8] Addr: %08X\n", address);
1048 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1049 /*      if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1050                 || address == 0x1AF05E)
1051                 WriteLog("[RM8  PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1052 #ifndef USE_NEW_MMU
1053         unsigned int retVal = 0;
1054
1055         // Note that the Jaguar only has 2M of RAM, not 4!
1056         if ((address >= 0x000000) && (address <= 0x1FFFFF))
1057                 retVal = jaguarMainRAM[address];
1058 //      else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1059         else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1060                 retVal = jaguarMainROM[address - 0x800000];
1061         else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1062 //              retVal = jaguarBootROM[address - 0xE00000];
1063 //              retVal = jaguarDevBootROM1[address - 0xE00000];
1064                 retVal = jagMemSpace[address];
1065         else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1066                 retVal = CDROMReadByte(address);
1067         else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1068                 retVal = TOMReadByte(address, M68K);
1069         else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1070                 retVal = JERRYReadByte(address, M68K);
1071         else
1072                 retVal = jaguar_unknown_readbyte(address, M68K);
1073
1074 //if (address >= 0x2800 && address <= 0x281F)
1075 //      WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1076 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1077 //      WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1078     return retVal;
1079 #else
1080         return MMURead8(address, M68K);
1081 #endif
1082 }
1083
1084
1085 void gpu_dump_disassembly(void);
1086 void gpu_dump_registers(void);
1087
1088 unsigned int m68k_read_memory_16(unsigned int address)
1089 {
1090 #ifdef ALPINE_FUNCTIONS
1091         // Check if breakpoint on memory is active, and deal with it
1092         if (bpmActive && address == bpmAddress1)
1093                 M68KDebugHalt();
1094 #endif
1095
1096         // Musashi does this automagically for you, UAE core does not :-P
1097         address &= 0x00FFFFFF;
1098 #ifdef CPU_DEBUG_MEMORY
1099 /*      if ((address >= 0x000000) && (address <= 0x3FFFFE))
1100         {
1101                 if (startMemLog)
1102                         readMem[address] = 1, readMem[address + 1] = 1;
1103         }//*/
1104 /*      if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1105         {
1106                 return 0x4E71;  // NOP
1107         }
1108         if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1109         {
1110                 return 0x4E71;  // NOP
1111         }
1112         if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1113         {
1114                 return 0x4E71;  // NOP
1115         }
1116         if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1117         {
1118                 return 0x4E71;  // NOP
1119         }
1120         if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1121         {
1122                 return 0x4E71;  // NOP
1123         }
1124         if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1125         {
1126                 return 0x4E71;  // NOP
1127         }//*/
1128 #endif
1129 //WriteLog("[RM16] Addr: %08X\n", address);
1130 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1131 //      for(int i=0; i<10000; i++)
1132         WriteLog("[M68K] In routine #6!\n");//*/
1133 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1134 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C)    // GPU Program #2
1135 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8)    // GPU Program #3
1136 {
1137         WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1138         gpu_dump_registers();
1139         gpu_dump_disassembly();
1140 //      for(int i=0; i<10000; i++)
1141 //              WriteLog("[M68K] About to run GPU!\n");
1142 }//*/
1143 //WriteLog("[WM8  PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1144 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1145 {
1146         if (address == 0x000066A0)
1147         {
1148                 gpu_dump_registers();
1149                 gpu_dump_disassembly();
1150         }
1151         for(int i=0; i<10000; i++)
1152                 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1153 }//*/
1154 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1155 /*      if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1156                 || address == 0x1AF05E)
1157                 WriteLog("[RM16  PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1158 #ifndef USE_NEW_MMU
1159     unsigned int retVal = 0;
1160
1161         // Note that the Jaguar only has 2M of RAM, not 4!
1162         if ((address >= 0x000000) && (address <= 0x1FFFFE))
1163 //              retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1164                 retVal = GET16(jaguarMainRAM, address);
1165 //      else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1166         else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1167         {
1168                 // Memory Track reading...
1169                 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1170                 {
1171                         retVal = MTReadWord(address);
1172                 }
1173                 else
1174                         retVal = (jaguarMainROM[address - 0x800000] << 8)
1175                                 | jaguarMainROM[address - 0x800000 + 1];
1176         }
1177         else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1178 //              retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1179 //              retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1180                 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1181         else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1182                 retVal = CDROMReadWord(address, M68K);
1183         else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1184                 retVal = TOMReadWord(address, M68K);
1185         else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1186                 retVal = JERRYReadWord(address, M68K);
1187         else
1188                 retVal = jaguar_unknown_readword(address, M68K);
1189
1190 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1191 //      WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1192 //if (address >= 0x2800 && address <= 0x281F)
1193 //      WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1194 //$8B3AE -> Transferred from $F1C010
1195 //$8B5E4 -> Only +1 read at $808AA
1196 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1197 //      WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1198     return retVal;
1199 #else
1200         return MMURead16(address, M68K);
1201 #endif
1202 }
1203
1204
1205 unsigned int m68k_read_memory_32(unsigned int address)
1206 {
1207 #ifdef ALPINE_FUNCTIONS
1208         // Check if breakpoint on memory is active, and deal with it
1209         if (bpmActive && address == bpmAddress1)
1210                 M68KDebugHalt();
1211 #endif
1212
1213         // Musashi does this automagically for you, UAE core does not :-P
1214         address &= 0x00FFFFFF;
1215 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1216 /*      if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1217                 WriteLog("[RM32  PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
1218
1219 //WriteLog("--> [RM32]\n");
1220 #ifndef USE_NEW_MMU
1221         uint32_t retVal = 0;
1222
1223         if ((address >= 0x800000) && (address <= 0xDFFEFE))
1224         {
1225                 // Memory Track reading...
1226                 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1227                         retVal = MTReadLong(address);
1228                 else
1229                         retVal = GET32(jaguarMainROM, address - 0x800000);
1230
1231                 return retVal;
1232         }
1233
1234         return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1235 #else
1236         return MMURead32(address, M68K);
1237 #endif
1238 }
1239
1240
1241 void m68k_write_memory_8(unsigned int address, unsigned int value)
1242 {
1243 #ifdef ALPINE_FUNCTIONS
1244         // Check if breakpoint on memory is active, and deal with it
1245         if (bpmActive && address == bpmAddress1)
1246                 M68KDebugHalt();
1247 #endif
1248
1249         // Musashi does this automagically for you, UAE core does not :-P
1250         address &= 0x00FFFFFF;
1251 #ifdef CPU_DEBUG_MEMORY
1252         // Note that the Jaguar only has 2M of RAM, not 4!
1253         if ((address >= 0x000000) && (address <= 0x1FFFFF))
1254         {
1255                 if (startMemLog)
1256                 {
1257                         if (value > writeMemMax[address])
1258                                 writeMemMax[address] = value;
1259                         if (value < writeMemMin[address])
1260                                 writeMemMin[address] = value;
1261                 }
1262         }
1263 #endif
1264 /*if (address == 0x4E00)
1265         WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1266 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1267 //      WriteLog("M68K: Writing %02X at %08X\n", value, address);
1268 //WriteLog("[WM8  PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1269 /*if (effect_start)
1270         if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1271                 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1272 //$53D0
1273 /*if (address >= 0x53D0 && address <= 0x53FF)
1274         printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1275 //Testing AvP on UAE core...
1276 //000075A0: FFFFF80E B6320220 (BITMAP)
1277 /*if (address == 0x75A0 && value == 0xFF)
1278         printf("M68K: (8) Tripwire hit...\n");//*/
1279
1280 #ifndef USE_NEW_MMU
1281         // Note that the Jaguar only has 2M of RAM, not 4!
1282         if ((address >= 0x000000) && (address <= 0x1FFFFF))
1283                 jaguarMainRAM[address] = value;
1284         else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1285                 CDROMWriteByte(address, value, M68K);
1286         else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1287                 TOMWriteByte(address, value, M68K);
1288         else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1289                 JERRYWriteByte(address, value, M68K);
1290         else
1291                 jaguar_unknown_writebyte(address, value, M68K);
1292 #else
1293         MMUWrite8(address, value, M68K);
1294 #endif
1295 }
1296
1297
1298 void m68k_write_memory_16(unsigned int address, unsigned int value)
1299 {
1300 #ifdef ALPINE_FUNCTIONS
1301         // Check if breakpoint on memory is active, and deal with it
1302         if (bpmActive && address == bpmAddress1)
1303                 M68KDebugHalt();
1304 #endif
1305
1306         // Musashi does this automagically for you, UAE core does not :-P
1307         address &= 0x00FFFFFF;
1308 #ifdef CPU_DEBUG_MEMORY
1309         // Note that the Jaguar only has 2M of RAM, not 4!
1310         if ((address >= 0x000000) && (address <= 0x1FFFFE))
1311         {
1312                 if (startMemLog)
1313                 {
1314                         uint8_t hi = value >> 8, lo = value & 0xFF;
1315
1316                         if (hi > writeMemMax[address])
1317                                 writeMemMax[address] = hi;
1318                         if (hi < writeMemMin[address])
1319                                 writeMemMin[address] = hi;
1320
1321                         if (lo > writeMemMax[address+1])
1322                                 writeMemMax[address+1] = lo;
1323                         if (lo < writeMemMin[address+1])
1324                                 writeMemMin[address+1] = lo;
1325                 }
1326         }
1327 #endif
1328 /*if (address == 0x4E00)
1329         WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1330 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1331 //      WriteLog("M68K: Writing %04X at %08X\n", value, address);
1332 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1333 //if (address >= 0xF02200 && address <= 0xF0229F)
1334 //      WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1335 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1336 //      WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1337 /*extern uint32_t totalFrames;
1338 if (address == 0xF02114)
1339         WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1340 if (address == 0xF02110)
1341         WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1342 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1343 //      WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1344
1345 /*if (address == 0x0100)//64*4)
1346         WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1347 /*if (effect_start)
1348         if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1349                 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1350 /*      if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1351                 || address == 0x1AF05E)
1352                 WriteLog("[WM16  PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1353 //$53D0
1354 /*if (address >= 0x53D0 && address <= 0x53FF)
1355         printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1356 //Testing AvP on UAE core...
1357 //000075A0: FFFFF80E B6320220 (BITMAP)
1358 /*if (address == 0x75A0 && value == 0xFFFF)
1359 {
1360         printf("\nM68K: (16) Tripwire hit...\n");
1361         ShowM68KContext();
1362 }//*/
1363
1364 #ifndef USE_NEW_MMU
1365         // Note that the Jaguar only has 2M of RAM, not 4!
1366         if ((address >= 0x000000) && (address <= 0x1FFFFE))
1367         {
1368 /*              jaguar_mainRam[address] = value >> 8;
1369                 jaguar_mainRam[address + 1] = value & 0xFF;*/
1370                 SET16(jaguarMainRAM, address, value);
1371         }
1372         // Memory Track device writes....
1373         else if ((address >= 0x800000) && (address <= 0x87FFFE))
1374         {
1375                 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1376                         MTWriteWord(address, value);
1377         }
1378         else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1379                 CDROMWriteWord(address, value, M68K);
1380         else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1381                 TOMWriteWord(address, value, M68K);
1382         else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1383                 JERRYWriteWord(address, value, M68K);
1384         else
1385         {
1386                 jaguar_unknown_writeword(address, value, M68K);
1387 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1388                 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1389                         m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1390                         m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1391 #endif
1392         }
1393 #else
1394         MMUWrite16(address, value, M68K);
1395 #endif
1396 }
1397
1398
1399 void m68k_write_memory_32(unsigned int address, unsigned int value)
1400 {
1401 #ifdef ALPINE_FUNCTIONS
1402         // Check if breakpoint on memory is active, and deal with it
1403         if (bpmActive && address == bpmAddress1)
1404                 M68KDebugHalt();
1405 #endif
1406
1407         // Musashi does this automagically for you, UAE core does not :-P
1408         address &= 0x00FFFFFF;
1409 /*if (address == 0x4E00)
1410         WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1411 //WriteLog("--> [WM32]\n");
1412 /*if (address == 0x0100)//64*4)
1413         WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1414 /*if (address >= 0xF03214 && address < 0xF0321F)
1415         WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1416 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1417 /*extern bool doGPUDis;
1418 if (address == 0xF03214 && value == 0x88E30047)
1419 //      start = true;
1420         doGPUDis = true;//*/
1421 /*      if (address == 0x51136 || address == 0xFB074)
1422                 WriteLog("[WM32  PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1423 //Testing AvP on UAE core...
1424 //000075A0: FFFFF80E B6320220 (BITMAP)
1425 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1426 {
1427         printf("\nM68K: (32) Tripwire hit...\n");
1428         ShowM68KContext();
1429 }//*/
1430
1431 #ifndef USE_NEW_MMU
1432         m68k_write_memory_16(address, value >> 16);
1433         m68k_write_memory_16(address + 2, value & 0xFFFF);
1434 #else
1435         MMUWrite32(address, value, M68K);
1436 #endif
1437 }
1438
1439
1440 uint32_t JaguarGetHandler(uint32_t i)
1441 {
1442         return JaguarReadLong(i * 4);
1443 }
1444
1445
1446 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1447 {
1448         uint32_t handler = JaguarGetHandler(i);
1449         return (handler && (handler != 0xFFFFFFFF) ? true : false);
1450 }
1451
1452
1453 void M68K_show_context(void)
1454 {
1455         WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1456
1457         for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1458         {
1459                 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1460
1461                 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1462                         WriteLog("\n");
1463         }
1464
1465         for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1466         {
1467                 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1468
1469                 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1470                         WriteLog("\n");
1471         }
1472
1473         WriteLog("68K disasm\n");
1474 //      jaguar_dasm(s68000readPC()-0x1000,0x20000);
1475         JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1476 //      jaguar_dasm(0x5000, 0x14414);
1477
1478 //      WriteLog("\n.......[Cart start]...........\n\n");
1479 //      jaguar_dasm(0x192000, 0x1000);//0x200);
1480
1481         WriteLog("..................\n");
1482
1483         if (TOMIRQEnabled(IRQ_VIDEO))
1484         {
1485                 WriteLog("video int: enabled\n");
1486                 JaguarDasm(JaguarGetHandler(64), 0x200);
1487         }
1488         else
1489                 WriteLog("video int: disabled\n");
1490
1491         WriteLog("..................\n");
1492
1493         for(int i=0; i<256; i++)
1494         {
1495                 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1496                 uint32_t address = (uint32_t)JaguarGetHandler(i);
1497
1498                 if (address == 0)
1499                         WriteLog(".........\n");
1500                 else
1501                         WriteLog("$%08X\n", address);
1502         }
1503 }
1504
1505
1506 //
1507 // Unknown read/write byte/word routines
1508 //
1509
1510 // It's hard to believe that developers would be sloppy with their memory
1511 // writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1512 // has the following code:
1513 //
1514 // 807EC4: movea.l #$f1b000, A1
1515 // 807ECA: movea.l #$8129e0, A0
1516 // 807ED0: move.l  A0, D0
1517 // 807ED2: move.l  #$f1bb94, D1
1518 // 807ED8: sub.l   D0, D1
1519 // 807EDA: lsr.l   #2, D1
1520 // 807EDC: move.l  (A0)+, (A1)+
1521 // 807EDE: dbra    D1, 807edc
1522 //
1523 // The problem is at $807ED0--instead of putting A0 into D0, they really meant
1524 // to put A1 in. This mistake causes it to try and overwrite approximately
1525 // $700000 worth of address space! (That is, unless the 68K causes a bus
1526 // error...)
1527
1528 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1529 {
1530 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1531         WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1532 #endif
1533 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1534 //      extern bool finished;
1535         finished = true;
1536 //      extern bool doDSPDis;
1537         if (who == DSP)
1538                 doDSPDis = true;
1539 #endif
1540 }
1541
1542
1543 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1544 {
1545 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1546         WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1547 #endif
1548 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1549 //      extern bool finished;
1550         finished = true;
1551 //      extern bool doDSPDis;
1552         if (who == DSP)
1553                 doDSPDis = true;
1554 #endif
1555 }
1556
1557
1558 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1559 {
1560 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1561         WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1562 #endif
1563 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1564 //      extern bool finished;
1565         finished = true;
1566 //      extern bool doDSPDis;
1567         if (who == DSP)
1568                 doDSPDis = true;
1569 #endif
1570     return 0xFF;
1571 }
1572
1573
1574 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1575 {
1576 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1577         WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1578 #endif
1579 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1580 //      extern bool finished;
1581         finished = true;
1582 //      extern bool doDSPDis;
1583         if (who == DSP)
1584                 doDSPDis = true;
1585 #endif
1586     return 0xFFFF;
1587 }
1588
1589
1590 //
1591 // Disassemble M68K instructions at the given offset
1592 //
1593
1594 unsigned int m68k_read_disassembler_8(unsigned int address)
1595 {
1596         return m68k_read_memory_8(address);
1597 }
1598
1599
1600 unsigned int m68k_read_disassembler_16(unsigned int address)
1601 {
1602         return m68k_read_memory_16(address);
1603 }
1604
1605
1606 unsigned int m68k_read_disassembler_32(unsigned int address)
1607 {
1608         return m68k_read_memory_32(address);
1609 }
1610
1611
1612 void JaguarDasm(uint32_t offset, uint32_t qt)
1613 {
1614 #ifdef CPU_DEBUG
1615         static char buffer[2048];//, mem[64];
1616         int pc = offset, oldpc;
1617
1618         for(uint32_t i=0; i<qt; i++)
1619         {
1620 /*              oldpc = pc;
1621                 for(int j=0; j<64; j++)
1622                         mem[j^0x01] = jaguar_byte_read(pc + j);
1623
1624                 pc += Dasm68000((char *)mem, buffer, 0);
1625                 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1626                 oldpc = pc;
1627                 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1628                 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1629         }
1630 #endif
1631 }
1632
1633
1634 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1635 {
1636         uint8_t data = 0x00;
1637         offset &= 0xFFFFFF;
1638
1639         // First 2M is mirrored in the $0 - $7FFFFF range
1640         if (offset < 0x800000)
1641                 data = jaguarMainRAM[offset & 0x1FFFFF];
1642         else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1643                 data = jaguarMainROM[offset - 0x800000];
1644         else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1645                 data = CDROMReadByte(offset, who);
1646         else if ((offset >= 0xE00000) && (offset < 0xE40000))
1647 //              data = jaguarBootROM[offset & 0x3FFFF];
1648 //              data = jaguarDevBootROM1[offset & 0x3FFFF];
1649                 data = jagMemSpace[offset];
1650         else if ((offset >= 0xF00000) && (offset < 0xF10000))
1651                 data = TOMReadByte(offset, who);
1652         else if ((offset >= 0xF10000) && (offset < 0xF20000))
1653                 data = JERRYReadByte(offset, who);
1654         else
1655                 data = jaguar_unknown_readbyte(offset, who);
1656
1657         return data;
1658 }
1659
1660
1661 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1662 {
1663         offset &= 0xFFFFFF;
1664
1665         // First 2M is mirrored in the $0 - $7FFFFF range
1666         if (offset < 0x800000)
1667         {
1668                 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1669         }
1670         else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1671         {
1672                 offset -= 0x800000;
1673                 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1674         }
1675 //      else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1676         else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1677                 return CDROMReadWord(offset, who);
1678         else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1679 //              return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1680 //              return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1681                 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1682         else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1683                 return TOMReadWord(offset, who);
1684         else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1685                 return JERRYReadWord(offset, who);
1686
1687         return jaguar_unknown_readword(offset, who);
1688 }
1689
1690
1691 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1692 {
1693 /*      if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1694         {
1695                 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
1696         }//*/
1697 /*      if (offset >= 0x4E00 && offset < 0x4E04)
1698                 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1699 //Need to check for writes in the range of $18FA70 + 8000...
1700 /*if (effect_start)
1701         if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1702                 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1703
1704         offset &= 0xFFFFFF;
1705
1706         // First 2M is mirrored in the $0 - $7FFFFF range
1707         if (offset < 0x800000)
1708         {
1709                 jaguarMainRAM[offset & 0x1FFFFF] = data;
1710                 return;
1711         }
1712         else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1713         {
1714                 CDROMWriteByte(offset, data, who);
1715                 return;
1716         }
1717         else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1718         {
1719                 TOMWriteByte(offset, data, who);
1720                 return;
1721         }
1722         else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1723         {
1724                 JERRYWriteByte(offset, data, who);
1725                 return;
1726         }
1727
1728         jaguar_unknown_writebyte(offset, data, who);
1729 }
1730
1731
1732 uint32_t starCount;
1733 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1734 {
1735 /*      if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1736         {
1737                 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
1738                 WriteLog("     GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
1739         }//*/
1740 /*      if (offset >= 0x4E00 && offset < 0x4E04)
1741                 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1742 /*if (offset == 0x0100)//64*4)
1743         WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1744 if (offset == 0x0102)//64*4)
1745         WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1746 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1747 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1748 //Need to check for writes in the range of $18FA70 + 8000...
1749 /*if (effect_start)
1750         if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1751                 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1752 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1753         WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1754
1755         offset &= 0xFFFFFF;
1756
1757         // First 2M is mirrored in the $0 - $7FFFFF range
1758         if (offset <= 0x7FFFFE)
1759         {
1760 /*
1761 GPU Table (CD BIOS)
1762
1763 1A 69 F0 ($0000) -> Starfield
1764 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1765 1A 79 F0 ($0002)
1766 1A 88 C0 ($0003)
1767 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1768 1A 95 20 ($0005)
1769 1A 9F 08 ($0006)
1770 1A A1 38 ($0007)
1771 1A AB 38 ($0008)
1772 1A B3 C8 ($0009)
1773 1A B9 C0 ($000A)
1774 */
1775
1776 //This MUST be done by the 68K!
1777 /*if (offset == 0x670C)
1778         WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1779
1780 /*extern bool doGPUDis;
1781 //if ((offset == 0x100000 + 75522) && who == GPU)       // 76,226 -> 75522
1782 if ((offset == 0x100000 + 128470) && who == GPU)        // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1783 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1784         doGPUDis = true;//*/
1785 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1786         WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1787 if ((data & 0xFF00) != 0x7700)
1788         WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1789 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1790         return;//*/
1791 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1792         WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1793 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1794         return;//*/
1795 /*extern bool doGPUDis;
1796 if (offset == 0x120216 && who == GPU)
1797         doGPUDis = true;//*/
1798 /*extern uint32_t gpu_pc;
1799 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1800 {
1801         uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1802         uint32_t y = base / 0x300;
1803         uint32_t x = (base - (y * 0x300)) / 2;
1804         WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1805 }//*/
1806 /*
1807 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1808 */
1809 //if (offset == (0x001E17F8 + 0x34))
1810 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1811         data = 0xFE3C;//*/
1812 //      WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1813 /*extern uint32_t gpu_pc;
1814 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1815 {
1816         extern int objectPtr;
1817 //      if (offset > 0x148000)
1818 //              return;
1819         starCount++;
1820         if (starCount > objectPtr)
1821                 return;
1822
1823 //      if (starCount == 1)
1824 //              WriteLog("--> Drawing 1st star...\n");
1825 //
1826 //      uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1827 //      uint32_t y = base / 0x300;
1828 //      uint32_t x = (base - (y * 0x300)) / 2;
1829 //      WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1830
1831 //A star of interest...
1832 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1833 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1834 //JWW: Blitter writing echo 77B3 at 0011D022...
1835 }//*/
1836 //extern bool doGPUDis;
1837 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1838 {
1839 //      doGPUDis = true;
1840         WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1841 //      LogBlit();
1842 }
1843 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1844         WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1845
1846                 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1847                 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1848                 return;
1849         }
1850         else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1851         {
1852                 CDROMWriteWord(offset, data, who);
1853                 return;
1854         }
1855         else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1856         {
1857                 TOMWriteWord(offset, data, who);
1858                 return;
1859         }
1860         else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1861         {
1862                 JERRYWriteWord(offset, data, who);
1863                 return;
1864         }
1865         // Don't bomb on attempts to write to ROM
1866         else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1867                 return;
1868
1869         jaguar_unknown_writeword(offset, data, who);
1870 }
1871
1872
1873 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1874 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1875 {
1876         return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1877 }
1878
1879
1880 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1881 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1882 {
1883 /*      extern bool doDSPDis;
1884         if (offset < 0x400 && !doDSPDis)
1885         {
1886                 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1887                 doDSPDis = true;
1888         }//*/
1889 /*if (offset == 0x0100)//64*4)
1890         WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1891
1892         JaguarWriteWord(offset, data >> 16, who);
1893         JaguarWriteWord(offset+2, data & 0xFFFF, who);
1894 }
1895
1896
1897 void JaguarSetScreenBuffer(uint32_t * buffer)
1898 {
1899         // This is in TOM, but we set it here...
1900         screenBuffer = buffer;
1901 }
1902
1903
1904 void JaguarSetScreenPitch(uint32_t pitch)
1905 {
1906         // This is in TOM, but we set it here...
1907         screenPitch = pitch;
1908 }
1909
1910
1911 //
1912 // Jaguar console initialization
1913 //
1914 void JaguarInit(void)
1915 {
1916         // For randomizing RAM
1917         srand(time(NULL));
1918
1919         // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1920         for(uint32_t i=0; i<0x200000; i+=4)
1921                 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1922
1923 #ifdef CPU_DEBUG_MEMORY
1924         memset(readMem, 0x00, 0x400000);
1925         memset(writeMemMin, 0xFF, 0x400000);
1926         memset(writeMemMax, 0x00, 0x400000);
1927 #endif
1928 //      memset(jaguarMainRAM, 0x00, 0x200000);
1929 //      memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1930 //      memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1931 //NOTE: This *doesn't* fix FlipOut...
1932 //Or does it? Hmm...
1933 //Seems to want $01010101... Dunno why. Investigate!
1934 //      memset(jaguarMainROM, 0x01, 0x600000);  // & set it to all 01s...
1935 //      memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1936         lowerField = false;                                                     // Reset the lower field flag
1937 //temp, for crappy crap that sux
1938 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1939
1940         m68k_pulse_reset();                                                     // Need to do this so UAE disasm doesn't segfault on exit
1941         GPUInit();
1942         DSPInit();
1943         TOMInit();
1944         JERRYInit();
1945         CDROMInit();
1946 }
1947
1948
1949 //New timer based code stuffola...
1950 void HalflineCallback(void);
1951 void RenderCallback(void);
1952 void JaguarReset(void)
1953 {
1954         // Only problem with this approach: It wipes out RAM loaded files...!
1955         // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1956         for(uint32_t i=8; i<0x200000; i+=4)
1957                 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1958
1959         // New timer base code stuffola...
1960         InitializeEventList();
1961 //Need to change this so it uses the single RAM space and load the BIOS
1962 //into it somewhere...
1963 //Also, have to change this here and in JaguarReadXX() currently
1964         // Only use the system BIOS if it's available...! (it's always available now!)
1965         // AND only if a jaguar cartridge has been inserted.
1966         if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1967                 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1968         else
1969                 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1970
1971 //      WriteLog("jaguar_reset():\n");
1972         TOMReset();
1973         JERRYReset();
1974         GPUReset();
1975         DSPReset();
1976         CDROMReset();
1977     m68k_pulse_reset();                                                         // Reset the 68000
1978         WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1979
1980         lowerField = false;                                                             // Reset the lower field flag
1981 //      SetCallbackTime(ScanlineCallback, 63.5555);
1982 //      SetCallbackTime(ScanlineCallback, 31.77775);
1983         SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1984 }
1985
1986
1987 void JaguarDone(void)
1988 {
1989 #ifdef CPU_DEBUG_MEMORY
1990 /*      WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1991
1992         for(uint32_t i=0; i<=raPtr; i++)
1993         {
1994                 WriteLog("\t%08X\n", returnAddr[i]);
1995                 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1996                 jaguar_dasm(returnAddr[i] - 16, 16);
1997                 WriteLog("\n");
1998         }
1999         WriteLog("\n");//*/
2000
2001 /*      int start = 0, end = 0;
2002         bool endTriggered = false, startTriggered = false;
2003         for(int i=0; i<0x400000; i++)
2004         {
2005                 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
2006                 {
2007                         if (!startTriggered)
2008                                 startTriggered = true, endTriggered = false, start = i;
2009
2010                         WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
2011                 }
2012                 else
2013                 {
2014                         if (!endTriggered)
2015                         {
2016                                 end = i - 1, endTriggered = true, startTriggered = false;
2017                                 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
2018                         }
2019                 }
2020         }
2021         WriteLog("\n");//*/
2022 #endif
2023 //#ifdef CPU_DEBUG
2024 //      for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
2025 //              WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
2026         int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
2027         WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2028 #if 0
2029         for(int i=-2; i<9; i++)
2030                 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2031 #else
2032         uint32_t address = topOfStack - (4 * 4 * 3);
2033
2034         for(int i=0; i<10; i++)
2035         {
2036                 WriteLog("%06X:", address);
2037
2038                 for(int j=0; j<4; j++)
2039                 {
2040                         WriteLog(" %08X", JaguarReadLong(address));
2041                         address += 4;
2042                 }
2043
2044                 WriteLog("\n");
2045         }
2046 #endif
2047
2048 /*      WriteLog("\nM68000 disassembly at $802288...\n");
2049         jaguar_dasm(0x802288, 3);
2050         WriteLog("\nM68000 disassembly at $802200...\n");
2051         jaguar_dasm(0x802200, 500);
2052         WriteLog("\nM68000 disassembly at $802518...\n");
2053         jaguar_dasm(0x802518, 100);//*/
2054
2055 /*      WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2056         jaguar_dasm(0x803F00, 500);
2057         WriteLog("\n");//*/
2058
2059 /*      WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2060         jaguar_dasm(0x802B00, 500);
2061         WriteLog("\n");//*/
2062
2063 /*      WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2064         jaguar_dasm(0x809900, 500);
2065         WriteLog("\n");//*/
2066 //8099F8
2067 /*      WriteLog("\n\nDump of $8093C8:\n\n");
2068         for(int i=0x8093C8; i<0x809900; i+=4)
2069                 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2070 /*      WriteLog("\n\nM68000 disassembly at $90006C...\n");
2071         jaguar_dasm(0x90006C, 500);
2072         WriteLog("\n");//*/
2073 /*      WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2074         jaguar_dasm(0x1AC000, 6000);
2075         WriteLog("\n");//*/
2076
2077 //      WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2078         WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2079         WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2080                 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2081         M68K_show_context();
2082 //#endif
2083
2084         CDROMDone();
2085         GPUDone();
2086         DSPDone();
2087         TOMDone();
2088         JERRYDone();
2089
2090         // temp, until debugger is in place
2091 //00802016: jsr     $836F1A.l
2092 //0080201C: jsr     $836B30.l
2093 //00802022: jsr     $836B18.l
2094 //00802028: jsr     $8135F0.l
2095 //00813C1E: jsr     $813F76.l
2096 //00802038: jsr     $836D00.l
2097 //00802098: jsr     $8373A4.l
2098 //008020A2: jsr     $83E24A.l
2099 //008020BA: jsr     $83E156.l
2100 //008020C6: jsr     $83E19C.l
2101 //008020E6: jsr     $8445E8.l
2102 //008020EC: jsr     $838C20.l
2103 //0080211A: jsr     $838ED6.l
2104 //00802124: jsr     $89CA56.l
2105 //0080212A: jsr     $802B48.l
2106 #if 0
2107         WriteLog("-------------------------------------------\n");
2108         JaguarDasm(0x8445E8, 0x200);
2109         WriteLog("-------------------------------------------\n");
2110         JaguarDasm(0x838C20, 0x200);
2111         WriteLog("-------------------------------------------\n");
2112         JaguarDasm(0x838ED6, 0x200);
2113         WriteLog("-------------------------------------------\n");
2114         JaguarDasm(0x89CA56, 0x200);
2115         WriteLog("-------------------------------------------\n");
2116         JaguarDasm(0x802B48, 0x200);
2117         WriteLog("\n\nM68000 disassembly at $802000...\n");
2118         JaguarDasm(0x802000, 6000);
2119         WriteLog("\n");//*/
2120 #endif
2121 /*      WriteLog("\n\nM68000 disassembly at $6004...\n");
2122         JaguarDasm(0x6004, 10000);
2123         WriteLog("\n");//*/
2124 //      WriteLog("\n\nM68000 disassembly at $802000...\n");
2125 //      JaguarDasm(0x802000, 0x1000);
2126 //      WriteLog("\n\nM68000 disassembly at $4100...\n");
2127 //      JaguarDasm(0x4100, 200);
2128 //      WriteLog("\n\nM68000 disassembly at $800800...\n");
2129 //      JaguarDasm(0x800800, 0x1000);
2130 }
2131
2132
2133 // Temp debugging stuff
2134
2135 void DumpMainMemory(void)
2136 {
2137         FILE * fp = fopen("./memdump.bin", "wb");
2138
2139         if (fp == NULL)
2140                 return;
2141
2142         fwrite(jaguarMainRAM, 1, 0x200000, fp);
2143         fclose(fp);
2144 }
2145
2146
2147 uint8_t * GetRamPtr(void)
2148 {
2149         return jaguarMainRAM;
2150 }
2151
2152
2153 //
2154 // New Jaguar execution stack
2155 // This executes 1 frame's worth of code.
2156 //
2157 bool frameDone;
2158 void JaguarExecuteNew(void)
2159 {
2160         frameDone = false;
2161
2162         do
2163         {
2164                 double timeToNextEvent = GetTimeToNextEvent();
2165 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2166
2167                 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2168
2169                 if (vjs.GPUEnabled)
2170                         GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2171
2172                 HandleNextEvent();
2173         }
2174         while (!frameDone);
2175 }
2176
2177
2178 //
2179 // The thing to keep in mind is that the VC is advanced every HALF line,
2180 // regardless of whether the display is interlaced or not. The only difference
2181 // with an interlaced display is that the high bit of VC will be set when the
2182 // lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2183 // lower field, regardless of whether it's in interlace mode or not.
2184 // NB2: Seems it doesn't always, not sure what the constraint is...)
2185 //
2186 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2187 // rendering two fields that are slighty vertically offset from each other.
2188 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2189 // is rendered in this mode so that each field, when overlaid on each other,
2190 // will yield the final picture at the full resolution for the full frame.
2191 //
2192 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2193 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2194 // it will be half this number for a half frame. BUT, since we're counting
2195 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2196 // PAL.
2197 //
2198 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2199 // Half line times are, naturally, half of this. :-P
2200 //
2201 void HalflineCallback(void)
2202 {
2203         uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2204         uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2205         uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2206 //      uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2207         vc++;
2208
2209         // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2210         // So we cut the number of half-lines in a frame in half. :-P
2211         uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2212
2213         if ((vc & 0x7FF) >= numHalfLines)
2214         {
2215                 lowerField = !lowerField;
2216                 // If we're rendering the lower field, set the high bit (#11, counting
2217                 // from 0) of VC
2218                 vc = (lowerField ? 0x0800 : 0x0000);
2219         }
2220
2221 //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2222         TOMWriteWord(0xF00006, vc, JAGUAR);
2223
2224         // Time for Vertical Interrupt?
2225         if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2226         {
2227                 // We don't have to worry about autovectors & whatnot because the Jaguar
2228                 // tells you through its HW registers who sent the interrupt...
2229                 TOMSetPendingVideoInt();
2230                 m68k_set_irq(2);
2231         }
2232
2233         TOMExecHalfline(vc, true);
2234
2235 //Change this to VBB???
2236 //Doesn't seem to matter (at least for Flip Out & I-War)
2237         if ((vc & 0x7FF) == 0)
2238 //      if (vc == vbb)
2239         {
2240                 JoystickExec();
2241                 frameDone = true;
2242         }//*/
2243
2244         SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2245 }
2246