4 // Originally by David Raingeard (Cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
6 // Cleanups and endian wrongness amelioration by James L. Hammons
7 // Note: Endian wrongness probably stems from the MAME origins of this emu and
8 // the braindead way in which MAME handles memory. :-)
14 #include "SDL_opengl.h"
34 //Do this in makefile??? Yes! Could, but it's easier to define here...
35 //#define LOG_UNMAPPED_MEMORY_ACCESSES
36 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
37 #define ABORT_ON_ILLEGAL_INSTRUCTIONS
38 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
39 #define CPU_DEBUG_MEMORY
41 // Private function prototypes
43 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who = UNKNOWN);
44 unsigned jaguar_unknown_readword(unsigned address, uint32 who = UNKNOWN);
45 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who = UNKNOWN);
46 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who = UNKNOWN);
47 void M68K_show_context(void);
51 #ifdef CPU_DEBUG_MEMORY
52 extern bool startMemLog; // Set by "e" key
53 extern int effect_start;
54 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
57 // Memory debugging identifiers
59 const char * whoName[9] =
60 { "Unknown", "Jaguar", "DSP", "GPU", "TOM", "JERRY", "M68K", "Blitter", "OP" };
62 uint32 jaguar_active_memory_dumps = 0;
64 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
66 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
67 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
68 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
69 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
70 bool BIOSLoaded = false;
71 bool CDBIOSLoaded = false;
75 uint8 jerryRAM[0x10000];
77 #ifdef CPU_DEBUG_MEMORY
78 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
79 uint8 readMem[0x400000];
80 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
83 uint32 pcQueue[0x400];
87 // Callback function to detect illegal instructions
89 void GPUDumpDisassembly(void);
90 void GPUDumpRegisters(void);
91 static bool start = false;
93 void M68KInstructionHook(void)
95 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
98 // Ideally, we'd save all the registers as well...
99 pcQueue[pcQPtr++] = m68kPC;
102 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
104 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
106 static char buffer[2048];
107 for(int i=0; i<0x400; i++)
109 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
110 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
114 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
115 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
116 for(int i=0; i<10; i++)
117 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
118 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
124 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
126 static char buffer[2048];
127 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
128 WriteLog("%08X: %s", m68kPC, buffer);
129 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
130 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
131 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
133 /* if (m68kPC == 0x8D0E48 && effect_start5)
135 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
137 GPUDumpDisassembly();
141 /* uint16 opcode = JaguarReadWord(m68kPC);
142 if (opcode == 0x4E75) // RTS
145 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
147 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
149 if (raPtr != 0xFFFFFFFF)
151 for(uint32 i=0; i<=raPtr; i++)
153 if (returnAddr[i] == addr)
162 returnAddr[++raPtr] = addr;
166 //Flip Out! debugging...
169 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
170 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
171 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
172 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
174 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
176 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
177 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
178 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
179 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
180 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
181 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
182 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
184 /* static char buffer[2048];
185 //if (m68kPC > 0x805F48) start = true;
186 //if (m68kPC > 0x806486) start = true;
187 //if (m68kPC == 0x805FEE) start = true;
188 //if (m68kPC == 0x80600C)// start = true;
189 if (m68kPC == 0x802058) start = true;
191 // GPUDumpRegisters();
192 // GPUDumpDisassembly();
194 // M68K_show_context();
200 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
201 WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1));
204 /* if (m68kPC == 0x803F16)
206 WriteLog("M68K: Registers found at $803F16:\n");
207 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
208 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
209 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
211 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
212 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
214 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
215 // !!! Investigate !!!
216 /*extern bool doDSPDis;
217 static bool disgo = false;
218 if (m68kPC == 0x50222)
221 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
222 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
225 if (m68kPC == 0x5000)
230 static char buffer[2048];
231 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
232 WriteLog("%08X: %s", m68kPC, buffer);
233 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
234 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
235 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
237 if (m68kPC == 0x82E1A)
239 static char buffer[2048];
240 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
241 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
242 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
243 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
244 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
246 if (m68kPC == 0x82E58)
247 WriteLog("--> [Routine end]\n");
248 if (m68kPC == 0x80004)
250 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
251 // m68k_set_reg(M68K_REG_D2, 0x12345678);
275 if (m68kPC == 0x3000)
276 WriteLog("M68K: CD_init\n");
277 else if (m68kPC == 0x3006 + (6 * 0))
278 WriteLog("M68K: CD_mode\n");
279 else if (m68kPC == 0x3006 + (6 * 1))
280 WriteLog("M68K: CD_ack\n");
281 else if (m68kPC == 0x3006 + (6 * 2))
282 WriteLog("M68K: CD_jeri\n");
283 else if (m68kPC == 0x3006 + (6 * 3))
284 WriteLog("M68K: CD_spin\n");
285 else if (m68kPC == 0x3006 + (6 * 4))
286 WriteLog("M68K: CD_stop\n");
287 else if (m68kPC == 0x3006 + (6 * 5))
288 WriteLog("M68K: CD_mute\n");
289 else if (m68kPC == 0x3006 + (6 * 6))
290 WriteLog("M68K: CD_umute\n");
291 else if (m68kPC == 0x3006 + (6 * 7))
292 WriteLog("M68K: CD_paus\n");
293 else if (m68kPC == 0x3006 + (6 * 8))
294 WriteLog("M68K: CD_upaus\n");
295 else if (m68kPC == 0x3006 + (6 * 9))
296 WriteLog("M68K: CD_read\n");
297 else if (m68kPC == 0x3006 + (6 * 10))
298 WriteLog("M68K: CD_uread\n");
299 else if (m68kPC == 0x3006 + (6 * 11))
300 WriteLog("M68K: CD_setup\n");
301 else if (m68kPC == 0x3006 + (6 * 12))
302 WriteLog("M68K: CD_ptr\n");
303 else if (m68kPC == 0x3006 + (6 * 13))
304 WriteLog("M68K: CD_osamp\n");
305 else if (m68kPC == 0x3006 + (6 * 14))
306 WriteLog("M68K: CD_getoc\n");
307 else if (m68kPC == 0x3006 + (6 * 15))
308 WriteLog("M68K: CD_initm\n");
309 else if (m68kPC == 0x3006 + (6 * 16))
310 WriteLog("M68K: CD_initf\n");
311 else if (m68kPC == 0x3006 + (6 * 17))
312 WriteLog("M68K: CD_switch\n");
314 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
315 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
316 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
317 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
319 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
320 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
322 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
323 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
325 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
326 // keep going even when the 68K dumped back to the debugger or what have you).
328 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
329 // Try setting the vector to the illegal instruction...
330 //This doesn't work right either! Do something else! Quick!
331 // SET32(jaguar_mainRam, 0x10, m68kPC);
337 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
338 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
339 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
340 for(int i=0; i<10; i++)
341 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
342 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
346 // WriteLog("\n\n68K disasm\n\n");
347 // jaguar_dasm(0x802000, 0x50C);
358 Now here be dragons...
359 Here is how memory ranges are defined in the CoJag driver.
360 Note that we only have to be concerned with 3 entities read/writing anything:
361 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
362 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
363 things that are entirely internal to those modules. This way we should be able to get a handle on all
364 this crap which is currently scattered over Hell's Half Acre(tm).
366 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
367 is a good way to collapse that shit.
369 /*************************************
371 * Main CPU memory handlers
373 *************************************/
375 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
376 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
377 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
378 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
379 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
380 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
381 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
382 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
383 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
384 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
385 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
386 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
387 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
388 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
389 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
390 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
391 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
392 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
393 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
394 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
395 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
396 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
397 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
400 /*************************************
402 * GPU memory handlers
404 *************************************/
406 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
407 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
408 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
409 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
410 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
411 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
412 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
413 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
414 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
415 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
416 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
419 /*************************************
421 * DSP memory handlers
423 *************************************/
425 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
426 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
427 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
428 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
429 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
430 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
431 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
432 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
433 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
438 #define EXPERIMENTAL_MEMORY_HANDLING
439 // Experimental memory mappage...
440 // Dunno if this is a good approach or not, but it seems to make better
441 // sense to have all this crap in one spot intstead of scattered all over
442 // the place the way it is now.
443 #ifdef EXPERIMENTAL_MEMORY_HANDLING
445 #define NEW_TIMER_SYSTEM
446 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
448 // Not sure, but I think the system only has 24 address bits...
449 address &= 0x00FFFFFF;
451 // RAM ($000000 - $3FFFFF) 4M
452 if (address <= 0x3FFFFF)
453 jaguarMainRAM[address] = byte;
454 // hole ($400000 - $7FFFFF) 4M
455 else if (address <= 0x7FFFFF)
457 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
458 else if (address <= 0xDFFEFF)
460 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
461 else if (address <= 0xDFFFFF)
463 cdRAM[address & 0xFF] = byte;
465 if ((address & 0xFF) < 12 * 4)
466 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
467 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
470 // BIOS ROM ($E00000 - $E3FFFF) 256K
471 else if (address <= 0xE3FFFF)
473 // hole ($E40000 - $EFFFFF) 768K
474 else if (address <= 0xEFFFFF)
476 // TOM ($F00000 - $F0FFFF) 64K
477 else if (address <= 0xF0FFFF)
480 if (address == 0xF00050)
482 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
486 else if (address == 0xF00051)
488 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
492 else if (address == 0xF00052)
494 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
498 else if (address == 0xF00053)
500 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
504 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
506 // Writing to one CLUT writes to the other
507 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
508 tomRAM[address] = tomRAM[address + 0x200] = byte;
511 //What about LBUF writes???
512 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
514 GPUWriteByte(address, byte, who);
517 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
519 BlitterWriteByte(address, byte, who);
522 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
524 GPUWriteByte(address, byte, who);
528 tomRAM[address & 0x3FFF] = byte;
530 // JERRY ($F10000 - $F1FFFF) 64K
531 else if (address <= 0xF1FFFF)
535 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
537 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
539 DSPWriteByte(address, byte, who);
542 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
544 DSPWriteByte(address, byte, who);
547 // SCLK ($F1A150--8 bits wide)
548 //NOTE: This should be taken care of in DAC...
549 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
551 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
552 if ((address & 0x03) == 2)
553 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
555 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
557 JERRYI2SInterruptTimer = -1;
558 #ifndef NEW_TIMER_SYSTEM
561 RemoveCallback(JERRYI2SCallback);
566 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
567 else if (address >= 0xF1A148 && address <= 0xF1A157)
569 DACWriteByte(address, byte, who);
572 else if (address >= 0xF10000 && address <= 0xF10007)
574 #ifndef NEW_TIMER_SYSTEM
575 switch (address & 0x07)
578 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
582 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
586 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
590 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
594 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
598 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
602 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
606 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
610 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
614 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
616 clock_byte_write(offset, byte);
619 // JERRY -> 68K interrupt enables/latches (need to be handled!)
620 else if (address >= 0xF10020 && address <= 0xF10023)
622 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
624 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
626 anajoy_byte_write(offset, byte);
629 else if ((address >= 0xF14000) && (address <= 0xF14003))
631 JoystickWriteByte(address, byte);
632 EepromWriteByte(address, byte);
635 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
637 EepromWriteByte(address, byte);
640 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
641 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
644 jerryRAM[address & 0xFFFF] = byte;
646 // hole ($F20000 - $FFFFFF) 1M - 128K
651 void WriteWord(uint32 adddress, uint16 word)
655 void WriteDWord(uint32 adddress, uint32 dword)
659 uint8 ReadByte(uint32 adddress)
663 uint16 ReadWord(uint32 adddress)
667 uint32 ReadDWord(uint32 adddress)
673 // Musashi 68000 read/write/IRQ functions
676 int irq_ack_handler(int level)
678 int vector = M68K_INT_ACK_AUTOVECTOR;
680 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
684 m68k_set_irq(0); // Clear the IRQ...
685 vector = 64; // Set user interrupt #0
691 unsigned int m68k_read_memory_8(unsigned int address)
693 #ifdef CPU_DEBUG_MEMORY
694 if ((address >= 0x000000) && (address <= 0x3FFFFF))
697 readMem[address] = 1;
700 //WriteLog("[RM8] Addr: %08X\n", address);
701 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
702 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
703 || address == 0x1AF05E)
704 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
705 unsigned int retVal = 0;
707 if ((address >= 0x000000) && (address <= 0x3FFFFF))
708 retVal = jaguarMainRam[address];
709 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
710 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
711 retVal = jaguarMainRom[address - 0x800000];
712 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
713 retVal = jaguarBootRom[address - 0xE00000];
714 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
715 retVal = CDROMReadByte(address);
716 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
717 retVal = TOMReadByte(address, M68K);
718 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
719 retVal = JERRYReadByte(address, M68K);
721 retVal = jaguar_unknown_readbyte(address, M68K);
723 //if (address >= 0x2800 && address <= 0x281F)
724 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
725 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
726 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
730 void gpu_dump_disassembly(void);
731 void gpu_dump_registers(void);
733 unsigned int m68k_read_memory_16(unsigned int address)
735 #ifdef CPU_DEBUG_MEMORY
736 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
739 readMem[address] = 1, readMem[address + 1] = 1;
741 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
743 return 0x4E71; // NOP
745 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
747 return 0x4E71; // NOP
749 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
751 return 0x4E71; // NOP
753 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
755 return 0x4E71; // NOP
757 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
759 return 0x4E71; // NOP
761 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
763 return 0x4E71; // NOP
766 //WriteLog("[RM16] Addr: %08X\n", address);
767 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
768 // for(int i=0; i<10000; i++)
769 WriteLog("[M68K] In routine #6!\n");//*/
770 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
771 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
772 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
774 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
775 gpu_dump_registers();
776 gpu_dump_disassembly();
777 // for(int i=0; i<10000; i++)
778 // WriteLog("[M68K] About to run GPU!\n");
780 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
781 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
783 if (address == 0x000066A0)
785 gpu_dump_registers();
786 gpu_dump_disassembly();
788 for(int i=0; i<10000; i++)
789 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
791 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
792 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
793 || address == 0x1AF05E)
794 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
795 unsigned int retVal = 0;
797 if ((address >= 0x000000) && (address <= 0x3FFFFE))
798 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
799 retVal = GET16(jaguarMainRam, address);
800 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
801 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
802 retVal = (jaguarMainRom[address - 0x800000] << 8) | jaguarMainRom[address - 0x800000 + 1];
803 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
804 retVal = (jaguarBootRom[address - 0xE00000] << 8) | jaguarBootRom[address - 0xE00000 + 1];
805 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
806 retVal = CDROMReadWord(address, M68K);
807 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
808 retVal = TOMReadWord(address, M68K);
809 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
810 retVal = JERRYReadWord(address, M68K);
812 retVal = jaguar_unknown_readword(address, M68K);
814 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
815 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
816 //if (address >= 0x2800 && address <= 0x281F)
817 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
818 //$8B3AE -> Transferred from $F1C010
819 //$8B5E4 -> Only +1 read at $808AA
820 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
821 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
825 unsigned int m68k_read_memory_32(unsigned int address)
827 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
828 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
829 WriteLog("[RM32 PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
831 //WriteLog("--> [RM32]\n");
832 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
835 void m68k_write_memory_8(unsigned int address, unsigned int value)
837 #ifdef CPU_DEBUG_MEMORY
838 if ((address >= 0x000000) && (address <= 0x3FFFFF))
842 if (value > writeMemMax[address])
843 writeMemMax[address] = value;
844 if (value < writeMemMin[address])
845 writeMemMin[address] = value;
849 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
850 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
851 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
853 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
854 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
856 if ((address >= 0x000000) && (address <= 0x3FFFFF))
857 jaguarMainRam[address] = value;
858 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
859 CDROMWriteByte(address, value, M68K);
860 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
861 TOMWriteByte(address, value, M68K);
862 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
863 JERRYWriteByte(address, value, M68K);
865 jaguar_unknown_writebyte(address, value, M68K);
868 void m68k_write_memory_16(unsigned int address, unsigned int value)
870 #ifdef CPU_DEBUG_MEMORY
871 if ((address >= 0x000000) && (address <= 0x3FFFFE))
875 uint8 hi = value >> 8, lo = value & 0xFF;
877 if (hi > writeMemMax[address])
878 writeMemMax[address] = hi;
879 if (hi < writeMemMin[address])
880 writeMemMin[address] = hi;
882 if (lo > writeMemMax[address+1])
883 writeMemMax[address+1] = lo;
884 if (lo < writeMemMin[address+1])
885 writeMemMin[address+1] = lo;
889 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
890 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
891 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
892 //if (address >= 0xF02200 && address <= 0xF0229F)
893 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
894 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
895 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
896 /*extern uint32 totalFrames;
897 if (address == 0xF02114)
898 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
899 if (address == 0xF02110)
900 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
901 //if (address >= 0xF03B00 && address <= 0xF03DFF)
902 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
904 /*if (address == 0x0100)//64*4)
905 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
907 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
908 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
909 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
910 || address == 0x1AF05E)
911 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
913 if ((address >= 0x000000) && (address <= 0x3FFFFE))
915 /* jaguar_mainRam[address] = value >> 8;
916 jaguar_mainRam[address + 1] = value & 0xFF;*/
917 SET16(jaguarMainRam, address, value);
919 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
920 CDROMWriteWord(address, value, M68K);
921 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
922 TOMWriteWord(address, value, M68K);
923 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
924 JERRYWriteWord(address, value, M68K);
927 jaguar_unknown_writeword(address, value, M68K);
928 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
929 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
930 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
931 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
936 void m68k_write_memory_32(unsigned int address, unsigned int value)
938 //WriteLog("--> [WM32]\n");
939 /*if (address == 0x0100)//64*4)
940 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
941 /*if (address >= 0xF03214 && address < 0xF0321F)
942 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
943 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
944 /*extern bool doGPUDis;
945 if (address == 0xF03214 && value == 0x88E30047)
948 /* if (address == 0x51136 || address == 0xFB074)
949 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
951 m68k_write_memory_16(address, value >> 16);
952 m68k_write_memory_16(address + 2, value & 0xFFFF);
956 uint32 JaguarGetHandler(uint32 i)
958 return JaguarReadLong(i * 4);
961 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
963 uint32 handler = JaguarGetHandler(i);
964 return (handler && (handler != 0xFFFFFFFF) ? true : false);
967 void M68K_show_context(void)
969 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
970 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
971 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
973 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
974 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
976 WriteLog("68K disasm\n");
977 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
978 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
979 // jaguar_dasm(0x5000, 0x14414);
981 // WriteLog("\n.......[Cart start]...........\n\n");
982 // jaguar_dasm(0x192000, 0x1000);//0x200);
984 WriteLog("..................\n");
986 if (TOMIRQEnabled(IRQ_VBLANK))
988 WriteLog("vblank int: enabled\n");
989 JaguarDasm(JaguarGetHandler(64), 0x200);
992 WriteLog("vblank int: disabled\n");
994 WriteLog("..................\n");
996 for(int i=0; i<256; i++)
997 WriteLog("handler %03i at $%08X\n", i, (unsigned int)JaguarGetHandler(i));
1001 // Unknown read/write byte/word routines
1004 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1005 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1007 // 807EC4: movea.l #$f1b000, A1
1008 // 807ECA: movea.l #$8129e0, A0
1009 // 807ED0: move.l A0, D0
1010 // 807ED2: move.l #$f1bb94, D1
1011 // 807ED8: sub.l D0, D1
1012 // 807EDA: lsr.l #2, D1
1013 // 807EDC: move.l (A0)+, (A1)+
1014 // 807EDE: dbra D1, 807edc
1016 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1017 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1018 // space! (That is, unless the 68K causes a bus error...)
1020 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1022 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1023 WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1025 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1026 // extern bool finished;
1028 // extern bool doDSPDis;
1034 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1036 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1037 WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1039 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1040 // extern bool finished;
1042 // extern bool doDSPDis;
1048 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1050 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1051 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1053 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1054 // extern bool finished;
1056 // extern bool doDSPDis;
1063 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1065 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1066 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1068 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1069 // extern bool finished;
1071 // extern bool doDSPDis;
1079 // Disassemble M68K instructions at the given offset
1082 unsigned int m68k_read_disassembler_8(unsigned int address)
1084 return m68k_read_memory_8(address);
1087 unsigned int m68k_read_disassembler_16(unsigned int address)
1089 return m68k_read_memory_16(address);
1092 unsigned int m68k_read_disassembler_32(unsigned int address)
1094 return m68k_read_memory_32(address);
1097 void JaguarDasm(uint32 offset, uint32 qt)
1100 static char buffer[2048];//, mem[64];
1101 int pc = offset, oldpc;
1103 for(uint32 i=0; i<qt; i++)
1106 for(int j=0; j<64; j++)
1107 mem[j^0x01] = jaguar_byte_read(pc + j);
1109 pc += Dasm68000((char *)mem, buffer, 0);
1110 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1112 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1113 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1118 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1123 if (offset < 0x400000)
1124 data = jaguarMainRam[offset & 0x3FFFFF];
1125 else if ((offset >= 0x800000) && (offset < 0xC00000))
1126 data = jaguarMainRom[offset - 0x800000];
1127 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1128 data = CDROMReadByte(offset, who);
1129 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1130 data = jaguarBootRom[offset & 0x3FFFF];
1131 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1132 data = TOMReadByte(offset, who);
1133 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1134 data = JERRYReadByte(offset, who);
1136 data = jaguar_unknown_readbyte(offset, who);
1141 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1144 if (offset <= 0x3FFFFE)
1146 return (jaguarMainRam[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRam[(offset+1) & 0x3FFFFF];
1148 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1151 return (jaguarMainRom[offset+0] << 8) | jaguarMainRom[offset+1];
1153 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1154 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1155 return CDROMReadWord(offset, who);
1156 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1157 return (jaguarBootRom[(offset+0) & 0x3FFFF] << 8) | jaguarBootRom[(offset+1) & 0x3FFFF];
1158 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1159 return TOMReadWord(offset, who);
1160 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1161 return JERRYReadWord(offset, who);
1163 return jaguar_unknown_readword(offset, who);
1166 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1168 //Need to check for writes in the range of $18FA70 + 8000...
1170 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1171 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1174 if (offset < 0x400000)
1176 jaguarMainRam[offset & 0x3FFFFF] = data;
1179 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1181 CDROMWriteByte(offset, data, who);
1184 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1186 TOMWriteByte(offset, data, who);
1189 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1191 JERRYWriteByte(offset, data, who);
1195 jaguar_unknown_writebyte(offset, data, who);
1199 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1201 /*if (offset == 0x0100)//64*4)
1202 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1203 if (offset == 0x0102)//64*4)
1204 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1205 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1206 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1207 //Need to check for writes in the range of $18FA70 + 8000...
1209 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1210 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1211 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1212 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1216 if (offset <= 0x3FFFFE)
1221 1A 69 F0 ($0000) -> Starfield
1222 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1225 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1234 //This MUST be done by the 68K!
1235 /*if (offset == 0x670C)
1236 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1238 /*extern bool doGPUDis;
1239 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1240 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1241 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1242 doGPUDis = true;//*/
1243 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1244 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1245 if ((data & 0xFF00) != 0x7700)
1246 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1247 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1249 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1250 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1251 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1253 /*extern bool doGPUDis;
1254 if (offset == 0x120216 && who == GPU)
1255 doGPUDis = true;//*/
1256 /*extern uint32 gpu_pc;
1257 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1259 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1260 uint32 y = base / 0x300;
1261 uint32 x = (base - (y * 0x300)) / 2;
1262 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1265 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1267 //if (offset == (0x001E17F8 + 0x34))
1268 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1270 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1271 /*extern uint32 gpu_pc;
1272 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1274 extern int objectPtr;
1275 // if (offset > 0x148000)
1278 if (starCount > objectPtr)
1281 // if (starCount == 1)
1282 // WriteLog("--> Drawing 1st star...\n");
1284 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1285 // uint32 y = base / 0x300;
1286 // uint32 x = (base - (y * 0x300)) / 2;
1287 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1289 //A star of interest...
1290 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1291 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1292 //JWW: Blitter writing echo 77B3 at 0011D022...
1294 //extern bool doGPUDis;
1295 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1298 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1301 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1302 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1304 jaguarMainRam[(offset+0) & 0x3FFFFF] = data >> 8;
1305 jaguarMainRam[(offset+1) & 0x3FFFFF] = data & 0xFF;
1308 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1310 CDROMWriteWord(offset, data, who);
1313 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1315 TOMWriteWord(offset, data, who);
1318 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1320 JERRYWriteWord(offset, data, who);
1323 // Don't bomb on attempts to write to ROM
1324 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1327 jaguar_unknown_writeword(offset, data, who);
1330 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1331 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1333 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1336 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1337 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1339 /* extern bool doDSPDis;
1340 if (offset < 0x400 && !doDSPDis)
1342 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1345 /*if (offset == 0x0100)//64*4)
1346 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1348 JaguarWriteWord(offset, data >> 16, who);
1349 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1353 // Jaguar console initialization
1355 void JaguarInit(void)
1357 #ifdef CPU_DEBUG_MEMORY
1358 memset(readMem, 0x00, 0x400000);
1359 memset(writeMemMin, 0xFF, 0x400000);
1360 memset(writeMemMax, 0x00, 0x400000);
1362 memset(jaguarMainRam, 0x00, 0x400000);
1363 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1364 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1365 //NOTE: This *doesn't* fix FlipOut...
1366 //Or does it? Hmm...
1367 //Seems to want $01010101... Dunno why. Investigate!
1368 memset(jaguarMainRom, 0x01, 0x600000); // & set it to all 01s...
1369 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1371 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1379 //New timer based code stuffola...
1380 void ScanlineCallback(void);
1381 void RenderCallback(void);
1382 //extern uint32 * backbuffer;
1383 void JaguarReset(void)
1385 //NOTE: This causes a (virtual) crash if this is set in the config but not found... !!! FIX !!!
1386 if (vjs.useJaguarBIOS)
1387 memcpy(jaguarMainRam, jaguarBootRom, 8);
1389 SET32(jaguarMainRam, 4, jaguarRunAddress);
1391 // WriteLog("jaguar_reset():\n");
1397 m68k_pulse_reset(); // Reset the 68000
1398 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1400 // New timer base code stuffola...
1401 InitializeEventList();
1402 TOMResetBackbuffer(backbuffer);
1403 // SetCallbackTime(ScanlineCallback, 63.5555);
1404 SetCallbackTime(ScanlineCallback, 31.77775);
1405 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1406 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
1409 void JaguarDone(void)
1411 #ifdef CPU_DEBUG_MEMORY
1412 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1414 for(uint32 i=0; i<=raPtr; i++)
1416 WriteLog("\t%08X\n", returnAddr[i]);
1417 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1418 jaguar_dasm(returnAddr[i] - 16, 16);
1423 /* int start = 0, end = 0;
1424 bool endTriggered = false, startTriggered = false;
1425 for(int i=0; i<0x400000; i++)
1427 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1429 if (!startTriggered)
1430 startTriggered = true, endTriggered = false, start = i;
1432 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1438 end = i - 1, endTriggered = true, startTriggered = false;
1439 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1446 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1447 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1448 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1449 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1450 for(int i=-2; i<9; i++)
1451 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1453 /* WriteLog("\nM68000 disassembly at $802288...\n");
1454 jaguar_dasm(0x802288, 3);
1455 WriteLog("\nM68000 disassembly at $802200...\n");
1456 jaguar_dasm(0x802200, 500);
1457 WriteLog("\nM68000 disassembly at $802518...\n");
1458 jaguar_dasm(0x802518, 100);//*/
1460 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1461 jaguar_dasm(0x803F00, 500);
1464 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1465 jaguar_dasm(0x802B00, 500);
1468 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1469 jaguar_dasm(0x809900, 500);
1472 /* WriteLog("\n\nDump of $8093C8:\n\n");
1473 for(int i=0x8093C8; i<0x809900; i+=4)
1474 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1475 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1476 jaguar_dasm(0x90006C, 500);
1478 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1479 jaguar_dasm(0x1AC000, 6000);
1482 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1483 WriteLog("Jaguar: Interrupt enable = %02X\n", TOMReadByte(0xF000E1) & 0x1F);
1484 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
1485 M68K_show_context();
1496 // Main Jaguar execution loop (1 frame)
1498 void JaguarExecute(uint32 * backbuffer, bool render)
1500 uint16 vp = TOMReadWord(0xF0003E) + 1;
1501 uint16 vi = TOMReadWord(0xF0004E);
1502 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1503 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1505 // uint16 vdb = TOMReadWord(0xF00046);
1506 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1507 // uint16 vbb = TOMReadWord(0xF00040);
1508 //It seems that they mean it when they say that VDE is the end of object processing.
1509 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1510 //buffer and not to write any more pixels... !!! FIX !!!
1511 // uint16 vde = TOMReadWord(0xF00048);
1513 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1514 uint32 m68kCockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1515 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1516 //seem to indicate the refresh rate is *half* the above...
1517 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1518 // Should these be hardwired or read from VP? Yes, from VP!
1519 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1520 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1522 TOMResetBackbuffer(backbuffer);
1523 /*extern int effect_start;
1525 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1527 //extern int start_logging;
1528 for(uint16 i=0; i<vp; i++)
1530 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1531 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004) + 1) & 0x7FF);
1533 TOMWriteWord(0xF00006, i); // Write the VC
1535 // if (i == vi) // Time for Vertical Interrupt?
1536 //Not sure if this is correct...
1537 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1538 //Which means that it normally wouldn't go when it's zero.
1539 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1541 // We don't have to worry about autovectors & whatnot because the Jaguar
1542 // tells you through its HW registers who sent the interrupt...
1543 TOMSetPendingVideoInt();
1547 //if (start_logging)
1548 // WriteLog("About to execute M68K (%u)...\n", i);
1549 m68k_execute(M68KCyclesPerScanline);
1550 //if (start_logging)
1551 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1552 TOMExecPIT(RISCCyclesPerScanline);
1553 //if (start_logging)
1554 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1555 JERRYExecPIT(RISCCyclesPerScanline);
1556 //if (start_logging)
1557 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1558 JERRYI2SExec(RISCCyclesPerScanline);
1559 BUTCHExec(RISCCyclesPerScanline);
1560 //if (start_logging)
1561 // WriteLog("About to execute GPU (%u)...\n", i);
1562 GPUExec(RISCCyclesPerScanline);
1566 if (vjs.usePipelinedDSP)
1567 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1569 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1570 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1573 //if (start_logging)
1574 // WriteLog("About to execute OP (%u)...\n", i);
1575 TOMExecScanline(i, render);
1579 // Temp debugging stuff
1581 void DumpMainMemory(void)
1583 FILE * fp = fopen("./memdump.bin", "wb");
1588 fwrite(jaguarMainRam, 1, 0x400000, fp);
1592 uint8 * GetRamPtr(void)
1594 return jaguarMainRam;
1598 // New Jaguar execution stack
1603 void JaguarExecuteNew(void)
1605 extern bool finished, showGUI;
1606 extern bool debounceRunKey;
1607 // Pass a message to the "joystick" code to debounce the ESC key...
1608 debounceRunKey = true;
1610 /* InitializeEventList();
1611 TOMResetBackbuffer(backbuffer);
1612 // SetCallbackTime(ScanlineCallback, 63.5555);
1613 SetCallbackTime(ScanlineCallback, 31.77775);
1614 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1615 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1616 // uint8 * keystate = SDL_GetKeyState(NULL);
1620 double timeToNextEvent = GetTimeToNextEvent();
1621 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1623 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1624 gpu_exec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1628 if (vjs.usePipelinedDSP)
1629 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1631 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1636 // if (keystate[SDLK_ESCAPE])
1639 // SDL_PumpEvents(); // Needed to keep the keystate current...
1644 void ScanlineCallback(void)
1646 uint16 vc = TOMReadWord(0xF00006);
1647 uint16 vp = TOMReadWord(0xF0003E) + 1;
1648 uint16 vi = TOMReadWord(0xF0004E);
1649 // uint16 vbb = TOMReadWord(0xF00040);
1655 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1656 TOMWriteWord(0xF00006, vc);
1658 //This is a crappy kludge, but maybe it'll work for now...
1659 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1660 if (vc == vi && vc > 0 && tom_irq_enabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1662 // We don't have to worry about autovectors & whatnot because the Jaguar
1663 // tells you through its HW registers who sent the interrupt...
1664 tom_set_pending_video_int();
1668 TOMExecScanline(vc, true);
1670 //Change this to VBB???
1671 //Doesn't seem to matter (at least for Flip Out & I-War)
1678 TOMResetBackbuffer(backbuffer);
1682 // TOMResetBackbuffer(backbuffer);
1684 // SetCallbackTime(ScanlineCallback, 63.5555);
1685 SetCallbackTime(ScanlineCallback, 31.77775);
1691 void JaguarExecuteNew(void)
1693 // extern bool finished, showGUI;
1694 // extern bool debounceRunKey;
1695 // Pass a message to the "joystick" code to debounce the ESC key...
1696 // debounceRunKey = true;
1697 // finished = false;
1698 /* InitializeEventList();
1699 TOMResetBackbuffer(backbuffer);
1700 // SetCallbackTime(ScanlineCallback, 63.5555);
1701 SetCallbackTime(ScanlineCallback, 31.77775);
1702 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1703 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1704 // uint8 * keystate = SDL_GetKeyState(NULL);
1709 double timeToNextEvent = GetTimeToNextEvent();
1710 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1712 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1713 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1717 if (vjs.usePipelinedDSP)
1718 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1720 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1725 // if (keystate[SDLK_ESCAPE])
1728 // SDL_PumpEvents(); // Needed to keep the keystate current...
1733 void ScanlineCallback(void)
1735 uint16 vc = TOMReadWord(0xF00006);
1736 uint16 vp = TOMReadWord(0xF0003E) + 1;
1737 uint16 vi = TOMReadWord(0xF0004E);
1738 // uint16 vbb = TOMReadWord(0xF00040);
1744 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1745 TOMWriteWord(0xF00006, vc);
1747 //This is a crappy kludge, but maybe it'll work for now...
1748 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1749 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1751 // We don't have to worry about autovectors & whatnot because the Jaguar
1752 // tells you through its HW registers who sent the interrupt...
1753 TOMSetPendingVideoInt();
1757 TOMExecScanline(vc, true);
1759 //Change this to VBB???
1760 //Doesn't seem to matter (at least for Flip Out & I-War)
1766 TOMResetBackbuffer(backbuffer);
1771 // TOMResetBackbuffer(backbuffer);
1773 // SetCallbackTime(ScanlineCallback, 63.5555);
1774 SetCallbackTime(ScanlineCallback, 31.77775);
1779 // This isn't currently used, but maybe it should be...
1780 void RenderCallback(void)
1783 TOMResetBackbuffer(backbuffer);
1784 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1785 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time