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