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