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