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. :-)
10 // JLH = James L. Hammons
13 // --- ---------- -----------------------------------------------------------
14 // JLH 11/25/2009 Major rewrite of memory subsystem and handlers
20 #include "SDL_opengl.h"
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
46 // Private function prototypes
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);
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;
62 // Really, need to include memory.h for this, but it might interfere with some stuff...
63 extern uint8 jagMemSpace[];
67 uint32 jaguar_active_memory_dumps = 0;
69 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
70 bool jaguarCartInserted = false;
72 #ifdef CPU_DEBUG_MEMORY
73 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
74 uint8 readMem[0x400000];
75 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
78 uint32 pcQueue[0x400];
82 // Callback function to detect illegal instructions
84 void GPUDumpDisassembly(void);
85 void GPUDumpRegisters(void);
86 static bool start = false;
88 void M68KInstructionHook(void)
90 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
91 // Temp, for comparing...
93 /* static char buffer[2048];//, mem[64];
94 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
95 printf("%08X: %s\n", m68kPC, buffer);//*/
97 //JaguarDasm(m68kPC, 1);
98 //Testing Hover Strike...
101 static int hitCount = 0;
102 static int inRoutine = 0;
105 //if (regs.pc == 0x80340A)
106 if (m68kPC == 0x803416)
111 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
113 else if (m68kPC == 0x803422)
116 printf("(%i instructions)\n", instSeen);
124 // Ideally, we'd save all the registers as well...
125 pcQueue[pcQPtr++] = m68kPC;
128 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
130 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
132 static char buffer[2048];
133 for(int i=0; i<0x400; i++)
135 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
136 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
140 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
141 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
142 for(int i=0; i<10; i++)
143 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
144 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
150 // Disassemble everything
152 static char buffer[2048];
153 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
154 WriteLog("%08X: %s", m68kPC, buffer);
155 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
156 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
157 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
159 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
161 static char buffer[2048];
162 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
163 WriteLog("%08X: %s", m68kPC, buffer);
164 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
165 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
166 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
168 /* if (m68kPC == 0x8D0E48 && effect_start5)
170 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
172 GPUDumpDisassembly();
176 /* uint16 opcode = JaguarReadWord(m68kPC);
177 if (opcode == 0x4E75) // RTS
180 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
182 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
184 if (raPtr != 0xFFFFFFFF)
186 for(uint32 i=0; i<=raPtr; i++)
188 if (returnAddr[i] == addr)
197 returnAddr[++raPtr] = addr;
201 //Flip Out! debugging...
204 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
205 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
206 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
207 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
209 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
211 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
212 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
213 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
214 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
215 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
216 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
217 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
219 /* static char buffer[2048];
220 //if (m68kPC > 0x805F48) start = true;
221 //if (m68kPC > 0x806486) start = true;
222 //if (m68kPC == 0x805FEE) start = true;
223 //if (m68kPC == 0x80600C)// start = true;
224 if (m68kPC == 0x802058) start = true;
226 // GPUDumpRegisters();
227 // GPUDumpDisassembly();
229 // M68K_show_context();
235 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
236 WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1));
239 /* if (m68kPC == 0x803F16)
241 WriteLog("M68K: Registers found at $803F16:\n");
242 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
243 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
244 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
246 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
247 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
249 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
250 // !!! Investigate !!!
251 /*extern bool doDSPDis;
252 static bool disgo = false;
253 if (m68kPC == 0x50222)
256 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
257 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
260 if (m68kPC == 0x5000)
265 static char buffer[2048];
266 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
267 WriteLog("%08X: %s", m68kPC, buffer);
268 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
269 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
270 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
272 if (m68kPC == 0x82E1A)
274 static char buffer[2048];
275 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
276 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
277 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
278 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
279 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
281 if (m68kPC == 0x82E58)
282 WriteLog("--> [Routine end]\n");
283 if (m68kPC == 0x80004)
285 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
286 // m68k_set_reg(M68K_REG_D2, 0x12345678);
289 #ifdef LOG_CD_BIOS_CALLS
312 if (m68kPC == 0x3000)
313 WriteLog("M68K: CD_init\n");
314 else if (m68kPC == 0x3006 + (6 * 0))
315 WriteLog("M68K: CD_mode\n");
316 else if (m68kPC == 0x3006 + (6 * 1))
317 WriteLog("M68K: CD_ack\n");
318 else if (m68kPC == 0x3006 + (6 * 2))
319 WriteLog("M68K: CD_jeri\n");
320 else if (m68kPC == 0x3006 + (6 * 3))
321 WriteLog("M68K: CD_spin\n");
322 else if (m68kPC == 0x3006 + (6 * 4))
323 WriteLog("M68K: CD_stop\n");
324 else if (m68kPC == 0x3006 + (6 * 5))
325 WriteLog("M68K: CD_mute\n");
326 else if (m68kPC == 0x3006 + (6 * 6))
327 WriteLog("M68K: CD_umute\n");
328 else if (m68kPC == 0x3006 + (6 * 7))
329 WriteLog("M68K: CD_paus\n");
330 else if (m68kPC == 0x3006 + (6 * 8))
331 WriteLog("M68K: CD_upaus\n");
332 else if (m68kPC == 0x3006 + (6 * 9))
333 WriteLog("M68K: CD_read\n");
334 else if (m68kPC == 0x3006 + (6 * 10))
335 WriteLog("M68K: CD_uread\n");
336 else if (m68kPC == 0x3006 + (6 * 11))
337 WriteLog("M68K: CD_setup\n");
338 else if (m68kPC == 0x3006 + (6 * 12))
339 WriteLog("M68K: CD_ptr\n");
340 else if (m68kPC == 0x3006 + (6 * 13))
341 WriteLog("M68K: CD_osamp\n");
342 else if (m68kPC == 0x3006 + (6 * 14))
343 WriteLog("M68K: CD_getoc\n");
344 else if (m68kPC == 0x3006 + (6 * 15))
345 WriteLog("M68K: CD_initm\n");
346 else if (m68kPC == 0x3006 + (6 * 16))
347 WriteLog("M68K: CD_initf\n");
348 else if (m68kPC == 0x3006 + (6 * 17))
349 WriteLog("M68K: CD_switch\n");
351 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
352 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
353 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
354 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
357 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
358 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
360 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
361 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
363 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
364 // keep going even when the 68K dumped back to the debugger or what have you).
366 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
367 // Try setting the vector to the illegal instruction...
368 //This doesn't work right either! Do something else! Quick!
369 // SET32(jaguar_mainRam, 0x10, m68kPC);
375 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
376 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
377 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
378 for(int i=0; i<10; i++)
379 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
380 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
384 // WriteLog("\n\n68K disasm\n\n");
385 // jaguar_dasm(0x802000, 0x50C);
396 Now here be dragons...
397 Here is how memory ranges are defined in the CoJag driver.
398 Note that we only have to be concerned with 3 entities read/writing anything:
399 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
400 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
401 things that are entirely internal to those modules. This way we should be able to get a handle on all
402 this crap which is currently scattered over Hell's Half Acre(tm).
404 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
405 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
407 /*************************************
409 * Main CPU memory handlers
411 *************************************/
413 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
414 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
415 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
416 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
417 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
418 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
419 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
420 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
421 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
422 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
423 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
424 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
425 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
426 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
427 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
428 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
429 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
430 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
431 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
432 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
433 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
434 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
435 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
438 /*************************************
440 * GPU memory handlers
442 *************************************/
444 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
445 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
446 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
447 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
448 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
449 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
450 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
451 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
452 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
453 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
454 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
457 /*************************************
459 * DSP memory handlers
461 *************************************/
463 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
464 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
465 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
466 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
467 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
468 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
469 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
470 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
471 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
476 //#define EXPERIMENTAL_MEMORY_HANDLING
477 // Experimental memory mappage...
478 // Dunno if this is a good approach or not, but it seems to make better
479 // sense to have all this crap in one spot intstead of scattered all over
480 // the place the way it is now.
481 #ifdef EXPERIMENTAL_MEMORY_HANDLING
483 #define NEW_TIMER_SYSTEM
486 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
487 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
488 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
489 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
490 bool BIOSLoaded = false;
491 bool CDBIOSLoaded = false;
494 uint8 tomRAM[0x4000];
495 uint8 jerryRAM[0x10000];
496 static uint16 eeprom_ram[64];
498 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
501 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
503 // M68K Memory map/handlers
505 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
506 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
507 // Note that this is really memory mapped I/O region...
508 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
509 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
510 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
511 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
512 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
513 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
514 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
515 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
516 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
517 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
518 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
519 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
521 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
523 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
524 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
525 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
526 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
527 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
528 //What about LBUF writes???
529 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
530 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
531 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
533 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
537 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
538 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
539 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
542 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
543 0 = pad0/1 button values (4 bits each), RO(?)
544 1 = pad0/1 index value (4 bits each), WO
546 3 = NTSC/PAL, certain button states, RO
548 JOYSTICK $F14000 Read/Write
550 Read fedcba98 7654321q f-1 Signals J15 to J1
551 q Cartridge EEPROM output data
552 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
553 0 = disable J7-J0 outputs
556 0 = Audio muted (reset state)
558 7-4 J7-J4 outputs (port 2)
559 3-0 J3-J0 outputs (port 1)
560 JOYBUTS $F14002 Read Only
562 Read xxxxxxxx rrdv3210 x don't care
565 v 1 = NTSC Video hardware
566 0 = PAL Video hardware
567 3-2 Button inputs B3 & B2 (port 2)
568 1-0 Button inputs B1 & B0 (port 1)
570 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
571 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
579 0 1 1 1 Row 3 C3 Option # 9 6 3
583 1 0 1 1 Row 2 C2 C 0 8 5 2
585 1 1 0 1 Row 1 C1 B * 7 4 1
586 1 1 1 0 Row 0 Pause A Up Down Left Right
589 0 bit read in any position means that button is pressed.
590 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
594 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
596 // Not sure, but I think the system only has 24 address bits...
597 address &= 0x00FFFFFF;
599 // RAM ($000000 - $3FFFFF) 4M
600 if (address <= 0x3FFFFF)
601 jaguarMainRAM[address] = byte;
602 // hole ($400000 - $7FFFFF) 4M
603 else if (address <= 0x7FFFFF)
605 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
606 else if (address <= 0xDFFEFF)
608 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
609 else if (address <= 0xDFFFFF)
611 cdRAM[address & 0xFF] = byte;
613 if ((address & 0xFF) < 12 * 4)
614 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
615 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
618 // BIOS ROM ($E00000 - $E3FFFF) 256K
619 else if (address <= 0xE3FFFF)
621 // hole ($E40000 - $EFFFFF) 768K
622 else if (address <= 0xEFFFFF)
624 // TOM ($F00000 - $F0FFFF) 64K
625 else if (address <= 0xF0FFFF)
628 if (address == 0xF00050)
630 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
634 else if (address == 0xF00051)
636 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
640 else if (address == 0xF00052)
642 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
646 else if (address == 0xF00053)
648 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
652 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
654 // Writing to one CLUT writes to the other
655 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
656 tomRAM[address] = tomRAM[address + 0x200] = byte;
659 //What about LBUF writes???
660 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
662 GPUWriteByte(address, byte, who);
665 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
667 BlitterWriteByte(address, byte, who);
670 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
672 GPUWriteByte(address, byte, who);
676 tomRAM[address & 0x3FFF] = byte;
678 // JERRY ($F10000 - $F1FFFF) 64K
679 else if (address <= 0xF1FFFF)
683 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
685 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
687 DSPWriteByte(address, byte, who);
690 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
692 DSPWriteByte(address, byte, who);
695 // SCLK ($F1A150--8 bits wide)
696 //NOTE: This should be taken care of in DAC...
697 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
699 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
700 if ((address & 0x03) == 2)
701 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
703 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
705 JERRYI2SInterruptTimer = -1;
706 #ifndef NEW_TIMER_SYSTEM
709 RemoveCallback(JERRYI2SCallback);
714 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
715 else if (address >= 0xF1A148 && address <= 0xF1A157)
717 DACWriteByte(address, byte, who);
720 else if (address >= 0xF10000 && address <= 0xF10007)
722 #ifndef NEW_TIMER_SYSTEM
723 switch (address & 0x07)
726 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
730 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
734 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
738 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
742 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
746 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
750 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
754 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
758 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
762 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
764 clock_byte_write(offset, byte);
767 // JERRY -> 68K interrupt enables/latches (need to be handled!)
768 else if (address >= 0xF10020 && address <= 0xF10023)
770 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
772 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
774 anajoy_byte_write(offset, byte);
777 else if ((address >= 0xF14000) && (address <= 0xF14003))
779 JoystickWriteByte(address, byte);
780 EepromWriteByte(address, byte);
783 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
785 EepromWriteByte(address, byte);
788 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
789 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
792 jerryRAM[address & 0xFFFF] = byte;
794 // hole ($F20000 - $FFFFFF) 1M - 128K
799 void WriteWord(uint32 adddress, uint16 word)
803 void WriteDWord(uint32 adddress, uint32 dword)
807 uint8 ReadByte(uint32 adddress)
811 uint16 ReadWord(uint32 adddress)
815 uint32 ReadDWord(uint32 adddress)
821 // Musashi 68000 read/write/IRQ functions
828 IPL Name Vector Control
829 ---------+---------------+---------------+---------------
830 2 VBLANK IRQ $100 INT1 bit #0
831 2 GPU IRQ $100 INT1 bit #1
832 2 HBLANK IRQ $100 INT1 bit #2
833 2 Timer IRQ $100 INT1 bit #3
835 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
836 and are therefore indistinguishable.
838 A typical way to install a LEVEL2 handler for the 68000 would be
839 something like this, you gotta supply "last_line" and "handler".
840 Note that the interrupt is auto vectored thru $100 (not $68)
848 IRQS_HANDLED=$909 ;; VBLANK and TIMER
850 move.w #$2700,sr ;; no IRQs please
851 move.l #handler,V_AUTO ;; install our routine
853 move.w #last_line,VI ;; scanline where IRQ should occur
854 ;; should be 'odd' BTW
855 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
856 move.w #$2100,sr ;; enable IRQs on the 68K
874 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
875 move.w #0,INT2 ; let GPU run again
879 As you can see, if you have multiple INT1 interrupts coming in,
880 you need to check the lower byte of INT1, to see which interrupt
883 int irq_ack_handler(int level)
885 // Tracing the IPL lines on the Jaguar schematic yields the following:
886 // IPL1 is connected to INTL on TOM (OUT to 68K)
887 // IPL0-2 are also tied to Vcc via 4.7K resistors!
888 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
889 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
890 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
892 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
893 // They aren't, and this causes problems with a, err, specific ROM. :-D
897 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
898 return 64; // Set user interrupt #0
901 return M68K_INT_ACK_AUTOVECTOR;
904 //#define USE_NEW_MMU
906 unsigned int m68k_read_memory_8(unsigned int address)
908 #ifdef CPU_DEBUG_MEMORY
909 if ((address >= 0x000000) && (address <= 0x3FFFFF))
912 readMem[address] = 1;
915 //WriteLog("[RM8] Addr: %08X\n", address);
916 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
917 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
918 || address == 0x1AF05E)
919 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
921 unsigned int retVal = 0;
923 if ((address >= 0x000000) && (address <= 0x3FFFFF))
924 retVal = jaguarMainRAM[address];
925 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
926 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
927 retVal = jaguarMainROM[address - 0x800000];
928 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
929 // retVal = jaguarBootROM[address - 0xE00000];
930 // retVal = jaguarDevBootROM1[address - 0xE00000];
931 retVal = jagMemSpace[address];
932 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
933 retVal = CDROMReadByte(address);
934 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
935 retVal = TOMReadByte(address, M68K);
936 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
937 retVal = JERRYReadByte(address, M68K);
939 retVal = jaguar_unknown_readbyte(address, M68K);
941 //if (address >= 0x2800 && address <= 0x281F)
942 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
943 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
944 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
947 return MMURead8(address, M68K);
951 void gpu_dump_disassembly(void);
952 void gpu_dump_registers(void);
954 unsigned int m68k_read_memory_16(unsigned int address)
956 #ifdef CPU_DEBUG_MEMORY
957 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
960 readMem[address] = 1, readMem[address + 1] = 1;
962 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
964 return 0x4E71; // NOP
966 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
968 return 0x4E71; // NOP
970 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
972 return 0x4E71; // NOP
974 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
976 return 0x4E71; // NOP
978 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
980 return 0x4E71; // NOP
982 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
984 return 0x4E71; // NOP
987 //WriteLog("[RM16] Addr: %08X\n", address);
988 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
989 // for(int i=0; i<10000; i++)
990 WriteLog("[M68K] In routine #6!\n");//*/
991 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
992 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
993 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
995 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
996 gpu_dump_registers();
997 gpu_dump_disassembly();
998 // for(int i=0; i<10000; i++)
999 // WriteLog("[M68K] About to run GPU!\n");
1001 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1002 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1004 if (address == 0x000066A0)
1006 gpu_dump_registers();
1007 gpu_dump_disassembly();
1009 for(int i=0; i<10000; i++)
1010 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1012 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1013 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1014 || address == 0x1AF05E)
1015 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1017 unsigned int retVal = 0;
1019 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1020 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1021 retVal = GET16(jaguarMainRAM, address);
1022 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1023 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1024 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1025 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1026 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1027 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1028 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1029 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1030 retVal = CDROMReadWord(address, M68K);
1031 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1032 retVal = TOMReadWord(address, M68K);
1033 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1034 retVal = JERRYReadWord(address, M68K);
1036 retVal = jaguar_unknown_readword(address, M68K);
1038 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1039 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1040 //if (address >= 0x2800 && address <= 0x281F)
1041 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1042 //$8B3AE -> Transferred from $F1C010
1043 //$8B5E4 -> Only +1 read at $808AA
1044 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1045 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1048 return MMURead16(address, M68K);
1052 unsigned int m68k_read_memory_32(unsigned int address)
1054 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1055 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1056 WriteLog("[RM32 PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
1058 //WriteLog("--> [RM32]\n");
1060 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1062 return MMURead32(address, M68K);
1066 void m68k_write_memory_8(unsigned int address, unsigned int value)
1068 #ifdef CPU_DEBUG_MEMORY
1069 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1073 if (value > writeMemMax[address])
1074 writeMemMax[address] = value;
1075 if (value < writeMemMin[address])
1076 writeMemMin[address] = value;
1080 /*if (address == 0x4E00)
1081 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1082 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1083 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1084 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1086 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1087 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1089 /*if (address >= 0x53D0 && address <= 0x53FF)
1090 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1093 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1094 jaguarMainRAM[address] = value;
1095 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1096 CDROMWriteByte(address, value, M68K);
1097 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1098 TOMWriteByte(address, value, M68K);
1099 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1100 JERRYWriteByte(address, value, M68K);
1102 jaguar_unknown_writebyte(address, value, M68K);
1104 MMUWrite8(address, value, M68K);
1108 void m68k_write_memory_16(unsigned int address, unsigned int value)
1110 #ifdef CPU_DEBUG_MEMORY
1111 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1115 uint8 hi = value >> 8, lo = value & 0xFF;
1117 if (hi > writeMemMax[address])
1118 writeMemMax[address] = hi;
1119 if (hi < writeMemMin[address])
1120 writeMemMin[address] = hi;
1122 if (lo > writeMemMax[address+1])
1123 writeMemMax[address+1] = lo;
1124 if (lo < writeMemMin[address+1])
1125 writeMemMin[address+1] = lo;
1129 /*if (address == 0x4E00)
1130 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1131 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1132 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1133 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1134 //if (address >= 0xF02200 && address <= 0xF0229F)
1135 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1136 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1137 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1138 /*extern uint32 totalFrames;
1139 if (address == 0xF02114)
1140 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1141 if (address == 0xF02110)
1142 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1143 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1144 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1146 /*if (address == 0x0100)//64*4)
1147 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1149 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1150 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1151 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1152 || address == 0x1AF05E)
1153 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1155 /*if (address >= 0x53D0 && address <= 0x53FF)
1156 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1159 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1161 /* jaguar_mainRam[address] = value >> 8;
1162 jaguar_mainRam[address + 1] = value & 0xFF;*/
1163 SET16(jaguarMainRAM, address, value);
1165 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1166 CDROMWriteWord(address, value, M68K);
1167 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1168 TOMWriteWord(address, value, M68K);
1169 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1170 JERRYWriteWord(address, value, M68K);
1173 jaguar_unknown_writeword(address, value, M68K);
1174 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1175 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1176 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1177 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1181 MMUWrite16(address, value, M68K);
1185 void m68k_write_memory_32(unsigned int address, unsigned int value)
1187 /*if (address == 0x4E00)
1188 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1189 //WriteLog("--> [WM32]\n");
1190 /*if (address == 0x0100)//64*4)
1191 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1192 /*if (address >= 0xF03214 && address < 0xF0321F)
1193 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1194 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1195 /*extern bool doGPUDis;
1196 if (address == 0xF03214 && value == 0x88E30047)
1198 doGPUDis = true;//*/
1199 /* if (address == 0x51136 || address == 0xFB074)
1200 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1203 m68k_write_memory_16(address, value >> 16);
1204 m68k_write_memory_16(address + 2, value & 0xFFFF);
1206 MMUWrite32(address, value, M68K);
1211 uint32 JaguarGetHandler(uint32 i)
1213 return JaguarReadLong(i * 4);
1216 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1218 uint32 handler = JaguarGetHandler(i);
1219 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1222 void M68K_show_context(void)
1224 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1225 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1226 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1228 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1229 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1231 WriteLog("68K disasm\n");
1232 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1233 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1234 // jaguar_dasm(0x5000, 0x14414);
1236 // WriteLog("\n.......[Cart start]...........\n\n");
1237 // jaguar_dasm(0x192000, 0x1000);//0x200);
1239 WriteLog("..................\n");
1241 if (TOMIRQEnabled(IRQ_VIDEO))
1243 WriteLog("video int: enabled\n");
1244 JaguarDasm(JaguarGetHandler(64), 0x200);
1247 WriteLog("video int: disabled\n");
1249 WriteLog("..................\n");
1251 for(int i=0; i<256; i++)
1253 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1254 uint32 address = (uint32)JaguarGetHandler(i);
1257 WriteLog(".........\n");
1259 WriteLog("$%08X\n", address);
1264 // Unknown read/write byte/word routines
1267 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1268 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1270 // 807EC4: movea.l #$f1b000, A1
1271 // 807ECA: movea.l #$8129e0, A0
1272 // 807ED0: move.l A0, D0
1273 // 807ED2: move.l #$f1bb94, D1
1274 // 807ED8: sub.l D0, D1
1275 // 807EDA: lsr.l #2, D1
1276 // 807EDC: move.l (A0)+, (A1)+
1277 // 807EDE: dbra D1, 807edc
1279 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1280 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1281 // space! (That is, unless the 68K causes a bus error...)
1283 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1285 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1286 WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1288 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1289 // extern bool finished;
1291 // extern bool doDSPDis;
1297 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1299 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1300 WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1302 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1303 // extern bool finished;
1305 // extern bool doDSPDis;
1311 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1313 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1314 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1316 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1317 // extern bool finished;
1319 // extern bool doDSPDis;
1326 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1328 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1329 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1331 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1332 // extern bool finished;
1334 // extern bool doDSPDis;
1342 // Disassemble M68K instructions at the given offset
1345 unsigned int m68k_read_disassembler_8(unsigned int address)
1347 return m68k_read_memory_8(address);
1350 unsigned int m68k_read_disassembler_16(unsigned int address)
1352 return m68k_read_memory_16(address);
1355 unsigned int m68k_read_disassembler_32(unsigned int address)
1357 return m68k_read_memory_32(address);
1360 void JaguarDasm(uint32 offset, uint32 qt)
1363 static char buffer[2048];//, mem[64];
1364 int pc = offset, oldpc;
1366 for(uint32 i=0; i<qt; i++)
1369 for(int j=0; j<64; j++)
1370 mem[j^0x01] = jaguar_byte_read(pc + j);
1372 pc += Dasm68000((char *)mem, buffer, 0);
1373 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1375 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1376 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1381 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1386 if (offset < 0x400000)
1387 data = jaguarMainRAM[offset & 0x3FFFFF];
1388 else if ((offset >= 0x800000) && (offset < 0xC00000))
1389 data = jaguarMainROM[offset - 0x800000];
1390 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1391 data = CDROMReadByte(offset, who);
1392 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1393 // data = jaguarBootROM[offset & 0x3FFFF];
1394 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1395 data = jagMemSpace[offset];
1396 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1397 data = TOMReadByte(offset, who);
1398 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1399 data = JERRYReadByte(offset, who);
1401 data = jaguar_unknown_readbyte(offset, who);
1406 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1409 if (offset <= 0x3FFFFE)
1411 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1413 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1416 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1418 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1419 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1420 return CDROMReadWord(offset, who);
1421 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1422 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1423 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1424 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1425 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1426 return TOMReadWord(offset, who);
1427 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1428 return JERRYReadWord(offset, who);
1430 return jaguar_unknown_readword(offset, who);
1433 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1435 /* if (offset >= 0x4E00 && offset < 0x4E04)
1436 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1437 //Need to check for writes in the range of $18FA70 + 8000...
1439 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1440 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1443 if (offset < 0x400000)
1445 jaguarMainRAM[offset & 0x3FFFFF] = data;
1448 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1450 CDROMWriteByte(offset, data, who);
1453 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1455 TOMWriteByte(offset, data, who);
1458 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1460 JERRYWriteByte(offset, data, who);
1464 jaguar_unknown_writebyte(offset, data, who);
1468 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1470 /* if (offset >= 0x4E00 && offset < 0x4E04)
1471 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1472 /*if (offset == 0x0100)//64*4)
1473 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1474 if (offset == 0x0102)//64*4)
1475 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1476 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1477 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1478 //Need to check for writes in the range of $18FA70 + 8000...
1480 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1481 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1482 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1483 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1487 if (offset <= 0x3FFFFE)
1492 1A 69 F0 ($0000) -> Starfield
1493 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1496 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1505 //This MUST be done by the 68K!
1506 /*if (offset == 0x670C)
1507 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1509 /*extern bool doGPUDis;
1510 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1511 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1512 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1513 doGPUDis = true;//*/
1514 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1515 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1516 if ((data & 0xFF00) != 0x7700)
1517 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1518 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1520 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1521 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1522 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1524 /*extern bool doGPUDis;
1525 if (offset == 0x120216 && who == GPU)
1526 doGPUDis = true;//*/
1527 /*extern uint32 gpu_pc;
1528 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1530 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1531 uint32 y = base / 0x300;
1532 uint32 x = (base - (y * 0x300)) / 2;
1533 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1536 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1538 //if (offset == (0x001E17F8 + 0x34))
1539 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1541 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1542 /*extern uint32 gpu_pc;
1543 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1545 extern int objectPtr;
1546 // if (offset > 0x148000)
1549 if (starCount > objectPtr)
1552 // if (starCount == 1)
1553 // WriteLog("--> Drawing 1st star...\n");
1555 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1556 // uint32 y = base / 0x300;
1557 // uint32 x = (base - (y * 0x300)) / 2;
1558 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1560 //A star of interest...
1561 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1562 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1563 //JWW: Blitter writing echo 77B3 at 0011D022...
1565 //extern bool doGPUDis;
1566 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1569 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1572 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1573 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1575 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1576 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1579 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1581 CDROMWriteWord(offset, data, who);
1584 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1586 TOMWriteWord(offset, data, who);
1589 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1591 JERRYWriteWord(offset, data, who);
1594 // Don't bomb on attempts to write to ROM
1595 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1598 jaguar_unknown_writeword(offset, data, who);
1601 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1602 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1604 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1607 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1608 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1610 /* extern bool doDSPDis;
1611 if (offset < 0x400 && !doDSPDis)
1613 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1616 /*if (offset == 0x0100)//64*4)
1617 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1619 JaguarWriteWord(offset, data >> 16, who);
1620 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1623 void JaguarSetScreenBuffer(uint32 * buffer)
1625 // This is in TOM, but we set it here...
1626 screenBuffer = buffer;
1629 void JaguarSetScreenPitch(uint32 pitch)
1631 // This is in TOM, but we set it here...
1632 screenPitch = pitch;
1636 // Jaguar console initialization
1638 void JaguarInit(void)
1640 #ifdef CPU_DEBUG_MEMORY
1641 memset(readMem, 0x00, 0x400000);
1642 memset(writeMemMin, 0xFF, 0x400000);
1643 memset(writeMemMax, 0x00, 0x400000);
1645 memset(jaguarMainRAM, 0x00, 0x400000);
1646 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1647 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1648 //NOTE: This *doesn't* fix FlipOut...
1649 //Or does it? Hmm...
1650 //Seems to want $01010101... Dunno why. Investigate!
1651 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1652 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1654 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1662 //New timer based code stuffola...
1663 void HalflineCallback(void);
1664 void RenderCallback(void);
1665 void JaguarReset(void)
1667 //Need to change this so it uses the single RAM space and load the BIOS
1668 //into it somewhere...
1669 //Also, have to change this here and in JaguarReadXX() currently
1670 // Only use the system BIOS if it's available...! (it's always available now!)
1671 // AND only if a jaguar cartridge has been inserted.
1672 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1673 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1675 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1677 // WriteLog("jaguar_reset():\n");
1683 m68k_pulse_reset(); // Reset the 68000
1684 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1686 // New timer base code stuffola...
1687 InitializeEventList();
1688 // SetCallbackTime(ScanlineCallback, 63.5555);
1689 // SetCallbackTime(ScanlineCallback, 31.77775);
1690 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1693 void JaguarDone(void)
1695 #ifdef CPU_DEBUG_MEMORY
1696 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1698 for(uint32 i=0; i<=raPtr; i++)
1700 WriteLog("\t%08X\n", returnAddr[i]);
1701 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1702 jaguar_dasm(returnAddr[i] - 16, 16);
1707 /* int start = 0, end = 0;
1708 bool endTriggered = false, startTriggered = false;
1709 for(int i=0; i<0x400000; i++)
1711 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1713 if (!startTriggered)
1714 startTriggered = true, endTriggered = false, start = i;
1716 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1722 end = i - 1, endTriggered = true, startTriggered = false;
1723 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1730 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1731 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1732 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1733 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1734 for(int i=-2; i<9; i++)
1735 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1737 /* WriteLog("\nM68000 disassembly at $802288...\n");
1738 jaguar_dasm(0x802288, 3);
1739 WriteLog("\nM68000 disassembly at $802200...\n");
1740 jaguar_dasm(0x802200, 500);
1741 WriteLog("\nM68000 disassembly at $802518...\n");
1742 jaguar_dasm(0x802518, 100);//*/
1744 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1745 jaguar_dasm(0x803F00, 500);
1748 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1749 jaguar_dasm(0x802B00, 500);
1752 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1753 jaguar_dasm(0x809900, 500);
1756 /* WriteLog("\n\nDump of $8093C8:\n\n");
1757 for(int i=0x8093C8; i<0x809900; i+=4)
1758 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1759 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1760 jaguar_dasm(0x90006C, 500);
1762 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1763 jaguar_dasm(0x1AC000, 6000);
1766 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1767 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1768 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
1769 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1770 M68K_show_context();
1773 #if 0 // This is drawn already...
1774 WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
1775 for(uint32 i=0x64; i<=0x7C; i+=4)
1776 WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
1785 // temp, until debugger is in place
1786 //00802016: jsr $836F1A.l
1787 //0080201C: jsr $836B30.l
1788 //00802022: jsr $836B18.l
1789 //00802028: jsr $8135F0.l
1790 //00813C1E: jsr $813F76.l
1791 //00802038: jsr $836D00.l
1792 //00802098: jsr $8373A4.l
1793 //008020A2: jsr $83E24A.l
1794 //008020BA: jsr $83E156.l
1795 //008020C6: jsr $83E19C.l
1796 //008020E6: jsr $8445E8.l
1797 //008020EC: jsr $838C20.l
1798 //0080211A: jsr $838ED6.l
1799 //00802124: jsr $89CA56.l
1800 //0080212A: jsr $802B48.l
1802 WriteLog("-------------------------------------------\n");
1803 JaguarDasm(0x8445E8, 0x200);
1804 WriteLog("-------------------------------------------\n");
1805 JaguarDasm(0x838C20, 0x200);
1806 WriteLog("-------------------------------------------\n");
1807 JaguarDasm(0x838ED6, 0x200);
1808 WriteLog("-------------------------------------------\n");
1809 JaguarDasm(0x89CA56, 0x200);
1810 WriteLog("-------------------------------------------\n");
1811 JaguarDasm(0x802B48, 0x200);
1812 WriteLog("\n\nM68000 disassembly at $802000...\n");
1813 JaguarDasm(0x802000, 6000);
1816 /* WriteLog("\n\nM68000 disassembly at $4000...\n");
1817 JaguarDasm(0x4000, 10000);
1822 // Main Jaguar execution loop (1 frame)
1824 void JaguarExecute(uint32 * backbuffer, bool render)
1826 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1827 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1828 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1829 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1831 // uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
1832 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1833 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1834 //It seems that they mean it when they say that VDE is the end of object processing.
1835 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1836 //buffer and not to write any more pixels... !!! FIX !!!
1837 // uint16 vde = TOMReadWord(0xF00048, JAGUAR);
1839 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1840 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1841 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1842 //seem to indicate the refresh rate is *half* the above...
1843 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1844 // Should these be hardwired or read from VP? Yes, from VP!
1845 // Err, actually, they should be hardwired, and hardwired to a set # of
1847 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1848 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1850 /*extern int effect_start;
1852 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1854 //extern int start_logging;
1855 for(uint16 i=0; i<vp; i++)
1857 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1858 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
1859 TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
1861 //Not sure if this is correct...
1862 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1863 //Which means that it normally wouldn't go when it's zero.
1864 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
1866 // We don't have to worry about autovectors & whatnot because the Jaguar
1867 // tells you through its HW registers who sent the interrupt...
1868 TOMSetPendingVideoInt();
1872 //if (start_logging)
1873 // WriteLog("About to execute M68K (%u)...\n", i);
1874 m68k_execute(M68KCyclesPerScanline);
1875 //if (start_logging)
1876 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1877 TOMExecPIT(RISCCyclesPerScanline);
1878 //if (start_logging)
1879 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1880 JERRYExecPIT(RISCCyclesPerScanline);
1881 //if (start_logging)
1882 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1883 JERRYI2SExec(RISCCyclesPerScanline);
1884 BUTCHExec(RISCCyclesPerScanline);
1885 //if (start_logging)
1886 // WriteLog("About to execute GPU (%u)...\n", i);
1888 GPUExec(RISCCyclesPerScanline);
1892 if (vjs.usePipelinedDSP)
1893 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1895 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1896 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1899 //if (start_logging)
1900 // WriteLog("About to execute OP (%u)...\n", i);
1901 TOMExecHalfline(i, render);
1905 // Temp debugging stuff
1907 void DumpMainMemory(void)
1909 FILE * fp = fopen("./memdump.bin", "wb");
1914 fwrite(jaguarMainRAM, 1, 0x400000, fp);
1918 uint8 * GetRamPtr(void)
1920 return jaguarMainRAM;
1924 // New Jaguar execution stack
1925 // This executes 1 frame's worth of code.
1928 void JaguarExecuteNew(void)
1934 double timeToNextEvent = GetTimeToNextEvent();
1935 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1937 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1940 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1944 if (vjs.usePipelinedDSP)
1945 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1947 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1955 #define USE_CORRECT_PAL_TIMINGS
1956 // A lot of confusion comes from here...
1957 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
1958 // of whether the display is interlaced or not. The only difference with an
1959 // interlaced display is that the high bit of VC will be set when the lower
1960 // field is being rendered.
1962 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
1963 // rendering two fields that are slighty vertically offset from each other.
1964 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
1965 // is rendered in this mode so that each field, when overlaid on each other,
1966 // will yield the final picture at the full resolution for the full frame.
1968 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
1969 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
1970 // it will be half this number for a half frame. BUT, since we're counting
1971 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
1973 // Scanline times are 63.5555... µs in NTSC and 64 µs in PAL
1974 // Half line times are, naturally, half of this. :-P
1975 void HalflineCallback(void)
1977 //OK, this is hardwired to run in NTSC, and for who knows how long.
1978 //Need to fix this so that it does a half-line in the correct amount of time
1979 //and number of lines, depending on which mode we're in. [FIXED]
1980 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
1981 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1982 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1983 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1986 #ifdef USE_CORRECT_PAL_TIMINGS
1987 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
1988 // So we cut the number of half-lines in a frame in half. :-P
1989 uint16 numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
1991 if (vc >= numHalfLines)
1997 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1998 TOMWriteWord(0xF00006, vc, JAGUAR);
2000 //This is a crappy kludge, but maybe it'll work for now...
2001 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2002 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
2004 // We don't have to worry about autovectors & whatnot because the Jaguar
2005 // tells you through its HW registers who sent the interrupt...
2006 TOMSetPendingVideoInt();
2010 TOMExecHalfline(vc, true);
2012 //Change this to VBB???
2013 //Doesn't seem to matter (at least for Flip Out & I-War)
2021 #ifdef USE_CORRECT_PAL_TIMINGS
2022 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2024 // SetCallbackTime(HalflineCallback, 63.5555);
2025 SetCallbackTime(HalflineCallback, 31.77775);
2029 // This isn't currently used, but maybe it should be...
2031 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
2032 handles all the rest, so this isn't needed. :-P
2034 void RenderCallback(void)
2036 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2037 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time