4 // Originally by David Raingeard (Cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
6 // Cleanups and endian wrongness amelioration by James L. Hammons
7 // Note: Endian wrongness probably stems from the MAME origins of this emu and
8 // the braindead way in which MAME handled memory when this was written. :-)
10 // JLH = James L. Hammons
13 // --- ---------- -----------------------------------------------------------
14 // JLH 11/25/2009 Major rewrite of memory subsystem and handlers
20 #include "SDL_opengl.h"
38 //Do this in makefile??? Yes! Could, but it's easier to define here...
39 //#define LOG_UNMAPPED_MEMORY_ACCESSES
40 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
41 #define ABORT_ON_ILLEGAL_INSTRUCTIONS
42 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
43 #define CPU_DEBUG_MEMORY
44 //#define LOG_CD_BIOS_CALLS
46 // Private function prototypes
48 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who = UNKNOWN);
49 unsigned jaguar_unknown_readword(unsigned address, uint32 who = UNKNOWN);
50 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who = UNKNOWN);
51 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who = UNKNOWN);
52 void M68K_show_context(void);
56 #ifdef CPU_DEBUG_MEMORY
57 extern bool startMemLog; // Set by "e" key
58 extern int effect_start;
59 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
62 // Really, need to include memory.h for this, but it might interfere with some stuff...
63 extern uint8 jagMemSpace[];
67 uint32 jaguar_active_memory_dumps = 0;
69 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
70 bool jaguarCartInserted = false;
72 #ifdef CPU_DEBUG_MEMORY
73 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
74 uint8 readMem[0x400000];
75 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
78 uint32 pcQueue[0x400];
82 // Callback function to detect illegal instructions
84 void GPUDumpDisassembly(void);
85 void GPUDumpRegisters(void);
86 static bool start = false;
88 void M68KInstructionHook(void)
90 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
93 // Ideally, we'd save all the registers as well...
94 pcQueue[pcQPtr++] = m68kPC;
97 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
99 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
101 static char buffer[2048];
102 for(int i=0; i<0x400; i++)
104 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
105 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
109 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
110 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
111 for(int i=0; i<10; i++)
112 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
113 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
119 // Disassemble everything
121 static char buffer[2048];
122 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
123 WriteLog("%08X: %s", m68kPC, buffer);
124 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
125 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
126 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
128 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
130 static char buffer[2048];
131 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
132 WriteLog("%08X: %s", m68kPC, buffer);
133 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
134 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
135 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
137 /* if (m68kPC == 0x8D0E48 && effect_start5)
139 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
141 GPUDumpDisassembly();
145 /* uint16 opcode = JaguarReadWord(m68kPC);
146 if (opcode == 0x4E75) // RTS
149 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
151 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
153 if (raPtr != 0xFFFFFFFF)
155 for(uint32 i=0; i<=raPtr; i++)
157 if (returnAddr[i] == addr)
166 returnAddr[++raPtr] = addr;
170 //Flip Out! debugging...
173 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
174 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
175 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
176 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
178 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
180 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
181 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
182 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
183 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
184 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
185 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
186 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
188 /* static char buffer[2048];
189 //if (m68kPC > 0x805F48) start = true;
190 //if (m68kPC > 0x806486) start = true;
191 //if (m68kPC == 0x805FEE) start = true;
192 //if (m68kPC == 0x80600C)// start = true;
193 if (m68kPC == 0x802058) start = true;
195 // GPUDumpRegisters();
196 // GPUDumpDisassembly();
198 // M68K_show_context();
204 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
205 WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1));
208 /* if (m68kPC == 0x803F16)
210 WriteLog("M68K: Registers found at $803F16:\n");
211 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
212 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
213 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
215 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
216 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
218 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
219 // !!! Investigate !!!
220 /*extern bool doDSPDis;
221 static bool disgo = false;
222 if (m68kPC == 0x50222)
225 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
226 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
229 if (m68kPC == 0x5000)
234 static char buffer[2048];
235 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
236 WriteLog("%08X: %s", m68kPC, buffer);
237 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
238 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
239 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
241 if (m68kPC == 0x82E1A)
243 static char buffer[2048];
244 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
245 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
246 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
247 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
248 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
250 if (m68kPC == 0x82E58)
251 WriteLog("--> [Routine end]\n");
252 if (m68kPC == 0x80004)
254 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
255 // m68k_set_reg(M68K_REG_D2, 0x12345678);
258 #ifdef LOG_CD_BIOS_CALLS
281 if (m68kPC == 0x3000)
282 WriteLog("M68K: CD_init\n");
283 else if (m68kPC == 0x3006 + (6 * 0))
284 WriteLog("M68K: CD_mode\n");
285 else if (m68kPC == 0x3006 + (6 * 1))
286 WriteLog("M68K: CD_ack\n");
287 else if (m68kPC == 0x3006 + (6 * 2))
288 WriteLog("M68K: CD_jeri\n");
289 else if (m68kPC == 0x3006 + (6 * 3))
290 WriteLog("M68K: CD_spin\n");
291 else if (m68kPC == 0x3006 + (6 * 4))
292 WriteLog("M68K: CD_stop\n");
293 else if (m68kPC == 0x3006 + (6 * 5))
294 WriteLog("M68K: CD_mute\n");
295 else if (m68kPC == 0x3006 + (6 * 6))
296 WriteLog("M68K: CD_umute\n");
297 else if (m68kPC == 0x3006 + (6 * 7))
298 WriteLog("M68K: CD_paus\n");
299 else if (m68kPC == 0x3006 + (6 * 8))
300 WriteLog("M68K: CD_upaus\n");
301 else if (m68kPC == 0x3006 + (6 * 9))
302 WriteLog("M68K: CD_read\n");
303 else if (m68kPC == 0x3006 + (6 * 10))
304 WriteLog("M68K: CD_uread\n");
305 else if (m68kPC == 0x3006 + (6 * 11))
306 WriteLog("M68K: CD_setup\n");
307 else if (m68kPC == 0x3006 + (6 * 12))
308 WriteLog("M68K: CD_ptr\n");
309 else if (m68kPC == 0x3006 + (6 * 13))
310 WriteLog("M68K: CD_osamp\n");
311 else if (m68kPC == 0x3006 + (6 * 14))
312 WriteLog("M68K: CD_getoc\n");
313 else if (m68kPC == 0x3006 + (6 * 15))
314 WriteLog("M68K: CD_initm\n");
315 else if (m68kPC == 0x3006 + (6 * 16))
316 WriteLog("M68K: CD_initf\n");
317 else if (m68kPC == 0x3006 + (6 * 17))
318 WriteLog("M68K: CD_switch\n");
320 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
321 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
322 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
323 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
326 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
327 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
329 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
330 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
332 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
333 // keep going even when the 68K dumped back to the debugger or what have you).
335 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
336 // Try setting the vector to the illegal instruction...
337 //This doesn't work right either! Do something else! Quick!
338 // SET32(jaguar_mainRam, 0x10, m68kPC);
344 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
345 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
346 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
347 for(int i=0; i<10; i++)
348 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
349 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
353 // WriteLog("\n\n68K disasm\n\n");
354 // jaguar_dasm(0x802000, 0x50C);
365 Now here be dragons...
366 Here is how memory ranges are defined in the CoJag driver.
367 Note that we only have to be concerned with 3 entities read/writing anything:
368 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
369 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
370 things that are entirely internal to those modules. This way we should be able to get a handle on all
371 this crap which is currently scattered over Hell's Half Acre(tm).
373 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
374 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
376 /*************************************
378 * Main CPU memory handlers
380 *************************************/
382 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
383 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
384 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
385 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
386 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
387 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
388 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
389 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
390 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
391 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
392 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
393 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
394 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
395 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
396 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
397 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
398 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
399 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
400 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
401 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
402 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
403 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
404 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
407 /*************************************
409 * GPU memory handlers
411 *************************************/
413 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
414 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
415 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
416 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
417 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
418 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
419 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
420 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
421 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
422 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
423 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
426 /*************************************
428 * DSP memory handlers
430 *************************************/
432 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
433 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
434 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
435 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
436 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
437 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
438 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
439 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
440 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
445 //#define EXPERIMENTAL_MEMORY_HANDLING
446 // Experimental memory mappage...
447 // Dunno if this is a good approach or not, but it seems to make better
448 // sense to have all this crap in one spot intstead of scattered all over
449 // the place the way it is now.
450 #ifdef EXPERIMENTAL_MEMORY_HANDLING
452 #define NEW_TIMER_SYSTEM
455 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
456 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
457 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
458 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
459 bool BIOSLoaded = false;
460 bool CDBIOSLoaded = false;
463 uint8 tomRAM[0x4000];
464 uint8 jerryRAM[0x10000];
465 static uint16 eeprom_ram[64];
467 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
470 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
472 // M68K Memory map/handlers
474 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
475 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
476 // Note that this is really memory mapped I/O region...
477 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
478 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
479 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
480 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
481 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
482 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
483 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
484 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
485 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
486 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
487 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
488 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
490 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
492 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
493 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
494 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
495 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
496 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
497 //What about LBUF writes???
498 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
499 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
500 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
502 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
506 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
507 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
508 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
511 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
512 0 = pad0/1 button values (4 bits each), RO(?)
513 1 = pad0/1 index value (4 bits each), WO
515 3 = NTSC/PAL, certain button states, RO
517 JOYSTICK $F14000 Read/Write
519 Read fedcba98 7654321q f-1 Signals J15 to J1
520 q Cartridge EEPROM output data
521 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
522 0 = disable J7-J0 outputs
525 0 = Audio muted (reset state)
527 7-4 J7-J4 outputs (port 2)
528 3-0 J3-J0 outputs (port 1)
529 JOYBUTS $F14002 Read Only
531 Read xxxxxxxx rrdv3210 x don't care
534 v 1 = NTSC Video hardware
535 0 = PAL Video hardware
536 3-2 Button inputs B3 & B2 (port 2)
537 1-0 Button inputs B1 & B0 (port 1)
539 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
540 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
548 0 1 1 1 Row 3 C3 Option # 9 6 3
552 1 0 1 1 Row 2 C2 C 0 8 5 2
554 1 1 0 1 Row 1 C1 B * 7 4 1
555 1 1 1 0 Row 0 Pause A Up Down Left Right
558 0 bit read in any position means that button is pressed.
559 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
563 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
565 // Not sure, but I think the system only has 24 address bits...
566 address &= 0x00FFFFFF;
568 // RAM ($000000 - $3FFFFF) 4M
569 if (address <= 0x3FFFFF)
570 jaguarMainRAM[address] = byte;
571 // hole ($400000 - $7FFFFF) 4M
572 else if (address <= 0x7FFFFF)
574 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
575 else if (address <= 0xDFFEFF)
577 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
578 else if (address <= 0xDFFFFF)
580 cdRAM[address & 0xFF] = byte;
582 if ((address & 0xFF) < 12 * 4)
583 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
584 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
587 // BIOS ROM ($E00000 - $E3FFFF) 256K
588 else if (address <= 0xE3FFFF)
590 // hole ($E40000 - $EFFFFF) 768K
591 else if (address <= 0xEFFFFF)
593 // TOM ($F00000 - $F0FFFF) 64K
594 else if (address <= 0xF0FFFF)
597 if (address == 0xF00050)
599 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
603 else if (address == 0xF00051)
605 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
609 else if (address == 0xF00052)
611 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
615 else if (address == 0xF00053)
617 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
621 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
623 // Writing to one CLUT writes to the other
624 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
625 tomRAM[address] = tomRAM[address + 0x200] = byte;
628 //What about LBUF writes???
629 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
631 GPUWriteByte(address, byte, who);
634 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
636 BlitterWriteByte(address, byte, who);
639 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
641 GPUWriteByte(address, byte, who);
645 tomRAM[address & 0x3FFF] = byte;
647 // JERRY ($F10000 - $F1FFFF) 64K
648 else if (address <= 0xF1FFFF)
652 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
654 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
656 DSPWriteByte(address, byte, who);
659 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
661 DSPWriteByte(address, byte, who);
664 // SCLK ($F1A150--8 bits wide)
665 //NOTE: This should be taken care of in DAC...
666 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
668 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
669 if ((address & 0x03) == 2)
670 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
672 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
674 JERRYI2SInterruptTimer = -1;
675 #ifndef NEW_TIMER_SYSTEM
678 RemoveCallback(JERRYI2SCallback);
683 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
684 else if (address >= 0xF1A148 && address <= 0xF1A157)
686 DACWriteByte(address, byte, who);
689 else if (address >= 0xF10000 && address <= 0xF10007)
691 #ifndef NEW_TIMER_SYSTEM
692 switch (address & 0x07)
695 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
699 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
703 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
707 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
711 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
715 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
719 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
723 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
727 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
731 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
733 clock_byte_write(offset, byte);
736 // JERRY -> 68K interrupt enables/latches (need to be handled!)
737 else if (address >= 0xF10020 && address <= 0xF10023)
739 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
741 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
743 anajoy_byte_write(offset, byte);
746 else if ((address >= 0xF14000) && (address <= 0xF14003))
748 JoystickWriteByte(address, byte);
749 EepromWriteByte(address, byte);
752 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
754 EepromWriteByte(address, byte);
757 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
758 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
761 jerryRAM[address & 0xFFFF] = byte;
763 // hole ($F20000 - $FFFFFF) 1M - 128K
768 void WriteWord(uint32 adddress, uint16 word)
772 void WriteDWord(uint32 adddress, uint32 dword)
776 uint8 ReadByte(uint32 adddress)
780 uint16 ReadWord(uint32 adddress)
784 uint32 ReadDWord(uint32 adddress)
790 // Musashi 68000 read/write/IRQ functions
797 IPL Name Vector Control
798 ---------+---------------+---------------+---------------
799 2 VBLANK IRQ $100 INT1 bit #0
800 2 GPU IRQ $100 INT1 bit #1
801 2 HBLANK IRQ $100 INT1 bit #2
802 2 Timer IRQ $100 INT1 bit #3
804 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
805 and are therefore indistinguishable.
807 A typical way to install a LEVEL2 handler for the 68000 would be
808 something like this, you gotta supply "last_line" and "handler".
809 Note that the interrupt is auto vectored thru $100 (not $68)
817 IRQS_HANDLED=$909 ;; VBLANK and TIMER
819 move.w #$2700,sr ;; no IRQs please
820 move.l #handler,V_AUTO ;; install our routine
822 move.w #last_line,VI ;; scanline where IRQ should occur
823 ;; should be 'odd' BTW
824 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
825 move.w #$2100,sr ;; enable IRQs on the 68K
843 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
844 move.w #0,INT2 ; let GPU run again
848 As you can see, if you have multiple INT1 interrupts coming in,
849 you need to check the lower byte of INT1, to see which interrupt
852 int irq_ack_handler(int level)
854 // Tracing the IPL lines on the Jaguar schematic yields the following:
855 // IPL1 is connected to INTL on TOM (OUT to 68K)
856 // IPL0-2 are also tied to Vcc via 4.7K resistors!
857 // (DINT on TOM goes into DINT on JERRY (IN from Jerry))
858 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
859 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
861 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
862 // They aren't, and this causes problems with a, err, specific ROM. :-D
866 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
867 return 64; // Set user interrupt #0
870 return M68K_INT_ACK_AUTOVECTOR;
873 //#define USE_NEW_MMU
875 unsigned int m68k_read_memory_8(unsigned int address)
877 #ifdef CPU_DEBUG_MEMORY
878 if ((address >= 0x000000) && (address <= 0x3FFFFF))
881 readMem[address] = 1;
884 //WriteLog("[RM8] Addr: %08X\n", address);
885 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
886 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
887 || address == 0x1AF05E)
888 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
890 unsigned int retVal = 0;
892 if ((address >= 0x000000) && (address <= 0x3FFFFF))
893 retVal = jaguarMainRAM[address];
894 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
895 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
896 retVal = jaguarMainROM[address - 0x800000];
897 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
898 // retVal = jaguarBootROM[address - 0xE00000];
899 // retVal = jaguarDevBootROM1[address - 0xE00000];
900 retVal = jagMemSpace[address];
901 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
902 retVal = CDROMReadByte(address);
903 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
904 retVal = TOMReadByte(address, M68K);
905 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
906 retVal = JERRYReadByte(address, M68K);
908 retVal = jaguar_unknown_readbyte(address, M68K);
910 //if (address >= 0x2800 && address <= 0x281F)
911 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
912 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
913 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
916 return MMURead8(address, M68K);
920 void gpu_dump_disassembly(void);
921 void gpu_dump_registers(void);
923 unsigned int m68k_read_memory_16(unsigned int address)
925 #ifdef CPU_DEBUG_MEMORY
926 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
929 readMem[address] = 1, readMem[address + 1] = 1;
931 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
933 return 0x4E71; // NOP
935 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
937 return 0x4E71; // NOP
939 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
941 return 0x4E71; // NOP
943 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
945 return 0x4E71; // NOP
947 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
949 return 0x4E71; // NOP
951 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
953 return 0x4E71; // NOP
956 //WriteLog("[RM16] Addr: %08X\n", address);
957 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
958 // for(int i=0; i<10000; i++)
959 WriteLog("[M68K] In routine #6!\n");//*/
960 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
961 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
962 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
964 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
965 gpu_dump_registers();
966 gpu_dump_disassembly();
967 // for(int i=0; i<10000; i++)
968 // WriteLog("[M68K] About to run GPU!\n");
970 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
971 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
973 if (address == 0x000066A0)
975 gpu_dump_registers();
976 gpu_dump_disassembly();
978 for(int i=0; i<10000; i++)
979 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
981 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
982 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
983 || address == 0x1AF05E)
984 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
986 unsigned int retVal = 0;
988 if ((address >= 0x000000) && (address <= 0x3FFFFE))
989 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
990 retVal = GET16(jaguarMainRAM, address);
991 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
992 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
993 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
994 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
995 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
996 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
997 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
998 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
999 retVal = CDROMReadWord(address, M68K);
1000 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1001 retVal = TOMReadWord(address, M68K);
1002 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1003 retVal = JERRYReadWord(address, M68K);
1005 retVal = jaguar_unknown_readword(address, M68K);
1007 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1008 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1009 //if (address >= 0x2800 && address <= 0x281F)
1010 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1011 //$8B3AE -> Transferred from $F1C010
1012 //$8B5E4 -> Only +1 read at $808AA
1013 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1014 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1017 return MMURead16(address, M68K);
1021 unsigned int m68k_read_memory_32(unsigned int address)
1023 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1024 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1025 WriteLog("[RM32 PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
1027 //WriteLog("--> [RM32]\n");
1029 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1031 return MMURead32(address, M68K);
1035 void m68k_write_memory_8(unsigned int address, unsigned int value)
1037 #ifdef CPU_DEBUG_MEMORY
1038 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1042 if (value > writeMemMax[address])
1043 writeMemMax[address] = value;
1044 if (value < writeMemMin[address])
1045 writeMemMin[address] = value;
1049 /*if (address == 0x4E00)
1050 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1051 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1052 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1053 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1055 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1056 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1059 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1060 jaguarMainRAM[address] = value;
1061 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1062 CDROMWriteByte(address, value, M68K);
1063 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1064 TOMWriteByte(address, value, M68K);
1065 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1066 JERRYWriteByte(address, value, M68K);
1068 jaguar_unknown_writebyte(address, value, M68K);
1070 MMUWrite8(address, value, M68K);
1074 void m68k_write_memory_16(unsigned int address, unsigned int value)
1076 #ifdef CPU_DEBUG_MEMORY
1077 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1081 uint8 hi = value >> 8, lo = value & 0xFF;
1083 if (hi > writeMemMax[address])
1084 writeMemMax[address] = hi;
1085 if (hi < writeMemMin[address])
1086 writeMemMin[address] = hi;
1088 if (lo > writeMemMax[address+1])
1089 writeMemMax[address+1] = lo;
1090 if (lo < writeMemMin[address+1])
1091 writeMemMin[address+1] = lo;
1095 /*if (address == 0x4E00)
1096 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1097 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1098 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1099 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1100 //if (address >= 0xF02200 && address <= 0xF0229F)
1101 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1102 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1103 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1104 /*extern uint32 totalFrames;
1105 if (address == 0xF02114)
1106 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1107 if (address == 0xF02110)
1108 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1109 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1110 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1112 /*if (address == 0x0100)//64*4)
1113 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1115 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1116 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1117 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1118 || address == 0x1AF05E)
1119 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1122 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1124 /* jaguar_mainRam[address] = value >> 8;
1125 jaguar_mainRam[address + 1] = value & 0xFF;*/
1126 SET16(jaguarMainRAM, address, value);
1128 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1129 CDROMWriteWord(address, value, M68K);
1130 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1131 TOMWriteWord(address, value, M68K);
1132 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1133 JERRYWriteWord(address, value, M68K);
1136 jaguar_unknown_writeword(address, value, M68K);
1137 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1138 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1139 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1140 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1144 MMUWrite16(address, value, M68K);
1148 void m68k_write_memory_32(unsigned int address, unsigned int value)
1150 /*if (address == 0x4E00)
1151 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1152 //WriteLog("--> [WM32]\n");
1153 /*if (address == 0x0100)//64*4)
1154 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1155 /*if (address >= 0xF03214 && address < 0xF0321F)
1156 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1157 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1158 /*extern bool doGPUDis;
1159 if (address == 0xF03214 && value == 0x88E30047)
1161 doGPUDis = true;//*/
1162 /* if (address == 0x51136 || address == 0xFB074)
1163 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1166 m68k_write_memory_16(address, value >> 16);
1167 m68k_write_memory_16(address + 2, value & 0xFFFF);
1169 MMUWrite32(address, value, M68K);
1174 uint32 JaguarGetHandler(uint32 i)
1176 return JaguarReadLong(i * 4);
1179 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1181 uint32 handler = JaguarGetHandler(i);
1182 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1185 void M68K_show_context(void)
1187 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1188 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1189 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1191 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1192 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1194 WriteLog("68K disasm\n");
1195 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1196 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1197 // jaguar_dasm(0x5000, 0x14414);
1199 // WriteLog("\n.......[Cart start]...........\n\n");
1200 // jaguar_dasm(0x192000, 0x1000);//0x200);
1202 WriteLog("..................\n");
1204 if (TOMIRQEnabled(IRQ_VIDEO))
1206 WriteLog("video int: enabled\n");
1207 JaguarDasm(JaguarGetHandler(64), 0x200);
1210 WriteLog("video int: disabled\n");
1212 WriteLog("..................\n");
1214 for(int i=0; i<256; i++)
1216 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1217 uint32 address = (uint32)JaguarGetHandler(i);
1220 WriteLog(".........\n");
1222 WriteLog("$%08X\n", address);
1227 // Unknown read/write byte/word routines
1230 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1231 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1233 // 807EC4: movea.l #$f1b000, A1
1234 // 807ECA: movea.l #$8129e0, A0
1235 // 807ED0: move.l A0, D0
1236 // 807ED2: move.l #$f1bb94, D1
1237 // 807ED8: sub.l D0, D1
1238 // 807EDA: lsr.l #2, D1
1239 // 807EDC: move.l (A0)+, (A1)+
1240 // 807EDE: dbra D1, 807edc
1242 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1243 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1244 // space! (That is, unless the 68K causes a bus error...)
1246 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1248 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1249 WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1251 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1252 // extern bool finished;
1254 // extern bool doDSPDis;
1260 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1262 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1263 WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1265 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1266 // extern bool finished;
1268 // extern bool doDSPDis;
1274 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1276 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1277 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1279 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1280 // extern bool finished;
1282 // extern bool doDSPDis;
1289 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1291 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1292 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1294 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1295 // extern bool finished;
1297 // extern bool doDSPDis;
1305 // Disassemble M68K instructions at the given offset
1308 unsigned int m68k_read_disassembler_8(unsigned int address)
1310 return m68k_read_memory_8(address);
1313 unsigned int m68k_read_disassembler_16(unsigned int address)
1315 return m68k_read_memory_16(address);
1318 unsigned int m68k_read_disassembler_32(unsigned int address)
1320 return m68k_read_memory_32(address);
1323 void JaguarDasm(uint32 offset, uint32 qt)
1326 static char buffer[2048];//, mem[64];
1327 int pc = offset, oldpc;
1329 for(uint32 i=0; i<qt; i++)
1332 for(int j=0; j<64; j++)
1333 mem[j^0x01] = jaguar_byte_read(pc + j);
1335 pc += Dasm68000((char *)mem, buffer, 0);
1336 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1338 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1339 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1344 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1349 if (offset < 0x400000)
1350 data = jaguarMainRAM[offset & 0x3FFFFF];
1351 else if ((offset >= 0x800000) && (offset < 0xC00000))
1352 data = jaguarMainROM[offset - 0x800000];
1353 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1354 data = CDROMReadByte(offset, who);
1355 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1356 // data = jaguarBootROM[offset & 0x3FFFF];
1357 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1358 data = jagMemSpace[offset];
1359 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1360 data = TOMReadByte(offset, who);
1361 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1362 data = JERRYReadByte(offset, who);
1364 data = jaguar_unknown_readbyte(offset, who);
1369 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1372 if (offset <= 0x3FFFFE)
1374 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1376 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1379 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1381 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1382 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1383 return CDROMReadWord(offset, who);
1384 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1385 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1386 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1387 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1388 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1389 return TOMReadWord(offset, who);
1390 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1391 return JERRYReadWord(offset, who);
1393 return jaguar_unknown_readword(offset, who);
1396 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1398 /* if (offset >= 0x4E00 && offset < 0x4E04)
1399 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1400 //Need to check for writes in the range of $18FA70 + 8000...
1402 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1403 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1406 if (offset < 0x400000)
1408 jaguarMainRAM[offset & 0x3FFFFF] = data;
1411 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1413 CDROMWriteByte(offset, data, who);
1416 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1418 TOMWriteByte(offset, data, who);
1421 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1423 JERRYWriteByte(offset, data, who);
1427 jaguar_unknown_writebyte(offset, data, who);
1431 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1433 /* if (offset >= 0x4E00 && offset < 0x4E04)
1434 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1435 /*if (offset == 0x0100)//64*4)
1436 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1437 if (offset == 0x0102)//64*4)
1438 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1439 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1440 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1441 //Need to check for writes in the range of $18FA70 + 8000...
1443 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1444 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1445 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1446 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1450 if (offset <= 0x3FFFFE)
1455 1A 69 F0 ($0000) -> Starfield
1456 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1459 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1468 //This MUST be done by the 68K!
1469 /*if (offset == 0x670C)
1470 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1472 /*extern bool doGPUDis;
1473 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1474 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1475 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1476 doGPUDis = true;//*/
1477 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1478 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1479 if ((data & 0xFF00) != 0x7700)
1480 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1481 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1483 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1484 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1485 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1487 /*extern bool doGPUDis;
1488 if (offset == 0x120216 && who == GPU)
1489 doGPUDis = true;//*/
1490 /*extern uint32 gpu_pc;
1491 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1493 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1494 uint32 y = base / 0x300;
1495 uint32 x = (base - (y * 0x300)) / 2;
1496 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1499 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1501 //if (offset == (0x001E17F8 + 0x34))
1502 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1504 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1505 /*extern uint32 gpu_pc;
1506 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1508 extern int objectPtr;
1509 // if (offset > 0x148000)
1512 if (starCount > objectPtr)
1515 // if (starCount == 1)
1516 // WriteLog("--> Drawing 1st star...\n");
1518 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1519 // uint32 y = base / 0x300;
1520 // uint32 x = (base - (y * 0x300)) / 2;
1521 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1523 //A star of interest...
1524 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1525 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1526 //JWW: Blitter writing echo 77B3 at 0011D022...
1528 //extern bool doGPUDis;
1529 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1532 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1535 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1536 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1538 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1539 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1542 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1544 CDROMWriteWord(offset, data, who);
1547 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1549 TOMWriteWord(offset, data, who);
1552 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1554 JERRYWriteWord(offset, data, who);
1557 // Don't bomb on attempts to write to ROM
1558 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1561 jaguar_unknown_writeword(offset, data, who);
1564 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1565 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1567 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1570 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1571 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1573 /* extern bool doDSPDis;
1574 if (offset < 0x400 && !doDSPDis)
1576 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1579 /*if (offset == 0x0100)//64*4)
1580 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1582 JaguarWriteWord(offset, data >> 16, who);
1583 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1586 void JaguarSetScreenBuffer(uint32 * buffer)
1588 // This is in TOM, but we set it here...
1589 screenBuffer = buffer;
1592 void JaguarSetScreenPitch(uint32 pitch)
1594 // This is in TOM, but we set it here...
1595 screenPitch = pitch;
1599 // Jaguar console initialization
1601 void JaguarInit(void)
1603 #ifdef CPU_DEBUG_MEMORY
1604 memset(readMem, 0x00, 0x400000);
1605 memset(writeMemMin, 0xFF, 0x400000);
1606 memset(writeMemMax, 0x00, 0x400000);
1608 memset(jaguarMainRAM, 0x00, 0x400000);
1609 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1610 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1611 //NOTE: This *doesn't* fix FlipOut...
1612 //Or does it? Hmm...
1613 //Seems to want $01010101... Dunno why. Investigate!
1614 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1615 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1617 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1625 //New timer based code stuffola...
1626 void ScanlineCallback(void);
1627 void RenderCallback(void);
1628 void JaguarReset(void)
1630 //Need to change this so it uses the single RAM space and load the BIOS
1631 //into it somewhere...
1632 //Also, have to change this here and in JaguarReadXX() currently
1633 // Only use the system BIOS if it's available...! (it's always available now!)
1634 // AND only if a jaguar cartridge has been inserted.
1635 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1636 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1638 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1640 // WriteLog("jaguar_reset():\n");
1646 m68k_pulse_reset(); // Reset the 68000
1647 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1649 // New timer base code stuffola...
1650 InitializeEventList();
1651 // SetCallbackTime(ScanlineCallback, 63.5555);
1652 SetCallbackTime(ScanlineCallback, 31.77775);
1653 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1654 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
1657 void JaguarDone(void)
1659 #ifdef CPU_DEBUG_MEMORY
1660 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1662 for(uint32 i=0; i<=raPtr; i++)
1664 WriteLog("\t%08X\n", returnAddr[i]);
1665 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1666 jaguar_dasm(returnAddr[i] - 16, 16);
1671 /* int start = 0, end = 0;
1672 bool endTriggered = false, startTriggered = false;
1673 for(int i=0; i<0x400000; i++)
1675 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1677 if (!startTriggered)
1678 startTriggered = true, endTriggered = false, start = i;
1680 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1686 end = i - 1, endTriggered = true, startTriggered = false;
1687 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1694 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1695 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1696 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1697 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1698 for(int i=-2; i<9; i++)
1699 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1701 /* WriteLog("\nM68000 disassembly at $802288...\n");
1702 jaguar_dasm(0x802288, 3);
1703 WriteLog("\nM68000 disassembly at $802200...\n");
1704 jaguar_dasm(0x802200, 500);
1705 WriteLog("\nM68000 disassembly at $802518...\n");
1706 jaguar_dasm(0x802518, 100);//*/
1708 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1709 jaguar_dasm(0x803F00, 500);
1712 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1713 jaguar_dasm(0x802B00, 500);
1716 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1717 jaguar_dasm(0x809900, 500);
1720 /* WriteLog("\n\nDump of $8093C8:\n\n");
1721 for(int i=0x8093C8; i<0x809900; i+=4)
1722 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1723 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1724 jaguar_dasm(0x90006C, 500);
1726 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1727 jaguar_dasm(0x1AC000, 6000);
1730 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1731 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1732 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
1733 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1734 M68K_show_context();
1737 #if 0 // This is drawn already...
1738 WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
1739 for(uint32 i=0x64; i<=0x7C; i+=4)
1740 WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
1749 // temp, until debugger is in place
1750 //00802016: jsr $836F1A.l
1751 //0080201C: jsr $836B30.l
1752 //00802022: jsr $836B18.l
1753 //00802028: jsr $8135F0.l
1754 //00813C1E: jsr $813F76.l
1755 //00802038: jsr $836D00.l
1756 //00802098: jsr $8373A4.l
1757 //008020A2: jsr $83E24A.l
1758 //008020BA: jsr $83E156.l
1759 //008020C6: jsr $83E19C.l
1760 //008020E6: jsr $8445E8.l
1761 //008020EC: jsr $838C20.l
1762 //0080211A: jsr $838ED6.l
1763 //00802124: jsr $89CA56.l
1764 //0080212A: jsr $802B48.l
1766 WriteLog("-------------------------------------------\n");
1767 JaguarDasm(0x8445E8, 0x200);
1768 WriteLog("-------------------------------------------\n");
1769 JaguarDasm(0x838C20, 0x200);
1770 WriteLog("-------------------------------------------\n");
1771 JaguarDasm(0x838ED6, 0x200);
1772 WriteLog("-------------------------------------------\n");
1773 JaguarDasm(0x89CA56, 0x200);
1774 WriteLog("-------------------------------------------\n");
1775 JaguarDasm(0x802B48, 0x200);
1776 WriteLog("\n\nM68000 disassembly at $802000...\n");
1777 JaguarDasm(0x802000, 6000);
1780 /* WriteLog("\n\nM68000 disassembly at $080000...\n");
1781 JaguarDasm(0x080000, 10000);
1786 // Main Jaguar execution loop (1 frame)
1788 void JaguarExecute(uint32 * backbuffer, bool render)
1790 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1791 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1792 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1793 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1795 // uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
1796 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1797 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1798 //It seems that they mean it when they say that VDE is the end of object processing.
1799 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1800 //buffer and not to write any more pixels... !!! FIX !!!
1801 // uint16 vde = TOMReadWord(0xF00048, JAGUAR);
1803 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1804 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1805 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1806 //seem to indicate the refresh rate is *half* the above...
1807 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1808 // Should these be hardwired or read from VP? Yes, from VP!
1809 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1810 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1812 /*extern int effect_start;
1814 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1816 //extern int start_logging;
1817 for(uint16 i=0; i<vp; i++)
1819 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1820 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
1821 TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
1823 //Not sure if this is correct...
1824 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1825 //Which means that it normally wouldn't go when it's zero.
1826 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
1828 // We don't have to worry about autovectors & whatnot because the Jaguar
1829 // tells you through its HW registers who sent the interrupt...
1830 TOMSetPendingVideoInt();
1834 //if (start_logging)
1835 // WriteLog("About to execute M68K (%u)...\n", i);
1836 m68k_execute(M68KCyclesPerScanline);
1837 //if (start_logging)
1838 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1839 TOMExecPIT(RISCCyclesPerScanline);
1840 //if (start_logging)
1841 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1842 JERRYExecPIT(RISCCyclesPerScanline);
1843 //if (start_logging)
1844 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1845 JERRYI2SExec(RISCCyclesPerScanline);
1846 BUTCHExec(RISCCyclesPerScanline);
1847 //if (start_logging)
1848 // WriteLog("About to execute GPU (%u)...\n", i);
1850 GPUExec(RISCCyclesPerScanline);
1854 if (vjs.usePipelinedDSP)
1855 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1857 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1858 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1861 //if (start_logging)
1862 // WriteLog("About to execute OP (%u)...\n", i);
1863 TOMExecScanline(i, render);
1867 // Temp debugging stuff
1869 void DumpMainMemory(void)
1871 FILE * fp = fopen("./memdump.bin", "wb");
1876 fwrite(jaguarMainRAM, 1, 0x400000, fp);
1880 uint8 * GetRamPtr(void)
1882 return jaguarMainRAM;
1886 // New Jaguar execution stack
1887 // This executes 1 frame's worth of code.
1890 void JaguarExecuteNew(void)
1896 double timeToNextEvent = GetTimeToNextEvent();
1897 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1899 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1902 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1906 if (vjs.usePipelinedDSP)
1907 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1909 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1917 void ScanlineCallback(void)
1919 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
1920 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1921 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1922 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1928 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1929 TOMWriteWord(0xF00006, vc, JAGUAR);
1931 //This is a crappy kludge, but maybe it'll work for now...
1932 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1933 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
1935 // We don't have to worry about autovectors & whatnot because the Jaguar
1936 // tells you through its HW registers who sent the interrupt...
1937 TOMSetPendingVideoInt();
1941 TOMExecScanline(vc, true);
1943 //Change this to VBB???
1944 //Doesn't seem to matter (at least for Flip Out & I-War)
1952 // SetCallbackTime(ScanlineCallback, 63.5555);
1953 SetCallbackTime(ScanlineCallback, 31.77775);
1956 // This isn't currently used, but maybe it should be...
1958 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
1959 handles all the rest, so this isn't needed. :-P
1961 void RenderCallback(void)
1963 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1964 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time