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