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"
41 //Do this in makefile??? Yes! Could, but it's easier to define here...
42 //#define LOG_UNMAPPED_MEMORY_ACCESSES
43 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
44 //#define ABORT_ON_ILLEGAL_INSTRUCTIONS
45 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
46 #define CPU_DEBUG_MEMORY
47 //#define LOG_CD_BIOS_CALLS
48 #define CPU_DEBUG_TRACING
49 #define ALPINE_FUNCTIONS
51 // Private function prototypes
53 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
54 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
55 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
56 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
57 void M68K_show_context(void);
61 #ifdef CPU_DEBUG_MEMORY
62 extern bool startMemLog; // Set by "e" key
63 extern int effect_start;
64 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
67 // Really, need to include memory.h for this, but it might interfere with some stuff...
68 extern uint8_t jagMemSpace[];
72 uint32_t jaguar_active_memory_dumps = 0;
74 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
75 bool jaguarCartInserted = false;
76 bool lowerField = false;
78 #ifdef CPU_DEBUG_MEMORY
79 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
80 uint8_t readMem[0x400000];
81 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
84 uint32_t pcQueue[0x400];
85 uint32_t a0Queue[0x400];
86 uint32_t a1Queue[0x400];
87 uint32_t a2Queue[0x400];
88 uint32_t a3Queue[0x400];
89 uint32_t a4Queue[0x400];
90 uint32_t a5Queue[0x400];
91 uint32_t a6Queue[0x400];
92 uint32_t a7Queue[0x400];
93 uint32_t d0Queue[0x400];
94 uint32_t d1Queue[0x400];
95 uint32_t d2Queue[0x400];
96 uint32_t d3Queue[0x400];
97 uint32_t d4Queue[0x400];
98 uint32_t d5Queue[0x400];
99 uint32_t d6Queue[0x400];
100 uint32_t d7Queue[0x400];
101 uint32_t srQueue[0x400];
103 bool startM68KTracing = false;
105 // Breakpoint on memory access vars (exported)
106 bool bpmActive = false;
107 uint32_t bpmAddress1;
111 // Callback function to detect illegal instructions
113 void GPUDumpDisassembly(void);
114 void GPUDumpRegisters(void);
115 static bool start = false;
117 void M68KInstructionHook(void)
119 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
120 // Temp, for comparing...
122 /* static char buffer[2048];//, mem[64];
123 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
124 printf("%08X: %s\n", m68kPC, buffer);//*/
126 //JaguarDasm(m68kPC, 1);
127 //Testing Hover Strike...
130 static int hitCount = 0;
131 static int inRoutine = 0;
134 //if (regs.pc == 0x80340A)
135 if (m68kPC == 0x803416)
140 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
142 else if (m68kPC == 0x803422)
145 printf("(%i instructions)\n", instSeen);
152 // For code tracing...
153 #ifdef CPU_DEBUG_TRACING
154 if (startM68KTracing)
156 static char buffer[2048];
158 m68k_disassemble(buffer, m68kPC, 0);
159 WriteLog("%06X: %s\n", m68kPC, buffer);
164 // Ideally, we'd save all the registers as well...
165 pcQueue[pcQPtr] = m68kPC;
166 a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
167 a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
168 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
169 a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
170 a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
171 a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
172 a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
173 a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
174 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
175 d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
176 d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
177 d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
178 d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
179 d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
180 d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
181 d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
182 srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR);
186 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
188 WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
190 static char buffer[2048];
191 for(int i=0; i<0x400; i++)
193 // WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
194 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, SR=%04X]\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], srQueue[(pcQPtr + i) & 0x3FF]);
195 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
196 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
200 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
201 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
202 for(int i=0; i<10; i++)
203 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
204 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
210 // Disassemble everything
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 >= 0x807EC4 && m68kPC <= 0x807EDB)
221 static char buffer[2048];
222 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
223 WriteLog("%08X: %s", m68kPC, buffer);
224 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
225 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
226 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
228 /* if (m68kPC == 0x8D0E48 && effect_start5)
230 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
232 GPUDumpDisassembly();
236 /* uint16_t opcode = JaguarReadWord(m68kPC);
237 if (opcode == 0x4E75) // RTS
240 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
242 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
244 if (raPtr != 0xFFFFFFFF)
246 for(uint32_t i=0; i<=raPtr; i++)
248 if (returnAddr[i] == addr)
257 returnAddr[++raPtr] = addr;
261 //Flip Out! debugging...
264 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
265 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
266 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
267 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
269 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
271 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
272 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
273 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
274 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
275 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
276 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
277 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
279 /* static char buffer[2048];
280 //if (m68kPC > 0x805F48) start = true;
281 //if (m68kPC > 0x806486) start = true;
282 //if (m68kPC == 0x805FEE) start = true;
283 //if (m68kPC == 0x80600C)// start = true;
284 if (m68kPC == 0x802058) start = true;
286 // GPUDumpRegisters();
287 // GPUDumpDisassembly();
289 // M68K_show_context();
295 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
296 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));
299 /* if (m68kPC == 0x803F16)
301 WriteLog("M68K: Registers found at $803F16:\n");
302 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
303 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
304 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
306 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
307 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
309 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
310 // !!! Investigate !!!
311 /*extern bool doDSPDis;
312 static bool disgo = false;
313 if (m68kPC == 0x50222)
316 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
317 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
320 if (m68kPC == 0x5000)
325 static char buffer[2048];
326 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
327 WriteLog("%08X: %s", m68kPC, buffer);
328 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, 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 == 0x82E1A)
334 static char buffer[2048];
335 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
336 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
337 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
338 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
339 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
341 /* if (m68kPC == 0x82E58)
342 WriteLog("--> [Routine end]\n");
343 if (m68kPC == 0x80004)
345 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
346 // m68k_set_reg(M68K_REG_D2, 0x12345678);
349 #ifdef LOG_CD_BIOS_CALLS
372 if (m68kPC == 0x3000)
373 WriteLog("M68K: CD_init\n");
374 else if (m68kPC == 0x3006 + (6 * 0))
375 WriteLog("M68K: CD_mode\n");
376 else if (m68kPC == 0x3006 + (6 * 1))
377 WriteLog("M68K: CD_ack\n");
378 else if (m68kPC == 0x3006 + (6 * 2))
379 WriteLog("M68K: CD_jeri\n");
380 else if (m68kPC == 0x3006 + (6 * 3))
381 WriteLog("M68K: CD_spin\n");
382 else if (m68kPC == 0x3006 + (6 * 4))
383 WriteLog("M68K: CD_stop\n");
384 else if (m68kPC == 0x3006 + (6 * 5))
385 WriteLog("M68K: CD_mute\n");
386 else if (m68kPC == 0x3006 + (6 * 6))
387 WriteLog("M68K: CD_umute\n");
388 else if (m68kPC == 0x3006 + (6 * 7))
389 WriteLog("M68K: CD_paus\n");
390 else if (m68kPC == 0x3006 + (6 * 8))
391 WriteLog("M68K: CD_upaus\n");
392 else if (m68kPC == 0x3006 + (6 * 9))
393 WriteLog("M68K: CD_read\n");
394 else if (m68kPC == 0x3006 + (6 * 10))
395 WriteLog("M68K: CD_uread\n");
396 else if (m68kPC == 0x3006 + (6 * 11))
397 WriteLog("M68K: CD_setup\n");
398 else if (m68kPC == 0x3006 + (6 * 12))
399 WriteLog("M68K: CD_ptr\n");
400 else if (m68kPC == 0x3006 + (6 * 13))
401 WriteLog("M68K: CD_osamp\n");
402 else if (m68kPC == 0x3006 + (6 * 14))
403 WriteLog("M68K: CD_getoc\n");
404 else if (m68kPC == 0x3006 + (6 * 15))
405 WriteLog("M68K: CD_initm\n");
406 else if (m68kPC == 0x3006 + (6 * 16))
407 WriteLog("M68K: CD_initf\n");
408 else if (m68kPC == 0x3006 + (6 * 17))
409 WriteLog("M68K: CD_switch\n");
411 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
412 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
413 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
414 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
417 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
418 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
420 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
421 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
423 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
424 // keep going even when the 68K dumped back to the debugger or what have you).
426 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
427 // Try setting the vector to the illegal instruction...
428 //This doesn't work right either! Do something else! Quick!
429 // SET32(jaguar_mainRam, 0x10, m68kPC);
435 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
436 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
437 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
438 uint32_t address = topOfStack - (4 * 4 * 3);
440 for(int i=0; i<10; i++)
442 WriteLog("%06X:", address);
444 for(int j=0; j<4; j++)
446 WriteLog(" %08X", JaguarReadLong(address));
453 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
457 // WriteLog("\n\n68K disasm\n\n");
458 // jaguar_dasm(0x802000, 0x50C);
469 Now here be dragons...
470 Here is how memory ranges are defined in the CoJag driver.
471 Note that we only have to be concerned with 3 entities read/writing anything:
472 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
473 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
474 things that are entirely internal to those modules. This way we should be able to get a handle on all
475 this crap which is currently scattered over Hell's Half Acre(tm).
477 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
478 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
480 /*************************************
482 * Main CPU memory handlers
484 *************************************/
486 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
487 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
488 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
489 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
490 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
491 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
492 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
493 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
494 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
495 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
496 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
497 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
498 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
499 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
500 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
501 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
502 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
503 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
504 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
505 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
506 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
507 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
508 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
511 /*************************************
513 * GPU memory handlers
515 *************************************/
517 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
518 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
519 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
520 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
521 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
522 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
523 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
524 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
525 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
526 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
527 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
530 /*************************************
532 * DSP memory handlers
534 *************************************/
536 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
537 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
538 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
539 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
540 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
541 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
542 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
543 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
544 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
549 //#define EXPERIMENTAL_MEMORY_HANDLING
550 // Experimental memory mappage...
551 // Dunno if this is a good approach or not, but it seems to make better
552 // sense to have all this crap in one spot intstead of scattered all over
553 // the place the way it is now.
554 #ifdef EXPERIMENTAL_MEMORY_HANDLING
556 #define NEW_TIMER_SYSTEM
559 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
560 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
561 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
562 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
563 bool BIOSLoaded = false;
564 bool CDBIOSLoaded = false;
566 uint8_t cdRAM[0x100];
567 uint8_t tomRAM[0x4000];
568 uint8_t jerryRAM[0x10000];
569 static uint16_t eeprom_ram[64];
571 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
574 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
576 // M68K Memory map/handlers
578 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
579 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
580 // Note that this is really memory mapped I/O region...
581 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
582 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
583 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
584 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
585 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
586 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
587 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
588 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
589 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
590 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
591 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
592 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
594 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
596 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
597 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
598 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
599 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
600 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
601 //What about LBUF writes???
602 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
603 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
604 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
606 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
610 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
611 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
612 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
615 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
616 0 = pad0/1 button values (4 bits each), RO(?)
617 1 = pad0/1 index value (4 bits each), WO
619 3 = NTSC/PAL, certain button states, RO
621 JOYSTICK $F14000 Read/Write
623 Read fedcba98 7654321q f-1 Signals J15 to J1
624 q Cartridge EEPROM output data
625 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
626 0 = disable J7-J0 outputs
629 0 = Audio muted (reset state)
631 7-4 J7-J4 outputs (port 2)
632 3-0 J3-J0 outputs (port 1)
633 JOYBUTS $F14002 Read Only
635 Read xxxxxxxx rrdv3210 x don't care
638 v 1 = NTSC Video hardware
639 0 = PAL Video hardware
640 3-2 Button inputs B3 & B2 (port 2)
641 1-0 Button inputs B1 & B0 (port 1)
643 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
644 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
652 0 1 1 1 Row 3 C3 Option # 9 6 3
656 1 0 1 1 Row 2 C2 C 0 8 5 2
658 1 1 0 1 Row 1 C1 B * 7 4 1
659 1 1 1 0 Row 0 Pause A Up Down Left Right
662 0 bit read in any position means that button is pressed.
663 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
667 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
669 // Not sure, but I think the system only has 24 address bits...
670 address &= 0x00FFFFFF;
672 // RAM ($000000 - $3FFFFF) 4M
673 if (address <= 0x3FFFFF)
674 jaguarMainRAM[address] = byte;
675 // hole ($400000 - $7FFFFF) 4M
676 else if (address <= 0x7FFFFF)
678 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
679 else if (address <= 0xDFFEFF)
681 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
682 else if (address <= 0xDFFFFF)
684 cdRAM[address & 0xFF] = byte;
686 if ((address & 0xFF) < 12 * 4)
687 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
688 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
691 // BIOS ROM ($E00000 - $E3FFFF) 256K
692 else if (address <= 0xE3FFFF)
694 // hole ($E40000 - $EFFFFF) 768K
695 else if (address <= 0xEFFFFF)
697 // TOM ($F00000 - $F0FFFF) 64K
698 else if (address <= 0xF0FFFF)
701 if (address == 0xF00050)
703 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
707 else if (address == 0xF00051)
709 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
713 else if (address == 0xF00052)
715 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
719 else if (address == 0xF00053)
721 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
725 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
727 // Writing to one CLUT writes to the other
728 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
729 tomRAM[address] = tomRAM[address + 0x200] = byte;
732 //What about LBUF writes???
733 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
735 GPUWriteByte(address, byte, who);
738 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
740 BlitterWriteByte(address, byte, who);
743 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
745 GPUWriteByte(address, byte, who);
749 tomRAM[address & 0x3FFF] = byte;
751 // JERRY ($F10000 - $F1FFFF) 64K
752 else if (address <= 0xF1FFFF)
756 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
758 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
760 DSPWriteByte(address, byte, who);
763 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
765 DSPWriteByte(address, byte, who);
768 // SCLK ($F1A150--8 bits wide)
769 //NOTE: This should be taken care of in DAC...
770 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
772 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
773 if ((address & 0x03) == 2)
774 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
776 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
778 JERRYI2SInterruptTimer = -1;
779 #ifndef NEW_TIMER_SYSTEM
782 RemoveCallback(JERRYI2SCallback);
787 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
788 else if (address >= 0xF1A148 && address <= 0xF1A157)
790 DACWriteByte(address, byte, who);
793 else if (address >= 0xF10000 && address <= 0xF10007)
795 #ifndef NEW_TIMER_SYSTEM
796 switch (address & 0x07)
799 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
803 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
807 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
811 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
815 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
819 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
823 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
827 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
831 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
835 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
837 clock_byte_write(offset, byte);
840 // JERRY -> 68K interrupt enables/latches (need to be handled!)
841 else if (address >= 0xF10020 && address <= 0xF10023)
843 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
845 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
847 anajoy_byte_write(offset, byte);
850 else if ((address >= 0xF14000) && (address <= 0xF14003))
852 JoystickWriteByte(address, byte);
853 EepromWriteByte(address, byte);
856 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
858 EepromWriteByte(address, byte);
861 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
862 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
865 jerryRAM[address & 0xFFFF] = byte;
867 // hole ($F20000 - $FFFFFF) 1M - 128K
873 void WriteWord(uint32_t adddress, uint16_t word)
878 void WriteDWord(uint32_t adddress, uint32_t dword)
883 uint8_t ReadByte(uint32_t adddress)
888 uint16_t ReadWord(uint32_t adddress)
893 uint32_t ReadDWord(uint32_t adddress)
899 void ShowM68KContext(void)
901 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
903 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
905 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
907 if (i == M68K_REG_D3 || i == M68K_REG_D7)
911 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
913 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
915 if (i == M68K_REG_A3 || i == M68K_REG_A7)
919 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
920 uint32_t disPC = currpc - 30;
925 uint32_t oldpc = disPC;
926 disPC += m68k_disassemble(buffer, disPC, 0);
927 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
929 while (disPC < (currpc + 10));
934 // Custom UAE 68000 read/write/IRQ functions
941 IPL Name Vector Control
942 ---------+---------------+---------------+---------------
943 2 VBLANK IRQ $100 INT1 bit #0
944 2 GPU IRQ $100 INT1 bit #1
945 2 HBLANK IRQ $100 INT1 bit #2
946 2 Timer IRQ $100 INT1 bit #3
948 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
949 and are therefore indistinguishable.
951 A typical way to install a LEVEL2 handler for the 68000 would be
952 something like this, you gotta supply "last_line" and "handler".
953 Note that the interrupt is auto vectored thru $100 (not $68)
961 IRQS_HANDLED=$909 ;; VBLANK and TIMER
963 move.w #$2700,sr ;; no IRQs please
964 move.l #handler,V_AUTO ;; install our routine
966 move.w #last_line,VI ;; scanline where IRQ should occur
967 ;; should be 'odd' BTW
968 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
969 move.w #$2100,sr ;; enable IRQs on the 68K
987 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
988 move.w #0,INT2 ; let GPU run again
992 As you can see, if you have multiple INT1 interrupts coming in,
993 you need to check the lower byte of INT1, to see which interrupt
996 int irq_ack_handler(int level)
998 #ifdef CPU_DEBUG_TRACING
999 if (startM68KTracing)
1001 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1005 // Tracing the IPL lines on the Jaguar schematic yields the following:
1006 // IPL1 is connected to INTL on TOM (OUT to 68K)
1007 // IPL0-2 are also tied to Vcc via 4.7K resistors!
1008 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
1009 // There doesn't seem to be any other path to IPL0 or 2 on the schematic,
1010 // which means that *all* IRQs to the 68K are routed thru TOM at level 2.
1011 // Which means they're all maskable.
1013 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work
1015 // They aren't, and this causes problems with a, err, specific ROM. :-D
1019 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1020 return 64; // Set user interrupt #0
1023 return M68K_INT_ACK_AUTOVECTOR;
1027 //#define USE_NEW_MMU
1029 unsigned int m68k_read_memory_8(unsigned int address)
1031 #ifdef ALPINE_FUNCTIONS
1032 // Check if breakpoint on memory is active, and deal with it
1033 if (bpmActive && address == bpmAddress1)
1037 // Musashi does this automagically for you, UAE core does not :-P
1038 address &= 0x00FFFFFF;
1039 #ifdef CPU_DEBUG_MEMORY
1040 // Note that the Jaguar only has 2M of RAM, not 4!
1041 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1044 readMem[address] = 1;
1047 //WriteLog("[RM8] Addr: %08X\n", address);
1048 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1049 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1050 || address == 0x1AF05E)
1051 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1053 unsigned int retVal = 0;
1055 // Note that the Jaguar only has 2M of RAM, not 4!
1056 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1057 retVal = jaguarMainRAM[address];
1058 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1059 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1060 retVal = jaguarMainROM[address - 0x800000];
1061 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1062 // retVal = jaguarBootROM[address - 0xE00000];
1063 // retVal = jaguarDevBootROM1[address - 0xE00000];
1064 retVal = jagMemSpace[address];
1065 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1066 retVal = CDROMReadByte(address);
1067 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1068 retVal = TOMReadByte(address, M68K);
1069 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1070 retVal = JERRYReadByte(address, M68K);
1072 retVal = jaguar_unknown_readbyte(address, M68K);
1074 //if (address >= 0x2800 && address <= 0x281F)
1075 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1076 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1077 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1080 return MMURead8(address, M68K);
1085 void gpu_dump_disassembly(void);
1086 void gpu_dump_registers(void);
1088 unsigned int m68k_read_memory_16(unsigned int address)
1090 #ifdef ALPINE_FUNCTIONS
1091 // Check if breakpoint on memory is active, and deal with it
1092 if (bpmActive && address == bpmAddress1)
1096 // Musashi does this automagically for you, UAE core does not :-P
1097 address &= 0x00FFFFFF;
1098 #ifdef CPU_DEBUG_MEMORY
1099 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1102 readMem[address] = 1, readMem[address + 1] = 1;
1104 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1106 return 0x4E71; // NOP
1108 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1110 return 0x4E71; // NOP
1112 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1114 return 0x4E71; // NOP
1116 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1118 return 0x4E71; // NOP
1120 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1122 return 0x4E71; // NOP
1124 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1126 return 0x4E71; // NOP
1129 //WriteLog("[RM16] Addr: %08X\n", address);
1130 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1131 // for(int i=0; i<10000; i++)
1132 WriteLog("[M68K] In routine #6!\n");//*/
1133 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1134 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1135 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1137 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1138 gpu_dump_registers();
1139 gpu_dump_disassembly();
1140 // for(int i=0; i<10000; i++)
1141 // WriteLog("[M68K] About to run GPU!\n");
1143 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1144 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1146 if (address == 0x000066A0)
1148 gpu_dump_registers();
1149 gpu_dump_disassembly();
1151 for(int i=0; i<10000; i++)
1152 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1154 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1155 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1156 || address == 0x1AF05E)
1157 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1159 unsigned int retVal = 0;
1161 // Note that the Jaguar only has 2M of RAM, not 4!
1162 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1163 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1164 retVal = GET16(jaguarMainRAM, address);
1165 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1166 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1168 // Memory Track reading...
1169 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1171 retVal = MTReadWord(address);
1174 retVal = (jaguarMainROM[address - 0x800000] << 8)
1175 | jaguarMainROM[address - 0x800000 + 1];
1177 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1178 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1179 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1180 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1181 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1182 retVal = CDROMReadWord(address, M68K);
1183 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1184 retVal = TOMReadWord(address, M68K);
1185 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1186 retVal = JERRYReadWord(address, M68K);
1188 retVal = jaguar_unknown_readword(address, M68K);
1190 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1191 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1192 //if (address >= 0x2800 && address <= 0x281F)
1193 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1194 //$8B3AE -> Transferred from $F1C010
1195 //$8B5E4 -> Only +1 read at $808AA
1196 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1197 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1200 return MMURead16(address, M68K);
1205 unsigned int m68k_read_memory_32(unsigned int address)
1207 #ifdef ALPINE_FUNCTIONS
1208 // Check if breakpoint on memory is active, and deal with it
1209 if (bpmActive && address == bpmAddress1)
1213 // Musashi does this automagically for you, UAE core does not :-P
1214 address &= 0x00FFFFFF;
1215 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1216 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1217 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));//*/
1219 //WriteLog("--> [RM32]\n");
1221 uint32_t retVal = 0;
1223 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1225 // Memory Track reading...
1226 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1227 retVal = MTReadLong(address);
1229 retVal = GET32(jaguarMainROM, address - 0x800000);
1234 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1236 return MMURead32(address, M68K);
1241 void m68k_write_memory_8(unsigned int address, unsigned int value)
1243 #ifdef ALPINE_FUNCTIONS
1244 // Check if breakpoint on memory is active, and deal with it
1245 if (bpmActive && address == bpmAddress1)
1249 // Musashi does this automagically for you, UAE core does not :-P
1250 address &= 0x00FFFFFF;
1251 #ifdef CPU_DEBUG_MEMORY
1252 // Note that the Jaguar only has 2M of RAM, not 4!
1253 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1257 if (value > writeMemMax[address])
1258 writeMemMax[address] = value;
1259 if (value < writeMemMin[address])
1260 writeMemMin[address] = value;
1264 /*if (address == 0x4E00)
1265 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1266 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1267 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1268 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1270 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1271 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1273 /*if (address >= 0x53D0 && address <= 0x53FF)
1274 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1275 //Testing AvP on UAE core...
1276 //000075A0: FFFFF80E B6320220 (BITMAP)
1277 /*if (address == 0x75A0 && value == 0xFF)
1278 printf("M68K: (8) Tripwire hit...\n");//*/
1281 // Note that the Jaguar only has 2M of RAM, not 4!
1282 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1283 jaguarMainRAM[address] = value;
1284 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1285 CDROMWriteByte(address, value, M68K);
1286 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1287 TOMWriteByte(address, value, M68K);
1288 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1289 JERRYWriteByte(address, value, M68K);
1291 jaguar_unknown_writebyte(address, value, M68K);
1293 MMUWrite8(address, value, M68K);
1298 void m68k_write_memory_16(unsigned int address, unsigned int value)
1300 #ifdef ALPINE_FUNCTIONS
1301 // Check if breakpoint on memory is active, and deal with it
1302 if (bpmActive && address == bpmAddress1)
1306 // Musashi does this automagically for you, UAE core does not :-P
1307 address &= 0x00FFFFFF;
1308 #ifdef CPU_DEBUG_MEMORY
1309 // Note that the Jaguar only has 2M of RAM, not 4!
1310 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1314 uint8_t hi = value >> 8, lo = value & 0xFF;
1316 if (hi > writeMemMax[address])
1317 writeMemMax[address] = hi;
1318 if (hi < writeMemMin[address])
1319 writeMemMin[address] = hi;
1321 if (lo > writeMemMax[address+1])
1322 writeMemMax[address+1] = lo;
1323 if (lo < writeMemMin[address+1])
1324 writeMemMin[address+1] = lo;
1328 /*if (address == 0x4E00)
1329 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1330 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1331 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1332 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1333 //if (address >= 0xF02200 && address <= 0xF0229F)
1334 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1335 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1336 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1337 /*extern uint32_t totalFrames;
1338 if (address == 0xF02114)
1339 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1340 if (address == 0xF02110)
1341 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1342 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1343 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1345 /*if (address == 0x0100)//64*4)
1346 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1348 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1349 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1350 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1351 || address == 0x1AF05E)
1352 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1354 /*if (address >= 0x53D0 && address <= 0x53FF)
1355 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1356 //Testing AvP on UAE core...
1357 //000075A0: FFFFF80E B6320220 (BITMAP)
1358 /*if (address == 0x75A0 && value == 0xFFFF)
1360 printf("\nM68K: (16) Tripwire hit...\n");
1365 // Note that the Jaguar only has 2M of RAM, not 4!
1366 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1368 /* jaguar_mainRam[address] = value >> 8;
1369 jaguar_mainRam[address + 1] = value & 0xFF;*/
1370 SET16(jaguarMainRAM, address, value);
1372 // Memory Track device writes....
1373 else if ((address >= 0x800000) && (address <= 0x87FFFE))
1375 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1376 MTWriteWord(address, value);
1378 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1379 CDROMWriteWord(address, value, M68K);
1380 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1381 TOMWriteWord(address, value, M68K);
1382 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1383 JERRYWriteWord(address, value, M68K);
1386 jaguar_unknown_writeword(address, value, M68K);
1387 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1388 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1389 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1390 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1394 MMUWrite16(address, value, M68K);
1399 void m68k_write_memory_32(unsigned int address, unsigned int value)
1401 #ifdef ALPINE_FUNCTIONS
1402 // Check if breakpoint on memory is active, and deal with it
1403 if (bpmActive && address == bpmAddress1)
1407 // Musashi does this automagically for you, UAE core does not :-P
1408 address &= 0x00FFFFFF;
1409 /*if (address == 0x4E00)
1410 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1411 //WriteLog("--> [WM32]\n");
1412 /*if (address == 0x0100)//64*4)
1413 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1414 /*if (address >= 0xF03214 && address < 0xF0321F)
1415 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1416 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1417 /*extern bool doGPUDis;
1418 if (address == 0xF03214 && value == 0x88E30047)
1420 doGPUDis = true;//*/
1421 /* if (address == 0x51136 || address == 0xFB074)
1422 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1423 //Testing AvP on UAE core...
1424 //000075A0: FFFFF80E B6320220 (BITMAP)
1425 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1427 printf("\nM68K: (32) Tripwire hit...\n");
1432 m68k_write_memory_16(address, value >> 16);
1433 m68k_write_memory_16(address + 2, value & 0xFFFF);
1435 MMUWrite32(address, value, M68K);
1440 uint32_t JaguarGetHandler(uint32_t i)
1442 return JaguarReadLong(i * 4);
1446 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1448 uint32_t handler = JaguarGetHandler(i);
1449 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1453 void M68K_show_context(void)
1455 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1457 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1459 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1461 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1465 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1467 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1469 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1473 WriteLog("68K disasm\n");
1474 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1475 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1476 // jaguar_dasm(0x5000, 0x14414);
1478 // WriteLog("\n.......[Cart start]...........\n\n");
1479 // jaguar_dasm(0x192000, 0x1000);//0x200);
1481 WriteLog("..................\n");
1483 if (TOMIRQEnabled(IRQ_VIDEO))
1485 WriteLog("video int: enabled\n");
1486 JaguarDasm(JaguarGetHandler(64), 0x200);
1489 WriteLog("video int: disabled\n");
1491 WriteLog("..................\n");
1493 for(int i=0; i<256; i++)
1495 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1496 uint32_t address = (uint32_t)JaguarGetHandler(i);
1499 WriteLog(".........\n");
1501 WriteLog("$%08X\n", address);
1507 // Unknown read/write byte/word routines
1510 // It's hard to believe that developers would be sloppy with their memory
1511 // writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1512 // has the following code:
1514 // 807EC4: movea.l #$f1b000, A1
1515 // 807ECA: movea.l #$8129e0, A0
1516 // 807ED0: move.l A0, D0
1517 // 807ED2: move.l #$f1bb94, D1
1518 // 807ED8: sub.l D0, D1
1519 // 807EDA: lsr.l #2, D1
1520 // 807EDC: move.l (A0)+, (A1)+
1521 // 807EDE: dbra D1, 807edc
1523 // The problem is at $807ED0--instead of putting A0 into D0, they really meant
1524 // to put A1 in. This mistake causes it to try and overwrite approximately
1525 // $700000 worth of address space! (That is, unless the 68K causes a bus
1528 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1530 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1531 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));
1533 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1534 // extern bool finished;
1536 // extern bool doDSPDis;
1543 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1545 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1546 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));
1548 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1549 // extern bool finished;
1551 // extern bool doDSPDis;
1558 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1560 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1561 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1563 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1564 // extern bool finished;
1566 // extern bool doDSPDis;
1574 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1576 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1577 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1579 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1580 // extern bool finished;
1582 // extern bool doDSPDis;
1591 // Disassemble M68K instructions at the given offset
1594 unsigned int m68k_read_disassembler_8(unsigned int address)
1596 return m68k_read_memory_8(address);
1600 unsigned int m68k_read_disassembler_16(unsigned int address)
1602 return m68k_read_memory_16(address);
1606 unsigned int m68k_read_disassembler_32(unsigned int address)
1608 return m68k_read_memory_32(address);
1612 void JaguarDasm(uint32_t offset, uint32_t qt)
1615 static char buffer[2048];//, mem[64];
1616 int pc = offset, oldpc;
1618 for(uint32_t i=0; i<qt; i++)
1621 for(int j=0; j<64; j++)
1622 mem[j^0x01] = jaguar_byte_read(pc + j);
1624 pc += Dasm68000((char *)mem, buffer, 0);
1625 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1627 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1628 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1634 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1636 uint8_t data = 0x00;
1639 // First 2M is mirrored in the $0 - $7FFFFF range
1640 if (offset < 0x800000)
1641 data = jaguarMainRAM[offset & 0x1FFFFF];
1642 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1643 data = jaguarMainROM[offset - 0x800000];
1644 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1645 data = CDROMReadByte(offset, who);
1646 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1647 // data = jaguarBootROM[offset & 0x3FFFF];
1648 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1649 data = jagMemSpace[offset];
1650 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1651 data = TOMReadByte(offset, who);
1652 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1653 data = JERRYReadByte(offset, who);
1655 data = jaguar_unknown_readbyte(offset, who);
1661 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1665 // First 2M is mirrored in the $0 - $7FFFFF range
1666 if (offset < 0x800000)
1668 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1670 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1673 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1675 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1676 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1677 return CDROMReadWord(offset, who);
1678 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1679 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1680 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1681 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1682 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1683 return TOMReadWord(offset, who);
1684 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1685 return JERRYReadWord(offset, who);
1687 return jaguar_unknown_readword(offset, who);
1691 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1693 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1695 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
1697 /* if (offset >= 0x4E00 && offset < 0x4E04)
1698 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1699 //Need to check for writes in the range of $18FA70 + 8000...
1701 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1702 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1706 // First 2M is mirrored in the $0 - $7FFFFF range
1707 if (offset < 0x800000)
1709 jaguarMainRAM[offset & 0x1FFFFF] = data;
1712 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1714 CDROMWriteByte(offset, data, who);
1717 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1719 TOMWriteByte(offset, data, who);
1722 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1724 JERRYWriteByte(offset, data, who);
1728 jaguar_unknown_writebyte(offset, data, who);
1733 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1735 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1737 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
1738 WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
1740 /* if (offset >= 0x4E00 && offset < 0x4E04)
1741 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1742 /*if (offset == 0x0100)//64*4)
1743 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1744 if (offset == 0x0102)//64*4)
1745 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1746 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1747 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1748 //Need to check for writes in the range of $18FA70 + 8000...
1750 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1751 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1752 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1753 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1757 // First 2M is mirrored in the $0 - $7FFFFF range
1758 if (offset <= 0x7FFFFE)
1763 1A 69 F0 ($0000) -> Starfield
1764 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1767 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1776 //This MUST be done by the 68K!
1777 /*if (offset == 0x670C)
1778 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1780 /*extern bool doGPUDis;
1781 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1782 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1783 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1784 doGPUDis = true;//*/
1785 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1786 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1787 if ((data & 0xFF00) != 0x7700)
1788 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1789 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1791 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1792 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1793 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1795 /*extern bool doGPUDis;
1796 if (offset == 0x120216 && who == GPU)
1797 doGPUDis = true;//*/
1798 /*extern uint32_t gpu_pc;
1799 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1801 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1802 uint32_t y = base / 0x300;
1803 uint32_t x = (base - (y * 0x300)) / 2;
1804 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1807 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1809 //if (offset == (0x001E17F8 + 0x34))
1810 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1812 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1813 /*extern uint32_t gpu_pc;
1814 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1816 extern int objectPtr;
1817 // if (offset > 0x148000)
1820 if (starCount > objectPtr)
1823 // if (starCount == 1)
1824 // WriteLog("--> Drawing 1st star...\n");
1826 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1827 // uint32_t y = base / 0x300;
1828 // uint32_t x = (base - (y * 0x300)) / 2;
1829 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1831 //A star of interest...
1832 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1833 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1834 //JWW: Blitter writing echo 77B3 at 0011D022...
1836 //extern bool doGPUDis;
1837 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1840 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1843 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1844 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1846 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1847 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1850 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1852 CDROMWriteWord(offset, data, who);
1855 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1857 TOMWriteWord(offset, data, who);
1860 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1862 JERRYWriteWord(offset, data, who);
1865 // Don't bomb on attempts to write to ROM
1866 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1869 jaguar_unknown_writeword(offset, data, who);
1873 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1874 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1876 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1880 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1881 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1883 /* extern bool doDSPDis;
1884 if (offset < 0x400 && !doDSPDis)
1886 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1889 /*if (offset == 0x0100)//64*4)
1890 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1892 JaguarWriteWord(offset, data >> 16, who);
1893 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1897 void JaguarSetScreenBuffer(uint32_t * buffer)
1899 // This is in TOM, but we set it here...
1900 screenBuffer = buffer;
1904 void JaguarSetScreenPitch(uint32_t pitch)
1906 // This is in TOM, but we set it here...
1907 screenPitch = pitch;
1912 // Jaguar console initialization
1914 void JaguarInit(void)
1916 // For randomizing RAM
1919 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1920 for(uint32_t i=0; i<0x200000; i+=4)
1921 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1923 #ifdef CPU_DEBUG_MEMORY
1924 memset(readMem, 0x00, 0x400000);
1925 memset(writeMemMin, 0xFF, 0x400000);
1926 memset(writeMemMax, 0x00, 0x400000);
1928 // memset(jaguarMainRAM, 0x00, 0x200000);
1929 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1930 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1931 //NOTE: This *doesn't* fix FlipOut...
1932 //Or does it? Hmm...
1933 //Seems to want $01010101... Dunno why. Investigate!
1934 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1935 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1936 lowerField = false; // Reset the lower field flag
1937 //temp, for crappy crap that sux
1938 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1940 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1949 //New timer based code stuffola...
1950 void HalflineCallback(void);
1951 void RenderCallback(void);
1952 void JaguarReset(void)
1954 // Only problem with this approach: It wipes out RAM loaded files...!
1955 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1956 for(uint32_t i=8; i<0x200000; i+=4)
1957 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1959 // New timer base code stuffola...
1960 InitializeEventList();
1961 //Need to change this so it uses the single RAM space and load the BIOS
1962 //into it somewhere...
1963 //Also, have to change this here and in JaguarReadXX() currently
1964 // Only use the system BIOS if it's available...! (it's always available now!)
1965 // AND only if a jaguar cartridge has been inserted.
1966 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1967 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1969 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1971 // WriteLog("jaguar_reset():\n");
1977 m68k_pulse_reset(); // Reset the 68000
1978 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1980 lowerField = false; // Reset the lower field flag
1981 // SetCallbackTime(ScanlineCallback, 63.5555);
1982 // SetCallbackTime(ScanlineCallback, 31.77775);
1983 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1987 void JaguarDone(void)
1989 #ifdef CPU_DEBUG_MEMORY
1990 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1992 for(uint32_t i=0; i<=raPtr; i++)
1994 WriteLog("\t%08X\n", returnAddr[i]);
1995 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1996 jaguar_dasm(returnAddr[i] - 16, 16);
2001 /* int start = 0, end = 0;
2002 bool endTriggered = false, startTriggered = false;
2003 for(int i=0; i<0x400000; i++)
2005 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
2007 if (!startTriggered)
2008 startTriggered = true, endTriggered = false, start = i;
2010 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
2016 end = i - 1, endTriggered = true, startTriggered = false;
2017 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
2024 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
2025 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
2026 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
2027 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2029 for(int i=-2; i<9; i++)
2030 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2032 uint32_t address = topOfStack - (4 * 4 * 3);
2034 for(int i=0; i<10; i++)
2036 WriteLog("%06X:", address);
2038 for(int j=0; j<4; j++)
2040 WriteLog(" %08X", JaguarReadLong(address));
2048 /* WriteLog("\nM68000 disassembly at $802288...\n");
2049 jaguar_dasm(0x802288, 3);
2050 WriteLog("\nM68000 disassembly at $802200...\n");
2051 jaguar_dasm(0x802200, 500);
2052 WriteLog("\nM68000 disassembly at $802518...\n");
2053 jaguar_dasm(0x802518, 100);//*/
2055 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2056 jaguar_dasm(0x803F00, 500);
2059 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2060 jaguar_dasm(0x802B00, 500);
2063 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2064 jaguar_dasm(0x809900, 500);
2067 /* WriteLog("\n\nDump of $8093C8:\n\n");
2068 for(int i=0x8093C8; i<0x809900; i+=4)
2069 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2070 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2071 jaguar_dasm(0x90006C, 500);
2073 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2074 jaguar_dasm(0x1AC000, 6000);
2077 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2078 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2079 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2080 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2081 M68K_show_context();
2090 // temp, until debugger is in place
2091 //00802016: jsr $836F1A.l
2092 //0080201C: jsr $836B30.l
2093 //00802022: jsr $836B18.l
2094 //00802028: jsr $8135F0.l
2095 //00813C1E: jsr $813F76.l
2096 //00802038: jsr $836D00.l
2097 //00802098: jsr $8373A4.l
2098 //008020A2: jsr $83E24A.l
2099 //008020BA: jsr $83E156.l
2100 //008020C6: jsr $83E19C.l
2101 //008020E6: jsr $8445E8.l
2102 //008020EC: jsr $838C20.l
2103 //0080211A: jsr $838ED6.l
2104 //00802124: jsr $89CA56.l
2105 //0080212A: jsr $802B48.l
2107 WriteLog("-------------------------------------------\n");
2108 JaguarDasm(0x8445E8, 0x200);
2109 WriteLog("-------------------------------------------\n");
2110 JaguarDasm(0x838C20, 0x200);
2111 WriteLog("-------------------------------------------\n");
2112 JaguarDasm(0x838ED6, 0x200);
2113 WriteLog("-------------------------------------------\n");
2114 JaguarDasm(0x89CA56, 0x200);
2115 WriteLog("-------------------------------------------\n");
2116 JaguarDasm(0x802B48, 0x200);
2117 WriteLog("\n\nM68000 disassembly at $802000...\n");
2118 JaguarDasm(0x802000, 6000);
2121 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2122 JaguarDasm(0x6004, 10000);
2124 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2125 // JaguarDasm(0x802000, 0x1000);
2126 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2127 // JaguarDasm(0x4100, 200);
2128 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2129 // JaguarDasm(0x800800, 0x1000);
2133 // Temp debugging stuff
2135 void DumpMainMemory(void)
2137 FILE * fp = fopen("./memdump.bin", "wb");
2142 fwrite(jaguarMainRAM, 1, 0x200000, fp);
2147 uint8_t * GetRamPtr(void)
2149 return jaguarMainRAM;
2154 // New Jaguar execution stack
2155 // This executes 1 frame's worth of code.
2158 void JaguarExecuteNew(void)
2164 double timeToNextEvent = GetTimeToNextEvent();
2165 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2167 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2170 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2179 // The thing to keep in mind is that the VC is advanced every HALF line,
2180 // regardless of whether the display is interlaced or not. The only difference
2181 // with an interlaced display is that the high bit of VC will be set when the
2182 // lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2183 // lower field, regardless of whether it's in interlace mode or not.
2184 // NB2: Seems it doesn't always, not sure what the constraint is...)
2186 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2187 // rendering two fields that are slighty vertically offset from each other.
2188 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2189 // is rendered in this mode so that each field, when overlaid on each other,
2190 // will yield the final picture at the full resolution for the full frame.
2192 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2193 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2194 // it will be half this number for a half frame. BUT, since we're counting
2195 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2198 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2199 // Half line times are, naturally, half of this. :-P
2201 void HalflineCallback(void)
2203 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2204 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2205 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2206 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2209 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2210 // So we cut the number of half-lines in a frame in half. :-P
2211 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2213 if ((vc & 0x7FF) >= numHalfLines)
2215 lowerField = !lowerField;
2216 // If we're rendering the lower field, set the high bit (#11, counting
2218 vc = (lowerField ? 0x0800 : 0x0000);
2221 //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2222 TOMWriteWord(0xF00006, vc, JAGUAR);
2224 // Time for Vertical Interrupt?
2225 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2227 // We don't have to worry about autovectors & whatnot because the Jaguar
2228 // tells you through its HW registers who sent the interrupt...
2229 TOMSetPendingVideoInt();
2233 TOMExecHalfline(vc, true);
2235 //Change this to VBB???
2236 //Doesn't seem to matter (at least for Flip Out & I-War)
2237 if ((vc & 0x7FF) == 0)
2244 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));