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