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