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"
33 #include "m68000/m68kinterface.h"
40 //Do this in makefile??? Yes! Could, but it's easier to define here...
41 //#define LOG_UNMAPPED_MEMORY_ACCESSES
42 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
43 //#define ABORT_ON_ILLEGAL_INSTRUCTIONS
44 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
45 #define CPU_DEBUG_MEMORY
46 //#define LOG_CD_BIOS_CALLS
47 #define CPU_DEBUG_TRACING
49 // Private function prototypes
51 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
52 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
53 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
54 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
55 void M68K_show_context(void);
59 #ifdef CPU_DEBUG_MEMORY
60 extern bool startMemLog; // Set by "e" key
61 extern int effect_start;
62 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
65 // Really, need to include memory.h for this, but it might interfere with some stuff...
66 extern uint8_t jagMemSpace[];
70 uint32_t jaguar_active_memory_dumps = 0;
72 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
73 bool jaguarCartInserted = false;
74 bool lowerField = false;
76 #ifdef CPU_DEBUG_MEMORY
77 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
78 uint8_t readMem[0x400000];
79 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
82 uint32_t pcQueue[0x400];
83 uint32_t a0Queue[0x400];
84 uint32_t a1Queue[0x400];
85 uint32_t a2Queue[0x400];
86 uint32_t a3Queue[0x400];
87 uint32_t a4Queue[0x400];
88 uint32_t a5Queue[0x400];
89 uint32_t a6Queue[0x400];
90 uint32_t a7Queue[0x400];
91 uint32_t d0Queue[0x400];
92 uint32_t d1Queue[0x400];
93 uint32_t d2Queue[0x400];
94 uint32_t d3Queue[0x400];
95 uint32_t d4Queue[0x400];
96 uint32_t d5Queue[0x400];
97 uint32_t d6Queue[0x400];
98 uint32_t d7Queue[0x400];
100 bool startM68KTracing = false;
103 // Callback function to detect illegal instructions
105 void GPUDumpDisassembly(void);
106 void GPUDumpRegisters(void);
107 static bool start = false;
109 void M68KInstructionHook(void)
111 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
112 // Temp, for comparing...
114 /* static char buffer[2048];//, mem[64];
115 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
116 printf("%08X: %s\n", m68kPC, buffer);//*/
118 //JaguarDasm(m68kPC, 1);
119 //Testing Hover Strike...
122 static int hitCount = 0;
123 static int inRoutine = 0;
126 //if (regs.pc == 0x80340A)
127 if (m68kPC == 0x803416)
132 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
134 else if (m68kPC == 0x803422)
137 printf("(%i instructions)\n", instSeen);
144 // For code tracing...
145 #ifdef CPU_DEBUG_TRACING
146 if (startM68KTracing)
148 static char buffer[2048];
150 m68k_disassemble(buffer, m68kPC, 0);
151 WriteLog("%06X: %s\n", m68kPC, buffer);
156 // Ideally, we'd save all the registers as well...
157 pcQueue[pcQPtr] = m68kPC;
158 a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
159 a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
160 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
161 a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
162 a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
163 a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
164 a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
165 a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
166 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
167 d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
168 d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
169 d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
170 d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
171 d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
172 d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
173 d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
177 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
179 WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
181 static char buffer[2048];
182 for(int i=0; i<0x400; i++)
184 // WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
185 WriteLog("[A0=%08X, A1=%08X, A2=%08X, A3=%08X, A4=%08X, A5=%08X, A6=%08X, A7=%08X, D0=%08X, D1=%08X, D2=%08X, D3=%08X, D4=%08X, D5=%08X, D6=%08X, D7=%08X]\n", a0Queue[(pcQPtr + i) & 0x3FF], a1Queue[(pcQPtr + i) & 0x3FF], a2Queue[(pcQPtr + i) & 0x3FF], a3Queue[(pcQPtr + i) & 0x3FF], a4Queue[(pcQPtr + i) & 0x3FF], a5Queue[(pcQPtr + i) & 0x3FF], a6Queue[(pcQPtr + i) & 0x3FF], a7Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF], d1Queue[(pcQPtr + i) & 0x3FF], d2Queue[(pcQPtr + i) & 0x3FF], d3Queue[(pcQPtr + i) & 0x3FF], d4Queue[(pcQPtr + i) & 0x3FF], d5Queue[(pcQPtr + i) & 0x3FF], d6Queue[(pcQPtr + i) & 0x3FF], d7Queue[(pcQPtr + i) & 0x3FF]);
186 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
187 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
191 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
192 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
193 for(int i=0; i<10; i++)
194 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
195 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
201 // Disassemble everything
203 static char buffer[2048];
204 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
205 WriteLog("%08X: %s", m68kPC, buffer);
206 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
207 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
208 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
210 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
212 static char buffer[2048];
213 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
214 WriteLog("%08X: %s", m68kPC, buffer);
215 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
216 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
217 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
219 /* if (m68kPC == 0x8D0E48 && effect_start5)
221 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
223 GPUDumpDisassembly();
227 /* uint16_t opcode = JaguarReadWord(m68kPC);
228 if (opcode == 0x4E75) // RTS
231 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
233 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
235 if (raPtr != 0xFFFFFFFF)
237 for(uint32_t i=0; i<=raPtr; i++)
239 if (returnAddr[i] == addr)
248 returnAddr[++raPtr] = addr;
252 //Flip Out! debugging...
255 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
256 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
257 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
258 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
260 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
262 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
263 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
264 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
265 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
266 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
267 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
268 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
270 /* static char buffer[2048];
271 //if (m68kPC > 0x805F48) start = true;
272 //if (m68kPC > 0x806486) start = true;
273 //if (m68kPC == 0x805FEE) start = true;
274 //if (m68kPC == 0x80600C)// start = true;
275 if (m68kPC == 0x802058) start = true;
277 // GPUDumpRegisters();
278 // GPUDumpDisassembly();
280 // M68K_show_context();
286 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
287 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));
290 /* if (m68kPC == 0x803F16)
292 WriteLog("M68K: Registers found at $803F16:\n");
293 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
294 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
295 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
297 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
298 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
300 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
301 // !!! Investigate !!!
302 /*extern bool doDSPDis;
303 static bool disgo = false;
304 if (m68kPC == 0x50222)
307 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
308 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
311 if (m68kPC == 0x5000)
316 static char buffer[2048];
317 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
318 WriteLog("%08X: %s", m68kPC, buffer);
319 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
320 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
321 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
323 /* if (m68kPC == 0x82E1A)
325 static char buffer[2048];
326 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
327 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
328 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
329 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
330 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
332 /* if (m68kPC == 0x82E58)
333 WriteLog("--> [Routine end]\n");
334 if (m68kPC == 0x80004)
336 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
337 // m68k_set_reg(M68K_REG_D2, 0x12345678);
340 #ifdef LOG_CD_BIOS_CALLS
363 if (m68kPC == 0x3000)
364 WriteLog("M68K: CD_init\n");
365 else if (m68kPC == 0x3006 + (6 * 0))
366 WriteLog("M68K: CD_mode\n");
367 else if (m68kPC == 0x3006 + (6 * 1))
368 WriteLog("M68K: CD_ack\n");
369 else if (m68kPC == 0x3006 + (6 * 2))
370 WriteLog("M68K: CD_jeri\n");
371 else if (m68kPC == 0x3006 + (6 * 3))
372 WriteLog("M68K: CD_spin\n");
373 else if (m68kPC == 0x3006 + (6 * 4))
374 WriteLog("M68K: CD_stop\n");
375 else if (m68kPC == 0x3006 + (6 * 5))
376 WriteLog("M68K: CD_mute\n");
377 else if (m68kPC == 0x3006 + (6 * 6))
378 WriteLog("M68K: CD_umute\n");
379 else if (m68kPC == 0x3006 + (6 * 7))
380 WriteLog("M68K: CD_paus\n");
381 else if (m68kPC == 0x3006 + (6 * 8))
382 WriteLog("M68K: CD_upaus\n");
383 else if (m68kPC == 0x3006 + (6 * 9))
384 WriteLog("M68K: CD_read\n");
385 else if (m68kPC == 0x3006 + (6 * 10))
386 WriteLog("M68K: CD_uread\n");
387 else if (m68kPC == 0x3006 + (6 * 11))
388 WriteLog("M68K: CD_setup\n");
389 else if (m68kPC == 0x3006 + (6 * 12))
390 WriteLog("M68K: CD_ptr\n");
391 else if (m68kPC == 0x3006 + (6 * 13))
392 WriteLog("M68K: CD_osamp\n");
393 else if (m68kPC == 0x3006 + (6 * 14))
394 WriteLog("M68K: CD_getoc\n");
395 else if (m68kPC == 0x3006 + (6 * 15))
396 WriteLog("M68K: CD_initm\n");
397 else if (m68kPC == 0x3006 + (6 * 16))
398 WriteLog("M68K: CD_initf\n");
399 else if (m68kPC == 0x3006 + (6 * 17))
400 WriteLog("M68K: CD_switch\n");
402 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
403 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
404 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
405 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
408 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
409 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
411 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
412 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
414 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
415 // keep going even when the 68K dumped back to the debugger or what have you).
417 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
418 // Try setting the vector to the illegal instruction...
419 //This doesn't work right either! Do something else! Quick!
420 // SET32(jaguar_mainRam, 0x10, m68kPC);
426 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
427 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
428 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
429 uint32_t address = topOfStack - (4 * 4 * 3);
431 for(int i=0; i<10; i++)
433 WriteLog("%06X:", address);
435 for(int j=0; j<4; j++)
437 WriteLog(" %08X", JaguarReadLong(address));
444 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
448 // WriteLog("\n\n68K disasm\n\n");
449 // jaguar_dasm(0x802000, 0x50C);
460 Now here be dragons...
461 Here is how memory ranges are defined in the CoJag driver.
462 Note that we only have to be concerned with 3 entities read/writing anything:
463 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
464 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
465 things that are entirely internal to those modules. This way we should be able to get a handle on all
466 this crap which is currently scattered over Hell's Half Acre(tm).
468 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
469 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
471 /*************************************
473 * Main CPU memory handlers
475 *************************************/
477 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
478 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
479 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
480 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
481 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
482 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
483 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
484 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
485 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
486 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
487 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
488 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
489 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
490 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
491 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
492 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
493 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
494 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
495 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
496 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
497 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
498 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
499 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
502 /*************************************
504 * GPU memory handlers
506 *************************************/
508 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
509 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
510 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
511 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
512 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
513 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
514 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
515 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
516 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
517 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
518 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
521 /*************************************
523 * DSP memory handlers
525 *************************************/
527 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
528 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
529 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
530 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
531 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
532 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
533 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
534 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
535 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
540 //#define EXPERIMENTAL_MEMORY_HANDLING
541 // Experimental memory mappage...
542 // Dunno if this is a good approach or not, but it seems to make better
543 // sense to have all this crap in one spot intstead of scattered all over
544 // the place the way it is now.
545 #ifdef EXPERIMENTAL_MEMORY_HANDLING
547 #define NEW_TIMER_SYSTEM
550 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
551 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
552 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
553 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
554 bool BIOSLoaded = false;
555 bool CDBIOSLoaded = false;
557 uint8_t cdRAM[0x100];
558 uint8_t tomRAM[0x4000];
559 uint8_t jerryRAM[0x10000];
560 static uint16_t eeprom_ram[64];
562 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
565 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
567 // M68K Memory map/handlers
569 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
570 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
571 // Note that this is really memory mapped I/O region...
572 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
573 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
574 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
575 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
576 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
577 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
578 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
579 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
580 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
581 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
582 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
583 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
585 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
587 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
588 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
589 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
590 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
591 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
592 //What about LBUF writes???
593 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
594 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
595 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
597 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
601 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
602 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
603 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
606 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
607 0 = pad0/1 button values (4 bits each), RO(?)
608 1 = pad0/1 index value (4 bits each), WO
610 3 = NTSC/PAL, certain button states, RO
612 JOYSTICK $F14000 Read/Write
614 Read fedcba98 7654321q f-1 Signals J15 to J1
615 q Cartridge EEPROM output data
616 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
617 0 = disable J7-J0 outputs
620 0 = Audio muted (reset state)
622 7-4 J7-J4 outputs (port 2)
623 3-0 J3-J0 outputs (port 1)
624 JOYBUTS $F14002 Read Only
626 Read xxxxxxxx rrdv3210 x don't care
629 v 1 = NTSC Video hardware
630 0 = PAL Video hardware
631 3-2 Button inputs B3 & B2 (port 2)
632 1-0 Button inputs B1 & B0 (port 1)
634 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
635 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
643 0 1 1 1 Row 3 C3 Option # 9 6 3
647 1 0 1 1 Row 2 C2 C 0 8 5 2
649 1 1 0 1 Row 1 C1 B * 7 4 1
650 1 1 1 0 Row 0 Pause A Up Down Left Right
653 0 bit read in any position means that button is pressed.
654 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
658 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
660 // Not sure, but I think the system only has 24 address bits...
661 address &= 0x00FFFFFF;
663 // RAM ($000000 - $3FFFFF) 4M
664 if (address <= 0x3FFFFF)
665 jaguarMainRAM[address] = byte;
666 // hole ($400000 - $7FFFFF) 4M
667 else if (address <= 0x7FFFFF)
669 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
670 else if (address <= 0xDFFEFF)
672 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
673 else if (address <= 0xDFFFFF)
675 cdRAM[address & 0xFF] = byte;
677 if ((address & 0xFF) < 12 * 4)
678 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
679 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
682 // BIOS ROM ($E00000 - $E3FFFF) 256K
683 else if (address <= 0xE3FFFF)
685 // hole ($E40000 - $EFFFFF) 768K
686 else if (address <= 0xEFFFFF)
688 // TOM ($F00000 - $F0FFFF) 64K
689 else if (address <= 0xF0FFFF)
692 if (address == 0xF00050)
694 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
698 else if (address == 0xF00051)
700 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
704 else if (address == 0xF00052)
706 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
710 else if (address == 0xF00053)
712 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
716 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
718 // Writing to one CLUT writes to the other
719 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
720 tomRAM[address] = tomRAM[address + 0x200] = byte;
723 //What about LBUF writes???
724 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
726 GPUWriteByte(address, byte, who);
729 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
731 BlitterWriteByte(address, byte, who);
734 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
736 GPUWriteByte(address, byte, who);
740 tomRAM[address & 0x3FFF] = byte;
742 // JERRY ($F10000 - $F1FFFF) 64K
743 else if (address <= 0xF1FFFF)
747 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
749 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
751 DSPWriteByte(address, byte, who);
754 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
756 DSPWriteByte(address, byte, who);
759 // SCLK ($F1A150--8 bits wide)
760 //NOTE: This should be taken care of in DAC...
761 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
763 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
764 if ((address & 0x03) == 2)
765 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
767 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
769 JERRYI2SInterruptTimer = -1;
770 #ifndef NEW_TIMER_SYSTEM
773 RemoveCallback(JERRYI2SCallback);
778 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
779 else if (address >= 0xF1A148 && address <= 0xF1A157)
781 DACWriteByte(address, byte, who);
784 else if (address >= 0xF10000 && address <= 0xF10007)
786 #ifndef NEW_TIMER_SYSTEM
787 switch (address & 0x07)
790 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
794 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
798 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
802 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
806 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
810 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
814 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
818 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
822 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
826 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
828 clock_byte_write(offset, byte);
831 // JERRY -> 68K interrupt enables/latches (need to be handled!)
832 else if (address >= 0xF10020 && address <= 0xF10023)
834 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
836 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
838 anajoy_byte_write(offset, byte);
841 else if ((address >= 0xF14000) && (address <= 0xF14003))
843 JoystickWriteByte(address, byte);
844 EepromWriteByte(address, byte);
847 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
849 EepromWriteByte(address, byte);
852 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
853 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
856 jerryRAM[address & 0xFFFF] = byte;
858 // hole ($F20000 - $FFFFFF) 1M - 128K
863 void WriteWord(uint32_t adddress, uint16_t word)
867 void WriteDWord(uint32_t adddress, uint32_t dword)
871 uint8_t ReadByte(uint32_t adddress)
875 uint16_t ReadWord(uint32_t adddress)
879 uint32_t ReadDWord(uint32_t adddress)
884 void ShowM68KContext(void)
886 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
888 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
890 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
892 if (i == M68K_REG_D3 || i == M68K_REG_D7)
896 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
898 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
900 if (i == M68K_REG_A3 || i == M68K_REG_A7)
904 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
905 uint32_t disPC = currpc - 30;
910 uint32_t oldpc = disPC;
911 disPC += m68k_disassemble(buffer, disPC, 0);
912 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
914 while (disPC < (currpc + 10));
918 // Custom UAE 68000 read/write/IRQ functions
925 IPL Name Vector Control
926 ---------+---------------+---------------+---------------
927 2 VBLANK IRQ $100 INT1 bit #0
928 2 GPU IRQ $100 INT1 bit #1
929 2 HBLANK IRQ $100 INT1 bit #2
930 2 Timer IRQ $100 INT1 bit #3
932 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
933 and are therefore indistinguishable.
935 A typical way to install a LEVEL2 handler for the 68000 would be
936 something like this, you gotta supply "last_line" and "handler".
937 Note that the interrupt is auto vectored thru $100 (not $68)
945 IRQS_HANDLED=$909 ;; VBLANK and TIMER
947 move.w #$2700,sr ;; no IRQs please
948 move.l #handler,V_AUTO ;; install our routine
950 move.w #last_line,VI ;; scanline where IRQ should occur
951 ;; should be 'odd' BTW
952 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
953 move.w #$2100,sr ;; enable IRQs on the 68K
971 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
972 move.w #0,INT2 ; let GPU run again
976 As you can see, if you have multiple INT1 interrupts coming in,
977 you need to check the lower byte of INT1, to see which interrupt
980 int irq_ack_handler(int level)
982 #ifdef CPU_DEBUG_TRACING
983 if (startM68KTracing)
985 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
989 // Tracing the IPL lines on the Jaguar schematic yields the following:
990 // IPL1 is connected to INTL on TOM (OUT to 68K)
991 // IPL0-2 are also tied to Vcc via 4.7K resistors!
992 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
993 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
994 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
996 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
997 // They aren't, and this causes problems with a, err, specific ROM. :-D
1001 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1002 return 64; // Set user interrupt #0
1005 return M68K_INT_ACK_AUTOVECTOR;
1008 //#define USE_NEW_MMU
1010 unsigned int m68k_read_memory_8(unsigned int address)
1012 // Musashi does this automagically for you, UAE core does not :-P
1013 address &= 0x00FFFFFF;
1014 #ifdef CPU_DEBUG_MEMORY
1015 // Note that the Jaguar only has 2M of RAM, not 4!
1016 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1019 readMem[address] = 1;
1022 //WriteLog("[RM8] Addr: %08X\n", address);
1023 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1024 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1025 || address == 0x1AF05E)
1026 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1028 unsigned int retVal = 0;
1030 // Note that the Jaguar only has 2M of RAM, not 4!
1031 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1032 retVal = jaguarMainRAM[address];
1033 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1034 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1035 retVal = jaguarMainROM[address - 0x800000];
1036 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1037 // retVal = jaguarBootROM[address - 0xE00000];
1038 // retVal = jaguarDevBootROM1[address - 0xE00000];
1039 retVal = jagMemSpace[address];
1040 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1041 retVal = CDROMReadByte(address);
1042 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1043 retVal = TOMReadByte(address, M68K);
1044 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1045 retVal = JERRYReadByte(address, M68K);
1047 retVal = jaguar_unknown_readbyte(address, M68K);
1049 //if (address >= 0x2800 && address <= 0x281F)
1050 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1051 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1052 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1055 return MMURead8(address, M68K);
1059 void gpu_dump_disassembly(void);
1060 void gpu_dump_registers(void);
1062 unsigned int m68k_read_memory_16(unsigned int address)
1064 // Musashi does this automagically for you, UAE core does not :-P
1065 address &= 0x00FFFFFF;
1066 #ifdef CPU_DEBUG_MEMORY
1067 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1070 readMem[address] = 1, readMem[address + 1] = 1;
1072 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1074 return 0x4E71; // NOP
1076 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1078 return 0x4E71; // NOP
1080 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1082 return 0x4E71; // NOP
1084 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1086 return 0x4E71; // NOP
1088 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1090 return 0x4E71; // NOP
1092 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1094 return 0x4E71; // NOP
1097 //WriteLog("[RM16] Addr: %08X\n", address);
1098 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1099 // for(int i=0; i<10000; i++)
1100 WriteLog("[M68K] In routine #6!\n");//*/
1101 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1102 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1103 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1105 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1106 gpu_dump_registers();
1107 gpu_dump_disassembly();
1108 // for(int i=0; i<10000; i++)
1109 // WriteLog("[M68K] About to run GPU!\n");
1111 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1112 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1114 if (address == 0x000066A0)
1116 gpu_dump_registers();
1117 gpu_dump_disassembly();
1119 for(int i=0; i<10000; i++)
1120 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1122 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1123 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1124 || address == 0x1AF05E)
1125 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1127 unsigned int retVal = 0;
1129 // Note that the Jaguar only has 2M of RAM, not 4!
1130 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1131 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1132 retVal = GET16(jaguarMainRAM, address);
1133 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1134 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1135 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1136 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1137 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1138 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1139 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1140 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1141 retVal = CDROMReadWord(address, M68K);
1142 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1143 retVal = TOMReadWord(address, M68K);
1144 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1145 retVal = JERRYReadWord(address, M68K);
1147 retVal = jaguar_unknown_readword(address, M68K);
1149 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1150 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1151 //if (address >= 0x2800 && address <= 0x281F)
1152 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1153 //$8B3AE -> Transferred from $F1C010
1154 //$8B5E4 -> Only +1 read at $808AA
1155 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1156 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1159 return MMURead16(address, M68K);
1163 unsigned int m68k_read_memory_32(unsigned int address)
1165 // Musashi does this automagically for you, UAE core does not :-P
1166 address &= 0x00FFFFFF;
1167 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1168 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1169 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));//*/
1171 //WriteLog("--> [RM32]\n");
1173 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1175 return MMURead32(address, M68K);
1179 void m68k_write_memory_8(unsigned int address, unsigned int value)
1181 // Musashi does this automagically for you, UAE core does not :-P
1182 address &= 0x00FFFFFF;
1183 #ifdef CPU_DEBUG_MEMORY
1184 // Note that the Jaguar only has 2M of RAM, not 4!
1185 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1189 if (value > writeMemMax[address])
1190 writeMemMax[address] = value;
1191 if (value < writeMemMin[address])
1192 writeMemMin[address] = value;
1196 /*if (address == 0x4E00)
1197 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1198 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1199 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1200 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1202 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1203 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1205 /*if (address >= 0x53D0 && address <= 0x53FF)
1206 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1207 //Testing AvP on UAE core...
1208 //000075A0: FFFFF80E B6320220 (BITMAP)
1209 /*if (address == 0x75A0 && value == 0xFF)
1210 printf("M68K: (8) Tripwire hit...\n");//*/
1213 // Note that the Jaguar only has 2M of RAM, not 4!
1214 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1215 jaguarMainRAM[address] = value;
1216 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1217 CDROMWriteByte(address, value, M68K);
1218 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1219 TOMWriteByte(address, value, M68K);
1220 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1221 JERRYWriteByte(address, value, M68K);
1223 jaguar_unknown_writebyte(address, value, M68K);
1225 MMUWrite8(address, value, M68K);
1229 void m68k_write_memory_16(unsigned int address, unsigned int value)
1231 // Musashi does this automagically for you, UAE core does not :-P
1232 address &= 0x00FFFFFF;
1233 #ifdef CPU_DEBUG_MEMORY
1234 // Note that the Jaguar only has 2M of RAM, not 4!
1235 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1239 uint8_t hi = value >> 8, lo = value & 0xFF;
1241 if (hi > writeMemMax[address])
1242 writeMemMax[address] = hi;
1243 if (hi < writeMemMin[address])
1244 writeMemMin[address] = hi;
1246 if (lo > writeMemMax[address+1])
1247 writeMemMax[address+1] = lo;
1248 if (lo < writeMemMin[address+1])
1249 writeMemMin[address+1] = lo;
1253 /*if (address == 0x4E00)
1254 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1255 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1256 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1257 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1258 //if (address >= 0xF02200 && address <= 0xF0229F)
1259 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1260 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1261 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1262 /*extern uint32_t totalFrames;
1263 if (address == 0xF02114)
1264 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1265 if (address == 0xF02110)
1266 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1267 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1268 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1270 /*if (address == 0x0100)//64*4)
1271 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1273 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1274 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1275 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1276 || address == 0x1AF05E)
1277 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1279 /*if (address >= 0x53D0 && address <= 0x53FF)
1280 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1281 //Testing AvP on UAE core...
1282 //000075A0: FFFFF80E B6320220 (BITMAP)
1283 /*if (address == 0x75A0 && value == 0xFFFF)
1285 printf("\nM68K: (16) Tripwire hit...\n");
1290 // Note that the Jaguar only has 2M of RAM, not 4!
1291 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1293 /* jaguar_mainRam[address] = value >> 8;
1294 jaguar_mainRam[address + 1] = value & 0xFF;*/
1295 SET16(jaguarMainRAM, address, value);
1297 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1298 CDROMWriteWord(address, value, M68K);
1299 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1300 TOMWriteWord(address, value, M68K);
1301 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1302 JERRYWriteWord(address, value, M68K);
1305 jaguar_unknown_writeword(address, value, M68K);
1306 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1307 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1308 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1309 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1313 MMUWrite16(address, value, M68K);
1317 void m68k_write_memory_32(unsigned int address, unsigned int value)
1319 // Musashi does this automagically for you, UAE core does not :-P
1320 address &= 0x00FFFFFF;
1321 /*if (address == 0x4E00)
1322 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1323 //WriteLog("--> [WM32]\n");
1324 /*if (address == 0x0100)//64*4)
1325 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1326 /*if (address >= 0xF03214 && address < 0xF0321F)
1327 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1328 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1329 /*extern bool doGPUDis;
1330 if (address == 0xF03214 && value == 0x88E30047)
1332 doGPUDis = true;//*/
1333 /* if (address == 0x51136 || address == 0xFB074)
1334 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1335 //Testing AvP on UAE core...
1336 //000075A0: FFFFF80E B6320220 (BITMAP)
1337 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1339 printf("\nM68K: (32) Tripwire hit...\n");
1344 m68k_write_memory_16(address, value >> 16);
1345 m68k_write_memory_16(address + 2, value & 0xFFFF);
1347 MMUWrite32(address, value, M68K);
1352 uint32_t JaguarGetHandler(uint32_t i)
1354 return JaguarReadLong(i * 4);
1357 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1359 uint32_t handler = JaguarGetHandler(i);
1360 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1363 void M68K_show_context(void)
1365 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1367 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1369 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1371 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1375 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1377 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1379 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1383 WriteLog("68K disasm\n");
1384 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1385 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1386 // jaguar_dasm(0x5000, 0x14414);
1388 // WriteLog("\n.......[Cart start]...........\n\n");
1389 // jaguar_dasm(0x192000, 0x1000);//0x200);
1391 WriteLog("..................\n");
1393 if (TOMIRQEnabled(IRQ_VIDEO))
1395 WriteLog("video int: enabled\n");
1396 JaguarDasm(JaguarGetHandler(64), 0x200);
1399 WriteLog("video int: disabled\n");
1401 WriteLog("..................\n");
1403 for(int i=0; i<256; i++)
1405 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1406 uint32_t address = (uint32_t)JaguarGetHandler(i);
1409 WriteLog(".........\n");
1411 WriteLog("$%08X\n", address);
1416 // Unknown read/write byte/word routines
1419 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1420 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1422 // 807EC4: movea.l #$f1b000, A1
1423 // 807ECA: movea.l #$8129e0, A0
1424 // 807ED0: move.l A0, D0
1425 // 807ED2: move.l #$f1bb94, D1
1426 // 807ED8: sub.l D0, D1
1427 // 807EDA: lsr.l #2, D1
1428 // 807EDC: move.l (A0)+, (A1)+
1429 // 807EDE: dbra D1, 807edc
1431 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1432 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1433 // space! (That is, unless the 68K causes a bus error...)
1435 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1437 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1438 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));
1440 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1441 // extern bool finished;
1443 // extern bool doDSPDis;
1449 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1451 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1452 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));
1454 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1455 // extern bool finished;
1457 // extern bool doDSPDis;
1463 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1465 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1466 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1468 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1469 // extern bool finished;
1471 // extern bool doDSPDis;
1478 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1480 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1481 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1483 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1484 // extern bool finished;
1486 // extern bool doDSPDis;
1494 // Disassemble M68K instructions at the given offset
1497 unsigned int m68k_read_disassembler_8(unsigned int address)
1499 return m68k_read_memory_8(address);
1502 unsigned int m68k_read_disassembler_16(unsigned int address)
1504 return m68k_read_memory_16(address);
1507 unsigned int m68k_read_disassembler_32(unsigned int address)
1509 return m68k_read_memory_32(address);
1512 void JaguarDasm(uint32_t offset, uint32_t qt)
1515 static char buffer[2048];//, mem[64];
1516 int pc = offset, oldpc;
1518 for(uint32_t i=0; i<qt; i++)
1521 for(int j=0; j<64; j++)
1522 mem[j^0x01] = jaguar_byte_read(pc + j);
1524 pc += Dasm68000((char *)mem, buffer, 0);
1525 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1527 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1528 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1533 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1535 uint8_t data = 0x00;
1538 // First 2M is mirrored in the $0 - $7FFFFF range
1539 if (offset < 0x800000)
1540 data = jaguarMainRAM[offset & 0x1FFFFF];
1541 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1542 data = jaguarMainROM[offset - 0x800000];
1543 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1544 data = CDROMReadByte(offset, who);
1545 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1546 // data = jaguarBootROM[offset & 0x3FFFF];
1547 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1548 data = jagMemSpace[offset];
1549 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1550 data = TOMReadByte(offset, who);
1551 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1552 data = JERRYReadByte(offset, who);
1554 data = jaguar_unknown_readbyte(offset, who);
1559 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1563 // First 2M is mirrored in the $0 - $7FFFFF range
1564 if (offset < 0x800000)
1566 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1568 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1571 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1573 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1574 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1575 return CDROMReadWord(offset, who);
1576 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1577 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1578 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1579 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1580 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1581 return TOMReadWord(offset, who);
1582 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1583 return JERRYReadWord(offset, who);
1585 return jaguar_unknown_readword(offset, who);
1588 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1590 /* if (offset >= 0x4E00 && offset < 0x4E04)
1591 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1592 //Need to check for writes in the range of $18FA70 + 8000...
1594 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1595 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1599 // First 2M is mirrored in the $0 - $7FFFFF range
1600 if (offset < 0x800000)
1602 jaguarMainRAM[offset & 0x1FFFFF] = data;
1605 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1607 CDROMWriteByte(offset, data, who);
1610 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1612 TOMWriteByte(offset, data, who);
1615 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1617 JERRYWriteByte(offset, data, who);
1621 jaguar_unknown_writebyte(offset, data, who);
1625 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1627 /* if (offset >= 0x4E00 && offset < 0x4E04)
1628 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1629 /*if (offset == 0x0100)//64*4)
1630 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1631 if (offset == 0x0102)//64*4)
1632 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1633 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1634 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1635 //Need to check for writes in the range of $18FA70 + 8000...
1637 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1638 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1639 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1640 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1644 // First 2M is mirrored in the $0 - $7FFFFF range
1645 if (offset <= 0x7FFFFE)
1650 1A 69 F0 ($0000) -> Starfield
1651 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1654 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1663 //This MUST be done by the 68K!
1664 /*if (offset == 0x670C)
1665 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1667 /*extern bool doGPUDis;
1668 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1669 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1670 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1671 doGPUDis = true;//*/
1672 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1673 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1674 if ((data & 0xFF00) != 0x7700)
1675 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1676 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1678 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1679 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1680 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1682 /*extern bool doGPUDis;
1683 if (offset == 0x120216 && who == GPU)
1684 doGPUDis = true;//*/
1685 /*extern uint32_t gpu_pc;
1686 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1688 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1689 uint32_t y = base / 0x300;
1690 uint32_t x = (base - (y * 0x300)) / 2;
1691 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1694 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1696 //if (offset == (0x001E17F8 + 0x34))
1697 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1699 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1700 /*extern uint32_t gpu_pc;
1701 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1703 extern int objectPtr;
1704 // if (offset > 0x148000)
1707 if (starCount > objectPtr)
1710 // if (starCount == 1)
1711 // WriteLog("--> Drawing 1st star...\n");
1713 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1714 // uint32_t y = base / 0x300;
1715 // uint32_t x = (base - (y * 0x300)) / 2;
1716 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1718 //A star of interest...
1719 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1720 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1721 //JWW: Blitter writing echo 77B3 at 0011D022...
1723 //extern bool doGPUDis;
1724 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1727 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1730 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1731 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1733 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1734 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1737 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1739 CDROMWriteWord(offset, data, who);
1742 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1744 TOMWriteWord(offset, data, who);
1747 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1749 JERRYWriteWord(offset, data, who);
1752 // Don't bomb on attempts to write to ROM
1753 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1756 jaguar_unknown_writeword(offset, data, who);
1759 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1760 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1762 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1765 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1766 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1768 /* extern bool doDSPDis;
1769 if (offset < 0x400 && !doDSPDis)
1771 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1774 /*if (offset == 0x0100)//64*4)
1775 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1777 JaguarWriteWord(offset, data >> 16, who);
1778 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1781 void JaguarSetScreenBuffer(uint32_t * buffer)
1783 // This is in TOM, but we set it here...
1784 screenBuffer = buffer;
1787 void JaguarSetScreenPitch(uint32_t pitch)
1789 // This is in TOM, but we set it here...
1790 screenPitch = pitch;
1794 // Jaguar console initialization
1796 void JaguarInit(void)
1798 // For randomizing RAM
1801 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1802 for(uint32_t i=0; i<0x200000; i+=4)
1803 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1805 #ifdef CPU_DEBUG_MEMORY
1806 memset(readMem, 0x00, 0x400000);
1807 memset(writeMemMin, 0xFF, 0x400000);
1808 memset(writeMemMax, 0x00, 0x400000);
1810 // memset(jaguarMainRAM, 0x00, 0x200000);
1811 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1812 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1813 //NOTE: This *doesn't* fix FlipOut...
1814 //Or does it? Hmm...
1815 //Seems to want $01010101... Dunno why. Investigate!
1816 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1817 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1818 lowerField = false; // Reset the lower field flag
1819 //temp, for crappy crap that sux
1820 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1822 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1831 //New timer based code stuffola...
1832 void HalflineCallback(void);
1833 void RenderCallback(void);
1834 void JaguarReset(void)
1836 // Only problem with this approach: It wipes out RAM loaded files...!
1837 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1838 for(uint32_t i=8; i<0x200000; i+=4)
1839 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1841 // New timer base code stuffola...
1842 InitializeEventList();
1843 //Need to change this so it uses the single RAM space and load the BIOS
1844 //into it somewhere...
1845 //Also, have to change this here and in JaguarReadXX() currently
1846 // Only use the system BIOS if it's available...! (it's always available now!)
1847 // AND only if a jaguar cartridge has been inserted.
1848 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1849 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1851 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1853 // WriteLog("jaguar_reset():\n");
1859 m68k_pulse_reset(); // Reset the 68000
1860 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1862 lowerField = false; // Reset the lower field flag
1863 // SetCallbackTime(ScanlineCallback, 63.5555);
1864 // SetCallbackTime(ScanlineCallback, 31.77775);
1865 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1869 void JaguarDone(void)
1871 #ifdef CPU_DEBUG_MEMORY
1872 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1874 for(uint32_t i=0; i<=raPtr; i++)
1876 WriteLog("\t%08X\n", returnAddr[i]);
1877 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1878 jaguar_dasm(returnAddr[i] - 16, 16);
1883 /* int start = 0, end = 0;
1884 bool endTriggered = false, startTriggered = false;
1885 for(int i=0; i<0x400000; i++)
1887 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1889 if (!startTriggered)
1890 startTriggered = true, endTriggered = false, start = i;
1892 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1898 end = i - 1, endTriggered = true, startTriggered = false;
1899 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1906 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1907 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1908 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1909 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
1911 for(int i=-2; i<9; i++)
1912 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1914 uint32_t address = topOfStack - (4 * 4 * 3);
1916 for(int i=0; i<10; i++)
1918 WriteLog("%06X:", address);
1920 for(int j=0; j<4; j++)
1922 WriteLog(" %08X", JaguarReadLong(address));
1930 /* WriteLog("\nM68000 disassembly at $802288...\n");
1931 jaguar_dasm(0x802288, 3);
1932 WriteLog("\nM68000 disassembly at $802200...\n");
1933 jaguar_dasm(0x802200, 500);
1934 WriteLog("\nM68000 disassembly at $802518...\n");
1935 jaguar_dasm(0x802518, 100);//*/
1937 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
1938 jaguar_dasm(0x803F00, 500);
1941 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
1942 jaguar_dasm(0x802B00, 500);
1945 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
1946 jaguar_dasm(0x809900, 500);
1949 /* WriteLog("\n\nDump of $8093C8:\n\n");
1950 for(int i=0x8093C8; i<0x809900; i+=4)
1951 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
1952 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
1953 jaguar_dasm(0x90006C, 500);
1955 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
1956 jaguar_dasm(0x1AC000, 6000);
1959 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
1960 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
1961 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
1962 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
1963 M68K_show_context();
1972 // temp, until debugger is in place
1973 //00802016: jsr $836F1A.l
1974 //0080201C: jsr $836B30.l
1975 //00802022: jsr $836B18.l
1976 //00802028: jsr $8135F0.l
1977 //00813C1E: jsr $813F76.l
1978 //00802038: jsr $836D00.l
1979 //00802098: jsr $8373A4.l
1980 //008020A2: jsr $83E24A.l
1981 //008020BA: jsr $83E156.l
1982 //008020C6: jsr $83E19C.l
1983 //008020E6: jsr $8445E8.l
1984 //008020EC: jsr $838C20.l
1985 //0080211A: jsr $838ED6.l
1986 //00802124: jsr $89CA56.l
1987 //0080212A: jsr $802B48.l
1989 WriteLog("-------------------------------------------\n");
1990 JaguarDasm(0x8445E8, 0x200);
1991 WriteLog("-------------------------------------------\n");
1992 JaguarDasm(0x838C20, 0x200);
1993 WriteLog("-------------------------------------------\n");
1994 JaguarDasm(0x838ED6, 0x200);
1995 WriteLog("-------------------------------------------\n");
1996 JaguarDasm(0x89CA56, 0x200);
1997 WriteLog("-------------------------------------------\n");
1998 JaguarDasm(0x802B48, 0x200);
1999 WriteLog("\n\nM68000 disassembly at $802000...\n");
2000 JaguarDasm(0x802000, 6000);
2003 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2004 JaguarDasm(0x6004, 10000);
2006 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2007 // JaguarDasm(0x802000, 0x1000);
2008 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2009 // JaguarDasm(0x4100, 200);
2010 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2011 // JaguarDasm(0x800800, 0x1000);
2015 // Temp debugging stuff
2017 void DumpMainMemory(void)
2019 FILE * fp = fopen("./memdump.bin", "wb");
2024 fwrite(jaguarMainRAM, 1, 0x200000, fp);
2029 uint8_t * GetRamPtr(void)
2031 return jaguarMainRAM;
2036 // New Jaguar execution stack
2037 // This executes 1 frame's worth of code.
2040 void JaguarExecuteNew(void)
2046 double timeToNextEvent = GetTimeToNextEvent();
2047 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2049 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2052 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2060 #define USE_CORRECT_PAL_TIMINGS
2061 // A lot of confusion comes from here...
2062 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
2063 // of whether the display is interlaced or not. The only difference with an
2064 // interlaced display is that the high bit of VC will be set when the lower
2065 // field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
2066 // regardless of whether it's in interlace mode or not.
2067 // NB2: Seems it doens't always, not sure what the constraint is...)
2069 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2070 // rendering two fields that are slighty vertically offset from each other.
2071 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2072 // is rendered in this mode so that each field, when overlaid on each other,
2073 // will yield the final picture at the full resolution for the full frame.
2075 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2076 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2077 // it will be half this number for a half frame. BUT, since we're counting
2078 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
2080 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2081 // Half line times are, naturally, half of this. :-P
2082 void HalflineCallback(void)
2084 //OK, this is hardwired to run in NTSC, and for who knows how long.
2085 //Need to fix this so that it does a half-line in the correct amount of time
2086 //and number of lines, depending on which mode we're in. [FIXED]
2087 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2088 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2089 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2090 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2093 #ifdef USE_CORRECT_PAL_TIMINGS
2094 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2095 // So we cut the number of half-lines in a frame in half. :-P
2096 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2098 if ((vc & 0x7FF) >= numHalfLines)
2100 if ((vc & 0x7FF) >= vp)
2104 // lowerField = !lowerField;
2106 // If we're rendering the lower field, set the high bit (#12, counting
2112 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2113 TOMWriteWord(0xF00006, vc, JAGUAR);
2115 //This is a crappy kludge, but maybe it'll work for now...
2116 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2117 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
2119 // We don't have to worry about autovectors & whatnot because the Jaguar
2120 // tells you through its HW registers who sent the interrupt...
2121 TOMSetPendingVideoInt();
2125 TOMExecHalfline(vc, true);
2127 //Change this to VBB???
2128 //Doesn't seem to matter (at least for Flip Out & I-War)
2129 if ((vc & 0x7FF) == 0)
2136 #ifdef USE_CORRECT_PAL_TIMINGS
2137 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2139 // SetCallbackTime(HalflineCallback, 63.5555);
2140 SetCallbackTime(HalflineCallback, 31.77775);
2145 // This isn't currently used, but maybe it should be...
2147 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
2148 handles all the rest, so this isn't needed. :-P
2150 void RenderCallback(void)
2152 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2153 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time