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