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