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);
355 Now here be dragons...
356 Here is how memory ranges are defined in the CoJag driver.
357 Note that we only have to be concerned with 3 entities read/writing anything:
358 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
359 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
360 things that are entirely internal to those modules. This way we should be able to get a handle on all
361 this crap which is currently scattered over Hell's Half Acre(tm).
363 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
364 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
366 /*************************************
368 * Main CPU memory handlers
370 *************************************/
372 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
373 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
374 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
375 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
376 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
377 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
378 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
379 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
380 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
381 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
382 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
383 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
384 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
385 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
386 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
387 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
388 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
389 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
390 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
391 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
392 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
393 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
394 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
397 /*************************************
399 * GPU memory handlers
401 *************************************/
403 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
404 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
405 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
406 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
407 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
408 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
409 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
410 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
411 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
412 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
413 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
416 /*************************************
418 * DSP memory handlers
420 *************************************/
422 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
423 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
424 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
425 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
426 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
427 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
428 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
429 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
430 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
435 //#define EXPERIMENTAL_MEMORY_HANDLING
436 // Experimental memory mappage...
437 // Dunno if this is a good approach or not, but it seems to make better
438 // sense to have all this crap in one spot intstead of scattered all over
439 // the place the way it is now.
440 #ifdef EXPERIMENTAL_MEMORY_HANDLING
442 #define NEW_TIMER_SYSTEM
445 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
446 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
447 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
448 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
449 bool BIOSLoaded = false;
450 bool CDBIOSLoaded = false;
453 uint8 tomRAM[0x4000];
454 uint8 jerryRAM[0x10000];
455 static uint16 eeprom_ram[64];
457 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
460 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
462 // M68K Memory map/handlers
464 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
465 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
466 // Note that this is really memory mapped I/O region...
467 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
468 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
469 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
470 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
471 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
472 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
473 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
474 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
475 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
476 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
477 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
478 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
480 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
482 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
483 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
484 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
485 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
486 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
487 //What about LBUF writes???
488 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
489 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
490 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
492 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
496 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
497 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
498 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
501 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
502 0 = pad0/1 button values (4 bits each), RO(?)
503 1 = pad0/1 index value (4 bits each), WO
505 3 = NTSC/PAL, certain button states, RO
507 JOYSTICK $F14000 Read/Write
509 Read fedcba98 7654321q f-1 Signals J15 to J1
510 q Cartridge EEPROM output data
511 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
512 0 = disable J7-J0 outputs
515 0 = Audio muted (reset state)
517 7-4 J7-J4 outputs (port 2)
518 3-0 J3-J0 outputs (port 1)
519 JOYBUTS $F14002 Read Only
521 Read xxxxxxxx rrdv3210 x don't care
524 v 1 = NTSC Video hardware
525 0 = PAL Video hardware
526 3-2 Button inputs B3 & B2 (port 2)
527 1-0 Button inputs B1 & B0 (port 1)
529 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
530 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
538 0 1 1 1 Row 3 C3 Option # 9 6 3
542 1 0 1 1 Row 2 C2 C 0 8 5 2
544 1 1 0 1 Row 1 C1 B * 7 4 1
545 1 1 1 0 Row 0 Pause A Up Down Left Right
548 0 bit read in any position means that button is pressed.
549 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
553 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
555 // Not sure, but I think the system only has 24 address bits...
556 address &= 0x00FFFFFF;
558 // RAM ($000000 - $3FFFFF) 4M
559 if (address <= 0x3FFFFF)
560 jaguarMainRAM[address] = byte;
561 // hole ($400000 - $7FFFFF) 4M
562 else if (address <= 0x7FFFFF)
564 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
565 else if (address <= 0xDFFEFF)
567 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
568 else if (address <= 0xDFFFFF)
570 cdRAM[address & 0xFF] = byte;
572 if ((address & 0xFF) < 12 * 4)
573 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
574 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
577 // BIOS ROM ($E00000 - $E3FFFF) 256K
578 else if (address <= 0xE3FFFF)
580 // hole ($E40000 - $EFFFFF) 768K
581 else if (address <= 0xEFFFFF)
583 // TOM ($F00000 - $F0FFFF) 64K
584 else if (address <= 0xF0FFFF)
587 if (address == 0xF00050)
589 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
593 else if (address == 0xF00051)
595 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
599 else if (address == 0xF00052)
601 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
605 else if (address == 0xF00053)
607 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
611 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
613 // Writing to one CLUT writes to the other
614 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
615 tomRAM[address] = tomRAM[address + 0x200] = byte;
618 //What about LBUF writes???
619 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
621 GPUWriteByte(address, byte, who);
624 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
626 BlitterWriteByte(address, byte, who);
629 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
631 GPUWriteByte(address, byte, who);
635 tomRAM[address & 0x3FFF] = byte;
637 // JERRY ($F10000 - $F1FFFF) 64K
638 else if (address <= 0xF1FFFF)
642 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
644 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
646 DSPWriteByte(address, byte, who);
649 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
651 DSPWriteByte(address, byte, who);
654 // SCLK ($F1A150--8 bits wide)
655 //NOTE: This should be taken care of in DAC...
656 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
658 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
659 if ((address & 0x03) == 2)
660 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
662 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
664 JERRYI2SInterruptTimer = -1;
665 #ifndef NEW_TIMER_SYSTEM
668 RemoveCallback(JERRYI2SCallback);
673 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
674 else if (address >= 0xF1A148 && address <= 0xF1A157)
676 DACWriteByte(address, byte, who);
679 else if (address >= 0xF10000 && address <= 0xF10007)
681 #ifndef NEW_TIMER_SYSTEM
682 switch (address & 0x07)
685 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
689 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
693 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
697 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
701 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
705 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
709 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
713 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
717 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
721 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
723 clock_byte_write(offset, byte);
726 // JERRY -> 68K interrupt enables/latches (need to be handled!)
727 else if (address >= 0xF10020 && address <= 0xF10023)
729 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
731 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
733 anajoy_byte_write(offset, byte);
736 else if ((address >= 0xF14000) && (address <= 0xF14003))
738 JoystickWriteByte(address, byte);
739 EepromWriteByte(address, byte);
742 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
744 EepromWriteByte(address, byte);
747 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
748 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
751 jerryRAM[address & 0xFFFF] = byte;
753 // hole ($F20000 - $FFFFFF) 1M - 128K
758 void WriteWord(uint32 adddress, uint16 word)
762 void WriteDWord(uint32 adddress, uint32 dword)
766 uint8 ReadByte(uint32 adddress)
770 uint16 ReadWord(uint32 adddress)
774 uint32 ReadDWord(uint32 adddress)
780 // Musashi 68000 read/write/IRQ functions
783 int irq_ack_handler(int level)
785 int vector = M68K_INT_ACK_AUTOVECTOR;
787 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
791 m68k_set_irq(0); // Clear the IRQ...
792 vector = 64; // Set user interrupt #0
798 //#define USE_NEW_MMU
800 unsigned int m68k_read_memory_8(unsigned int address)
802 #ifdef CPU_DEBUG_MEMORY
803 if ((address >= 0x000000) && (address <= 0x3FFFFF))
806 readMem[address] = 1;
809 //WriteLog("[RM8] Addr: %08X\n", address);
810 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
811 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
812 || address == 0x1AF05E)
813 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
815 unsigned int retVal = 0;
817 if ((address >= 0x000000) && (address <= 0x3FFFFF))
818 retVal = jaguarMainRAM[address];
819 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
820 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
821 retVal = jaguarMainROM[address - 0x800000];
822 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
823 retVal = jaguarBootROM[address - 0xE00000];
824 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
825 retVal = CDROMReadByte(address);
826 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
827 retVal = TOMReadByte(address, M68K);
828 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
829 retVal = JERRYReadByte(address, M68K);
831 retVal = jaguar_unknown_readbyte(address, M68K);
833 //if (address >= 0x2800 && address <= 0x281F)
834 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
835 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
836 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
839 return MMURead8(address, M68K);
843 void gpu_dump_disassembly(void);
844 void gpu_dump_registers(void);
846 unsigned int m68k_read_memory_16(unsigned int address)
848 #ifdef CPU_DEBUG_MEMORY
849 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
852 readMem[address] = 1, readMem[address + 1] = 1;
854 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
856 return 0x4E71; // NOP
858 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
860 return 0x4E71; // NOP
862 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
864 return 0x4E71; // NOP
866 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
868 return 0x4E71; // NOP
870 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
872 return 0x4E71; // NOP
874 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
876 return 0x4E71; // NOP
879 //WriteLog("[RM16] Addr: %08X\n", address);
880 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
881 // for(int i=0; i<10000; i++)
882 WriteLog("[M68K] In routine #6!\n");//*/
883 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
884 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
885 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
887 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
888 gpu_dump_registers();
889 gpu_dump_disassembly();
890 // for(int i=0; i<10000; i++)
891 // WriteLog("[M68K] About to run GPU!\n");
893 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
894 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
896 if (address == 0x000066A0)
898 gpu_dump_registers();
899 gpu_dump_disassembly();
901 for(int i=0; i<10000; i++)
902 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
904 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
905 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
906 || address == 0x1AF05E)
907 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
909 unsigned int retVal = 0;
911 if ((address >= 0x000000) && (address <= 0x3FFFFE))
912 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
913 retVal = GET16(jaguarMainRAM, address);
914 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
915 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
916 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
917 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
918 retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
919 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
920 retVal = CDROMReadWord(address, M68K);
921 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
922 retVal = TOMReadWord(address, M68K);
923 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
924 retVal = JERRYReadWord(address, M68K);
926 retVal = jaguar_unknown_readword(address, M68K);
928 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
929 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
930 //if (address >= 0x2800 && address <= 0x281F)
931 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
932 //$8B3AE -> Transferred from $F1C010
933 //$8B5E4 -> Only +1 read at $808AA
934 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
935 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
938 return MMURead16(address, M68K);
942 unsigned int m68k_read_memory_32(unsigned int address)
944 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
945 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
946 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));//*/
948 //WriteLog("--> [RM32]\n");
950 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
952 return MMURead32(address, M68K);
956 void m68k_write_memory_8(unsigned int address, unsigned int value)
958 #ifdef CPU_DEBUG_MEMORY
959 if ((address >= 0x000000) && (address <= 0x3FFFFF))
963 if (value > writeMemMax[address])
964 writeMemMax[address] = value;
965 if (value < writeMemMin[address])
966 writeMemMin[address] = value;
970 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
971 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
972 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
974 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
975 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
978 if ((address >= 0x000000) && (address <= 0x3FFFFF))
979 jaguarMainRAM[address] = value;
980 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
981 CDROMWriteByte(address, value, M68K);
982 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
983 TOMWriteByte(address, value, M68K);
984 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
985 JERRYWriteByte(address, value, M68K);
987 jaguar_unknown_writebyte(address, value, M68K);
989 MMUWrite8(address, value, M68K);
993 void m68k_write_memory_16(unsigned int address, unsigned int value)
995 #ifdef CPU_DEBUG_MEMORY
996 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1000 uint8 hi = value >> 8, lo = value & 0xFF;
1002 if (hi > writeMemMax[address])
1003 writeMemMax[address] = hi;
1004 if (hi < writeMemMin[address])
1005 writeMemMin[address] = hi;
1007 if (lo > writeMemMax[address+1])
1008 writeMemMax[address+1] = lo;
1009 if (lo < writeMemMin[address+1])
1010 writeMemMin[address+1] = lo;
1014 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1015 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1016 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1017 //if (address >= 0xF02200 && address <= 0xF0229F)
1018 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1019 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1020 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1021 /*extern uint32 totalFrames;
1022 if (address == 0xF02114)
1023 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1024 if (address == 0xF02110)
1025 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1026 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1027 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1029 /*if (address == 0x0100)//64*4)
1030 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1032 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1033 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1034 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1035 || address == 0x1AF05E)
1036 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1039 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1041 /* jaguar_mainRam[address] = value >> 8;
1042 jaguar_mainRam[address + 1] = value & 0xFF;*/
1043 SET16(jaguarMainRAM, address, value);
1045 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1046 CDROMWriteWord(address, value, M68K);
1047 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1048 TOMWriteWord(address, value, M68K);
1049 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1050 JERRYWriteWord(address, value, M68K);
1053 jaguar_unknown_writeword(address, value, M68K);
1054 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1055 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1056 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1057 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1061 MMUWrite16(address, value, M68K);
1065 void m68k_write_memory_32(unsigned int address, unsigned int value)
1067 //WriteLog("--> [WM32]\n");
1068 /*if (address == 0x0100)//64*4)
1069 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1070 /*if (address >= 0xF03214 && address < 0xF0321F)
1071 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1072 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1073 /*extern bool doGPUDis;
1074 if (address == 0xF03214 && value == 0x88E30047)
1076 doGPUDis = true;//*/
1077 /* if (address == 0x51136 || address == 0xFB074)
1078 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1081 m68k_write_memory_16(address, value >> 16);
1082 m68k_write_memory_16(address + 2, value & 0xFFFF);
1084 MMUWrite32(address, value, M68K);
1089 uint32 JaguarGetHandler(uint32 i)
1091 return JaguarReadLong(i * 4);
1094 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1096 uint32 handler = JaguarGetHandler(i);
1097 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1100 void M68K_show_context(void)
1102 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1103 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1104 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1106 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1107 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1109 WriteLog("68K disasm\n");
1110 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1111 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1112 // jaguar_dasm(0x5000, 0x14414);
1114 // WriteLog("\n.......[Cart start]...........\n\n");
1115 // jaguar_dasm(0x192000, 0x1000);//0x200);
1117 WriteLog("..................\n");
1119 if (TOMIRQEnabled(IRQ_VBLANK))
1121 WriteLog("vblank int: enabled\n");
1122 JaguarDasm(JaguarGetHandler(64), 0x200);
1125 WriteLog("vblank int: disabled\n");
1127 WriteLog("..................\n");
1129 for(int i=0; i<256; i++)
1130 WriteLog("handler %03i at $%08X\n", i, (unsigned int)JaguarGetHandler(i));
1134 // Unknown read/write byte/word routines
1137 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1138 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1140 // 807EC4: movea.l #$f1b000, A1
1141 // 807ECA: movea.l #$8129e0, A0
1142 // 807ED0: move.l A0, D0
1143 // 807ED2: move.l #$f1bb94, D1
1144 // 807ED8: sub.l D0, D1
1145 // 807EDA: lsr.l #2, D1
1146 // 807EDC: move.l (A0)+, (A1)+
1147 // 807EDE: dbra D1, 807edc
1149 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1150 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1151 // space! (That is, unless the 68K causes a bus error...)
1153 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1155 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1156 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));
1158 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1159 // extern bool finished;
1161 // extern bool doDSPDis;
1167 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1169 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1170 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));
1172 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1173 // extern bool finished;
1175 // extern bool doDSPDis;
1181 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1183 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1184 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1186 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1187 // extern bool finished;
1189 // extern bool doDSPDis;
1196 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1198 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1199 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1201 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1202 // extern bool finished;
1204 // extern bool doDSPDis;
1212 // Disassemble M68K instructions at the given offset
1215 unsigned int m68k_read_disassembler_8(unsigned int address)
1217 return m68k_read_memory_8(address);
1220 unsigned int m68k_read_disassembler_16(unsigned int address)
1222 return m68k_read_memory_16(address);
1225 unsigned int m68k_read_disassembler_32(unsigned int address)
1227 return m68k_read_memory_32(address);
1230 void JaguarDasm(uint32 offset, uint32 qt)
1233 static char buffer[2048];//, mem[64];
1234 int pc = offset, oldpc;
1236 for(uint32 i=0; i<qt; i++)
1239 for(int j=0; j<64; j++)
1240 mem[j^0x01] = jaguar_byte_read(pc + j);
1242 pc += Dasm68000((char *)mem, buffer, 0);
1243 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1245 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1246 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1251 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1256 if (offset < 0x400000)
1257 data = jaguarMainRAM[offset & 0x3FFFFF];
1258 else if ((offset >= 0x800000) && (offset < 0xC00000))
1259 data = jaguarMainROM[offset - 0x800000];
1260 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1261 data = CDROMReadByte(offset, who);
1262 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1263 data = jaguarBootROM[offset & 0x3FFFF];
1264 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1265 data = TOMReadByte(offset, who);
1266 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1267 data = JERRYReadByte(offset, who);
1269 data = jaguar_unknown_readbyte(offset, who);
1274 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1277 if (offset <= 0x3FFFFE)
1279 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1281 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1284 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1286 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1287 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1288 return CDROMReadWord(offset, who);
1289 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1290 return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1291 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1292 return TOMReadWord(offset, who);
1293 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1294 return JERRYReadWord(offset, who);
1296 return jaguar_unknown_readword(offset, who);
1299 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1301 //Need to check for writes in the range of $18FA70 + 8000...
1303 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1304 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1307 if (offset < 0x400000)
1309 jaguarMainRAM[offset & 0x3FFFFF] = data;
1312 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1314 CDROMWriteByte(offset, data, who);
1317 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1319 TOMWriteByte(offset, data, who);
1322 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1324 JERRYWriteByte(offset, data, who);
1328 jaguar_unknown_writebyte(offset, data, who);
1332 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1334 /*if (offset == 0x0100)//64*4)
1335 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1336 if (offset == 0x0102)//64*4)
1337 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1338 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1339 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1340 //Need to check for writes in the range of $18FA70 + 8000...
1342 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1343 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1344 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1345 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1349 if (offset <= 0x3FFFFE)
1354 1A 69 F0 ($0000) -> Starfield
1355 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1358 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1367 //This MUST be done by the 68K!
1368 /*if (offset == 0x670C)
1369 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1371 /*extern bool doGPUDis;
1372 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1373 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1374 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1375 doGPUDis = true;//*/
1376 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1377 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1378 if ((data & 0xFF00) != 0x7700)
1379 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1380 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1382 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1383 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1384 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1386 /*extern bool doGPUDis;
1387 if (offset == 0x120216 && who == GPU)
1388 doGPUDis = true;//*/
1389 /*extern uint32 gpu_pc;
1390 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1392 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1393 uint32 y = base / 0x300;
1394 uint32 x = (base - (y * 0x300)) / 2;
1395 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1398 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1400 //if (offset == (0x001E17F8 + 0x34))
1401 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1403 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1404 /*extern uint32 gpu_pc;
1405 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1407 extern int objectPtr;
1408 // if (offset > 0x148000)
1411 if (starCount > objectPtr)
1414 // if (starCount == 1)
1415 // WriteLog("--> Drawing 1st star...\n");
1417 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1418 // uint32 y = base / 0x300;
1419 // uint32 x = (base - (y * 0x300)) / 2;
1420 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1422 //A star of interest...
1423 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1424 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1425 //JWW: Blitter writing echo 77B3 at 0011D022...
1427 //extern bool doGPUDis;
1428 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1431 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1434 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1435 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1437 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1438 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1441 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1443 CDROMWriteWord(offset, data, who);
1446 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1448 TOMWriteWord(offset, data, who);
1451 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1453 JERRYWriteWord(offset, data, who);
1456 // Don't bomb on attempts to write to ROM
1457 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1460 jaguar_unknown_writeword(offset, data, who);
1463 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1464 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1466 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1469 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1470 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1472 /* extern bool doDSPDis;
1473 if (offset < 0x400 && !doDSPDis)
1475 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1478 /*if (offset == 0x0100)//64*4)
1479 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1481 JaguarWriteWord(offset, data >> 16, who);
1482 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1486 // Jaguar console initialization
1488 void JaguarInit(void)
1490 #ifdef CPU_DEBUG_MEMORY
1491 memset(readMem, 0x00, 0x400000);
1492 memset(writeMemMin, 0xFF, 0x400000);
1493 memset(writeMemMax, 0x00, 0x400000);
1495 memset(jaguarMainRAM, 0x00, 0x400000);
1496 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1497 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1498 //NOTE: This *doesn't* fix FlipOut...
1499 //Or does it? Hmm...
1500 //Seems to want $01010101... Dunno why. Investigate!
1501 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1502 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1504 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1512 //New timer based code stuffola...
1513 void ScanlineCallback(void);
1514 void RenderCallback(void);
1515 //extern uint32 * backbuffer;
1516 void JaguarReset(void)
1518 // Only use the system BIOS if it's available...!
1519 if (vjs.useJaguarBIOS && (biosAvailable & (BIOS_NORMAL | BIOS_STUB1 | BIOS_STUB2)))
1520 memcpy(jaguarMainRAM, jaguarBootROM, 8);
1522 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1524 // WriteLog("jaguar_reset():\n");
1530 m68k_pulse_reset(); // Reset the 68000
1531 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1533 // New timer base code stuffola...
1534 InitializeEventList();
1535 TOMResetBackbuffer(backbuffer);
1536 // SetCallbackTime(ScanlineCallback, 63.5555);
1537 SetCallbackTime(ScanlineCallback, 31.77775);
1538 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1539 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
1542 void JaguarDone(void)
1544 #ifdef CPU_DEBUG_MEMORY
1545 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1547 for(uint32 i=0; i<=raPtr; i++)
1549 WriteLog("\t%08X\n", returnAddr[i]);
1550 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1551 jaguar_dasm(returnAddr[i] - 16, 16);
1556 /* int start = 0, end = 0;
1557 bool endTriggered = false, startTriggered = false;
1558 for(int i=0; i<0x400000; i++)
1560 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1562 if (!startTriggered)
1563 startTriggered = true, endTriggered = false, start = i;
1565 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1571 end = i - 1, endTriggered = true, startTriggered = false;
1572 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1579 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1580 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1581 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1582 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1583 for(int i=-2; i<9; i++)
1584 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1586 /* WriteLog("\nM68000 disassembly at $802288...\n");
1587 jaguar_dasm(0x802288, 3);
1588 WriteLog("\nM68000 disassembly at $802200...\n");
1589 jaguar_dasm(0x802200, 500);
1590 WriteLog("\nM68000 disassembly at $802518...\n");
1591 jaguar_dasm(0x802518, 100);//*/
1593 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1594 jaguar_dasm(0x803F00, 500);
1597 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1598 jaguar_dasm(0x802B00, 500);
1601 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1602 jaguar_dasm(0x809900, 500);
1605 /* WriteLog("\n\nDump of $8093C8:\n\n");
1606 for(int i=0x8093C8; i<0x809900; i+=4)
1607 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1608 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1609 jaguar_dasm(0x90006C, 500);
1611 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1612 jaguar_dasm(0x1AC000, 6000);
1615 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1616 WriteLog("Jaguar: Interrupt enable = %02X\n", TOMReadByte(0xF000E1) & 0x1F);
1617 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
1618 M68K_show_context();
1629 // Main Jaguar execution loop (1 frame)
1631 void JaguarExecute(uint32 * backbuffer, bool render)
1633 uint16 vp = TOMReadWord(0xF0003E) + 1;
1634 uint16 vi = TOMReadWord(0xF0004E);
1635 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1636 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1638 // uint16 vdb = TOMReadWord(0xF00046);
1639 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1640 // uint16 vbb = TOMReadWord(0xF00040);
1641 //It seems that they mean it when they say that VDE is the end of object processing.
1642 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1643 //buffer and not to write any more pixels... !!! FIX !!!
1644 // uint16 vde = TOMReadWord(0xF00048);
1646 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1647 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1648 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1649 //seem to indicate the refresh rate is *half* the above...
1650 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1651 // Should these be hardwired or read from VP? Yes, from VP!
1652 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1653 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1655 TOMResetBackbuffer(backbuffer);
1656 /*extern int effect_start;
1658 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1660 //extern int start_logging;
1661 for(uint16 i=0; i<vp; i++)
1663 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1664 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004) + 1) & 0x7FF);
1666 TOMWriteWord(0xF00006, i); // Write the VC
1668 // if (i == vi) // Time for Vertical Interrupt?
1669 //Not sure if this is correct...
1670 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1671 //Which means that it normally wouldn't go when it's zero.
1672 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1674 // We don't have to worry about autovectors & whatnot because the Jaguar
1675 // tells you through its HW registers who sent the interrupt...
1676 TOMSetPendingVideoInt();
1680 //if (start_logging)
1681 // WriteLog("About to execute M68K (%u)...\n", i);
1682 m68k_execute(M68KCyclesPerScanline);
1683 //if (start_logging)
1684 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1685 TOMExecPIT(RISCCyclesPerScanline);
1686 //if (start_logging)
1687 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1688 JERRYExecPIT(RISCCyclesPerScanline);
1689 //if (start_logging)
1690 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1691 JERRYI2SExec(RISCCyclesPerScanline);
1692 BUTCHExec(RISCCyclesPerScanline);
1693 //if (start_logging)
1694 // WriteLog("About to execute GPU (%u)...\n", i);
1695 GPUExec(RISCCyclesPerScanline);
1699 if (vjs.usePipelinedDSP)
1700 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1702 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1703 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1706 //if (start_logging)
1707 // WriteLog("About to execute OP (%u)...\n", i);
1708 TOMExecScanline(i, render);
1712 // Temp debugging stuff
1714 void DumpMainMemory(void)
1716 FILE * fp = fopen("./memdump.bin", "wb");
1721 fwrite(jaguarMainRAM, 1, 0x400000, fp);
1725 uint8 * GetRamPtr(void)
1727 return jaguarMainRAM;
1731 // New Jaguar execution stack
1736 void JaguarExecuteNew(void)
1738 extern bool finished, showGUI;
1739 extern bool debounceRunKey;
1740 // Pass a message to the "joystick" code to debounce the ESC key...
1741 debounceRunKey = true;
1743 /* InitializeEventList();
1744 TOMResetBackbuffer(backbuffer);
1745 // SetCallbackTime(ScanlineCallback, 63.5555);
1746 SetCallbackTime(ScanlineCallback, 31.77775);
1747 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1748 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1749 // uint8 * keystate = SDL_GetKeyState(NULL);
1753 double timeToNextEvent = GetTimeToNextEvent();
1754 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1756 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1757 gpu_exec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1761 if (vjs.usePipelinedDSP)
1762 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1764 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1769 // if (keystate[SDLK_ESCAPE])
1772 // SDL_PumpEvents(); // Needed to keep the keystate current...
1777 void ScanlineCallback(void)
1779 uint16 vc = TOMReadWord(0xF00006);
1780 uint16 vp = TOMReadWord(0xF0003E) + 1;
1781 uint16 vi = TOMReadWord(0xF0004E);
1782 // uint16 vbb = TOMReadWord(0xF00040);
1788 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1789 TOMWriteWord(0xF00006, vc);
1791 //This is a crappy kludge, but maybe it'll work for now...
1792 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1793 if (vc == vi && vc > 0 && tom_irq_enabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1795 // We don't have to worry about autovectors & whatnot because the Jaguar
1796 // tells you through its HW registers who sent the interrupt...
1797 tom_set_pending_video_int();
1801 TOMExecScanline(vc, true);
1803 //Change this to VBB???
1804 //Doesn't seem to matter (at least for Flip Out & I-War)
1811 TOMResetBackbuffer(backbuffer);
1815 // TOMResetBackbuffer(backbuffer);
1817 // SetCallbackTime(ScanlineCallback, 63.5555);
1818 SetCallbackTime(ScanlineCallback, 31.77775);
1824 void JaguarExecuteNew(void)
1826 // extern bool finished, showGUI;
1827 // extern bool debounceRunKey;
1828 // Pass a message to the "joystick" code to debounce the ESC key...
1829 // debounceRunKey = true;
1830 // finished = false;
1831 /* InitializeEventList();
1832 TOMResetBackbuffer(backbuffer);
1833 // SetCallbackTime(ScanlineCallback, 63.5555);
1834 SetCallbackTime(ScanlineCallback, 31.77775);
1835 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1836 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1837 // uint8 * keystate = SDL_GetKeyState(NULL);
1842 double timeToNextEvent = GetTimeToNextEvent();
1843 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1845 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1846 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1850 if (vjs.usePipelinedDSP)
1851 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1853 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1858 // if (keystate[SDLK_ESCAPE])
1861 // SDL_PumpEvents(); // Needed to keep the keystate current...
1866 void ScanlineCallback(void)
1868 uint16 vc = TOMReadWord(0xF00006);
1869 uint16 vp = TOMReadWord(0xF0003E) + 1;
1870 uint16 vi = TOMReadWord(0xF0004E);
1871 // uint16 vbb = TOMReadWord(0xF00040);
1877 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1878 TOMWriteWord(0xF00006, vc);
1880 //This is a crappy kludge, but maybe it'll work for now...
1881 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1882 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1884 // We don't have to worry about autovectors & whatnot because the Jaguar
1885 // tells you through its HW registers who sent the interrupt...
1886 TOMSetPendingVideoInt();
1890 TOMExecScanline(vc, true);
1892 //Change this to VBB???
1893 //Doesn't seem to matter (at least for Flip Out & I-War)
1898 //We comment this out so that the GUI can manage this instead. Which is how it should be anyway.
1899 // RenderBackbuffer();
1900 TOMResetBackbuffer(backbuffer);
1905 // TOMResetBackbuffer(backbuffer);
1907 // SetCallbackTime(ScanlineCallback, 63.5555);
1908 SetCallbackTime(ScanlineCallback, 31.77775);
1913 // This isn't currently used, but maybe it should be...
1914 void RenderCallback(void)
1916 // RenderBackbuffer();
1917 TOMResetBackbuffer(backbuffer);
1918 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1919 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time