4 // Originally by David Raingeard (Cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
6 // Cleanups and endian wrongness amelioration by James Hammons
7 // Note: Endian wrongness probably stems from the MAME origins of this emu and
8 // the braindead way in which MAME handled memory when this was written. :-)
10 // JLH = James Hammons
13 // --- ---------- -----------------------------------------------------------
14 // JLH 11/25/2009 Major rewrite of memory subsystem and handlers
21 #include "SDL_opengl.h"
32 #include "m68000/m68kinterface.h"
39 //Do this in makefile??? Yes! Could, but it's easier to define here...
40 //#define LOG_UNMAPPED_MEMORY_ACCESSES
41 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
42 //#define ABORT_ON_ILLEGAL_INSTRUCTIONS
43 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
44 #define CPU_DEBUG_MEMORY
45 //#define LOG_CD_BIOS_CALLS
46 #define CPU_DEBUG_TRACING
48 // Private function prototypes
50 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
51 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
52 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
53 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
54 void M68K_show_context(void);
58 #ifdef CPU_DEBUG_MEMORY
59 extern bool startMemLog; // Set by "e" key
60 extern int effect_start;
61 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
64 // Really, need to include memory.h for this, but it might interfere with some stuff...
65 extern uint8_t jagMemSpace[];
69 uint32_t jaguar_active_memory_dumps = 0;
71 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
72 bool jaguarCartInserted = false;
73 bool lowerField = false;
75 #ifdef CPU_DEBUG_MEMORY
76 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
77 uint8_t readMem[0x400000];
78 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
81 uint32_t pcQueue[0x400];
82 uint32_t a2Queue[0x400];
83 uint32_t d0Queue[0x400];
85 bool startM68KTracing = false;
88 // Callback function to detect illegal instructions
90 void GPUDumpDisassembly(void);
91 void GPUDumpRegisters(void);
92 static bool start = false;
94 void M68KInstructionHook(void)
96 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
97 // Temp, for comparing...
99 /* static char buffer[2048];//, mem[64];
100 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
101 printf("%08X: %s\n", m68kPC, buffer);//*/
103 //JaguarDasm(m68kPC, 1);
104 //Testing Hover Strike...
107 static int hitCount = 0;
108 static int inRoutine = 0;
111 //if (regs.pc == 0x80340A)
112 if (m68kPC == 0x803416)
117 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
119 else if (m68kPC == 0x803422)
122 printf("(%i instructions)\n", instSeen);
129 // For code tracing...
130 #ifdef CPU_DEBUG_TRACING
131 if (startM68KTracing)
133 static char buffer[2048];
135 m68k_disassemble(buffer, m68kPC, 0);
136 WriteLog("%06X: %s\n", m68kPC, buffer);
141 // Ideally, we'd save all the registers as well...
142 pcQueue[pcQPtr] = m68kPC;
143 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
144 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
148 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
150 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
152 static char buffer[2048];
153 for(int i=0; i<0x400; i++)
155 WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
156 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
157 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
161 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
162 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
163 for(int i=0; i<10; i++)
164 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
165 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
171 // Disassemble everything
173 static char buffer[2048];
174 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
175 WriteLog("%08X: %s", m68kPC, buffer);
176 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
177 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
178 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
180 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
182 static char buffer[2048];
183 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
184 WriteLog("%08X: %s", m68kPC, buffer);
185 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
186 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
187 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
189 /* if (m68kPC == 0x8D0E48 && effect_start5)
191 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
193 GPUDumpDisassembly();
197 /* uint16_t opcode = JaguarReadWord(m68kPC);
198 if (opcode == 0x4E75) // RTS
201 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
203 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
205 if (raPtr != 0xFFFFFFFF)
207 for(uint32_t i=0; i<=raPtr; i++)
209 if (returnAddr[i] == addr)
218 returnAddr[++raPtr] = addr;
222 //Flip Out! debugging...
225 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
226 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
227 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
228 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
230 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
232 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
233 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
234 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
235 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
236 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
237 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
238 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
240 /* static char buffer[2048];
241 //if (m68kPC > 0x805F48) start = true;
242 //if (m68kPC > 0x806486) start = true;
243 //if (m68kPC == 0x805FEE) start = true;
244 //if (m68kPC == 0x80600C)// start = true;
245 if (m68kPC == 0x802058) start = true;
247 // GPUDumpRegisters();
248 // GPUDumpDisassembly();
250 // M68K_show_context();
256 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
257 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));
260 /* if (m68kPC == 0x803F16)
262 WriteLog("M68K: Registers found at $803F16:\n");
263 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
264 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
265 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
267 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
268 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
270 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
271 // !!! Investigate !!!
272 /*extern bool doDSPDis;
273 static bool disgo = false;
274 if (m68kPC == 0x50222)
277 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
278 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
281 if (m68kPC == 0x5000)
286 static char buffer[2048];
287 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
288 WriteLog("%08X: %s", m68kPC, buffer);
289 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
290 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
291 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
293 /* if (m68kPC == 0x82E1A)
295 static char buffer[2048];
296 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
297 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
298 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
299 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
300 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
302 /* if (m68kPC == 0x82E58)
303 WriteLog("--> [Routine end]\n");
304 if (m68kPC == 0x80004)
306 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
307 // m68k_set_reg(M68K_REG_D2, 0x12345678);
310 #ifdef LOG_CD_BIOS_CALLS
333 if (m68kPC == 0x3000)
334 WriteLog("M68K: CD_init\n");
335 else if (m68kPC == 0x3006 + (6 * 0))
336 WriteLog("M68K: CD_mode\n");
337 else if (m68kPC == 0x3006 + (6 * 1))
338 WriteLog("M68K: CD_ack\n");
339 else if (m68kPC == 0x3006 + (6 * 2))
340 WriteLog("M68K: CD_jeri\n");
341 else if (m68kPC == 0x3006 + (6 * 3))
342 WriteLog("M68K: CD_spin\n");
343 else if (m68kPC == 0x3006 + (6 * 4))
344 WriteLog("M68K: CD_stop\n");
345 else if (m68kPC == 0x3006 + (6 * 5))
346 WriteLog("M68K: CD_mute\n");
347 else if (m68kPC == 0x3006 + (6 * 6))
348 WriteLog("M68K: CD_umute\n");
349 else if (m68kPC == 0x3006 + (6 * 7))
350 WriteLog("M68K: CD_paus\n");
351 else if (m68kPC == 0x3006 + (6 * 8))
352 WriteLog("M68K: CD_upaus\n");
353 else if (m68kPC == 0x3006 + (6 * 9))
354 WriteLog("M68K: CD_read\n");
355 else if (m68kPC == 0x3006 + (6 * 10))
356 WriteLog("M68K: CD_uread\n");
357 else if (m68kPC == 0x3006 + (6 * 11))
358 WriteLog("M68K: CD_setup\n");
359 else if (m68kPC == 0x3006 + (6 * 12))
360 WriteLog("M68K: CD_ptr\n");
361 else if (m68kPC == 0x3006 + (6 * 13))
362 WriteLog("M68K: CD_osamp\n");
363 else if (m68kPC == 0x3006 + (6 * 14))
364 WriteLog("M68K: CD_getoc\n");
365 else if (m68kPC == 0x3006 + (6 * 15))
366 WriteLog("M68K: CD_initm\n");
367 else if (m68kPC == 0x3006 + (6 * 16))
368 WriteLog("M68K: CD_initf\n");
369 else if (m68kPC == 0x3006 + (6 * 17))
370 WriteLog("M68K: CD_switch\n");
372 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
373 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
374 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
375 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
378 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
379 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
381 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
382 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
384 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
385 // keep going even when the 68K dumped back to the debugger or what have you).
387 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
388 // Try setting the vector to the illegal instruction...
389 //This doesn't work right either! Do something else! Quick!
390 // SET32(jaguar_mainRam, 0x10, m68kPC);
396 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
397 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
398 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
399 uint32_t address = topOfStack - (4 * 4 * 3);
401 for(int i=0; i<10; i++)
403 WriteLog("%06X:", address);
405 for(int j=0; j<4; j++)
407 WriteLog(" %08X", JaguarReadLong(address));
414 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
418 // WriteLog("\n\n68K disasm\n\n");
419 // jaguar_dasm(0x802000, 0x50C);
430 Now here be dragons...
431 Here is how memory ranges are defined in the CoJag driver.
432 Note that we only have to be concerned with 3 entities read/writing anything:
433 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
434 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
435 things that are entirely internal to those modules. This way we should be able to get a handle on all
436 this crap which is currently scattered over Hell's Half Acre(tm).
438 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
439 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
441 /*************************************
443 * Main CPU memory handlers
445 *************************************/
447 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
448 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
449 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
450 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
451 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
452 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
453 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
454 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
455 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
456 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
457 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
458 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
459 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
460 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
461 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
462 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
463 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
464 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
465 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
466 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
467 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
468 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
469 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
472 /*************************************
474 * GPU memory handlers
476 *************************************/
478 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
479 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
480 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
481 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
482 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
483 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
484 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
485 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
486 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
487 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
488 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
491 /*************************************
493 * DSP memory handlers
495 *************************************/
497 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
498 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
499 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
500 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
501 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
502 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
503 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
504 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
505 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
510 //#define EXPERIMENTAL_MEMORY_HANDLING
511 // Experimental memory mappage...
512 // Dunno if this is a good approach or not, but it seems to make better
513 // sense to have all this crap in one spot intstead of scattered all over
514 // the place the way it is now.
515 #ifdef EXPERIMENTAL_MEMORY_HANDLING
517 #define NEW_TIMER_SYSTEM
520 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
521 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
522 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
523 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
524 bool BIOSLoaded = false;
525 bool CDBIOSLoaded = false;
527 uint8_t cdRAM[0x100];
528 uint8_t tomRAM[0x4000];
529 uint8_t jerryRAM[0x10000];
530 static uint16_t eeprom_ram[64];
532 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
535 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
537 // M68K Memory map/handlers
539 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
540 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
541 // Note that this is really memory mapped I/O region...
542 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
543 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
544 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
545 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
546 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
547 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
548 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
549 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
550 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
551 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
552 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
553 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
555 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
557 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
558 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
559 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
560 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
561 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
562 //What about LBUF writes???
563 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
564 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
565 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
567 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
571 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
572 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
573 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
576 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
577 0 = pad0/1 button values (4 bits each), RO(?)
578 1 = pad0/1 index value (4 bits each), WO
580 3 = NTSC/PAL, certain button states, RO
582 JOYSTICK $F14000 Read/Write
584 Read fedcba98 7654321q f-1 Signals J15 to J1
585 q Cartridge EEPROM output data
586 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
587 0 = disable J7-J0 outputs
590 0 = Audio muted (reset state)
592 7-4 J7-J4 outputs (port 2)
593 3-0 J3-J0 outputs (port 1)
594 JOYBUTS $F14002 Read Only
596 Read xxxxxxxx rrdv3210 x don't care
599 v 1 = NTSC Video hardware
600 0 = PAL Video hardware
601 3-2 Button inputs B3 & B2 (port 2)
602 1-0 Button inputs B1 & B0 (port 1)
604 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
605 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
613 0 1 1 1 Row 3 C3 Option # 9 6 3
617 1 0 1 1 Row 2 C2 C 0 8 5 2
619 1 1 0 1 Row 1 C1 B * 7 4 1
620 1 1 1 0 Row 0 Pause A Up Down Left Right
623 0 bit read in any position means that button is pressed.
624 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
628 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
630 // Not sure, but I think the system only has 24 address bits...
631 address &= 0x00FFFFFF;
633 // RAM ($000000 - $3FFFFF) 4M
634 if (address <= 0x3FFFFF)
635 jaguarMainRAM[address] = byte;
636 // hole ($400000 - $7FFFFF) 4M
637 else if (address <= 0x7FFFFF)
639 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
640 else if (address <= 0xDFFEFF)
642 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
643 else if (address <= 0xDFFFFF)
645 cdRAM[address & 0xFF] = byte;
647 if ((address & 0xFF) < 12 * 4)
648 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
649 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
652 // BIOS ROM ($E00000 - $E3FFFF) 256K
653 else if (address <= 0xE3FFFF)
655 // hole ($E40000 - $EFFFFF) 768K
656 else if (address <= 0xEFFFFF)
658 // TOM ($F00000 - $F0FFFF) 64K
659 else if (address <= 0xF0FFFF)
662 if (address == 0xF00050)
664 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
668 else if (address == 0xF00051)
670 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
674 else if (address == 0xF00052)
676 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
680 else if (address == 0xF00053)
682 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
686 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
688 // Writing to one CLUT writes to the other
689 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
690 tomRAM[address] = tomRAM[address + 0x200] = byte;
693 //What about LBUF writes???
694 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
696 GPUWriteByte(address, byte, who);
699 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
701 BlitterWriteByte(address, byte, who);
704 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
706 GPUWriteByte(address, byte, who);
710 tomRAM[address & 0x3FFF] = byte;
712 // JERRY ($F10000 - $F1FFFF) 64K
713 else if (address <= 0xF1FFFF)
717 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
719 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
721 DSPWriteByte(address, byte, who);
724 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
726 DSPWriteByte(address, byte, who);
729 // SCLK ($F1A150--8 bits wide)
730 //NOTE: This should be taken care of in DAC...
731 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
733 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
734 if ((address & 0x03) == 2)
735 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
737 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
739 JERRYI2SInterruptTimer = -1;
740 #ifndef NEW_TIMER_SYSTEM
743 RemoveCallback(JERRYI2SCallback);
748 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
749 else if (address >= 0xF1A148 && address <= 0xF1A157)
751 DACWriteByte(address, byte, who);
754 else if (address >= 0xF10000 && address <= 0xF10007)
756 #ifndef NEW_TIMER_SYSTEM
757 switch (address & 0x07)
760 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
764 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
768 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
772 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
776 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
780 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
784 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
788 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
792 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
796 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
798 clock_byte_write(offset, byte);
801 // JERRY -> 68K interrupt enables/latches (need to be handled!)
802 else if (address >= 0xF10020 && address <= 0xF10023)
804 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
806 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
808 anajoy_byte_write(offset, byte);
811 else if ((address >= 0xF14000) && (address <= 0xF14003))
813 JoystickWriteByte(address, byte);
814 EepromWriteByte(address, byte);
817 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
819 EepromWriteByte(address, byte);
822 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
823 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
826 jerryRAM[address & 0xFFFF] = byte;
828 // hole ($F20000 - $FFFFFF) 1M - 128K
833 void WriteWord(uint32_t adddress, uint16_t word)
837 void WriteDWord(uint32_t adddress, uint32_t dword)
841 uint8_t ReadByte(uint32_t adddress)
845 uint16_t ReadWord(uint32_t adddress)
849 uint32_t ReadDWord(uint32_t adddress)
854 void ShowM68KContext(void)
856 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
858 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
860 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
862 if (i == M68K_REG_D3 || i == M68K_REG_D7)
866 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
868 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
870 if (i == M68K_REG_A3 || i == M68K_REG_A7)
874 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
875 uint32_t disPC = currpc - 30;
880 uint32_t oldpc = disPC;
881 disPC += m68k_disassemble(buffer, disPC, 0);
882 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
884 while (disPC < (currpc + 10));
888 // Custom UAE 68000 read/write/IRQ functions
895 IPL Name Vector Control
896 ---------+---------------+---------------+---------------
897 2 VBLANK IRQ $100 INT1 bit #0
898 2 GPU IRQ $100 INT1 bit #1
899 2 HBLANK IRQ $100 INT1 bit #2
900 2 Timer IRQ $100 INT1 bit #3
902 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
903 and are therefore indistinguishable.
905 A typical way to install a LEVEL2 handler for the 68000 would be
906 something like this, you gotta supply "last_line" and "handler".
907 Note that the interrupt is auto vectored thru $100 (not $68)
915 IRQS_HANDLED=$909 ;; VBLANK and TIMER
917 move.w #$2700,sr ;; no IRQs please
918 move.l #handler,V_AUTO ;; install our routine
920 move.w #last_line,VI ;; scanline where IRQ should occur
921 ;; should be 'odd' BTW
922 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
923 move.w #$2100,sr ;; enable IRQs on the 68K
941 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
942 move.w #0,INT2 ; let GPU run again
946 As you can see, if you have multiple INT1 interrupts coming in,
947 you need to check the lower byte of INT1, to see which interrupt
950 int irq_ack_handler(int level)
952 #ifdef CPU_DEBUG_TRACING
953 if (startM68KTracing)
955 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
959 // Tracing the IPL lines on the Jaguar schematic yields the following:
960 // IPL1 is connected to INTL on TOM (OUT to 68K)
961 // IPL0-2 are also tied to Vcc via 4.7K resistors!
962 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
963 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
964 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
966 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
967 // They aren't, and this causes problems with a, err, specific ROM. :-D
971 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
972 return 64; // Set user interrupt #0
975 return M68K_INT_ACK_AUTOVECTOR;
978 //#define USE_NEW_MMU
980 unsigned int m68k_read_memory_8(unsigned int address)
982 // Musashi does this automagically for you, UAE core does not :-P
983 address &= 0x00FFFFFF;
984 #ifdef CPU_DEBUG_MEMORY
985 // Note that the Jaguar only has 2M of RAM, not 4!
986 if ((address >= 0x000000) && (address <= 0x1FFFFF))
989 readMem[address] = 1;
992 //WriteLog("[RM8] Addr: %08X\n", address);
993 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
994 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
995 || address == 0x1AF05E)
996 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
998 unsigned int retVal = 0;
1000 // Note that the Jaguar only has 2M of RAM, not 4!
1001 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1002 retVal = jaguarMainRAM[address];
1003 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1004 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1005 retVal = jaguarMainROM[address - 0x800000];
1006 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1007 // retVal = jaguarBootROM[address - 0xE00000];
1008 // retVal = jaguarDevBootROM1[address - 0xE00000];
1009 retVal = jagMemSpace[address];
1010 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1011 retVal = CDROMReadByte(address);
1012 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1013 retVal = TOMReadByte(address, M68K);
1014 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1015 retVal = JERRYReadByte(address, M68K);
1017 retVal = jaguar_unknown_readbyte(address, M68K);
1019 //if (address >= 0x2800 && address <= 0x281F)
1020 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1021 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1022 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1025 return MMURead8(address, M68K);
1029 void gpu_dump_disassembly(void);
1030 void gpu_dump_registers(void);
1032 unsigned int m68k_read_memory_16(unsigned int address)
1034 // Musashi does this automagically for you, UAE core does not :-P
1035 address &= 0x00FFFFFF;
1036 #ifdef CPU_DEBUG_MEMORY
1037 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1040 readMem[address] = 1, readMem[address + 1] = 1;
1042 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1044 return 0x4E71; // NOP
1046 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1048 return 0x4E71; // NOP
1050 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1052 return 0x4E71; // NOP
1054 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1056 return 0x4E71; // NOP
1058 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1060 return 0x4E71; // NOP
1062 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1064 return 0x4E71; // NOP
1067 //WriteLog("[RM16] Addr: %08X\n", address);
1068 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1069 // for(int i=0; i<10000; i++)
1070 WriteLog("[M68K] In routine #6!\n");//*/
1071 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1072 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1073 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1075 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1076 gpu_dump_registers();
1077 gpu_dump_disassembly();
1078 // for(int i=0; i<10000; i++)
1079 // WriteLog("[M68K] About to run GPU!\n");
1081 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1082 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1084 if (address == 0x000066A0)
1086 gpu_dump_registers();
1087 gpu_dump_disassembly();
1089 for(int i=0; i<10000; i++)
1090 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1092 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1093 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1094 || address == 0x1AF05E)
1095 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1097 unsigned int retVal = 0;
1099 // Note that the Jaguar only has 2M of RAM, not 4!
1100 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1101 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1102 retVal = GET16(jaguarMainRAM, address);
1103 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1104 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1105 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1106 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1107 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1108 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1109 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1110 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1111 retVal = CDROMReadWord(address, M68K);
1112 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1113 retVal = TOMReadWord(address, M68K);
1114 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1115 retVal = JERRYReadWord(address, M68K);
1117 retVal = jaguar_unknown_readword(address, M68K);
1119 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1120 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1121 //if (address >= 0x2800 && address <= 0x281F)
1122 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1123 //$8B3AE -> Transferred from $F1C010
1124 //$8B5E4 -> Only +1 read at $808AA
1125 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1126 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1129 return MMURead16(address, M68K);
1133 unsigned int m68k_read_memory_32(unsigned int address)
1135 // Musashi does this automagically for you, UAE core does not :-P
1136 address &= 0x00FFFFFF;
1137 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1138 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1139 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));//*/
1141 //WriteLog("--> [RM32]\n");
1143 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1145 return MMURead32(address, M68K);
1149 void m68k_write_memory_8(unsigned int address, unsigned int value)
1151 // Musashi does this automagically for you, UAE core does not :-P
1152 address &= 0x00FFFFFF;
1153 #ifdef CPU_DEBUG_MEMORY
1154 // Note that the Jaguar only has 2M of RAM, not 4!
1155 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1159 if (value > writeMemMax[address])
1160 writeMemMax[address] = value;
1161 if (value < writeMemMin[address])
1162 writeMemMin[address] = value;
1166 /*if (address == 0x4E00)
1167 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1168 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1169 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1170 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1172 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1173 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1175 /*if (address >= 0x53D0 && address <= 0x53FF)
1176 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1177 //Testing AvP on UAE core...
1178 //000075A0: FFFFF80E B6320220 (BITMAP)
1179 /*if (address == 0x75A0 && value == 0xFF)
1180 printf("M68K: (8) Tripwire hit...\n");//*/
1183 // Note that the Jaguar only has 2M of RAM, not 4!
1184 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1185 jaguarMainRAM[address] = value;
1186 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1187 CDROMWriteByte(address, value, M68K);
1188 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1189 TOMWriteByte(address, value, M68K);
1190 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1191 JERRYWriteByte(address, value, M68K);
1193 jaguar_unknown_writebyte(address, value, M68K);
1195 MMUWrite8(address, value, M68K);
1199 void m68k_write_memory_16(unsigned int address, unsigned int value)
1201 // Musashi does this automagically for you, UAE core does not :-P
1202 address &= 0x00FFFFFF;
1203 #ifdef CPU_DEBUG_MEMORY
1204 // Note that the Jaguar only has 2M of RAM, not 4!
1205 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1209 uint8_t hi = value >> 8, lo = value & 0xFF;
1211 if (hi > writeMemMax[address])
1212 writeMemMax[address] = hi;
1213 if (hi < writeMemMin[address])
1214 writeMemMin[address] = hi;
1216 if (lo > writeMemMax[address+1])
1217 writeMemMax[address+1] = lo;
1218 if (lo < writeMemMin[address+1])
1219 writeMemMin[address+1] = lo;
1223 /*if (address == 0x4E00)
1224 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1225 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1226 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1227 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1228 //if (address >= 0xF02200 && address <= 0xF0229F)
1229 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1230 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1231 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1232 /*extern uint32_t totalFrames;
1233 if (address == 0xF02114)
1234 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1235 if (address == 0xF02110)
1236 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1237 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1238 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1240 /*if (address == 0x0100)//64*4)
1241 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1243 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1244 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1245 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1246 || address == 0x1AF05E)
1247 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1249 /*if (address >= 0x53D0 && address <= 0x53FF)
1250 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1251 //Testing AvP on UAE core...
1252 //000075A0: FFFFF80E B6320220 (BITMAP)
1253 /*if (address == 0x75A0 && value == 0xFFFF)
1255 printf("\nM68K: (16) Tripwire hit...\n");
1260 // Note that the Jaguar only has 2M of RAM, not 4!
1261 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1263 /* jaguar_mainRam[address] = value >> 8;
1264 jaguar_mainRam[address + 1] = value & 0xFF;*/
1265 SET16(jaguarMainRAM, address, value);
1267 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1268 CDROMWriteWord(address, value, M68K);
1269 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1270 TOMWriteWord(address, value, M68K);
1271 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1272 JERRYWriteWord(address, value, M68K);
1275 jaguar_unknown_writeword(address, value, M68K);
1276 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1277 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1278 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1279 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1283 MMUWrite16(address, value, M68K);
1287 void m68k_write_memory_32(unsigned int address, unsigned int value)
1289 // Musashi does this automagically for you, UAE core does not :-P
1290 address &= 0x00FFFFFF;
1291 /*if (address == 0x4E00)
1292 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1293 //WriteLog("--> [WM32]\n");
1294 /*if (address == 0x0100)//64*4)
1295 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1296 /*if (address >= 0xF03214 && address < 0xF0321F)
1297 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1298 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1299 /*extern bool doGPUDis;
1300 if (address == 0xF03214 && value == 0x88E30047)
1302 doGPUDis = true;//*/
1303 /* if (address == 0x51136 || address == 0xFB074)
1304 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1305 //Testing AvP on UAE core...
1306 //000075A0: FFFFF80E B6320220 (BITMAP)
1307 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1309 printf("\nM68K: (32) Tripwire hit...\n");
1314 m68k_write_memory_16(address, value >> 16);
1315 m68k_write_memory_16(address + 2, value & 0xFFFF);
1317 MMUWrite32(address, value, M68K);
1322 uint32_t JaguarGetHandler(uint32_t i)
1324 return JaguarReadLong(i * 4);
1327 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1329 uint32_t handler = JaguarGetHandler(i);
1330 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1333 void M68K_show_context(void)
1335 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1337 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1339 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1341 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1345 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1347 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1349 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1353 WriteLog("68K disasm\n");
1354 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1355 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1356 // jaguar_dasm(0x5000, 0x14414);
1358 // WriteLog("\n.......[Cart start]...........\n\n");
1359 // jaguar_dasm(0x192000, 0x1000);//0x200);
1361 WriteLog("..................\n");
1363 if (TOMIRQEnabled(IRQ_VIDEO))
1365 WriteLog("video int: enabled\n");
1366 JaguarDasm(JaguarGetHandler(64), 0x200);
1369 WriteLog("video int: disabled\n");
1371 WriteLog("..................\n");
1373 for(int i=0; i<256; i++)
1375 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1376 uint32_t address = (uint32_t)JaguarGetHandler(i);
1379 WriteLog(".........\n");
1381 WriteLog("$%08X\n", address);
1386 // Unknown read/write byte/word routines
1389 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1390 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1392 // 807EC4: movea.l #$f1b000, A1
1393 // 807ECA: movea.l #$8129e0, A0
1394 // 807ED0: move.l A0, D0
1395 // 807ED2: move.l #$f1bb94, D1
1396 // 807ED8: sub.l D0, D1
1397 // 807EDA: lsr.l #2, D1
1398 // 807EDC: move.l (A0)+, (A1)+
1399 // 807EDE: dbra D1, 807edc
1401 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1402 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1403 // space! (That is, unless the 68K causes a bus error...)
1405 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1407 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1408 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));
1410 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1411 // extern bool finished;
1413 // extern bool doDSPDis;
1419 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1421 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1422 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));
1424 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1425 // extern bool finished;
1427 // extern bool doDSPDis;
1433 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1435 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1436 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1438 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1439 // extern bool finished;
1441 // extern bool doDSPDis;
1448 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1450 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1451 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1453 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1454 // extern bool finished;
1456 // extern bool doDSPDis;
1464 // Disassemble M68K instructions at the given offset
1467 unsigned int m68k_read_disassembler_8(unsigned int address)
1469 return m68k_read_memory_8(address);
1472 unsigned int m68k_read_disassembler_16(unsigned int address)
1474 return m68k_read_memory_16(address);
1477 unsigned int m68k_read_disassembler_32(unsigned int address)
1479 return m68k_read_memory_32(address);
1482 void JaguarDasm(uint32_t offset, uint32_t qt)
1485 static char buffer[2048];//, mem[64];
1486 int pc = offset, oldpc;
1488 for(uint32_t i=0; i<qt; i++)
1491 for(int j=0; j<64; j++)
1492 mem[j^0x01] = jaguar_byte_read(pc + j);
1494 pc += Dasm68000((char *)mem, buffer, 0);
1495 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1497 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1498 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1503 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1505 uint8_t data = 0x00;
1508 // First 2M is mirrored in the $0 - $7FFFFF range
1509 if (offset < 0x800000)
1510 data = jaguarMainRAM[offset & 0x1FFFFF];
1511 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1512 data = jaguarMainROM[offset - 0x800000];
1513 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1514 data = CDROMReadByte(offset, who);
1515 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1516 // data = jaguarBootROM[offset & 0x3FFFF];
1517 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1518 data = jagMemSpace[offset];
1519 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1520 data = TOMReadByte(offset, who);
1521 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1522 data = JERRYReadByte(offset, who);
1524 data = jaguar_unknown_readbyte(offset, who);
1529 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1533 // First 2M is mirrored in the $0 - $7FFFFF range
1534 if (offset < 0x800000)
1536 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1538 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1541 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1543 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1544 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1545 return CDROMReadWord(offset, who);
1546 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1547 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1548 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1549 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1550 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1551 return TOMReadWord(offset, who);
1552 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1553 return JERRYReadWord(offset, who);
1555 return jaguar_unknown_readword(offset, who);
1558 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1560 /* if (offset >= 0x4E00 && offset < 0x4E04)
1561 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1562 //Need to check for writes in the range of $18FA70 + 8000...
1564 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1565 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1569 // First 2M is mirrored in the $0 - $7FFFFF range
1570 if (offset < 0x800000)
1572 jaguarMainRAM[offset & 0x1FFFFF] = data;
1575 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1577 CDROMWriteByte(offset, data, who);
1580 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1582 TOMWriteByte(offset, data, who);
1585 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1587 JERRYWriteByte(offset, data, who);
1591 jaguar_unknown_writebyte(offset, data, who);
1595 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1597 /* if (offset >= 0x4E00 && offset < 0x4E04)
1598 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1599 /*if (offset == 0x0100)//64*4)
1600 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1601 if (offset == 0x0102)//64*4)
1602 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1603 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1604 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1605 //Need to check for writes in the range of $18FA70 + 8000...
1607 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1608 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1609 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1610 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1614 // First 2M is mirrored in the $0 - $7FFFFF range
1615 if (offset <= 0x7FFFFE)
1620 1A 69 F0 ($0000) -> Starfield
1621 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1624 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1633 //This MUST be done by the 68K!
1634 /*if (offset == 0x670C)
1635 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1637 /*extern bool doGPUDis;
1638 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1639 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1640 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1641 doGPUDis = true;//*/
1642 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1643 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1644 if ((data & 0xFF00) != 0x7700)
1645 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1646 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1648 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1649 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1650 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1652 /*extern bool doGPUDis;
1653 if (offset == 0x120216 && who == GPU)
1654 doGPUDis = true;//*/
1655 /*extern uint32_t gpu_pc;
1656 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1658 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1659 uint32_t y = base / 0x300;
1660 uint32_t x = (base - (y * 0x300)) / 2;
1661 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1664 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1666 //if (offset == (0x001E17F8 + 0x34))
1667 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1669 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1670 /*extern uint32_t gpu_pc;
1671 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1673 extern int objectPtr;
1674 // if (offset > 0x148000)
1677 if (starCount > objectPtr)
1680 // if (starCount == 1)
1681 // WriteLog("--> Drawing 1st star...\n");
1683 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1684 // uint32_t y = base / 0x300;
1685 // uint32_t x = (base - (y * 0x300)) / 2;
1686 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1688 //A star of interest...
1689 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1690 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1691 //JWW: Blitter writing echo 77B3 at 0011D022...
1693 //extern bool doGPUDis;
1694 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1697 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1700 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1701 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1703 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1704 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1707 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1709 CDROMWriteWord(offset, data, who);
1712 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1714 TOMWriteWord(offset, data, who);
1717 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1719 JERRYWriteWord(offset, data, who);
1722 // Don't bomb on attempts to write to ROM
1723 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1726 jaguar_unknown_writeword(offset, data, who);
1729 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1730 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1732 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1735 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1736 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1738 /* extern bool doDSPDis;
1739 if (offset < 0x400 && !doDSPDis)
1741 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1744 /*if (offset == 0x0100)//64*4)
1745 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1747 JaguarWriteWord(offset, data >> 16, who);
1748 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1751 void JaguarSetScreenBuffer(uint32_t * buffer)
1753 // This is in TOM, but we set it here...
1754 screenBuffer = buffer;
1757 void JaguarSetScreenPitch(uint32_t pitch)
1759 // This is in TOM, but we set it here...
1760 screenPitch = pitch;
1764 // Jaguar console initialization
1766 void JaguarInit(void)
1768 // For randomizing RAM
1771 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1772 for(uint32_t i=0; i<0x200000; i+=4)
1773 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1775 #ifdef CPU_DEBUG_MEMORY
1776 memset(readMem, 0x00, 0x400000);
1777 memset(writeMemMin, 0xFF, 0x400000);
1778 memset(writeMemMax, 0x00, 0x400000);
1780 // memset(jaguarMainRAM, 0x00, 0x200000);
1781 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1782 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1783 //NOTE: This *doesn't* fix FlipOut...
1784 //Or does it? Hmm...
1785 //Seems to want $01010101... Dunno why. Investigate!
1786 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1787 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1788 lowerField = false; // Reset the lower field flag
1789 //temp, for crappy crap that sux
1790 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1792 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1801 //New timer based code stuffola...
1802 void HalflineCallback(void);
1803 void RenderCallback(void);
1804 void JaguarReset(void)
1806 // Only problem with this approach: It wipes out RAM loaded files...!
1807 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1808 for(uint32_t i=8; i<0x200000; i+=4)
1809 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1811 // New timer base code stuffola...
1812 InitializeEventList();
1813 //Need to change this so it uses the single RAM space and load the BIOS
1814 //into it somewhere...
1815 //Also, have to change this here and in JaguarReadXX() currently
1816 // Only use the system BIOS if it's available...! (it's always available now!)
1817 // AND only if a jaguar cartridge has been inserted.
1818 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1819 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1821 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1823 // WriteLog("jaguar_reset():\n");
1829 m68k_pulse_reset(); // Reset the 68000
1830 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1832 lowerField = false; // Reset the lower field flag
1833 // SetCallbackTime(ScanlineCallback, 63.5555);
1834 // SetCallbackTime(ScanlineCallback, 31.77775);
1835 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1839 void JaguarDone(void)
1841 #ifdef CPU_DEBUG_MEMORY
1842 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1844 for(uint32_t i=0; i<=raPtr; i++)
1846 WriteLog("\t%08X\n", returnAddr[i]);
1847 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1848 jaguar_dasm(returnAddr[i] - 16, 16);
1853 /* int start = 0, end = 0;
1854 bool endTriggered = false, startTriggered = false;
1855 for(int i=0; i<0x400000; i++)
1857 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1859 if (!startTriggered)
1860 startTriggered = true, endTriggered = false, start = i;
1862 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1868 end = i - 1, endTriggered = true, startTriggered = false;
1869 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1876 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1877 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1878 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1879 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
1881 for(int i=-2; i<9; i++)
1882 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1884 uint32_t address = topOfStack - (4 * 4 * 3);
1886 for(int i=0; i<10; i++)
1888 WriteLog("%06X:", address);
1890 for(int j=0; j<4; j++)
1892 WriteLog(" %08X", JaguarReadLong(address));
1900 /* WriteLog("\nM68000 disassembly at $802288...\n");
1901 jaguar_dasm(0x802288, 3);
1902 WriteLog("\nM68000 disassembly at $802200...\n");
1903 jaguar_dasm(0x802200, 500);
1904 WriteLog("\nM68000 disassembly at $802518...\n");
1905 jaguar_dasm(0x802518, 100);//*/
1907 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1908 jaguar_dasm(0x803F00, 500);
1911 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1912 jaguar_dasm(0x802B00, 500);
1915 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1916 jaguar_dasm(0x809900, 500);
1919 /* WriteLog("\n\nDump of $8093C8:\n\n");
1920 for(int i=0x8093C8; i<0x809900; i+=4)
1921 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1922 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1923 jaguar_dasm(0x90006C, 500);
1925 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1926 jaguar_dasm(0x1AC000, 6000);
1929 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1930 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1931 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
1932 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1933 M68K_show_context();
1942 // temp, until debugger is in place
1943 //00802016: jsr $836F1A.l
1944 //0080201C: jsr $836B30.l
1945 //00802022: jsr $836B18.l
1946 //00802028: jsr $8135F0.l
1947 //00813C1E: jsr $813F76.l
1948 //00802038: jsr $836D00.l
1949 //00802098: jsr $8373A4.l
1950 //008020A2: jsr $83E24A.l
1951 //008020BA: jsr $83E156.l
1952 //008020C6: jsr $83E19C.l
1953 //008020E6: jsr $8445E8.l
1954 //008020EC: jsr $838C20.l
1955 //0080211A: jsr $838ED6.l
1956 //00802124: jsr $89CA56.l
1957 //0080212A: jsr $802B48.l
1959 WriteLog("-------------------------------------------\n");
1960 JaguarDasm(0x8445E8, 0x200);
1961 WriteLog("-------------------------------------------\n");
1962 JaguarDasm(0x838C20, 0x200);
1963 WriteLog("-------------------------------------------\n");
1964 JaguarDasm(0x838ED6, 0x200);
1965 WriteLog("-------------------------------------------\n");
1966 JaguarDasm(0x89CA56, 0x200);
1967 WriteLog("-------------------------------------------\n");
1968 JaguarDasm(0x802B48, 0x200);
1969 WriteLog("\n\nM68000 disassembly at $802000...\n");
1970 JaguarDasm(0x802000, 6000);
1973 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
1974 JaguarDasm(0x6004, 10000);
1976 // WriteLog("\n\nM68000 disassembly at $802000...\n");
1977 // JaguarDasm(0x802000, 0x1000);
1978 // WriteLog("\n\nM68000 disassembly at $4100...\n");
1979 // JaguarDasm(0x4100, 200);
1980 // WriteLog("\n\nM68000 disassembly at $800800...\n");
1981 // JaguarDasm(0x800800, 0x1000);
1985 // Temp debugging stuff
1987 void DumpMainMemory(void)
1989 FILE * fp = fopen("./memdump.bin", "wb");
1994 fwrite(jaguarMainRAM, 1, 0x200000, fp);
1999 uint8_t * GetRamPtr(void)
2001 return jaguarMainRAM;
2006 // New Jaguar execution stack
2007 // This executes 1 frame's worth of code.
2010 void JaguarExecuteNew(void)
2016 double timeToNextEvent = GetTimeToNextEvent();
2017 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2019 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2022 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2030 #define USE_CORRECT_PAL_TIMINGS
2031 // A lot of confusion comes from here...
2032 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
2033 // of whether the display is interlaced or not. The only difference with an
2034 // interlaced display is that the high bit of VC will be set when the lower
2035 // field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
2036 // regardless of whether it's in interlace mode or not.
2037 // NB2: Seems it doens't always, not sure what the constraint is...)
2039 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2040 // rendering two fields that are slighty vertically offset from each other.
2041 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2042 // is rendered in this mode so that each field, when overlaid on each other,
2043 // will yield the final picture at the full resolution for the full frame.
2045 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2046 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2047 // it will be half this number for a half frame. BUT, since we're counting
2048 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
2050 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2051 // Half line times are, naturally, half of this. :-P
2052 void HalflineCallback(void)
2054 //OK, this is hardwired to run in NTSC, and for who knows how long.
2055 //Need to fix this so that it does a half-line in the correct amount of time
2056 //and number of lines, depending on which mode we're in. [FIXED]
2057 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2058 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2059 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2060 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2063 #ifdef USE_CORRECT_PAL_TIMINGS
2064 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2065 // So we cut the number of half-lines in a frame in half. :-P
2066 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2068 if ((vc & 0x7FF) >= numHalfLines)
2070 if ((vc & 0x7FF) >= vp)
2074 // lowerField = !lowerField;
2076 // If we're rendering the lower field, set the high bit (#12, counting
2082 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2083 TOMWriteWord(0xF00006, vc, JAGUAR);
2085 //This is a crappy kludge, but maybe it'll work for now...
2086 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2087 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
2089 // We don't have to worry about autovectors & whatnot because the Jaguar
2090 // tells you through its HW registers who sent the interrupt...
2091 TOMSetPendingVideoInt();
2095 TOMExecHalfline(vc, true);
2097 //Change this to VBB???
2098 //Doesn't seem to matter (at least for Flip Out & I-War)
2099 if ((vc & 0x7FF) == 0)
2106 #ifdef USE_CORRECT_PAL_TIMINGS
2107 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2109 // SetCallbackTime(HalflineCallback, 63.5555);
2110 SetCallbackTime(HalflineCallback, 31.77775);
2115 // This isn't currently used, but maybe it should be...
2117 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
2118 handles all the rest, so this isn't needed. :-P
2120 void RenderCallback(void)
2122 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2123 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time