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 uint32 jaguar_active_memory_dumps = 0;
64 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
66 bool BIOSLoaded = false;
67 bool CDBIOSLoaded = false;
71 #ifdef CPU_DEBUG_MEMORY
72 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
73 uint8 readMem[0x400000];
74 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
77 uint32 pcQueue[0x400];
81 // Callback function to detect illegal instructions
83 void GPUDumpDisassembly(void);
84 void GPUDumpRegisters(void);
85 static bool start = false;
87 void M68KInstructionHook(void)
89 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
92 // Ideally, we'd save all the registers as well...
93 pcQueue[pcQPtr++] = m68kPC;
96 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
98 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
100 static char buffer[2048];
101 for(int i=0; i<0x400; i++)
103 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
104 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
108 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
109 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
110 for(int i=0; i<10; i++)
111 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
112 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
118 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
120 static char buffer[2048];
121 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
122 WriteLog("%08X: %s", m68kPC, buffer);
123 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
124 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
125 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
127 /* if (m68kPC == 0x8D0E48 && effect_start5)
129 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
131 GPUDumpDisassembly();
135 /* uint16 opcode = JaguarReadWord(m68kPC);
136 if (opcode == 0x4E75) // RTS
139 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
141 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
143 if (raPtr != 0xFFFFFFFF)
145 for(uint32 i=0; i<=raPtr; i++)
147 if (returnAddr[i] == addr)
156 returnAddr[++raPtr] = addr;
160 //Flip Out! debugging...
163 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
164 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
165 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
166 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
168 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
170 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
171 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
172 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
173 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
174 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
175 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
176 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
178 /* static char buffer[2048];
179 //if (m68kPC > 0x805F48) start = true;
180 //if (m68kPC > 0x806486) start = true;
181 //if (m68kPC == 0x805FEE) start = true;
182 //if (m68kPC == 0x80600C)// start = true;
183 if (m68kPC == 0x802058) start = true;
185 // GPUDumpRegisters();
186 // GPUDumpDisassembly();
188 // M68K_show_context();
194 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
195 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));
198 /* if (m68kPC == 0x803F16)
200 WriteLog("M68K: Registers found at $803F16:\n");
201 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
202 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
203 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
205 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
206 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
208 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
209 // !!! Investigate !!!
210 /*extern bool doDSPDis;
211 static bool disgo = false;
212 if (m68kPC == 0x50222)
215 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
216 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
219 if (m68kPC == 0x5000)
224 static char buffer[2048];
225 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
226 WriteLog("%08X: %s", m68kPC, buffer);
227 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
228 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
229 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
231 if (m68kPC == 0x82E1A)
233 static char buffer[2048];
234 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
235 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
236 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
237 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
238 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
240 if (m68kPC == 0x82E58)
241 WriteLog("--> [Routine end]\n");
242 if (m68kPC == 0x80004)
244 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
245 // m68k_set_reg(M68K_REG_D2, 0x12345678);
248 #ifdef LOG_CD_BIOS_CALLS
271 if (m68kPC == 0x3000)
272 WriteLog("M68K: CD_init\n");
273 else if (m68kPC == 0x3006 + (6 * 0))
274 WriteLog("M68K: CD_mode\n");
275 else if (m68kPC == 0x3006 + (6 * 1))
276 WriteLog("M68K: CD_ack\n");
277 else if (m68kPC == 0x3006 + (6 * 2))
278 WriteLog("M68K: CD_jeri\n");
279 else if (m68kPC == 0x3006 + (6 * 3))
280 WriteLog("M68K: CD_spin\n");
281 else if (m68kPC == 0x3006 + (6 * 4))
282 WriteLog("M68K: CD_stop\n");
283 else if (m68kPC == 0x3006 + (6 * 5))
284 WriteLog("M68K: CD_mute\n");
285 else if (m68kPC == 0x3006 + (6 * 6))
286 WriteLog("M68K: CD_umute\n");
287 else if (m68kPC == 0x3006 + (6 * 7))
288 WriteLog("M68K: CD_paus\n");
289 else if (m68kPC == 0x3006 + (6 * 8))
290 WriteLog("M68K: CD_upaus\n");
291 else if (m68kPC == 0x3006 + (6 * 9))
292 WriteLog("M68K: CD_read\n");
293 else if (m68kPC == 0x3006 + (6 * 10))
294 WriteLog("M68K: CD_uread\n");
295 else if (m68kPC == 0x3006 + (6 * 11))
296 WriteLog("M68K: CD_setup\n");
297 else if (m68kPC == 0x3006 + (6 * 12))
298 WriteLog("M68K: CD_ptr\n");
299 else if (m68kPC == 0x3006 + (6 * 13))
300 WriteLog("M68K: CD_osamp\n");
301 else if (m68kPC == 0x3006 + (6 * 14))
302 WriteLog("M68K: CD_getoc\n");
303 else if (m68kPC == 0x3006 + (6 * 15))
304 WriteLog("M68K: CD_initm\n");
305 else if (m68kPC == 0x3006 + (6 * 16))
306 WriteLog("M68K: CD_initf\n");
307 else if (m68kPC == 0x3006 + (6 * 17))
308 WriteLog("M68K: CD_switch\n");
310 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
311 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
312 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
313 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
316 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
317 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
319 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
320 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
322 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
323 // keep going even when the 68K dumped back to the debugger or what have you).
325 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
326 // Try setting the vector to the illegal instruction...
327 //This doesn't work right either! Do something else! Quick!
328 // SET32(jaguar_mainRam, 0x10, m68kPC);
334 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
335 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
336 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
337 for(int i=0; i<10; i++)
338 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
339 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
343 // WriteLog("\n\n68K disasm\n\n");
344 // jaguar_dasm(0x802000, 0x50C);
354 //001A0110: move.w #$0, $F000E2.l ; Restore Blitter/GPU bus priorities
355 //001A015C: rte ; Return from the interrupt
356 static bool disassembleGo = false;
357 if (m68kPC == 0x1A0110)
359 static char buffer[2048];
360 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
361 WriteLog("--> [M68K IRQ Routine start] %08X: %s", m68kPC, buffer);
362 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
363 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
364 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
365 disassembleGo = true;
367 else if (m68kPC == 0x1A015C)
368 WriteLog("--> [M68K IRQ Routine end]\n");
372 static char buffer[2048];
373 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
374 WriteLog("%08X: %s", m68kPC, buffer);
375 WriteLog("\tD0=$%08X, D1=$%08X, D2=$%08X\n",
376 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
382 Now here be dragons...
383 Here is how memory ranges are defined in the CoJag driver.
384 Note that we only have to be concerned with 3 entities read/writing anything:
385 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
386 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
387 things that are entirely internal to those modules. This way we should be able to get a handle on all
388 this crap which is currently scattered over Hell's Half Acre(tm).
390 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
391 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
393 /*************************************
395 * Main CPU memory handlers
397 *************************************/
399 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
400 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
401 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
402 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
403 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
404 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
405 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
406 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
407 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
408 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
409 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
410 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
411 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
412 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
413 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
414 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
415 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
416 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
417 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
418 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
419 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
420 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
421 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
424 /*************************************
426 * GPU memory handlers
428 *************************************/
430 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
431 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
432 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
433 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
434 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
435 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
436 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
437 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
438 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
439 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
440 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
443 /*************************************
445 * DSP memory handlers
447 *************************************/
449 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
450 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
451 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
452 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
453 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
454 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
455 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
456 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
457 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
462 //#define EXPERIMENTAL_MEMORY_HANDLING
463 // Experimental memory mappage...
464 // Dunno if this is a good approach or not, but it seems to make better
465 // sense to have all this crap in one spot intstead of scattered all over
466 // the place the way it is now.
467 #ifdef EXPERIMENTAL_MEMORY_HANDLING
469 #define NEW_TIMER_SYSTEM
472 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
473 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
474 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
475 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
476 bool BIOSLoaded = false;
477 bool CDBIOSLoaded = false;
480 uint8 tomRAM[0x4000];
481 uint8 jerryRAM[0x10000];
482 static uint16 eeprom_ram[64];
484 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
487 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
489 // M68K Memory map/handlers
491 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
492 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
493 // Note that this is really memory mapped I/O region...
494 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
495 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
496 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
497 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
498 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
499 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
500 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
501 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
502 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
503 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
504 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
505 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
507 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
509 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
510 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
511 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
512 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
513 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
514 //What about LBUF writes???
515 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
516 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
517 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
519 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
523 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
524 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
525 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
528 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
529 0 = pad0/1 button values (4 bits each), RO(?)
530 1 = pad0/1 index value (4 bits each), WO
532 3 = NTSC/PAL, certain button states, RO
534 JOYSTICK $F14000 Read/Write
536 Read fedcba98 7654321q f-1 Signals J15 to J1
537 q Cartridge EEPROM output data
538 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
539 0 = disable J7-J0 outputs
542 0 = Audio muted (reset state)
544 7-4 J7-J4 outputs (port 2)
545 3-0 J3-J0 outputs (port 1)
546 JOYBUTS $F14002 Read Only
548 Read xxxxxxxx rrdv3210 x don't care
551 v 1 = NTSC Video hardware
552 0 = PAL Video hardware
553 3-2 Button inputs B3 & B2 (port 2)
554 1-0 Button inputs B1 & B0 (port 1)
556 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
557 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
565 0 1 1 1 Row 3 C3 Option # 9 6 3
569 1 0 1 1 Row 2 C2 C 0 8 5 2
571 1 1 0 1 Row 1 C1 B * 7 4 1
572 1 1 1 0 Row 0 Pause A Up Down Left Right
575 0 bit read in any position means that button is pressed.
576 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
580 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
582 // Not sure, but I think the system only has 24 address bits...
583 address &= 0x00FFFFFF;
585 // RAM ($000000 - $3FFFFF) 4M
586 if (address <= 0x3FFFFF)
587 jaguarMainRAM[address] = byte;
588 // hole ($400000 - $7FFFFF) 4M
589 else if (address <= 0x7FFFFF)
591 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
592 else if (address <= 0xDFFEFF)
594 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
595 else if (address <= 0xDFFFFF)
597 cdRAM[address & 0xFF] = byte;
599 if ((address & 0xFF) < 12 * 4)
600 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
601 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
604 // BIOS ROM ($E00000 - $E3FFFF) 256K
605 else if (address <= 0xE3FFFF)
607 // hole ($E40000 - $EFFFFF) 768K
608 else if (address <= 0xEFFFFF)
610 // TOM ($F00000 - $F0FFFF) 64K
611 else if (address <= 0xF0FFFF)
614 if (address == 0xF00050)
616 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
620 else if (address == 0xF00051)
622 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
626 else if (address == 0xF00052)
628 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
632 else if (address == 0xF00053)
634 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
638 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
640 // Writing to one CLUT writes to the other
641 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
642 tomRAM[address] = tomRAM[address + 0x200] = byte;
645 //What about LBUF writes???
646 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
648 GPUWriteByte(address, byte, who);
651 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
653 BlitterWriteByte(address, byte, who);
656 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
658 GPUWriteByte(address, byte, who);
662 tomRAM[address & 0x3FFF] = byte;
664 // JERRY ($F10000 - $F1FFFF) 64K
665 else if (address <= 0xF1FFFF)
669 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
671 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
673 DSPWriteByte(address, byte, who);
676 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
678 DSPWriteByte(address, byte, who);
681 // SCLK ($F1A150--8 bits wide)
682 //NOTE: This should be taken care of in DAC...
683 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
685 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
686 if ((address & 0x03) == 2)
687 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
689 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
691 JERRYI2SInterruptTimer = -1;
692 #ifndef NEW_TIMER_SYSTEM
695 RemoveCallback(JERRYI2SCallback);
700 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
701 else if (address >= 0xF1A148 && address <= 0xF1A157)
703 DACWriteByte(address, byte, who);
706 else if (address >= 0xF10000 && address <= 0xF10007)
708 #ifndef NEW_TIMER_SYSTEM
709 switch (address & 0x07)
712 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
716 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
720 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
724 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
728 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
732 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
736 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
740 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
744 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
748 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
750 clock_byte_write(offset, byte);
753 // JERRY -> 68K interrupt enables/latches (need to be handled!)
754 else if (address >= 0xF10020 && address <= 0xF10023)
756 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
758 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
760 anajoy_byte_write(offset, byte);
763 else if ((address >= 0xF14000) && (address <= 0xF14003))
765 JoystickWriteByte(address, byte);
766 EepromWriteByte(address, byte);
769 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
771 EepromWriteByte(address, byte);
774 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
775 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
778 jerryRAM[address & 0xFFFF] = byte;
780 // hole ($F20000 - $FFFFFF) 1M - 128K
785 void WriteWord(uint32 adddress, uint16 word)
789 void WriteDWord(uint32 adddress, uint32 dword)
793 uint8 ReadByte(uint32 adddress)
797 uint16 ReadWord(uint32 adddress)
801 uint32 ReadDWord(uint32 adddress)
807 // Musashi 68000 read/write/IRQ functions
814 IPL Name Vector Control
815 ---------+---------------+---------------+---------------
816 2 VBLANK IRQ $100 INT1 bit #0
817 2 GPU IRQ $100 INT1 bit #1
818 2 HBLANK IRQ $100 INT1 bit #2
819 2 Timer IRQ $100 INT1 bit #3
821 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
822 and are therefore indistinguishable.
824 A typical way to install a LEVEL2 handler for the 68000 would be
825 something like this, you gotta supply "last_line" and "handler".
826 Note that the interrupt is auto vectored thru $100 (not $68)
834 IRQS_HANDLED=$909 ;; VBLANK and TIMER
836 move.w #$2700,sr ;; no IRQs please
837 move.l #handler,V_AUTO ;; install our routine
839 move.w #last_line,VI ;; scanline where IRQ should occur
840 ;; should be 'odd' BTW
841 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
842 move.w #$2100,sr ;; enable IRQs on the 68K
860 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
861 move.w #0,INT2 ; let GPU run again
865 As you can see, if you have multiple INT1 interrupts coming in,
866 you need to check the lower byte of INT1, to see which interrupt
869 int irq_ack_handler(int level)
871 // Tracing the IPL lines on the Jaguar schematic yields the following:
872 // IPL1 is connected to INTL on TOM (OUT to 68K)
873 // IPL0-2 are also tied to Vcc via 4.7K resistors!
874 // (DINT on TOM goes into DINT on JERRY (IN from Jerry))
875 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
876 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
878 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
879 // They aren't, and this causes problems with a, err, specific ROM. :-D
883 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
884 return 64; // Set user interrupt #0
887 return M68K_INT_ACK_AUTOVECTOR;
890 //#define USE_NEW_MMU
892 unsigned int m68k_read_memory_8(unsigned int address)
894 #ifdef CPU_DEBUG_MEMORY
895 if ((address >= 0x000000) && (address <= 0x3FFFFF))
898 readMem[address] = 1;
901 //WriteLog("[RM8] Addr: %08X\n", address);
902 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
903 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
904 || address == 0x1AF05E)
905 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
907 unsigned int retVal = 0;
909 if ((address >= 0x000000) && (address <= 0x3FFFFF))
910 retVal = jaguarMainRAM[address];
911 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
912 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
913 retVal = jaguarMainROM[address - 0x800000];
914 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
915 retVal = jaguarBootROM[address - 0xE00000];
916 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
917 retVal = CDROMReadByte(address);
918 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
919 retVal = TOMReadByte(address, M68K);
920 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
921 retVal = JERRYReadByte(address, M68K);
923 retVal = jaguar_unknown_readbyte(address, M68K);
925 //if (address >= 0x2800 && address <= 0x281F)
926 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
927 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
928 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
931 return MMURead8(address, M68K);
935 void gpu_dump_disassembly(void);
936 void gpu_dump_registers(void);
938 unsigned int m68k_read_memory_16(unsigned int address)
940 #ifdef CPU_DEBUG_MEMORY
941 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
944 readMem[address] = 1, readMem[address + 1] = 1;
946 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
948 return 0x4E71; // NOP
950 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
952 return 0x4E71; // NOP
954 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
956 return 0x4E71; // NOP
958 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
960 return 0x4E71; // NOP
962 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
964 return 0x4E71; // NOP
966 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
968 return 0x4E71; // NOP
971 //WriteLog("[RM16] Addr: %08X\n", address);
972 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
973 // for(int i=0; i<10000; i++)
974 WriteLog("[M68K] In routine #6!\n");//*/
975 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
976 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
977 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
979 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
980 gpu_dump_registers();
981 gpu_dump_disassembly();
982 // for(int i=0; i<10000; i++)
983 // WriteLog("[M68K] About to run GPU!\n");
985 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
986 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
988 if (address == 0x000066A0)
990 gpu_dump_registers();
991 gpu_dump_disassembly();
993 for(int i=0; i<10000; i++)
994 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
996 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
997 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
998 || address == 0x1AF05E)
999 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1001 unsigned int retVal = 0;
1003 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1004 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1005 retVal = GET16(jaguarMainRAM, address);
1006 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1007 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1008 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1009 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1010 retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1011 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1012 retVal = CDROMReadWord(address, M68K);
1013 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1014 retVal = TOMReadWord(address, M68K);
1015 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1016 retVal = JERRYReadWord(address, M68K);
1018 retVal = jaguar_unknown_readword(address, M68K);
1020 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1021 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1022 //if (address >= 0x2800 && address <= 0x281F)
1023 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1024 //$8B3AE -> Transferred from $F1C010
1025 //$8B5E4 -> Only +1 read at $808AA
1026 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1027 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1030 return MMURead16(address, M68K);
1034 unsigned int m68k_read_memory_32(unsigned int address)
1036 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1037 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1038 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));//*/
1040 //WriteLog("--> [RM32]\n");
1042 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1044 return MMURead32(address, M68K);
1048 void m68k_write_memory_8(unsigned int address, unsigned int value)
1050 #ifdef CPU_DEBUG_MEMORY
1051 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1055 if (value > writeMemMax[address])
1056 writeMemMax[address] = value;
1057 if (value < writeMemMin[address])
1058 writeMemMin[address] = value;
1062 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1063 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1064 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1066 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1067 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1070 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1071 jaguarMainRAM[address] = value;
1072 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1073 CDROMWriteByte(address, value, M68K);
1074 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1075 TOMWriteByte(address, value, M68K);
1076 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1077 JERRYWriteByte(address, value, M68K);
1079 jaguar_unknown_writebyte(address, value, M68K);
1081 MMUWrite8(address, value, M68K);
1085 void m68k_write_memory_16(unsigned int address, unsigned int value)
1087 #ifdef CPU_DEBUG_MEMORY
1088 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1092 uint8 hi = value >> 8, lo = value & 0xFF;
1094 if (hi > writeMemMax[address])
1095 writeMemMax[address] = hi;
1096 if (hi < writeMemMin[address])
1097 writeMemMin[address] = hi;
1099 if (lo > writeMemMax[address+1])
1100 writeMemMax[address+1] = lo;
1101 if (lo < writeMemMin[address+1])
1102 writeMemMin[address+1] = lo;
1106 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1107 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1108 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1109 //if (address >= 0xF02200 && address <= 0xF0229F)
1110 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1111 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1112 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1113 /*extern uint32 totalFrames;
1114 if (address == 0xF02114)
1115 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1116 if (address == 0xF02110)
1117 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1118 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1119 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1121 /*if (address == 0x0100)//64*4)
1122 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1124 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1125 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1126 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1127 || address == 0x1AF05E)
1128 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1131 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1133 /* jaguar_mainRam[address] = value >> 8;
1134 jaguar_mainRam[address + 1] = value & 0xFF;*/
1135 SET16(jaguarMainRAM, address, value);
1137 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1138 CDROMWriteWord(address, value, M68K);
1139 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1140 TOMWriteWord(address, value, M68K);
1141 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1142 JERRYWriteWord(address, value, M68K);
1145 jaguar_unknown_writeword(address, value, M68K);
1146 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1147 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1148 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1149 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1153 MMUWrite16(address, value, M68K);
1157 void m68k_write_memory_32(unsigned int address, unsigned int value)
1159 //WriteLog("--> [WM32]\n");
1160 /*if (address == 0x0100)//64*4)
1161 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1162 /*if (address >= 0xF03214 && address < 0xF0321F)
1163 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1164 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1165 /*extern bool doGPUDis;
1166 if (address == 0xF03214 && value == 0x88E30047)
1168 doGPUDis = true;//*/
1169 /* if (address == 0x51136 || address == 0xFB074)
1170 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1173 m68k_write_memory_16(address, value >> 16);
1174 m68k_write_memory_16(address + 2, value & 0xFFFF);
1176 MMUWrite32(address, value, M68K);
1181 uint32 JaguarGetHandler(uint32 i)
1183 return JaguarReadLong(i * 4);
1186 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1188 uint32 handler = JaguarGetHandler(i);
1189 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1192 void M68K_show_context(void)
1194 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1195 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1196 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1198 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1199 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1201 WriteLog("68K disasm\n");
1202 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1203 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1204 // jaguar_dasm(0x5000, 0x14414);
1206 // WriteLog("\n.......[Cart start]...........\n\n");
1207 // jaguar_dasm(0x192000, 0x1000);//0x200);
1209 WriteLog("..................\n");
1211 if (TOMIRQEnabled(IRQ_VBLANK))
1213 WriteLog("video int: enabled\n");
1214 JaguarDasm(JaguarGetHandler(64), 0x200);
1217 WriteLog("video int: disabled\n");
1219 WriteLog("..................\n");
1221 for(int i=0; i<256; i++)
1223 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1224 uint32 address = (uint32)JaguarGetHandler(i);
1227 WriteLog(".........\n");
1229 WriteLog("$%08X\n", address);
1234 // Unknown read/write byte/word routines
1237 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1238 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1240 // 807EC4: movea.l #$f1b000, A1
1241 // 807ECA: movea.l #$8129e0, A0
1242 // 807ED0: move.l A0, D0
1243 // 807ED2: move.l #$f1bb94, D1
1244 // 807ED8: sub.l D0, D1
1245 // 807EDA: lsr.l #2, D1
1246 // 807EDC: move.l (A0)+, (A1)+
1247 // 807EDE: dbra D1, 807edc
1249 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1250 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1251 // space! (That is, unless the 68K causes a bus error...)
1253 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1255 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1256 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));
1258 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1259 // extern bool finished;
1261 // extern bool doDSPDis;
1267 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1269 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1270 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));
1272 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1273 // extern bool finished;
1275 // extern bool doDSPDis;
1281 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1283 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1284 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1286 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1287 // extern bool finished;
1289 // extern bool doDSPDis;
1296 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1298 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1299 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1301 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1302 // extern bool finished;
1304 // extern bool doDSPDis;
1312 // Disassemble M68K instructions at the given offset
1315 unsigned int m68k_read_disassembler_8(unsigned int address)
1317 return m68k_read_memory_8(address);
1320 unsigned int m68k_read_disassembler_16(unsigned int address)
1322 return m68k_read_memory_16(address);
1325 unsigned int m68k_read_disassembler_32(unsigned int address)
1327 return m68k_read_memory_32(address);
1330 void JaguarDasm(uint32 offset, uint32 qt)
1333 static char buffer[2048];//, mem[64];
1334 int pc = offset, oldpc;
1336 for(uint32 i=0; i<qt; i++)
1339 for(int j=0; j<64; j++)
1340 mem[j^0x01] = jaguar_byte_read(pc + j);
1342 pc += Dasm68000((char *)mem, buffer, 0);
1343 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1345 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1346 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1351 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1356 if (offset < 0x400000)
1357 data = jaguarMainRAM[offset & 0x3FFFFF];
1358 else if ((offset >= 0x800000) && (offset < 0xC00000))
1359 data = jaguarMainROM[offset - 0x800000];
1360 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1361 data = CDROMReadByte(offset, who);
1362 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1363 data = jaguarBootROM[offset & 0x3FFFF];
1364 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1365 data = TOMReadByte(offset, who);
1366 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1367 data = JERRYReadByte(offset, who);
1369 data = jaguar_unknown_readbyte(offset, who);
1374 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1377 if (offset <= 0x3FFFFE)
1379 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1381 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1384 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1386 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1387 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1388 return CDROMReadWord(offset, who);
1389 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1390 return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1391 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1392 return TOMReadWord(offset, who);
1393 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1394 return JERRYReadWord(offset, who);
1396 return jaguar_unknown_readword(offset, who);
1399 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1401 //Need to check for writes in the range of $18FA70 + 8000...
1403 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1404 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1407 if (offset < 0x400000)
1409 jaguarMainRAM[offset & 0x3FFFFF] = data;
1412 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1414 CDROMWriteByte(offset, data, who);
1417 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1419 TOMWriteByte(offset, data, who);
1422 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1424 JERRYWriteByte(offset, data, who);
1428 jaguar_unknown_writebyte(offset, data, who);
1432 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1434 /*if (offset == 0x0100)//64*4)
1435 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1436 if (offset == 0x0102)//64*4)
1437 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1438 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1439 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1440 //Need to check for writes in the range of $18FA70 + 8000...
1442 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1443 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1444 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1445 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1449 if (offset <= 0x3FFFFE)
1454 1A 69 F0 ($0000) -> Starfield
1455 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1458 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1467 //This MUST be done by the 68K!
1468 /*if (offset == 0x670C)
1469 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1471 /*extern bool doGPUDis;
1472 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1473 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1474 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1475 doGPUDis = true;//*/
1476 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1477 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1478 if ((data & 0xFF00) != 0x7700)
1479 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1480 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1482 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1483 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1484 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1486 /*extern bool doGPUDis;
1487 if (offset == 0x120216 && who == GPU)
1488 doGPUDis = true;//*/
1489 /*extern uint32 gpu_pc;
1490 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1492 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1493 uint32 y = base / 0x300;
1494 uint32 x = (base - (y * 0x300)) / 2;
1495 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1498 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1500 //if (offset == (0x001E17F8 + 0x34))
1501 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1503 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1504 /*extern uint32 gpu_pc;
1505 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1507 extern int objectPtr;
1508 // if (offset > 0x148000)
1511 if (starCount > objectPtr)
1514 // if (starCount == 1)
1515 // WriteLog("--> Drawing 1st star...\n");
1517 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1518 // uint32 y = base / 0x300;
1519 // uint32 x = (base - (y * 0x300)) / 2;
1520 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1522 //A star of interest...
1523 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1524 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1525 //JWW: Blitter writing echo 77B3 at 0011D022...
1527 //extern bool doGPUDis;
1528 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1531 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1534 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1535 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1537 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1538 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1541 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1543 CDROMWriteWord(offset, data, who);
1546 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1548 TOMWriteWord(offset, data, who);
1551 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1553 JERRYWriteWord(offset, data, who);
1556 // Don't bomb on attempts to write to ROM
1557 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1560 jaguar_unknown_writeword(offset, data, who);
1563 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1564 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1566 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1569 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1570 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1572 /* extern bool doDSPDis;
1573 if (offset < 0x400 && !doDSPDis)
1575 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1578 /*if (offset == 0x0100)//64*4)
1579 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1581 JaguarWriteWord(offset, data >> 16, who);
1582 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1586 // Jaguar console initialization
1588 void JaguarInit(void)
1590 #ifdef CPU_DEBUG_MEMORY
1591 memset(readMem, 0x00, 0x400000);
1592 memset(writeMemMin, 0xFF, 0x400000);
1593 memset(writeMemMax, 0x00, 0x400000);
1595 memset(jaguarMainRAM, 0x00, 0x400000);
1596 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1597 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1598 //NOTE: This *doesn't* fix FlipOut...
1599 //Or does it? Hmm...
1600 //Seems to want $01010101... Dunno why. Investigate!
1601 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1602 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1604 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1612 //New timer based code stuffola...
1613 void ScanlineCallback(void);
1614 void RenderCallback(void);
1615 //extern uint32 * backbuffer;
1616 void JaguarReset(void)
1618 // Only use the system BIOS if it's available...!
1619 if (vjs.useJaguarBIOS && (biosAvailable & (BIOS_NORMAL | BIOS_STUB1 | BIOS_STUB2)))
1620 memcpy(jaguarMainRAM, jaguarBootROM, 8);
1622 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1624 if (vjs.useJaguarBIOS && !(biosAvailable & (BIOS_NORMAL | BIOS_STUB1 | BIOS_STUB2)))
1625 WriteLog("Jaguar: Requested BIOS, but none available.\n");
1627 // WriteLog("jaguar_reset():\n");
1633 m68k_pulse_reset(); // Reset the 68000
1634 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1636 // New timer base code stuffola...
1637 InitializeEventList();
1638 TOMResetBackbuffer(backbuffer);
1639 // SetCallbackTime(ScanlineCallback, 63.5555);
1640 SetCallbackTime(ScanlineCallback, 31.77775);
1641 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1642 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
1645 void JaguarDone(void)
1647 #ifdef CPU_DEBUG_MEMORY
1648 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1650 for(uint32 i=0; i<=raPtr; i++)
1652 WriteLog("\t%08X\n", returnAddr[i]);
1653 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1654 jaguar_dasm(returnAddr[i] - 16, 16);
1659 /* int start = 0, end = 0;
1660 bool endTriggered = false, startTriggered = false;
1661 for(int i=0; i<0x400000; i++)
1663 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1665 if (!startTriggered)
1666 startTriggered = true, endTriggered = false, start = i;
1668 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1674 end = i - 1, endTriggered = true, startTriggered = false;
1675 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1682 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1683 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1684 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1685 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1686 for(int i=-2; i<9; i++)
1687 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1689 /* WriteLog("\nM68000 disassembly at $802288...\n");
1690 jaguar_dasm(0x802288, 3);
1691 WriteLog("\nM68000 disassembly at $802200...\n");
1692 jaguar_dasm(0x802200, 500);
1693 WriteLog("\nM68000 disassembly at $802518...\n");
1694 jaguar_dasm(0x802518, 100);//*/
1696 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1697 jaguar_dasm(0x803F00, 500);
1700 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1701 jaguar_dasm(0x802B00, 500);
1704 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1705 jaguar_dasm(0x809900, 500);
1708 /* WriteLog("\n\nDump of $8093C8:\n\n");
1709 for(int i=0x8093C8; i<0x809900; i+=4)
1710 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1711 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1712 jaguar_dasm(0x90006C, 500);
1714 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1715 jaguar_dasm(0x1AC000, 6000);
1718 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1719 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1720 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VBLANK))
1721 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1722 M68K_show_context();
1725 #if 0 // This is drawn already...
1726 WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
1727 for(uint32 i=0x64; i<=0x7C; i+=4)
1728 WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
1737 // temp, until debugger is in place
1738 //00802016: jsr $836F1A.l
1739 //0080201C: jsr $836B30.l
1740 //00802022: jsr $836B18.l
1741 //00802028: jsr $8135F0.l
1742 //00813C1E: jsr $813F76.l
1743 //00802038: jsr $836D00.l
1744 //00802098: jsr $8373A4.l
1745 //008020A2: jsr $83E24A.l
1746 //008020BA: jsr $83E156.l
1747 //008020C6: jsr $83E19C.l
1748 //008020E6: jsr $8445E8.l
1749 //008020EC: jsr $838C20.l
1750 //0080211A: jsr $838ED6.l
1751 //00802124: jsr $89CA56.l
1752 //0080212A: jsr $802B48.l
1754 WriteLog("-------------------------------------------\n");
1755 JaguarDasm(0x8445E8, 0x200);
1756 WriteLog("-------------------------------------------\n");
1757 JaguarDasm(0x838C20, 0x200);
1758 WriteLog("-------------------------------------------\n");
1759 JaguarDasm(0x838ED6, 0x200);
1760 WriteLog("-------------------------------------------\n");
1761 JaguarDasm(0x89CA56, 0x200);
1762 WriteLog("-------------------------------------------\n");
1763 JaguarDasm(0x802B48, 0x200);
1768 // Main Jaguar execution loop (1 frame)
1770 void JaguarExecute(uint32 * backbuffer, bool render)
1772 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1773 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1774 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1775 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1777 // uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
1778 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1779 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1780 //It seems that they mean it when they say that VDE is the end of object processing.
1781 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1782 //buffer and not to write any more pixels... !!! FIX !!!
1783 // uint16 vde = TOMReadWord(0xF00048, JAGUAR);
1785 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1786 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1787 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1788 //seem to indicate the refresh rate is *half* the above...
1789 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1790 // Should these be hardwired or read from VP? Yes, from VP!
1791 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1792 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1794 TOMResetBackbuffer(backbuffer);
1795 /*extern int effect_start;
1797 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1799 //extern int start_logging;
1800 for(uint16 i=0; i<vp; i++)
1802 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1803 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
1805 TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
1807 // if (i == vi) // Time for Vertical Interrupt?
1808 //Not sure if this is correct...
1809 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1810 //Which means that it normally wouldn't go when it's zero.
1811 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1813 // We don't have to worry about autovectors & whatnot because the Jaguar
1814 // tells you through its HW registers who sent the interrupt...
1815 TOMSetPendingVideoInt();
1819 //if (start_logging)
1820 // WriteLog("About to execute M68K (%u)...\n", i);
1821 m68k_execute(M68KCyclesPerScanline);
1822 //if (start_logging)
1823 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1824 TOMExecPIT(RISCCyclesPerScanline);
1825 //if (start_logging)
1826 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1827 JERRYExecPIT(RISCCyclesPerScanline);
1828 //if (start_logging)
1829 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1830 JERRYI2SExec(RISCCyclesPerScanline);
1831 BUTCHExec(RISCCyclesPerScanline);
1832 //if (start_logging)
1833 // WriteLog("About to execute GPU (%u)...\n", i);
1834 GPUExec(RISCCyclesPerScanline);
1838 if (vjs.usePipelinedDSP)
1839 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1841 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1842 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1845 //if (start_logging)
1846 // WriteLog("About to execute OP (%u)...\n", i);
1847 TOMExecScanline(i, render);
1851 // Temp debugging stuff
1853 void DumpMainMemory(void)
1855 FILE * fp = fopen("./memdump.bin", "wb");
1860 fwrite(jaguarMainRAM, 1, 0x400000, fp);
1864 uint8 * GetRamPtr(void)
1866 return jaguarMainRAM;
1870 // New Jaguar execution stack
1875 void JaguarExecuteNew(void)
1877 extern bool finished, showGUI;
1878 extern bool debounceRunKey;
1879 // Pass a message to the "joystick" code to debounce the ESC key...
1880 debounceRunKey = true;
1882 /* InitializeEventList();
1883 TOMResetBackbuffer(backbuffer);
1884 // SetCallbackTime(ScanlineCallback, 63.5555);
1885 SetCallbackTime(ScanlineCallback, 31.77775);
1886 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1887 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1888 // uint8 * keystate = SDL_GetKeyState(NULL);
1892 double timeToNextEvent = GetTimeToNextEvent();
1893 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1895 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1896 gpu_exec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1900 if (vjs.usePipelinedDSP)
1901 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1903 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1908 // if (keystate[SDLK_ESCAPE])
1911 // SDL_PumpEvents(); // Needed to keep the keystate current...
1916 void ScanlineCallback(void)
1918 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
1919 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1920 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1921 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1927 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1928 TOMWriteWord(0xF00006, vc, JAGUAR);
1930 //This is a crappy kludge, but maybe it'll work for now...
1931 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1932 if (vc == vi && vc > 0 && tom_irq_enabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1934 // We don't have to worry about autovectors & whatnot because the Jaguar
1935 // tells you through its HW registers who sent the interrupt...
1936 tom_set_pending_video_int();
1940 TOMExecScanline(vc, true);
1942 //Change this to VBB???
1943 //Doesn't seem to matter (at least for Flip Out & I-War)
1950 TOMResetBackbuffer(backbuffer);
1954 // TOMResetBackbuffer(backbuffer);
1956 // SetCallbackTime(ScanlineCallback, 63.5555);
1957 SetCallbackTime(ScanlineCallback, 31.77775);
1963 void JaguarExecuteNew(void)
1965 // extern bool finished, showGUI;
1966 // extern bool debounceRunKey;
1967 // Pass a message to the "joystick" code to debounce the ESC key...
1968 // debounceRunKey = true;
1969 // finished = false;
1970 /* InitializeEventList();
1971 TOMResetBackbuffer(backbuffer);
1972 // SetCallbackTime(ScanlineCallback, 63.5555);
1973 SetCallbackTime(ScanlineCallback, 31.77775);
1974 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1975 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1976 // uint8 * keystate = SDL_GetKeyState(NULL);
1981 double timeToNextEvent = GetTimeToNextEvent();
1982 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1984 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1985 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1989 if (vjs.usePipelinedDSP)
1990 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1992 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1997 // if (keystate[SDLK_ESCAPE])
2000 // SDL_PumpEvents(); // Needed to keep the keystate current...
2005 void ScanlineCallback(void)
2007 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
2008 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2009 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
2010 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
2016 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2017 TOMWriteWord(0xF00006, vc, JAGUAR);
2019 //This is a crappy kludge, but maybe it'll work for now...
2020 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2021 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
2023 // We don't have to worry about autovectors & whatnot because the Jaguar
2024 // tells you through its HW registers who sent the interrupt...
2025 TOMSetPendingVideoInt();
2029 TOMExecScanline(vc, true);
2031 //Change this to VBB???
2032 //Doesn't seem to matter (at least for Flip Out & I-War)
2037 //We comment this out so that the GUI can manage this instead. Which is how it should be anyway.
2038 // RenderBackbuffer();
2039 TOMResetBackbuffer(backbuffer);
2044 // TOMResetBackbuffer(backbuffer);
2046 // SetCallbackTime(ScanlineCallback, 63.5555);
2047 SetCallbackTime(ScanlineCallback, 31.77775);
2052 // This isn't currently used, but maybe it should be...
2053 void RenderCallback(void)
2055 // RenderBackbuffer();
2056 TOMResetBackbuffer(backbuffer);
2057 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2058 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time