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