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