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 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 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;
71 bool lowerField = false;
73 #ifdef CPU_DEBUG_MEMORY
74 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
75 uint8 readMem[0x400000];
76 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
79 uint32 pcQueue[0x400];
83 // Callback function to detect illegal instructions
85 void GPUDumpDisassembly(void);
86 void GPUDumpRegisters(void);
87 static bool start = false;
89 void M68KInstructionHook(void)
91 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
92 // Temp, for comparing...
94 /* static char buffer[2048];//, mem[64];
95 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
96 printf("%08X: %s\n", m68kPC, buffer);//*/
98 //JaguarDasm(m68kPC, 1);
99 //Testing Hover Strike...
102 static int hitCount = 0;
103 static int inRoutine = 0;
106 //if (regs.pc == 0x80340A)
107 if (m68kPC == 0x803416)
112 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
114 else if (m68kPC == 0x803422)
117 printf("(%i instructions)\n", instSeen);
125 // Ideally, we'd save all the registers as well...
126 pcQueue[pcQPtr++] = m68kPC;
129 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
131 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
133 static char buffer[2048];
134 for(int i=0; i<0x400; i++)
136 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
137 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
141 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
142 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
143 for(int i=0; i<10; i++)
144 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
145 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
151 // Disassemble everything
153 static char buffer[2048];
154 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
155 WriteLog("%08X: %s", m68kPC, buffer);
156 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
157 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
158 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
160 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
162 static char buffer[2048];
163 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
164 WriteLog("%08X: %s", m68kPC, buffer);
165 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
166 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
167 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
169 /* if (m68kPC == 0x8D0E48 && effect_start5)
171 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
173 GPUDumpDisassembly();
177 /* uint16 opcode = JaguarReadWord(m68kPC);
178 if (opcode == 0x4E75) // RTS
181 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
183 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
185 if (raPtr != 0xFFFFFFFF)
187 for(uint32 i=0; i<=raPtr; i++)
189 if (returnAddr[i] == addr)
198 returnAddr[++raPtr] = addr;
202 //Flip Out! debugging...
205 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
206 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
207 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
208 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
210 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
212 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
213 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
214 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
215 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
216 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
217 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
218 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
220 /* static char buffer[2048];
221 //if (m68kPC > 0x805F48) start = true;
222 //if (m68kPC > 0x806486) start = true;
223 //if (m68kPC == 0x805FEE) start = true;
224 //if (m68kPC == 0x80600C)// start = true;
225 if (m68kPC == 0x802058) start = true;
227 // GPUDumpRegisters();
228 // GPUDumpDisassembly();
230 // M68K_show_context();
236 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
237 WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1));
240 /* if (m68kPC == 0x803F16)
242 WriteLog("M68K: Registers found at $803F16:\n");
243 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
244 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
245 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
247 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
248 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
250 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
251 // !!! Investigate !!!
252 /*extern bool doDSPDis;
253 static bool disgo = false;
254 if (m68kPC == 0x50222)
257 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
258 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
261 if (m68kPC == 0x5000)
266 static char buffer[2048];
267 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
268 WriteLog("%08X: %s", m68kPC, buffer);
269 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
270 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
271 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
273 if (m68kPC == 0x82E1A)
275 static char buffer[2048];
276 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
277 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
278 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
279 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
280 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
282 if (m68kPC == 0x82E58)
283 WriteLog("--> [Routine end]\n");
284 if (m68kPC == 0x80004)
286 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
287 // m68k_set_reg(M68K_REG_D2, 0x12345678);
290 #ifdef LOG_CD_BIOS_CALLS
313 if (m68kPC == 0x3000)
314 WriteLog("M68K: CD_init\n");
315 else if (m68kPC == 0x3006 + (6 * 0))
316 WriteLog("M68K: CD_mode\n");
317 else if (m68kPC == 0x3006 + (6 * 1))
318 WriteLog("M68K: CD_ack\n");
319 else if (m68kPC == 0x3006 + (6 * 2))
320 WriteLog("M68K: CD_jeri\n");
321 else if (m68kPC == 0x3006 + (6 * 3))
322 WriteLog("M68K: CD_spin\n");
323 else if (m68kPC == 0x3006 + (6 * 4))
324 WriteLog("M68K: CD_stop\n");
325 else if (m68kPC == 0x3006 + (6 * 5))
326 WriteLog("M68K: CD_mute\n");
327 else if (m68kPC == 0x3006 + (6 * 6))
328 WriteLog("M68K: CD_umute\n");
329 else if (m68kPC == 0x3006 + (6 * 7))
330 WriteLog("M68K: CD_paus\n");
331 else if (m68kPC == 0x3006 + (6 * 8))
332 WriteLog("M68K: CD_upaus\n");
333 else if (m68kPC == 0x3006 + (6 * 9))
334 WriteLog("M68K: CD_read\n");
335 else if (m68kPC == 0x3006 + (6 * 10))
336 WriteLog("M68K: CD_uread\n");
337 else if (m68kPC == 0x3006 + (6 * 11))
338 WriteLog("M68K: CD_setup\n");
339 else if (m68kPC == 0x3006 + (6 * 12))
340 WriteLog("M68K: CD_ptr\n");
341 else if (m68kPC == 0x3006 + (6 * 13))
342 WriteLog("M68K: CD_osamp\n");
343 else if (m68kPC == 0x3006 + (6 * 14))
344 WriteLog("M68K: CD_getoc\n");
345 else if (m68kPC == 0x3006 + (6 * 15))
346 WriteLog("M68K: CD_initm\n");
347 else if (m68kPC == 0x3006 + (6 * 16))
348 WriteLog("M68K: CD_initf\n");
349 else if (m68kPC == 0x3006 + (6 * 17))
350 WriteLog("M68K: CD_switch\n");
352 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
353 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
354 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
355 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
358 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
359 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
361 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
362 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
364 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
365 // keep going even when the 68K dumped back to the debugger or what have you).
367 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
368 // Try setting the vector to the illegal instruction...
369 //This doesn't work right either! Do something else! Quick!
370 // SET32(jaguar_mainRam, 0x10, m68kPC);
376 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
377 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
378 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
379 for(int i=0; i<10; i++)
380 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
381 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
385 // WriteLog("\n\n68K disasm\n\n");
386 // jaguar_dasm(0x802000, 0x50C);
397 Now here be dragons...
398 Here is how memory ranges are defined in the CoJag driver.
399 Note that we only have to be concerned with 3 entities read/writing anything:
400 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
401 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
402 things that are entirely internal to those modules. This way we should be able to get a handle on all
403 this crap which is currently scattered over Hell's Half Acre(tm).
405 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
406 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
408 /*************************************
410 * Main CPU memory handlers
412 *************************************/
414 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
415 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
416 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
417 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
418 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
419 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
420 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
421 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
422 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
423 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
424 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
425 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
426 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
427 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
428 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
429 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
430 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
431 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
432 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
433 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
434 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
435 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
436 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
439 /*************************************
441 * GPU memory handlers
443 *************************************/
445 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
446 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
447 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
448 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
449 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
450 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
451 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
452 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
453 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
454 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
455 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
458 /*************************************
460 * DSP memory handlers
462 *************************************/
464 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
465 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
466 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
467 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
468 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
469 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
470 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
471 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
472 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
477 //#define EXPERIMENTAL_MEMORY_HANDLING
478 // Experimental memory mappage...
479 // Dunno if this is a good approach or not, but it seems to make better
480 // sense to have all this crap in one spot intstead of scattered all over
481 // the place the way it is now.
482 #ifdef EXPERIMENTAL_MEMORY_HANDLING
484 #define NEW_TIMER_SYSTEM
487 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
488 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
489 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
490 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
491 bool BIOSLoaded = false;
492 bool CDBIOSLoaded = false;
495 uint8 tomRAM[0x4000];
496 uint8 jerryRAM[0x10000];
497 static uint16 eeprom_ram[64];
499 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
502 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
504 // M68K Memory map/handlers
506 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
507 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
508 // Note that this is really memory mapped I/O region...
509 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
510 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
511 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
512 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
513 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
514 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
515 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
516 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
517 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
518 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
519 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
520 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
522 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
524 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
525 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
526 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
527 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
528 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
529 //What about LBUF writes???
530 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
531 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
532 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
534 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
538 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
539 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
540 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
543 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
544 0 = pad0/1 button values (4 bits each), RO(?)
545 1 = pad0/1 index value (4 bits each), WO
547 3 = NTSC/PAL, certain button states, RO
549 JOYSTICK $F14000 Read/Write
551 Read fedcba98 7654321q f-1 Signals J15 to J1
552 q Cartridge EEPROM output data
553 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
554 0 = disable J7-J0 outputs
557 0 = Audio muted (reset state)
559 7-4 J7-J4 outputs (port 2)
560 3-0 J3-J0 outputs (port 1)
561 JOYBUTS $F14002 Read Only
563 Read xxxxxxxx rrdv3210 x don't care
566 v 1 = NTSC Video hardware
567 0 = PAL Video hardware
568 3-2 Button inputs B3 & B2 (port 2)
569 1-0 Button inputs B1 & B0 (port 1)
571 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
572 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
580 0 1 1 1 Row 3 C3 Option # 9 6 3
584 1 0 1 1 Row 2 C2 C 0 8 5 2
586 1 1 0 1 Row 1 C1 B * 7 4 1
587 1 1 1 0 Row 0 Pause A Up Down Left Right
590 0 bit read in any position means that button is pressed.
591 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
595 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
597 // Not sure, but I think the system only has 24 address bits...
598 address &= 0x00FFFFFF;
600 // RAM ($000000 - $3FFFFF) 4M
601 if (address <= 0x3FFFFF)
602 jaguarMainRAM[address] = byte;
603 // hole ($400000 - $7FFFFF) 4M
604 else if (address <= 0x7FFFFF)
606 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
607 else if (address <= 0xDFFEFF)
609 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
610 else if (address <= 0xDFFFFF)
612 cdRAM[address & 0xFF] = byte;
614 if ((address & 0xFF) < 12 * 4)
615 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
616 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
619 // BIOS ROM ($E00000 - $E3FFFF) 256K
620 else if (address <= 0xE3FFFF)
622 // hole ($E40000 - $EFFFFF) 768K
623 else if (address <= 0xEFFFFF)
625 // TOM ($F00000 - $F0FFFF) 64K
626 else if (address <= 0xF0FFFF)
629 if (address == 0xF00050)
631 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
635 else if (address == 0xF00051)
637 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
641 else if (address == 0xF00052)
643 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
647 else if (address == 0xF00053)
649 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
653 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
655 // Writing to one CLUT writes to the other
656 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
657 tomRAM[address] = tomRAM[address + 0x200] = byte;
660 //What about LBUF writes???
661 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
663 GPUWriteByte(address, byte, who);
666 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
668 BlitterWriteByte(address, byte, who);
671 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
673 GPUWriteByte(address, byte, who);
677 tomRAM[address & 0x3FFF] = byte;
679 // JERRY ($F10000 - $F1FFFF) 64K
680 else if (address <= 0xF1FFFF)
684 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
686 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
688 DSPWriteByte(address, byte, who);
691 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
693 DSPWriteByte(address, byte, who);
696 // SCLK ($F1A150--8 bits wide)
697 //NOTE: This should be taken care of in DAC...
698 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
700 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
701 if ((address & 0x03) == 2)
702 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
704 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
706 JERRYI2SInterruptTimer = -1;
707 #ifndef NEW_TIMER_SYSTEM
710 RemoveCallback(JERRYI2SCallback);
715 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
716 else if (address >= 0xF1A148 && address <= 0xF1A157)
718 DACWriteByte(address, byte, who);
721 else if (address >= 0xF10000 && address <= 0xF10007)
723 #ifndef NEW_TIMER_SYSTEM
724 switch (address & 0x07)
727 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
731 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
735 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
739 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
743 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
747 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
751 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
755 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
759 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
763 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
765 clock_byte_write(offset, byte);
768 // JERRY -> 68K interrupt enables/latches (need to be handled!)
769 else if (address >= 0xF10020 && address <= 0xF10023)
771 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
773 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
775 anajoy_byte_write(offset, byte);
778 else if ((address >= 0xF14000) && (address <= 0xF14003))
780 JoystickWriteByte(address, byte);
781 EepromWriteByte(address, byte);
784 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
786 EepromWriteByte(address, byte);
789 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
790 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
793 jerryRAM[address & 0xFFFF] = byte;
795 // hole ($F20000 - $FFFFFF) 1M - 128K
800 void WriteWord(uint32 adddress, uint16 word)
804 void WriteDWord(uint32 adddress, uint32 dword)
808 uint8 ReadByte(uint32 adddress)
812 uint16 ReadWord(uint32 adddress)
816 uint32 ReadDWord(uint32 adddress)
821 void ShowM68KContext(void)
823 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
825 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
827 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
829 if (i == M68K_REG_D3 || i == M68K_REG_D7)
833 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
835 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
837 if (i == M68K_REG_A3 || i == M68K_REG_A7)
841 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
842 uint32_t disPC = currpc - 30;
847 uint32_t oldpc = disPC;
848 disPC += m68k_disassemble(buffer, disPC, 0);
849 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
851 while (disPC < (currpc + 10));
855 // Musashi 68000 read/write/IRQ functions
862 IPL Name Vector Control
863 ---------+---------------+---------------+---------------
864 2 VBLANK IRQ $100 INT1 bit #0
865 2 GPU IRQ $100 INT1 bit #1
866 2 HBLANK IRQ $100 INT1 bit #2
867 2 Timer IRQ $100 INT1 bit #3
869 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
870 and are therefore indistinguishable.
872 A typical way to install a LEVEL2 handler for the 68000 would be
873 something like this, you gotta supply "last_line" and "handler".
874 Note that the interrupt is auto vectored thru $100 (not $68)
882 IRQS_HANDLED=$909 ;; VBLANK and TIMER
884 move.w #$2700,sr ;; no IRQs please
885 move.l #handler,V_AUTO ;; install our routine
887 move.w #last_line,VI ;; scanline where IRQ should occur
888 ;; should be 'odd' BTW
889 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
890 move.w #$2100,sr ;; enable IRQs on the 68K
908 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
909 move.w #0,INT2 ; let GPU run again
913 As you can see, if you have multiple INT1 interrupts coming in,
914 you need to check the lower byte of INT1, to see which interrupt
917 int irq_ack_handler(int level)
919 // Tracing the IPL lines on the Jaguar schematic yields the following:
920 // IPL1 is connected to INTL on TOM (OUT to 68K)
921 // IPL0-2 are also tied to Vcc via 4.7K resistors!
922 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
923 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
924 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
926 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
927 // They aren't, and this causes problems with a, err, specific ROM. :-D
931 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
932 return 64; // Set user interrupt #0
935 return M68K_INT_ACK_AUTOVECTOR;
938 //#define USE_NEW_MMU
940 unsigned int m68k_read_memory_8(unsigned int address)
942 // Musashi does this automagically for you, UAE core does not :-P
943 address &= 0x00FFFFFF;
944 #ifdef CPU_DEBUG_MEMORY
945 if ((address >= 0x000000) && (address <= 0x3FFFFF))
948 readMem[address] = 1;
951 //WriteLog("[RM8] Addr: %08X\n", address);
952 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
953 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
954 || address == 0x1AF05E)
955 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
957 unsigned int retVal = 0;
959 if ((address >= 0x000000) && (address <= 0x3FFFFF))
960 retVal = jaguarMainRAM[address];
961 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
962 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
963 retVal = jaguarMainROM[address - 0x800000];
964 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
965 // retVal = jaguarBootROM[address - 0xE00000];
966 // retVal = jaguarDevBootROM1[address - 0xE00000];
967 retVal = jagMemSpace[address];
968 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
969 retVal = CDROMReadByte(address);
970 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
971 retVal = TOMReadByte(address, M68K);
972 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
973 retVal = JERRYReadByte(address, M68K);
975 retVal = jaguar_unknown_readbyte(address, M68K);
977 //if (address >= 0x2800 && address <= 0x281F)
978 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
979 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
980 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
983 return MMURead8(address, M68K);
987 void gpu_dump_disassembly(void);
988 void gpu_dump_registers(void);
990 unsigned int m68k_read_memory_16(unsigned int address)
992 // Musashi does this automagically for you, UAE core does not :-P
993 address &= 0x00FFFFFF;
994 #ifdef CPU_DEBUG_MEMORY
995 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
998 readMem[address] = 1, readMem[address + 1] = 1;
1000 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1002 return 0x4E71; // NOP
1004 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1006 return 0x4E71; // NOP
1008 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1010 return 0x4E71; // NOP
1012 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1014 return 0x4E71; // NOP
1016 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1018 return 0x4E71; // NOP
1020 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1022 return 0x4E71; // NOP
1025 //WriteLog("[RM16] Addr: %08X\n", address);
1026 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1027 // for(int i=0; i<10000; i++)
1028 WriteLog("[M68K] In routine #6!\n");//*/
1029 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1030 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1031 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1033 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1034 gpu_dump_registers();
1035 gpu_dump_disassembly();
1036 // for(int i=0; i<10000; i++)
1037 // WriteLog("[M68K] About to run GPU!\n");
1039 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1040 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1042 if (address == 0x000066A0)
1044 gpu_dump_registers();
1045 gpu_dump_disassembly();
1047 for(int i=0; i<10000; i++)
1048 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1050 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1051 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1052 || address == 0x1AF05E)
1053 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1055 unsigned int retVal = 0;
1057 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1058 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1059 retVal = GET16(jaguarMainRAM, address);
1060 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1061 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1062 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1063 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1064 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1065 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1066 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1067 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1068 retVal = CDROMReadWord(address, M68K);
1069 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1070 retVal = TOMReadWord(address, M68K);
1071 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1072 retVal = JERRYReadWord(address, M68K);
1074 retVal = jaguar_unknown_readword(address, M68K);
1076 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1077 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1078 //if (address >= 0x2800 && address <= 0x281F)
1079 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1080 //$8B3AE -> Transferred from $F1C010
1081 //$8B5E4 -> Only +1 read at $808AA
1082 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1083 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1086 return MMURead16(address, M68K);
1090 unsigned int m68k_read_memory_32(unsigned int address)
1092 // Musashi does this automagically for you, UAE core does not :-P
1093 address &= 0x00FFFFFF;
1094 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1095 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1096 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));//*/
1098 //WriteLog("--> [RM32]\n");
1100 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1102 return MMURead32(address, M68K);
1106 void m68k_write_memory_8(unsigned int address, unsigned int value)
1108 // Musashi does this automagically for you, UAE core does not :-P
1109 address &= 0x00FFFFFF;
1110 #ifdef CPU_DEBUG_MEMORY
1111 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1115 if (value > writeMemMax[address])
1116 writeMemMax[address] = value;
1117 if (value < writeMemMin[address])
1118 writeMemMin[address] = value;
1122 /*if (address == 0x4E00)
1123 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1124 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1125 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1126 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1128 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1129 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1131 /*if (address >= 0x53D0 && address <= 0x53FF)
1132 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1133 //Testing AvP on UAE core...
1134 //000075A0: FFFFF80E B6320220 (BITMAP)
1135 /*if (address == 0x75A0 && value == 0xFF)
1136 printf("M68K: (8) Tripwire hit...\n");//*/
1139 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1140 jaguarMainRAM[address] = value;
1141 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1142 CDROMWriteByte(address, value, M68K);
1143 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1144 TOMWriteByte(address, value, M68K);
1145 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1146 JERRYWriteByte(address, value, M68K);
1148 jaguar_unknown_writebyte(address, value, M68K);
1150 MMUWrite8(address, value, M68K);
1154 void m68k_write_memory_16(unsigned int address, unsigned int value)
1156 // Musashi does this automagically for you, UAE core does not :-P
1157 address &= 0x00FFFFFF;
1158 #ifdef CPU_DEBUG_MEMORY
1159 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1163 uint8 hi = value >> 8, lo = value & 0xFF;
1165 if (hi > writeMemMax[address])
1166 writeMemMax[address] = hi;
1167 if (hi < writeMemMin[address])
1168 writeMemMin[address] = hi;
1170 if (lo > writeMemMax[address+1])
1171 writeMemMax[address+1] = lo;
1172 if (lo < writeMemMin[address+1])
1173 writeMemMin[address+1] = lo;
1177 /*if (address == 0x4E00)
1178 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1179 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1180 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1181 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1182 //if (address >= 0xF02200 && address <= 0xF0229F)
1183 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1184 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1185 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1186 /*extern uint32 totalFrames;
1187 if (address == 0xF02114)
1188 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1189 if (address == 0xF02110)
1190 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1191 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1192 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1194 /*if (address == 0x0100)//64*4)
1195 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1197 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1198 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1199 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1200 || address == 0x1AF05E)
1201 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1203 /*if (address >= 0x53D0 && address <= 0x53FF)
1204 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1205 //Testing AvP on UAE core...
1206 //000075A0: FFFFF80E B6320220 (BITMAP)
1207 /*if (address == 0x75A0 && value == 0xFFFF)
1209 printf("\nM68K: (16) Tripwire hit...\n");
1214 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1216 /* jaguar_mainRam[address] = value >> 8;
1217 jaguar_mainRam[address + 1] = value & 0xFF;*/
1218 SET16(jaguarMainRAM, address, value);
1220 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1221 CDROMWriteWord(address, value, M68K);
1222 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1223 TOMWriteWord(address, value, M68K);
1224 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1225 JERRYWriteWord(address, value, M68K);
1228 jaguar_unknown_writeword(address, value, M68K);
1229 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1230 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1231 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1232 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1236 MMUWrite16(address, value, M68K);
1240 void m68k_write_memory_32(unsigned int address, unsigned int value)
1242 // Musashi does this automagically for you, UAE core does not :-P
1243 address &= 0x00FFFFFF;
1244 /*if (address == 0x4E00)
1245 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1246 //WriteLog("--> [WM32]\n");
1247 /*if (address == 0x0100)//64*4)
1248 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1249 /*if (address >= 0xF03214 && address < 0xF0321F)
1250 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1251 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1252 /*extern bool doGPUDis;
1253 if (address == 0xF03214 && value == 0x88E30047)
1255 doGPUDis = true;//*/
1256 /* if (address == 0x51136 || address == 0xFB074)
1257 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1258 //Testing AvP on UAE core...
1259 //000075A0: FFFFF80E B6320220 (BITMAP)
1260 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1262 printf("\nM68K: (32) Tripwire hit...\n");
1267 m68k_write_memory_16(address, value >> 16);
1268 m68k_write_memory_16(address + 2, value & 0xFFFF);
1270 MMUWrite32(address, value, M68K);
1275 uint32 JaguarGetHandler(uint32 i)
1277 return JaguarReadLong(i * 4);
1280 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1282 uint32 handler = JaguarGetHandler(i);
1283 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1286 void M68K_show_context(void)
1288 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1290 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1292 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1294 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1298 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1300 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1302 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1306 WriteLog("68K disasm\n");
1307 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1308 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1309 // jaguar_dasm(0x5000, 0x14414);
1311 // WriteLog("\n.......[Cart start]...........\n\n");
1312 // jaguar_dasm(0x192000, 0x1000);//0x200);
1314 WriteLog("..................\n");
1316 if (TOMIRQEnabled(IRQ_VIDEO))
1318 WriteLog("video int: enabled\n");
1319 JaguarDasm(JaguarGetHandler(64), 0x200);
1322 WriteLog("video int: disabled\n");
1324 WriteLog("..................\n");
1326 for(int i=0; i<256; i++)
1328 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1329 uint32 address = (uint32)JaguarGetHandler(i);
1332 WriteLog(".........\n");
1334 WriteLog("$%08X\n", address);
1339 // Unknown read/write byte/word routines
1342 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1343 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1345 // 807EC4: movea.l #$f1b000, A1
1346 // 807ECA: movea.l #$8129e0, A0
1347 // 807ED0: move.l A0, D0
1348 // 807ED2: move.l #$f1bb94, D1
1349 // 807ED8: sub.l D0, D1
1350 // 807EDA: lsr.l #2, D1
1351 // 807EDC: move.l (A0)+, (A1)+
1352 // 807EDE: dbra D1, 807edc
1354 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1355 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1356 // space! (That is, unless the 68K causes a bus error...)
1358 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1360 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1361 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));
1363 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1364 // extern bool finished;
1366 // extern bool doDSPDis;
1372 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1374 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1375 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));
1377 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1378 // extern bool finished;
1380 // extern bool doDSPDis;
1386 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1388 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1389 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1391 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1392 // extern bool finished;
1394 // extern bool doDSPDis;
1401 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1403 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1404 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1406 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1407 // extern bool finished;
1409 // extern bool doDSPDis;
1417 // Disassemble M68K instructions at the given offset
1420 unsigned int m68k_read_disassembler_8(unsigned int address)
1422 return m68k_read_memory_8(address);
1425 unsigned int m68k_read_disassembler_16(unsigned int address)
1427 return m68k_read_memory_16(address);
1430 unsigned int m68k_read_disassembler_32(unsigned int address)
1432 return m68k_read_memory_32(address);
1435 void JaguarDasm(uint32 offset, uint32 qt)
1438 static char buffer[2048];//, mem[64];
1439 int pc = offset, oldpc;
1441 for(uint32 i=0; i<qt; i++)
1444 for(int j=0; j<64; j++)
1445 mem[j^0x01] = jaguar_byte_read(pc + j);
1447 pc += Dasm68000((char *)mem, buffer, 0);
1448 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1450 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1451 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1456 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1461 if (offset < 0x400000)
1462 data = jaguarMainRAM[offset & 0x3FFFFF];
1463 else if ((offset >= 0x800000) && (offset < 0xC00000))
1464 data = jaguarMainROM[offset - 0x800000];
1465 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1466 data = CDROMReadByte(offset, who);
1467 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1468 // data = jaguarBootROM[offset & 0x3FFFF];
1469 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1470 data = jagMemSpace[offset];
1471 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1472 data = TOMReadByte(offset, who);
1473 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1474 data = JERRYReadByte(offset, who);
1476 data = jaguar_unknown_readbyte(offset, who);
1481 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1484 if (offset <= 0x3FFFFE)
1486 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1488 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1491 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1493 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1494 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1495 return CDROMReadWord(offset, who);
1496 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1497 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1498 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1499 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1500 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1501 return TOMReadWord(offset, who);
1502 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1503 return JERRYReadWord(offset, who);
1505 return jaguar_unknown_readword(offset, who);
1508 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1510 /* if (offset >= 0x4E00 && offset < 0x4E04)
1511 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1512 //Need to check for writes in the range of $18FA70 + 8000...
1514 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1515 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1518 if (offset < 0x400000)
1520 jaguarMainRAM[offset & 0x3FFFFF] = data;
1523 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1525 CDROMWriteByte(offset, data, who);
1528 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1530 TOMWriteByte(offset, data, who);
1533 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1535 JERRYWriteByte(offset, data, who);
1539 jaguar_unknown_writebyte(offset, data, who);
1543 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1545 /* if (offset >= 0x4E00 && offset < 0x4E04)
1546 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1547 /*if (offset == 0x0100)//64*4)
1548 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1549 if (offset == 0x0102)//64*4)
1550 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1551 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1552 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1553 //Need to check for writes in the range of $18FA70 + 8000...
1555 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1556 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1557 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1558 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1562 if (offset <= 0x3FFFFE)
1567 1A 69 F0 ($0000) -> Starfield
1568 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1571 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1580 //This MUST be done by the 68K!
1581 /*if (offset == 0x670C)
1582 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1584 /*extern bool doGPUDis;
1585 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1586 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1587 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1588 doGPUDis = true;//*/
1589 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1590 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1591 if ((data & 0xFF00) != 0x7700)
1592 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1593 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1595 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1596 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1597 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1599 /*extern bool doGPUDis;
1600 if (offset == 0x120216 && who == GPU)
1601 doGPUDis = true;//*/
1602 /*extern uint32 gpu_pc;
1603 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1605 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1606 uint32 y = base / 0x300;
1607 uint32 x = (base - (y * 0x300)) / 2;
1608 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1611 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1613 //if (offset == (0x001E17F8 + 0x34))
1614 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1616 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1617 /*extern uint32 gpu_pc;
1618 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1620 extern int objectPtr;
1621 // if (offset > 0x148000)
1624 if (starCount > objectPtr)
1627 // if (starCount == 1)
1628 // WriteLog("--> Drawing 1st star...\n");
1630 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1631 // uint32 y = base / 0x300;
1632 // uint32 x = (base - (y * 0x300)) / 2;
1633 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1635 //A star of interest...
1636 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1637 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1638 //JWW: Blitter writing echo 77B3 at 0011D022...
1640 //extern bool doGPUDis;
1641 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1644 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1647 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1648 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1650 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1651 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1654 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1656 CDROMWriteWord(offset, data, who);
1659 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1661 TOMWriteWord(offset, data, who);
1664 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1666 JERRYWriteWord(offset, data, who);
1669 // Don't bomb on attempts to write to ROM
1670 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1673 jaguar_unknown_writeword(offset, data, who);
1676 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1677 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1679 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1682 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1683 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1685 /* extern bool doDSPDis;
1686 if (offset < 0x400 && !doDSPDis)
1688 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1691 /*if (offset == 0x0100)//64*4)
1692 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1694 JaguarWriteWord(offset, data >> 16, who);
1695 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1698 void JaguarSetScreenBuffer(uint32 * buffer)
1700 // This is in TOM, but we set it here...
1701 screenBuffer = buffer;
1704 void JaguarSetScreenPitch(uint32 pitch)
1706 // This is in TOM, but we set it here...
1707 screenPitch = pitch;
1711 // Jaguar console initialization
1713 void JaguarInit(void)
1715 #ifdef CPU_DEBUG_MEMORY
1716 memset(readMem, 0x00, 0x400000);
1717 memset(writeMemMin, 0xFF, 0x400000);
1718 memset(writeMemMax, 0x00, 0x400000);
1720 memset(jaguarMainRAM, 0x00, 0x400000);
1721 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1722 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1723 //NOTE: This *doesn't* fix FlipOut...
1724 //Or does it? Hmm...
1725 //Seems to want $01010101... Dunno why. Investigate!
1726 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1727 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1728 lowerField = false; // Reset the lower field flag
1730 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1731 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1739 //New timer based code stuffola...
1740 void HalflineCallback(void);
1741 void RenderCallback(void);
1742 void JaguarReset(void)
1744 //Need to change this so it uses the single RAM space and load the BIOS
1745 //into it somewhere...
1746 //Also, have to change this here and in JaguarReadXX() currently
1747 // Only use the system BIOS if it's available...! (it's always available now!)
1748 // AND only if a jaguar cartridge has been inserted.
1749 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1750 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1752 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1754 // WriteLog("jaguar_reset():\n");
1760 m68k_pulse_reset(); // Reset the 68000
1761 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1763 lowerField = false; // Reset the lower field flag
1764 // New timer base code stuffola...
1765 InitializeEventList();
1766 // SetCallbackTime(ScanlineCallback, 63.5555);
1767 // SetCallbackTime(ScanlineCallback, 31.77775);
1768 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1771 void JaguarDone(void)
1773 #ifdef CPU_DEBUG_MEMORY
1774 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1776 for(uint32 i=0; i<=raPtr; i++)
1778 WriteLog("\t%08X\n", returnAddr[i]);
1779 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1780 jaguar_dasm(returnAddr[i] - 16, 16);
1785 /* int start = 0, end = 0;
1786 bool endTriggered = false, startTriggered = false;
1787 for(int i=0; i<0x400000; i++)
1789 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1791 if (!startTriggered)
1792 startTriggered = true, endTriggered = false, start = i;
1794 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1800 end = i - 1, endTriggered = true, startTriggered = false;
1801 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1808 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1809 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1810 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1811 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1812 for(int i=-2; i<9; i++)
1813 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1815 /* WriteLog("\nM68000 disassembly at $802288...\n");
1816 jaguar_dasm(0x802288, 3);
1817 WriteLog("\nM68000 disassembly at $802200...\n");
1818 jaguar_dasm(0x802200, 500);
1819 WriteLog("\nM68000 disassembly at $802518...\n");
1820 jaguar_dasm(0x802518, 100);//*/
1822 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1823 jaguar_dasm(0x803F00, 500);
1826 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1827 jaguar_dasm(0x802B00, 500);
1830 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1831 jaguar_dasm(0x809900, 500);
1834 /* WriteLog("\n\nDump of $8093C8:\n\n");
1835 for(int i=0x8093C8; i<0x809900; i+=4)
1836 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1837 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1838 jaguar_dasm(0x90006C, 500);
1840 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1841 jaguar_dasm(0x1AC000, 6000);
1844 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1845 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1846 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
1847 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1848 M68K_show_context();
1851 #if 0 // This is drawn already...
1852 WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
1853 for(uint32 i=0x64; i<=0x7C; i+=4)
1854 WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
1863 // temp, until debugger is in place
1864 //00802016: jsr $836F1A.l
1865 //0080201C: jsr $836B30.l
1866 //00802022: jsr $836B18.l
1867 //00802028: jsr $8135F0.l
1868 //00813C1E: jsr $813F76.l
1869 //00802038: jsr $836D00.l
1870 //00802098: jsr $8373A4.l
1871 //008020A2: jsr $83E24A.l
1872 //008020BA: jsr $83E156.l
1873 //008020C6: jsr $83E19C.l
1874 //008020E6: jsr $8445E8.l
1875 //008020EC: jsr $838C20.l
1876 //0080211A: jsr $838ED6.l
1877 //00802124: jsr $89CA56.l
1878 //0080212A: jsr $802B48.l
1880 WriteLog("-------------------------------------------\n");
1881 JaguarDasm(0x8445E8, 0x200);
1882 WriteLog("-------------------------------------------\n");
1883 JaguarDasm(0x838C20, 0x200);
1884 WriteLog("-------------------------------------------\n");
1885 JaguarDasm(0x838ED6, 0x200);
1886 WriteLog("-------------------------------------------\n");
1887 JaguarDasm(0x89CA56, 0x200);
1888 WriteLog("-------------------------------------------\n");
1889 JaguarDasm(0x802B48, 0x200);
1890 WriteLog("\n\nM68000 disassembly at $802000...\n");
1891 JaguarDasm(0x802000, 6000);
1894 /* WriteLog("\n\nM68000 disassembly at $4000...\n");
1895 JaguarDasm(0x4000, 10000);
1897 // WriteLog("\n\nM68000 disassembly at $802000...\n");
1898 // JaguarDasm(0x800830, 0x1000);
1899 // WriteLog("\n\nM68000 disassembly at $4100...\n");
1900 // JaguarDasm(0x4100, 200);
1901 // WriteLog("\n\nM68000 disassembly at $800800...\n");
1902 // JaguarDasm(0x800800, 0x1000);
1906 // Main Jaguar execution loop (1 frame)
1908 void JaguarExecute(uint32 * backbuffer, bool render)
1910 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1911 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1912 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1913 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1915 // uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
1916 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1917 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1918 //It seems that they mean it when they say that VDE is the end of object processing.
1919 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1920 //buffer and not to write any more pixels... !!! FIX !!!
1921 // uint16 vde = TOMReadWord(0xF00048, JAGUAR);
1923 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1924 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1925 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1926 //seem to indicate the refresh rate is *half* the above...
1927 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1928 // Should these be hardwired or read from VP? Yes, from VP!
1929 // Err, actually, they should be hardwired, and hardwired to a set # of
1931 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1932 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1934 /*extern int effect_start;
1936 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1938 //extern int start_logging;
1939 for(uint16 i=0; i<vp; i++)
1941 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1942 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
1943 TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
1945 //Not sure if this is correct...
1946 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1947 //Which means that it normally wouldn't go when it's zero.
1948 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
1950 // We don't have to worry about autovectors & whatnot because the Jaguar
1951 // tells you through its HW registers who sent the interrupt...
1952 TOMSetPendingVideoInt();
1956 //if (start_logging)
1957 // WriteLog("About to execute M68K (%u)...\n", i);
1958 m68k_execute(M68KCyclesPerScanline);
1959 //if (start_logging)
1960 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1961 TOMExecPIT(RISCCyclesPerScanline);
1962 //if (start_logging)
1963 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1964 JERRYExecPIT(RISCCyclesPerScanline);
1965 //if (start_logging)
1966 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1967 JERRYI2SExec(RISCCyclesPerScanline);
1968 BUTCHExec(RISCCyclesPerScanline);
1969 //if (start_logging)
1970 // WriteLog("About to execute GPU (%u)...\n", i);
1972 GPUExec(RISCCyclesPerScanline);
1976 if (vjs.usePipelinedDSP)
1977 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1979 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1980 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1983 //if (start_logging)
1984 // WriteLog("About to execute OP (%u)...\n", i);
1985 TOMExecHalfline(i, render);
1989 // Temp debugging stuff
1991 void DumpMainMemory(void)
1993 FILE * fp = fopen("./memdump.bin", "wb");
1998 fwrite(jaguarMainRAM, 1, 0x400000, fp);
2002 uint8 * GetRamPtr(void)
2004 return jaguarMainRAM;
2008 // New Jaguar execution stack
2009 // This executes 1 frame's worth of code.
2012 void JaguarExecuteNew(void)
2018 double timeToNextEvent = GetTimeToNextEvent();
2019 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2021 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2024 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2028 if (vjs.usePipelinedDSP)
2029 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
2031 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
2039 #define USE_CORRECT_PAL_TIMINGS
2040 // A lot of confusion comes from here...
2041 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
2042 // of whether the display is interlaced or not. The only difference with an
2043 // interlaced display is that the high bit of VC will be set when the lower
2044 // field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
2045 // regardless of whether it's in interlace mode or not.
2046 // NB2: Seems it doens't always, not sure what the constraint is...)
2048 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2049 // rendering two fields that are slighty vertically offset from each other.
2050 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2051 // is rendered in this mode so that each field, when overlaid on each other,
2052 // will yield the final picture at the full resolution for the full frame.
2054 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2055 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2056 // it will be half this number for a half frame. BUT, since we're counting
2057 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
2059 // Scanline times are 63.5555... µs in NTSC and 64 µs in PAL
2060 // Half line times are, naturally, half of this. :-P
2061 void HalflineCallback(void)
2063 //OK, this is hardwired to run in NTSC, and for who knows how long.
2064 //Need to fix this so that it does a half-line in the correct amount of time
2065 //and number of lines, depending on which mode we're in. [FIXED]
2066 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
2067 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2068 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
2069 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
2072 #ifdef USE_CORRECT_PAL_TIMINGS
2073 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2074 // So we cut the number of half-lines in a frame in half. :-P
2075 uint16 numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2077 if ((vc & 0x7FF) >= numHalfLines)
2079 if ((vc & 0x7FF) >= vp)
2083 // lowerField = !lowerField;
2085 // If we're rendering the lower field, set the high bit (#12, counting
2091 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2092 TOMWriteWord(0xF00006, vc, JAGUAR);
2094 //This is a crappy kludge, but maybe it'll work for now...
2095 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2096 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
2098 // We don't have to worry about autovectors & whatnot because the Jaguar
2099 // tells you through its HW registers who sent the interrupt...
2100 TOMSetPendingVideoInt();
2104 TOMExecHalfline(vc, true);
2106 //Change this to VBB???
2107 //Doesn't seem to matter (at least for Flip Out & I-War)
2108 if ((vc & 0x7FF) == 0)
2115 #ifdef USE_CORRECT_PAL_TIMINGS
2116 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2118 // SetCallbackTime(HalflineCallback, 63.5555);
2119 SetCallbackTime(HalflineCallback, 31.77775);
2123 // This isn't currently used, but maybe it should be...
2125 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
2126 handles all the rest, so this isn't needed. :-P
2128 void RenderCallback(void)
2130 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2131 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time