4 // Originally by David Raingeard (Cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
6 // Cleanups and endian wrongness amelioration by James L. Hammons
7 // Note: Endian wrongness probably stems from the MAME origins of this emu and
8 // the braindead way in which MAME handled memory when this was written. :-)
10 // JLH = James L. Hammons
13 // --- ---------- -----------------------------------------------------------
14 // JLH 11/25/2009 Major rewrite of memory subsystem and handlers
20 #include "SDL_opengl.h"
38 //Do this in makefile??? Yes! Could, but it's easier to define here...
39 //#define LOG_UNMAPPED_MEMORY_ACCESSES
40 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
41 #define ABORT_ON_ILLEGAL_INSTRUCTIONS
42 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
43 #define CPU_DEBUG_MEMORY
44 //#define LOG_CD_BIOS_CALLS
46 // Private function prototypes
48 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who = UNKNOWN);
49 unsigned jaguar_unknown_readword(unsigned address, uint32 who = UNKNOWN);
50 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who = UNKNOWN);
51 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who = UNKNOWN);
52 void M68K_show_context(void);
56 #ifdef CPU_DEBUG_MEMORY
57 extern bool startMemLog; // Set by "e" key
58 extern int effect_start;
59 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
62 // Really, need to include memory.h for this, but it might interfere with some stuff...
63 extern uint8 jagMemSpace[];
67 uint32 jaguar_active_memory_dumps = 0;
69 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
71 bool BIOSLoaded = false;
72 bool CDBIOSLoaded = false;
76 #ifdef CPU_DEBUG_MEMORY
77 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
78 uint8 readMem[0x400000];
79 uint32 returnAddr[4000], raPtr = 0xFFFFFFFF;
82 uint32 pcQueue[0x400];
86 // Callback function to detect illegal instructions
88 void GPUDumpDisassembly(void);
89 void GPUDumpRegisters(void);
90 static bool start = false;
92 void M68KInstructionHook(void)
94 uint32 m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
97 // Ideally, we'd save all the registers as well...
98 pcQueue[pcQPtr++] = m68kPC;
101 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
103 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
105 static char buffer[2048];
106 for(int i=0; i<0x400; i++)
108 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], M68K_CPU_TYPE_68000);
109 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
113 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
114 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
115 for(int i=0; i<10; i++)
116 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
117 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
123 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
125 static char buffer[2048];
126 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
127 WriteLog("%08X: %s", m68kPC, buffer);
128 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
129 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
130 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
132 /* if (m68kPC == 0x8D0E48 && effect_start5)
134 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
136 GPUDumpDisassembly();
140 /* uint16 opcode = JaguarReadWord(m68kPC);
141 if (opcode == 0x4E75) // RTS
144 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
146 uint32 addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
148 if (raPtr != 0xFFFFFFFF)
150 for(uint32 i=0; i<=raPtr; i++)
152 if (returnAddr[i] == addr)
161 returnAddr[++raPtr] = addr;
165 //Flip Out! debugging...
168 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
169 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
170 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
171 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
173 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
175 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
176 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
177 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
178 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
179 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
180 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
181 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
183 /* static char buffer[2048];
184 //if (m68kPC > 0x805F48) start = true;
185 //if (m68kPC > 0x806486) start = true;
186 //if (m68kPC == 0x805FEE) start = true;
187 //if (m68kPC == 0x80600C)// start = true;
188 if (m68kPC == 0x802058) start = true;
190 // GPUDumpRegisters();
191 // GPUDumpDisassembly();
193 // M68K_show_context();
199 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
200 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));
203 /* if (m68kPC == 0x803F16)
205 WriteLog("M68K: Registers found at $803F16:\n");
206 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
207 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
208 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
210 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
211 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
213 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
214 // !!! Investigate !!!
215 /*extern bool doDSPDis;
216 static bool disgo = false;
217 if (m68kPC == 0x50222)
220 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
221 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
224 if (m68kPC == 0x5000)
229 static char buffer[2048];
230 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
231 WriteLog("%08X: %s", m68kPC, buffer);
232 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
233 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
234 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
236 if (m68kPC == 0x82E1A)
238 static char buffer[2048];
239 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
240 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
241 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
242 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
243 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
245 if (m68kPC == 0x82E58)
246 WriteLog("--> [Routine end]\n");
247 if (m68kPC == 0x80004)
249 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
250 // m68k_set_reg(M68K_REG_D2, 0x12345678);
253 #ifdef LOG_CD_BIOS_CALLS
276 if (m68kPC == 0x3000)
277 WriteLog("M68K: CD_init\n");
278 else if (m68kPC == 0x3006 + (6 * 0))
279 WriteLog("M68K: CD_mode\n");
280 else if (m68kPC == 0x3006 + (6 * 1))
281 WriteLog("M68K: CD_ack\n");
282 else if (m68kPC == 0x3006 + (6 * 2))
283 WriteLog("M68K: CD_jeri\n");
284 else if (m68kPC == 0x3006 + (6 * 3))
285 WriteLog("M68K: CD_spin\n");
286 else if (m68kPC == 0x3006 + (6 * 4))
287 WriteLog("M68K: CD_stop\n");
288 else if (m68kPC == 0x3006 + (6 * 5))
289 WriteLog("M68K: CD_mute\n");
290 else if (m68kPC == 0x3006 + (6 * 6))
291 WriteLog("M68K: CD_umute\n");
292 else if (m68kPC == 0x3006 + (6 * 7))
293 WriteLog("M68K: CD_paus\n");
294 else if (m68kPC == 0x3006 + (6 * 8))
295 WriteLog("M68K: CD_upaus\n");
296 else if (m68kPC == 0x3006 + (6 * 9))
297 WriteLog("M68K: CD_read\n");
298 else if (m68kPC == 0x3006 + (6 * 10))
299 WriteLog("M68K: CD_uread\n");
300 else if (m68kPC == 0x3006 + (6 * 11))
301 WriteLog("M68K: CD_setup\n");
302 else if (m68kPC == 0x3006 + (6 * 12))
303 WriteLog("M68K: CD_ptr\n");
304 else if (m68kPC == 0x3006 + (6 * 13))
305 WriteLog("M68K: CD_osamp\n");
306 else if (m68kPC == 0x3006 + (6 * 14))
307 WriteLog("M68K: CD_getoc\n");
308 else if (m68kPC == 0x3006 + (6 * 15))
309 WriteLog("M68K: CD_initm\n");
310 else if (m68kPC == 0x3006 + (6 * 16))
311 WriteLog("M68K: CD_initf\n");
312 else if (m68kPC == 0x3006 + (6 * 17))
313 WriteLog("M68K: CD_switch\n");
315 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
316 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
317 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
318 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
321 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
322 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
324 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
325 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
327 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
328 // keep going even when the 68K dumped back to the debugger or what have you).
330 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
331 // Try setting the vector to the illegal instruction...
332 //This doesn't work right either! Do something else! Quick!
333 // SET32(jaguar_mainRam, 0x10, m68kPC);
339 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
340 uint32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
341 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
342 for(int i=0; i<10; i++)
343 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
344 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
348 // WriteLog("\n\n68K disasm\n\n");
349 // jaguar_dasm(0x802000, 0x50C);
360 Now here be dragons...
361 Here is how memory ranges are defined in the CoJag driver.
362 Note that we only have to be concerned with 3 entities read/writing anything:
363 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
364 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
365 things that are entirely internal to those modules. This way we should be able to get a handle on all
366 this crap which is currently scattered over Hell's Half Acre(tm).
368 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
369 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
371 /*************************************
373 * Main CPU memory handlers
375 *************************************/
377 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
378 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
379 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
380 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
381 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
382 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
383 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
384 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
385 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
386 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
387 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
388 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
389 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
390 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
391 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
392 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
393 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
394 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
395 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
396 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
397 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
398 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
399 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
402 /*************************************
404 * GPU memory handlers
406 *************************************/
408 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
409 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
410 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
411 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
412 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
413 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
414 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
415 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
416 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
417 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
418 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
421 /*************************************
423 * DSP memory handlers
425 *************************************/
427 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
428 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
429 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
430 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
431 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
432 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
433 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
434 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
435 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
440 //#define EXPERIMENTAL_MEMORY_HANDLING
441 // Experimental memory mappage...
442 // Dunno if this is a good approach or not, but it seems to make better
443 // sense to have all this crap in one spot intstead of scattered all over
444 // the place the way it is now.
445 #ifdef EXPERIMENTAL_MEMORY_HANDLING
447 #define NEW_TIMER_SYSTEM
450 uint8 jaguarMainRAM[0x400000]; // 68K CPU RAM
451 uint8 jaguarMainROM[0x600000]; // 68K CPU ROM
452 uint8 jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
453 uint8 jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
454 bool BIOSLoaded = false;
455 bool CDBIOSLoaded = false;
458 uint8 tomRAM[0x4000];
459 uint8 jerryRAM[0x10000];
460 static uint16 eeprom_ram[64];
462 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
465 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
467 // M68K Memory map/handlers
469 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
470 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
471 // Note that this is really memory mapped I/O region...
472 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
473 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
474 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
475 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
476 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
477 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
478 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
479 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
480 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
481 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
482 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
483 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
485 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
487 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
488 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
489 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
490 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
491 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
492 //What about LBUF writes???
493 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
494 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
495 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
497 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
501 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
502 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
503 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
506 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
507 0 = pad0/1 button values (4 bits each), RO(?)
508 1 = pad0/1 index value (4 bits each), WO
510 3 = NTSC/PAL, certain button states, RO
512 JOYSTICK $F14000 Read/Write
514 Read fedcba98 7654321q f-1 Signals J15 to J1
515 q Cartridge EEPROM output data
516 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
517 0 = disable J7-J0 outputs
520 0 = Audio muted (reset state)
522 7-4 J7-J4 outputs (port 2)
523 3-0 J3-J0 outputs (port 1)
524 JOYBUTS $F14002 Read Only
526 Read xxxxxxxx rrdv3210 x don't care
529 v 1 = NTSC Video hardware
530 0 = PAL Video hardware
531 3-2 Button inputs B3 & B2 (port 2)
532 1-0 Button inputs B1 & B0 (port 1)
534 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
535 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
543 0 1 1 1 Row 3 C3 Option # 9 6 3
547 1 0 1 1 Row 2 C2 C 0 8 5 2
549 1 1 0 1 Row 1 C1 B * 7 4 1
550 1 1 1 0 Row 0 Pause A Up Down Left Right
553 0 bit read in any position means that button is pressed.
554 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
558 void WriteByte(uint32 address, uint8 byte, uint32 who/*=UNKNOWN*/)
560 // Not sure, but I think the system only has 24 address bits...
561 address &= 0x00FFFFFF;
563 // RAM ($000000 - $3FFFFF) 4M
564 if (address <= 0x3FFFFF)
565 jaguarMainRAM[address] = byte;
566 // hole ($400000 - $7FFFFF) 4M
567 else if (address <= 0x7FFFFF)
569 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
570 else if (address <= 0xDFFEFF)
572 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
573 else if (address <= 0xDFFFFF)
575 cdRAM[address & 0xFF] = byte;
577 if ((address & 0xFF) < 12 * 4)
578 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
579 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
582 // BIOS ROM ($E00000 - $E3FFFF) 256K
583 else if (address <= 0xE3FFFF)
585 // hole ($E40000 - $EFFFFF) 768K
586 else if (address <= 0xEFFFFF)
588 // TOM ($F00000 - $F0FFFF) 64K
589 else if (address <= 0xF0FFFF)
592 if (address == 0xF00050)
594 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16)byte << 8);
598 else if (address == 0xF00051)
600 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
604 else if (address == 0xF00052)
606 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16)byte << 8);
610 else if (address == 0xF00053)
612 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
616 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
618 // Writing to one CLUT writes to the other
619 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
620 tomRAM[address] = tomRAM[address + 0x200] = byte;
623 //What about LBUF writes???
624 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
626 GPUWriteByte(address, byte, who);
629 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
631 BlitterWriteByte(address, byte, who);
634 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
636 GPUWriteByte(address, byte, who);
640 tomRAM[address & 0x3FFF] = byte;
642 // JERRY ($F10000 - $F1FFFF) 64K
643 else if (address <= 0xF1FFFF)
647 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
649 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
651 DSPWriteByte(address, byte, who);
654 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
656 DSPWriteByte(address, byte, who);
659 // SCLK ($F1A150--8 bits wide)
660 //NOTE: This should be taken care of in DAC...
661 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
663 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
664 if ((address & 0x03) == 2)
665 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32)byte << 8);
667 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)byte;
669 JERRYI2SInterruptTimer = -1;
670 #ifndef NEW_TIMER_SYSTEM
673 RemoveCallback(JERRYI2SCallback);
678 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
679 else if (address >= 0xF1A148 && address <= 0xF1A157)
681 DACWriteByte(address, byte, who);
684 else if (address >= 0xF10000 && address <= 0xF10007)
686 #ifndef NEW_TIMER_SYSTEM
687 switch (address & 0x07)
690 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
694 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
698 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
702 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
706 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
710 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
714 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
718 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
722 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
726 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
728 clock_byte_write(offset, byte);
731 // JERRY -> 68K interrupt enables/latches (need to be handled!)
732 else if (address >= 0xF10020 && address <= 0xF10023)
734 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
736 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
738 anajoy_byte_write(offset, byte);
741 else if ((address >= 0xF14000) && (address <= 0xF14003))
743 JoystickWriteByte(address, byte);
744 EepromWriteByte(address, byte);
747 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
749 EepromWriteByte(address, byte);
752 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
753 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
756 jerryRAM[address & 0xFFFF] = byte;
758 // hole ($F20000 - $FFFFFF) 1M - 128K
763 void WriteWord(uint32 adddress, uint16 word)
767 void WriteDWord(uint32 adddress, uint32 dword)
771 uint8 ReadByte(uint32 adddress)
775 uint16 ReadWord(uint32 adddress)
779 uint32 ReadDWord(uint32 adddress)
785 // Musashi 68000 read/write/IRQ functions
792 IPL Name Vector Control
793 ---------+---------------+---------------+---------------
794 2 VBLANK IRQ $100 INT1 bit #0
795 2 GPU IRQ $100 INT1 bit #1
796 2 HBLANK IRQ $100 INT1 bit #2
797 2 Timer IRQ $100 INT1 bit #3
799 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
800 and are therefore indistinguishable.
802 A typical way to install a LEVEL2 handler for the 68000 would be
803 something like this, you gotta supply "last_line" and "handler".
804 Note that the interrupt is auto vectored thru $100 (not $68)
812 IRQS_HANDLED=$909 ;; VBLANK and TIMER
814 move.w #$2700,sr ;; no IRQs please
815 move.l #handler,V_AUTO ;; install our routine
817 move.w #last_line,VI ;; scanline where IRQ should occur
818 ;; should be 'odd' BTW
819 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
820 move.w #$2100,sr ;; enable IRQs on the 68K
838 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
839 move.w #0,INT2 ; let GPU run again
843 As you can see, if you have multiple INT1 interrupts coming in,
844 you need to check the lower byte of INT1, to see which interrupt
847 int irq_ack_handler(int level)
849 // Tracing the IPL lines on the Jaguar schematic yields the following:
850 // IPL1 is connected to INTL on TOM (OUT to 68K)
851 // IPL0-2 are also tied to Vcc via 4.7K resistors!
852 // (DINT on TOM goes into DINT on JERRY (IN from Jerry))
853 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
854 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
856 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
857 // They aren't, and this causes problems with a, err, specific ROM. :-D
861 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
862 return 64; // Set user interrupt #0
865 return M68K_INT_ACK_AUTOVECTOR;
868 //#define USE_NEW_MMU
870 unsigned int m68k_read_memory_8(unsigned int address)
872 #ifdef CPU_DEBUG_MEMORY
873 if ((address >= 0x000000) && (address <= 0x3FFFFF))
876 readMem[address] = 1;
879 //WriteLog("[RM8] Addr: %08X\n", address);
880 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
881 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
882 || address == 0x1AF05E)
883 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
885 unsigned int retVal = 0;
887 if ((address >= 0x000000) && (address <= 0x3FFFFF))
888 retVal = jaguarMainRAM[address];
889 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
890 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
891 retVal = jaguarMainROM[address - 0x800000];
892 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
893 // retVal = jaguarBootROM[address - 0xE00000];
894 // retVal = jaguarDevBootROM1[address - 0xE00000];
895 retVal = jagMemSpace[address];
896 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
897 retVal = CDROMReadByte(address);
898 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
899 retVal = TOMReadByte(address, M68K);
900 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
901 retVal = JERRYReadByte(address, M68K);
903 retVal = jaguar_unknown_readbyte(address, M68K);
905 //if (address >= 0x2800 && address <= 0x281F)
906 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
907 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
908 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
911 return MMURead8(address, M68K);
915 void gpu_dump_disassembly(void);
916 void gpu_dump_registers(void);
918 unsigned int m68k_read_memory_16(unsigned int address)
920 #ifdef CPU_DEBUG_MEMORY
921 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
924 readMem[address] = 1, readMem[address + 1] = 1;
926 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
928 return 0x4E71; // NOP
930 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
932 return 0x4E71; // NOP
934 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
936 return 0x4E71; // NOP
938 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
940 return 0x4E71; // NOP
942 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
944 return 0x4E71; // NOP
946 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
948 return 0x4E71; // NOP
951 //WriteLog("[RM16] Addr: %08X\n", address);
952 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
953 // for(int i=0; i<10000; i++)
954 WriteLog("[M68K] In routine #6!\n");//*/
955 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
956 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
957 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
959 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
960 gpu_dump_registers();
961 gpu_dump_disassembly();
962 // for(int i=0; i<10000; i++)
963 // WriteLog("[M68K] About to run GPU!\n");
965 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
966 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
968 if (address == 0x000066A0)
970 gpu_dump_registers();
971 gpu_dump_disassembly();
973 for(int i=0; i<10000; i++)
974 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
976 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
977 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
978 || address == 0x1AF05E)
979 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
981 unsigned int retVal = 0;
983 if ((address >= 0x000000) && (address <= 0x3FFFFE))
984 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
985 retVal = GET16(jaguarMainRAM, address);
986 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
987 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
988 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
989 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
990 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
991 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
992 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
993 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
994 retVal = CDROMReadWord(address, M68K);
995 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
996 retVal = TOMReadWord(address, M68K);
997 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
998 retVal = JERRYReadWord(address, M68K);
1000 retVal = jaguar_unknown_readword(address, M68K);
1002 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1003 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1004 //if (address >= 0x2800 && address <= 0x281F)
1005 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1006 //$8B3AE -> Transferred from $F1C010
1007 //$8B5E4 -> Only +1 read at $808AA
1008 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1009 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1012 return MMURead16(address, M68K);
1016 unsigned int m68k_read_memory_32(unsigned int address)
1018 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1019 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1020 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));//*/
1022 //WriteLog("--> [RM32]\n");
1024 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1026 return MMURead32(address, M68K);
1030 void m68k_write_memory_8(unsigned int address, unsigned int value)
1032 #ifdef CPU_DEBUG_MEMORY
1033 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1037 if (value > writeMemMax[address])
1038 writeMemMax[address] = value;
1039 if (value < writeMemMin[address])
1040 writeMemMin[address] = value;
1044 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1045 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1046 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1048 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1049 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1052 if ((address >= 0x000000) && (address <= 0x3FFFFF))
1053 jaguarMainRAM[address] = value;
1054 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1055 CDROMWriteByte(address, value, M68K);
1056 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1057 TOMWriteByte(address, value, M68K);
1058 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1059 JERRYWriteByte(address, value, M68K);
1061 jaguar_unknown_writebyte(address, value, M68K);
1063 MMUWrite8(address, value, M68K);
1067 void m68k_write_memory_16(unsigned int address, unsigned int value)
1069 #ifdef CPU_DEBUG_MEMORY
1070 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1074 uint8 hi = value >> 8, lo = value & 0xFF;
1076 if (hi > writeMemMax[address])
1077 writeMemMax[address] = hi;
1078 if (hi < writeMemMin[address])
1079 writeMemMin[address] = hi;
1081 if (lo > writeMemMax[address+1])
1082 writeMemMax[address+1] = lo;
1083 if (lo < writeMemMin[address+1])
1084 writeMemMin[address+1] = lo;
1088 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1089 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1090 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1091 //if (address >= 0xF02200 && address <= 0xF0229F)
1092 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1093 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1094 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1095 /*extern uint32 totalFrames;
1096 if (address == 0xF02114)
1097 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1098 if (address == 0xF02110)
1099 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1100 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1101 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1103 /*if (address == 0x0100)//64*4)
1104 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1106 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1107 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1108 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1109 || address == 0x1AF05E)
1110 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1113 if ((address >= 0x000000) && (address <= 0x3FFFFE))
1115 /* jaguar_mainRam[address] = value >> 8;
1116 jaguar_mainRam[address + 1] = value & 0xFF;*/
1117 SET16(jaguarMainRAM, address, value);
1119 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1120 CDROMWriteWord(address, value, M68K);
1121 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1122 TOMWriteWord(address, value, M68K);
1123 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1124 JERRYWriteWord(address, value, M68K);
1127 jaguar_unknown_writeword(address, value, M68K);
1128 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1129 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1130 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1131 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1135 MMUWrite16(address, value, M68K);
1139 void m68k_write_memory_32(unsigned int address, unsigned int value)
1141 //WriteLog("--> [WM32]\n");
1142 /*if (address == 0x0100)//64*4)
1143 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1144 /*if (address >= 0xF03214 && address < 0xF0321F)
1145 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1146 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1147 /*extern bool doGPUDis;
1148 if (address == 0xF03214 && value == 0x88E30047)
1150 doGPUDis = true;//*/
1151 /* if (address == 0x51136 || address == 0xFB074)
1152 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1155 m68k_write_memory_16(address, value >> 16);
1156 m68k_write_memory_16(address + 2, value & 0xFFFF);
1158 MMUWrite32(address, value, M68K);
1163 uint32 JaguarGetHandler(uint32 i)
1165 return JaguarReadLong(i * 4);
1168 bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
1170 uint32 handler = JaguarGetHandler(i);
1171 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1174 void M68K_show_context(void)
1176 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1177 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1178 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1180 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1181 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1183 WriteLog("68K disasm\n");
1184 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1185 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1186 // jaguar_dasm(0x5000, 0x14414);
1188 // WriteLog("\n.......[Cart start]...........\n\n");
1189 // jaguar_dasm(0x192000, 0x1000);//0x200);
1191 WriteLog("..................\n");
1193 if (TOMIRQEnabled(IRQ_VBLANK))
1195 WriteLog("video int: enabled\n");
1196 JaguarDasm(JaguarGetHandler(64), 0x200);
1199 WriteLog("video int: disabled\n");
1201 WriteLog("..................\n");
1203 for(int i=0; i<256; i++)
1205 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1206 uint32 address = (uint32)JaguarGetHandler(i);
1209 WriteLog(".........\n");
1211 WriteLog("$%08X\n", address);
1216 // Unknown read/write byte/word routines
1219 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1220 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1222 // 807EC4: movea.l #$f1b000, A1
1223 // 807ECA: movea.l #$8129e0, A0
1224 // 807ED0: move.l A0, D0
1225 // 807ED2: move.l #$f1bb94, D1
1226 // 807ED8: sub.l D0, D1
1227 // 807EDA: lsr.l #2, D1
1228 // 807EDC: move.l (A0)+, (A1)+
1229 // 807EDE: dbra D1, 807edc
1231 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1232 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1233 // space! (That is, unless the 68K causes a bus error...)
1235 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1237 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1238 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));
1240 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1241 // extern bool finished;
1243 // extern bool doDSPDis;
1249 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32 who/*=UNKNOWN*/)
1251 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1252 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));
1254 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1255 // extern bool finished;
1257 // extern bool doDSPDis;
1263 unsigned jaguar_unknown_readbyte(unsigned address, uint32 who/*=UNKNOWN*/)
1265 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1266 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1268 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1269 // extern bool finished;
1271 // extern bool doDSPDis;
1278 unsigned jaguar_unknown_readword(unsigned address, uint32 who/*=UNKNOWN*/)
1280 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1281 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1283 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1284 // extern bool finished;
1286 // extern bool doDSPDis;
1294 // Disassemble M68K instructions at the given offset
1297 unsigned int m68k_read_disassembler_8(unsigned int address)
1299 return m68k_read_memory_8(address);
1302 unsigned int m68k_read_disassembler_16(unsigned int address)
1304 return m68k_read_memory_16(address);
1307 unsigned int m68k_read_disassembler_32(unsigned int address)
1309 return m68k_read_memory_32(address);
1312 void JaguarDasm(uint32 offset, uint32 qt)
1315 static char buffer[2048];//, mem[64];
1316 int pc = offset, oldpc;
1318 for(uint32 i=0; i<qt; i++)
1321 for(int j=0; j<64; j++)
1322 mem[j^0x01] = jaguar_byte_read(pc + j);
1324 pc += Dasm68000((char *)mem, buffer, 0);
1325 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1327 pc += m68k_disassemble(buffer, pc, M68K_CPU_TYPE_68000);
1328 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1333 uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1338 if (offset < 0x400000)
1339 data = jaguarMainRAM[offset & 0x3FFFFF];
1340 else if ((offset >= 0x800000) && (offset < 0xC00000))
1341 data = jaguarMainROM[offset - 0x800000];
1342 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1343 data = CDROMReadByte(offset, who);
1344 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1345 // data = jaguarBootROM[offset & 0x3FFFF];
1346 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1347 data = jagMemSpace[offset];
1348 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1349 data = TOMReadByte(offset, who);
1350 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1351 data = JERRYReadByte(offset, who);
1353 data = jaguar_unknown_readbyte(offset, who);
1358 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1361 if (offset <= 0x3FFFFE)
1363 return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
1365 else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
1368 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1370 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1371 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1372 return CDROMReadWord(offset, who);
1373 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1374 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1375 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1376 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1377 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1378 return TOMReadWord(offset, who);
1379 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1380 return JERRYReadWord(offset, who);
1382 return jaguar_unknown_readword(offset, who);
1385 void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1387 //Need to check for writes in the range of $18FA70 + 8000...
1389 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1390 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1393 if (offset < 0x400000)
1395 jaguarMainRAM[offset & 0x3FFFFF] = data;
1398 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1400 CDROMWriteByte(offset, data, who);
1403 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1405 TOMWriteByte(offset, data, who);
1408 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1410 JERRYWriteByte(offset, data, who);
1414 jaguar_unknown_writebyte(offset, data, who);
1418 void JaguarWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1420 /*if (offset == 0x0100)//64*4)
1421 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1422 if (offset == 0x0102)//64*4)
1423 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1424 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1425 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1426 //Need to check for writes in the range of $18FA70 + 8000...
1428 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1429 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1430 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1431 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1435 if (offset <= 0x3FFFFE)
1440 1A 69 F0 ($0000) -> Starfield
1441 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1444 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1453 //This MUST be done by the 68K!
1454 /*if (offset == 0x670C)
1455 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1457 /*extern bool doGPUDis;
1458 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1459 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1460 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1461 doGPUDis = true;//*/
1462 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1463 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1464 if ((data & 0xFF00) != 0x7700)
1465 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1466 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1468 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1469 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1470 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1472 /*extern bool doGPUDis;
1473 if (offset == 0x120216 && who == GPU)
1474 doGPUDis = true;//*/
1475 /*extern uint32 gpu_pc;
1476 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1478 uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1479 uint32 y = base / 0x300;
1480 uint32 x = (base - (y * 0x300)) / 2;
1481 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1484 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1486 //if (offset == (0x001E17F8 + 0x34))
1487 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1489 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1490 /*extern uint32 gpu_pc;
1491 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1493 extern int objectPtr;
1494 // if (offset > 0x148000)
1497 if (starCount > objectPtr)
1500 // if (starCount == 1)
1501 // WriteLog("--> Drawing 1st star...\n");
1503 // uint32 base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1504 // uint32 y = base / 0x300;
1505 // uint32 x = (base - (y * 0x300)) / 2;
1506 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1508 //A star of interest...
1509 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1510 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1511 //JWW: Blitter writing echo 77B3 at 0011D022...
1513 //extern bool doGPUDis;
1514 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1517 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1520 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1521 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1523 jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
1524 jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
1527 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1529 CDROMWriteWord(offset, data, who);
1532 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1534 TOMWriteWord(offset, data, who);
1537 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1539 JERRYWriteWord(offset, data, who);
1542 // Don't bomb on attempts to write to ROM
1543 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1546 jaguar_unknown_writeword(offset, data, who);
1549 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1550 uint32 JaguarReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
1552 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1555 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1556 void JaguarWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
1558 /* extern bool doDSPDis;
1559 if (offset < 0x400 && !doDSPDis)
1561 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1564 /*if (offset == 0x0100)//64*4)
1565 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1567 JaguarWriteWord(offset, data >> 16, who);
1568 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1572 // Jaguar console initialization
1574 void JaguarInit(void)
1576 #ifdef CPU_DEBUG_MEMORY
1577 memset(readMem, 0x00, 0x400000);
1578 memset(writeMemMin, 0xFF, 0x400000);
1579 memset(writeMemMax, 0x00, 0x400000);
1581 memset(jaguarMainRAM, 0x00, 0x400000);
1582 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1583 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1584 //NOTE: This *doesn't* fix FlipOut...
1585 //Or does it? Hmm...
1586 //Seems to want $01010101... Dunno why. Investigate!
1587 memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1588 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1590 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
1598 //New timer based code stuffola...
1599 void ScanlineCallback(void);
1600 void RenderCallback(void);
1601 //extern uint32 * backbuffer;
1602 void JaguarReset(void)
1604 //Need to change this so it uses the single RAM space and load the BIOS
1605 //into it somewhere...
1606 //Also, have to change this here and in JaguarReadXX() currently
1607 // Only use the system BIOS if it's available...! (it's always available now!)
1608 if (vjs.useJaguarBIOS && !vjs.hardwareTypeAlpine)
1609 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1611 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1613 // WriteLog("jaguar_reset():\n");
1619 m68k_pulse_reset(); // Reset the 68000
1620 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1622 // New timer base code stuffola...
1623 InitializeEventList();
1624 TOMResetBackbuffer(backbuffer);
1625 // SetCallbackTime(ScanlineCallback, 63.5555);
1626 SetCallbackTime(ScanlineCallback, 31.77775);
1627 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1628 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
1631 void JaguarDone(void)
1633 #ifdef CPU_DEBUG_MEMORY
1634 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1636 for(uint32 i=0; i<=raPtr; i++)
1638 WriteLog("\t%08X\n", returnAddr[i]);
1639 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1640 jaguar_dasm(returnAddr[i] - 16, 16);
1645 /* int start = 0, end = 0;
1646 bool endTriggered = false, startTriggered = false;
1647 for(int i=0; i<0x400000; i++)
1649 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1651 if (!startTriggered)
1652 startTriggered = true, endTriggered = false, start = i;
1654 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1660 end = i - 1, endTriggered = true, startTriggered = false;
1661 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1668 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1669 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1670 int32 topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1671 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
1672 for(int i=-2; i<9; i++)
1673 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1675 /* WriteLog("\nM68000 disassembly at $802288...\n");
1676 jaguar_dasm(0x802288, 3);
1677 WriteLog("\nM68000 disassembly at $802200...\n");
1678 jaguar_dasm(0x802200, 500);
1679 WriteLog("\nM68000 disassembly at $802518...\n");
1680 jaguar_dasm(0x802518, 100);//*/
1682 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1683 jaguar_dasm(0x803F00, 500);
1686 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1687 jaguar_dasm(0x802B00, 500);
1690 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1691 jaguar_dasm(0x809900, 500);
1694 /* WriteLog("\n\nDump of $8093C8:\n\n");
1695 for(int i=0x8093C8; i<0x809900; i+=4)
1696 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1697 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1698 jaguar_dasm(0x90006C, 500);
1700 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1701 jaguar_dasm(0x1AC000, 6000);
1704 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1705 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1706 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VBLANK))
1707 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1708 M68K_show_context();
1711 #if 0 // This is drawn already...
1712 WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
1713 for(uint32 i=0x64; i<=0x7C; i+=4)
1714 WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
1723 // temp, until debugger is in place
1724 //00802016: jsr $836F1A.l
1725 //0080201C: jsr $836B30.l
1726 //00802022: jsr $836B18.l
1727 //00802028: jsr $8135F0.l
1728 //00813C1E: jsr $813F76.l
1729 //00802038: jsr $836D00.l
1730 //00802098: jsr $8373A4.l
1731 //008020A2: jsr $83E24A.l
1732 //008020BA: jsr $83E156.l
1733 //008020C6: jsr $83E19C.l
1734 //008020E6: jsr $8445E8.l
1735 //008020EC: jsr $838C20.l
1736 //0080211A: jsr $838ED6.l
1737 //00802124: jsr $89CA56.l
1738 //0080212A: jsr $802B48.l
1740 WriteLog("-------------------------------------------\n");
1741 JaguarDasm(0x8445E8, 0x200);
1742 WriteLog("-------------------------------------------\n");
1743 JaguarDasm(0x838C20, 0x200);
1744 WriteLog("-------------------------------------------\n");
1745 JaguarDasm(0x838ED6, 0x200);
1746 WriteLog("-------------------------------------------\n");
1747 JaguarDasm(0x89CA56, 0x200);
1748 WriteLog("-------------------------------------------\n");
1749 JaguarDasm(0x802B48, 0x200);
1754 // Main Jaguar execution loop (1 frame)
1756 void JaguarExecute(uint32 * backbuffer, bool render)
1758 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1759 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1760 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
1761 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
1763 // uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
1764 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
1765 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1766 //It seems that they mean it when they say that VDE is the end of object processing.
1767 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
1768 //buffer and not to write any more pixels... !!! FIX !!!
1769 // uint16 vde = TOMReadWord(0xF00048, JAGUAR);
1771 uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
1772 uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
1773 //Not sure the above is correct, since the number of lines and timings given in the JTRM
1774 //seem to indicate the refresh rate is *half* the above...
1775 // uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
1776 // Should these be hardwired or read from VP? Yes, from VP!
1777 uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1778 uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
1780 TOMResetBackbuffer(backbuffer);
1781 /*extern int effect_start;
1783 WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
1785 //extern int start_logging;
1786 for(uint16 i=0; i<vp; i++)
1788 // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
1789 TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
1791 TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
1793 // if (i == vi) // Time for Vertical Interrupt?
1794 //Not sure if this is correct...
1795 //Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
1796 //Which means that it normally wouldn't go when it's zero.
1797 if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1799 // We don't have to worry about autovectors & whatnot because the Jaguar
1800 // tells you through its HW registers who sent the interrupt...
1801 TOMSetPendingVideoInt();
1805 //if (start_logging)
1806 // WriteLog("About to execute M68K (%u)...\n", i);
1807 m68k_execute(M68KCyclesPerScanline);
1808 //if (start_logging)
1809 // WriteLog("About to execute TOM's PIT (%u)...\n", i);
1810 TOMExecPIT(RISCCyclesPerScanline);
1811 //if (start_logging)
1812 // WriteLog("About to execute JERRY's PIT (%u)...\n", i);
1813 JERRYExecPIT(RISCCyclesPerScanline);
1814 //if (start_logging)
1815 // WriteLog("About to execute JERRY's SSI (%u)...\n", i);
1816 JERRYI2SExec(RISCCyclesPerScanline);
1817 BUTCHExec(RISCCyclesPerScanline);
1818 //if (start_logging)
1819 // WriteLog("About to execute GPU (%u)...\n", i);
1820 GPUExec(RISCCyclesPerScanline);
1824 if (vjs.usePipelinedDSP)
1825 DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
1827 DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
1828 // DSPExecComp(RISCCyclesPerScanline); // Comparison core
1831 //if (start_logging)
1832 // WriteLog("About to execute OP (%u)...\n", i);
1833 TOMExecScanline(i, render);
1837 // Temp debugging stuff
1839 void DumpMainMemory(void)
1841 FILE * fp = fopen("./memdump.bin", "wb");
1846 fwrite(jaguarMainRAM, 1, 0x400000, fp);
1850 uint8 * GetRamPtr(void)
1852 return jaguarMainRAM;
1856 // New Jaguar execution stack
1861 void JaguarExecuteNew(void)
1863 extern bool finished, showGUI;
1864 extern bool debounceRunKey;
1865 // Pass a message to the "joystick" code to debounce the ESC key...
1866 debounceRunKey = true;
1868 /* InitializeEventList();
1869 TOMResetBackbuffer(backbuffer);
1870 // SetCallbackTime(ScanlineCallback, 63.5555);
1871 SetCallbackTime(ScanlineCallback, 31.77775);
1872 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1873 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1874 // uint8 * keystate = SDL_GetKeyState(NULL);
1878 double timeToNextEvent = GetTimeToNextEvent();
1879 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1881 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1882 gpu_exec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1886 if (vjs.usePipelinedDSP)
1887 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1889 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1894 // if (keystate[SDLK_ESCAPE])
1897 // SDL_PumpEvents(); // Needed to keep the keystate current...
1902 void ScanlineCallback(void)
1904 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
1905 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1906 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1907 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
1913 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
1914 TOMWriteWord(0xF00006, vc, JAGUAR);
1916 //This is a crappy kludge, but maybe it'll work for now...
1917 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
1918 if (vc == vi && vc > 0 && tom_irq_enabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
1920 // We don't have to worry about autovectors & whatnot because the Jaguar
1921 // tells you through its HW registers who sent the interrupt...
1922 tom_set_pending_video_int();
1926 TOMExecScanline(vc, true);
1928 //Change this to VBB???
1929 //Doesn't seem to matter (at least for Flip Out & I-War)
1936 TOMResetBackbuffer(backbuffer);
1940 // TOMResetBackbuffer(backbuffer);
1942 // SetCallbackTime(ScanlineCallback, 63.5555);
1943 SetCallbackTime(ScanlineCallback, 31.77775);
1949 void JaguarExecuteNew(void)
1951 // extern bool finished, showGUI;
1952 // extern bool debounceRunKey;
1953 // Pass a message to the "joystick" code to debounce the ESC key...
1954 // debounceRunKey = true;
1955 // finished = false;
1956 /* InitializeEventList();
1957 TOMResetBackbuffer(backbuffer);
1958 // SetCallbackTime(ScanlineCallback, 63.5555);
1959 SetCallbackTime(ScanlineCallback, 31.77775);
1960 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
1961 // SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time//*/
1962 // uint8 * keystate = SDL_GetKeyState(NULL);
1967 double timeToNextEvent = GetTimeToNextEvent();
1968 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
1970 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
1971 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
1975 if (vjs.usePipelinedDSP)
1976 DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
1978 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
1983 // if (keystate[SDLK_ESCAPE])
1986 // SDL_PumpEvents(); // Needed to keep the keystate current...
1991 void ScanlineCallback(void)
1993 uint16 vc = TOMReadWord(0xF00006, JAGUAR);
1994 uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
1995 uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
1996 // uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
2002 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2003 TOMWriteWord(0xF00006, vc, JAGUAR);
2005 //This is a crappy kludge, but maybe it'll work for now...
2006 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2007 if (vc == vi && vc > 0 && TOMIRQEnabled(IRQ_VBLANK)) // Time for Vertical Interrupt?
2009 // We don't have to worry about autovectors & whatnot because the Jaguar
2010 // tells you through its HW registers who sent the interrupt...
2011 TOMSetPendingVideoInt();
2015 TOMExecScanline(vc, true);
2017 //Change this to VBB???
2018 //Doesn't seem to matter (at least for Flip Out & I-War)
2023 //We comment this out so that the GUI can manage this instead. Which is how it should be anyway.
2024 // RenderBackbuffer();
2025 TOMResetBackbuffer(backbuffer);
2030 // TOMResetBackbuffer(backbuffer);
2032 // SetCallbackTime(ScanlineCallback, 63.5555);
2033 SetCallbackTime(ScanlineCallback, 31.77775);
2038 // This isn't currently used, but maybe it should be...
2039 void RenderCallback(void)
2041 // RenderBackbuffer();
2042 TOMResetBackbuffer(backbuffer);
2043 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2044 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time