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
48 #define ALPINE_FUNCTIONS
50 // Private function prototypes
52 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
53 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
54 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
55 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
56 void M68K_show_context(void);
60 #ifdef CPU_DEBUG_MEMORY
61 extern bool startMemLog; // Set by "e" key
62 extern int effect_start;
63 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
66 // Really, need to include memory.h for this, but it might interfere with some stuff...
67 extern uint8_t jagMemSpace[];
71 uint32_t jaguar_active_memory_dumps = 0;
73 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
74 bool jaguarCartInserted = false;
75 bool lowerField = false;
77 #ifdef CPU_DEBUG_MEMORY
78 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
79 uint8_t readMem[0x400000];
80 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
83 uint32_t pcQueue[0x400];
84 uint32_t a0Queue[0x400];
85 uint32_t a1Queue[0x400];
86 uint32_t a2Queue[0x400];
87 uint32_t a3Queue[0x400];
88 uint32_t a4Queue[0x400];
89 uint32_t a5Queue[0x400];
90 uint32_t a6Queue[0x400];
91 uint32_t a7Queue[0x400];
92 uint32_t d0Queue[0x400];
93 uint32_t d1Queue[0x400];
94 uint32_t d2Queue[0x400];
95 uint32_t d3Queue[0x400];
96 uint32_t d4Queue[0x400];
97 uint32_t d5Queue[0x400];
98 uint32_t d6Queue[0x400];
99 uint32_t d7Queue[0x400];
101 bool startM68KTracing = false;
103 // Breakpoint on memory access vars (exported)
104 bool bpmActive = false;
105 uint32_t bpmAddress1;
109 // Callback function to detect illegal instructions
111 void GPUDumpDisassembly(void);
112 void GPUDumpRegisters(void);
113 static bool start = false;
115 void M68KInstructionHook(void)
117 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
118 // Temp, for comparing...
120 /* static char buffer[2048];//, mem[64];
121 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
122 printf("%08X: %s\n", m68kPC, buffer);//*/
124 //JaguarDasm(m68kPC, 1);
125 //Testing Hover Strike...
128 static int hitCount = 0;
129 static int inRoutine = 0;
132 //if (regs.pc == 0x80340A)
133 if (m68kPC == 0x803416)
138 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
140 else if (m68kPC == 0x803422)
143 printf("(%i instructions)\n", instSeen);
150 // For code tracing...
151 #ifdef CPU_DEBUG_TRACING
152 if (startM68KTracing)
154 static char buffer[2048];
156 m68k_disassemble(buffer, m68kPC, 0);
157 WriteLog("%06X: %s\n", m68kPC, buffer);
162 // Ideally, we'd save all the registers as well...
163 pcQueue[pcQPtr] = m68kPC;
164 a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
165 a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
166 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
167 a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
168 a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
169 a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
170 a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
171 a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
172 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
173 d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
174 d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
175 d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
176 d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
177 d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
178 d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
179 d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
183 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
185 WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
187 static char buffer[2048];
188 for(int i=0; i<0x400; i++)
190 // WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
191 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]);
192 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
193 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
197 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
198 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
199 for(int i=0; i<10; i++)
200 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
201 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
207 // Disassemble everything
209 static char buffer[2048];
210 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
211 WriteLog("%08X: %s", m68kPC, buffer);
212 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
213 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
214 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
216 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
218 static char buffer[2048];
219 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
220 WriteLog("%08X: %s", m68kPC, buffer);
221 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
222 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
223 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
225 /* if (m68kPC == 0x8D0E48 && effect_start5)
227 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
229 GPUDumpDisassembly();
233 /* uint16_t opcode = JaguarReadWord(m68kPC);
234 if (opcode == 0x4E75) // RTS
237 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
239 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
241 if (raPtr != 0xFFFFFFFF)
243 for(uint32_t i=0; i<=raPtr; i++)
245 if (returnAddr[i] == addr)
254 returnAddr[++raPtr] = addr;
258 //Flip Out! debugging...
261 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
262 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
263 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
264 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
266 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
268 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
269 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
270 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
271 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
272 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
273 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
274 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
276 /* static char buffer[2048];
277 //if (m68kPC > 0x805F48) start = true;
278 //if (m68kPC > 0x806486) start = true;
279 //if (m68kPC == 0x805FEE) start = true;
280 //if (m68kPC == 0x80600C)// start = true;
281 if (m68kPC == 0x802058) start = true;
283 // GPUDumpRegisters();
284 // GPUDumpDisassembly();
286 // M68K_show_context();
292 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
293 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));
296 /* if (m68kPC == 0x803F16)
298 WriteLog("M68K: Registers found at $803F16:\n");
299 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
300 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
301 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
303 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
304 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
306 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
307 // !!! Investigate !!!
308 /*extern bool doDSPDis;
309 static bool disgo = false;
310 if (m68kPC == 0x50222)
313 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
314 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
317 if (m68kPC == 0x5000)
322 static char buffer[2048];
323 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
324 WriteLog("%08X: %s", m68kPC, buffer);
325 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
326 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
327 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
329 /* if (m68kPC == 0x82E1A)
331 static char buffer[2048];
332 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
333 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
334 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
335 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
336 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
338 /* if (m68kPC == 0x82E58)
339 WriteLog("--> [Routine end]\n");
340 if (m68kPC == 0x80004)
342 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
343 // m68k_set_reg(M68K_REG_D2, 0x12345678);
346 #ifdef LOG_CD_BIOS_CALLS
369 if (m68kPC == 0x3000)
370 WriteLog("M68K: CD_init\n");
371 else if (m68kPC == 0x3006 + (6 * 0))
372 WriteLog("M68K: CD_mode\n");
373 else if (m68kPC == 0x3006 + (6 * 1))
374 WriteLog("M68K: CD_ack\n");
375 else if (m68kPC == 0x3006 + (6 * 2))
376 WriteLog("M68K: CD_jeri\n");
377 else if (m68kPC == 0x3006 + (6 * 3))
378 WriteLog("M68K: CD_spin\n");
379 else if (m68kPC == 0x3006 + (6 * 4))
380 WriteLog("M68K: CD_stop\n");
381 else if (m68kPC == 0x3006 + (6 * 5))
382 WriteLog("M68K: CD_mute\n");
383 else if (m68kPC == 0x3006 + (6 * 6))
384 WriteLog("M68K: CD_umute\n");
385 else if (m68kPC == 0x3006 + (6 * 7))
386 WriteLog("M68K: CD_paus\n");
387 else if (m68kPC == 0x3006 + (6 * 8))
388 WriteLog("M68K: CD_upaus\n");
389 else if (m68kPC == 0x3006 + (6 * 9))
390 WriteLog("M68K: CD_read\n");
391 else if (m68kPC == 0x3006 + (6 * 10))
392 WriteLog("M68K: CD_uread\n");
393 else if (m68kPC == 0x3006 + (6 * 11))
394 WriteLog("M68K: CD_setup\n");
395 else if (m68kPC == 0x3006 + (6 * 12))
396 WriteLog("M68K: CD_ptr\n");
397 else if (m68kPC == 0x3006 + (6 * 13))
398 WriteLog("M68K: CD_osamp\n");
399 else if (m68kPC == 0x3006 + (6 * 14))
400 WriteLog("M68K: CD_getoc\n");
401 else if (m68kPC == 0x3006 + (6 * 15))
402 WriteLog("M68K: CD_initm\n");
403 else if (m68kPC == 0x3006 + (6 * 16))
404 WriteLog("M68K: CD_initf\n");
405 else if (m68kPC == 0x3006 + (6 * 17))
406 WriteLog("M68K: CD_switch\n");
408 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
409 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
410 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
411 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
414 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
415 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
417 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
418 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
420 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
421 // keep going even when the 68K dumped back to the debugger or what have you).
423 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
424 // Try setting the vector to the illegal instruction...
425 //This doesn't work right either! Do something else! Quick!
426 // SET32(jaguar_mainRam, 0x10, m68kPC);
432 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
433 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
434 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
435 uint32_t address = topOfStack - (4 * 4 * 3);
437 for(int i=0; i<10; i++)
439 WriteLog("%06X:", address);
441 for(int j=0; j<4; j++)
443 WriteLog(" %08X", JaguarReadLong(address));
450 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
454 // WriteLog("\n\n68K disasm\n\n");
455 // jaguar_dasm(0x802000, 0x50C);
466 Now here be dragons...
467 Here is how memory ranges are defined in the CoJag driver.
468 Note that we only have to be concerned with 3 entities read/writing anything:
469 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
470 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
471 things that are entirely internal to those modules. This way we should be able to get a handle on all
472 this crap which is currently scattered over Hell's Half Acre(tm).
474 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
475 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
477 /*************************************
479 * Main CPU memory handlers
481 *************************************/
483 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
484 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
485 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
486 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
487 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
488 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
489 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
490 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
491 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
492 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
493 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
494 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
495 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
496 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
497 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
498 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
499 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
500 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
501 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
502 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
503 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
504 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
505 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
508 /*************************************
510 * GPU memory handlers
512 *************************************/
514 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
515 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
516 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
517 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
518 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
519 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
520 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
521 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
522 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
523 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
524 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
527 /*************************************
529 * DSP memory handlers
531 *************************************/
533 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
534 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
535 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
536 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
537 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
538 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
539 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
540 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
541 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
546 //#define EXPERIMENTAL_MEMORY_HANDLING
547 // Experimental memory mappage...
548 // Dunno if this is a good approach or not, but it seems to make better
549 // sense to have all this crap in one spot intstead of scattered all over
550 // the place the way it is now.
551 #ifdef EXPERIMENTAL_MEMORY_HANDLING
553 #define NEW_TIMER_SYSTEM
556 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
557 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
558 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
559 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
560 bool BIOSLoaded = false;
561 bool CDBIOSLoaded = false;
563 uint8_t cdRAM[0x100];
564 uint8_t tomRAM[0x4000];
565 uint8_t jerryRAM[0x10000];
566 static uint16_t eeprom_ram[64];
568 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
571 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
573 // M68K Memory map/handlers
575 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
576 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
577 // Note that this is really memory mapped I/O region...
578 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
579 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
580 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
581 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
582 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
583 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
584 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
585 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
586 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
587 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
588 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
589 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
591 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
593 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
594 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
595 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
596 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
597 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
598 //What about LBUF writes???
599 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
600 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
601 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
603 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
607 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
608 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
609 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
612 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
613 0 = pad0/1 button values (4 bits each), RO(?)
614 1 = pad0/1 index value (4 bits each), WO
616 3 = NTSC/PAL, certain button states, RO
618 JOYSTICK $F14000 Read/Write
620 Read fedcba98 7654321q f-1 Signals J15 to J1
621 q Cartridge EEPROM output data
622 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
623 0 = disable J7-J0 outputs
626 0 = Audio muted (reset state)
628 7-4 J7-J4 outputs (port 2)
629 3-0 J3-J0 outputs (port 1)
630 JOYBUTS $F14002 Read Only
632 Read xxxxxxxx rrdv3210 x don't care
635 v 1 = NTSC Video hardware
636 0 = PAL Video hardware
637 3-2 Button inputs B3 & B2 (port 2)
638 1-0 Button inputs B1 & B0 (port 1)
640 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
641 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
649 0 1 1 1 Row 3 C3 Option # 9 6 3
653 1 0 1 1 Row 2 C2 C 0 8 5 2
655 1 1 0 1 Row 1 C1 B * 7 4 1
656 1 1 1 0 Row 0 Pause A Up Down Left Right
659 0 bit read in any position means that button is pressed.
660 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
664 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
666 // Not sure, but I think the system only has 24 address bits...
667 address &= 0x00FFFFFF;
669 // RAM ($000000 - $3FFFFF) 4M
670 if (address <= 0x3FFFFF)
671 jaguarMainRAM[address] = byte;
672 // hole ($400000 - $7FFFFF) 4M
673 else if (address <= 0x7FFFFF)
675 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
676 else if (address <= 0xDFFEFF)
678 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
679 else if (address <= 0xDFFFFF)
681 cdRAM[address & 0xFF] = byte;
683 if ((address & 0xFF) < 12 * 4)
684 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
685 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
688 // BIOS ROM ($E00000 - $E3FFFF) 256K
689 else if (address <= 0xE3FFFF)
691 // hole ($E40000 - $EFFFFF) 768K
692 else if (address <= 0xEFFFFF)
694 // TOM ($F00000 - $F0FFFF) 64K
695 else if (address <= 0xF0FFFF)
698 if (address == 0xF00050)
700 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
704 else if (address == 0xF00051)
706 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
710 else if (address == 0xF00052)
712 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
716 else if (address == 0xF00053)
718 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
722 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
724 // Writing to one CLUT writes to the other
725 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
726 tomRAM[address] = tomRAM[address + 0x200] = byte;
729 //What about LBUF writes???
730 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
732 GPUWriteByte(address, byte, who);
735 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
737 BlitterWriteByte(address, byte, who);
740 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
742 GPUWriteByte(address, byte, who);
746 tomRAM[address & 0x3FFF] = byte;
748 // JERRY ($F10000 - $F1FFFF) 64K
749 else if (address <= 0xF1FFFF)
753 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
755 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
757 DSPWriteByte(address, byte, who);
760 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
762 DSPWriteByte(address, byte, who);
765 // SCLK ($F1A150--8 bits wide)
766 //NOTE: This should be taken care of in DAC...
767 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
769 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
770 if ((address & 0x03) == 2)
771 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
773 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
775 JERRYI2SInterruptTimer = -1;
776 #ifndef NEW_TIMER_SYSTEM
779 RemoveCallback(JERRYI2SCallback);
784 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
785 else if (address >= 0xF1A148 && address <= 0xF1A157)
787 DACWriteByte(address, byte, who);
790 else if (address >= 0xF10000 && address <= 0xF10007)
792 #ifndef NEW_TIMER_SYSTEM
793 switch (address & 0x07)
796 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
800 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
804 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
808 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
812 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
816 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
820 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
824 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
828 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
832 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
834 clock_byte_write(offset, byte);
837 // JERRY -> 68K interrupt enables/latches (need to be handled!)
838 else if (address >= 0xF10020 && address <= 0xF10023)
840 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
842 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
844 anajoy_byte_write(offset, byte);
847 else if ((address >= 0xF14000) && (address <= 0xF14003))
849 JoystickWriteByte(address, byte);
850 EepromWriteByte(address, byte);
853 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
855 EepromWriteByte(address, byte);
858 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
859 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
862 jerryRAM[address & 0xFFFF] = byte;
864 // hole ($F20000 - $FFFFFF) 1M - 128K
870 void WriteWord(uint32_t adddress, uint16_t word)
875 void WriteDWord(uint32_t adddress, uint32_t dword)
880 uint8_t ReadByte(uint32_t adddress)
885 uint16_t ReadWord(uint32_t adddress)
890 uint32_t ReadDWord(uint32_t adddress)
896 void ShowM68KContext(void)
898 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
900 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
902 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
904 if (i == M68K_REG_D3 || i == M68K_REG_D7)
908 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
910 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
912 if (i == M68K_REG_A3 || i == M68K_REG_A7)
916 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
917 uint32_t disPC = currpc - 30;
922 uint32_t oldpc = disPC;
923 disPC += m68k_disassemble(buffer, disPC, 0);
924 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
926 while (disPC < (currpc + 10));
931 // Custom UAE 68000 read/write/IRQ functions
938 IPL Name Vector Control
939 ---------+---------------+---------------+---------------
940 2 VBLANK IRQ $100 INT1 bit #0
941 2 GPU IRQ $100 INT1 bit #1
942 2 HBLANK IRQ $100 INT1 bit #2
943 2 Timer IRQ $100 INT1 bit #3
945 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
946 and are therefore indistinguishable.
948 A typical way to install a LEVEL2 handler for the 68000 would be
949 something like this, you gotta supply "last_line" and "handler".
950 Note that the interrupt is auto vectored thru $100 (not $68)
958 IRQS_HANDLED=$909 ;; VBLANK and TIMER
960 move.w #$2700,sr ;; no IRQs please
961 move.l #handler,V_AUTO ;; install our routine
963 move.w #last_line,VI ;; scanline where IRQ should occur
964 ;; should be 'odd' BTW
965 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
966 move.w #$2100,sr ;; enable IRQs on the 68K
984 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
985 move.w #0,INT2 ; let GPU run again
989 As you can see, if you have multiple INT1 interrupts coming in,
990 you need to check the lower byte of INT1, to see which interrupt
993 int irq_ack_handler(int level)
995 #ifdef CPU_DEBUG_TRACING
996 if (startM68KTracing)
998 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1002 // Tracing the IPL lines on the Jaguar schematic yields the following:
1003 // IPL1 is connected to INTL on TOM (OUT to 68K)
1004 // IPL0-2 are also tied to Vcc via 4.7K resistors!
1005 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
1006 // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
1007 // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
1009 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
1010 // They aren't, and this causes problems with a, err, specific ROM. :-D
1014 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1015 return 64; // Set user interrupt #0
1018 return M68K_INT_ACK_AUTOVECTOR;
1022 //#define USE_NEW_MMU
1024 unsigned int m68k_read_memory_8(unsigned int address)
1026 #ifdef ALPINE_FUNCTIONS
1027 // Check if breakpoint on memory is active, and deal with it
1028 if (bpmActive && address == bpmAddress1)
1032 // Musashi does this automagically for you, UAE core does not :-P
1033 address &= 0x00FFFFFF;
1034 #ifdef CPU_DEBUG_MEMORY
1035 // Note that the Jaguar only has 2M of RAM, not 4!
1036 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1039 readMem[address] = 1;
1042 //WriteLog("[RM8] Addr: %08X\n", address);
1043 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1044 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1045 || address == 0x1AF05E)
1046 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1048 unsigned int retVal = 0;
1050 // Note that the Jaguar only has 2M of RAM, not 4!
1051 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1052 retVal = jaguarMainRAM[address];
1053 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1054 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1055 retVal = jaguarMainROM[address - 0x800000];
1056 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1057 // retVal = jaguarBootROM[address - 0xE00000];
1058 // retVal = jaguarDevBootROM1[address - 0xE00000];
1059 retVal = jagMemSpace[address];
1060 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1061 retVal = CDROMReadByte(address);
1062 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1063 retVal = TOMReadByte(address, M68K);
1064 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1065 retVal = JERRYReadByte(address, M68K);
1067 retVal = jaguar_unknown_readbyte(address, M68K);
1069 //if (address >= 0x2800 && address <= 0x281F)
1070 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1071 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1072 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1075 return MMURead8(address, M68K);
1080 void gpu_dump_disassembly(void);
1081 void gpu_dump_registers(void);
1083 unsigned int m68k_read_memory_16(unsigned int address)
1085 #ifdef ALPINE_FUNCTIONS
1086 // Check if breakpoint on memory is active, and deal with it
1087 if (bpmActive && address == bpmAddress1)
1091 // Musashi does this automagically for you, UAE core does not :-P
1092 address &= 0x00FFFFFF;
1093 #ifdef CPU_DEBUG_MEMORY
1094 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1097 readMem[address] = 1, readMem[address + 1] = 1;
1099 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1101 return 0x4E71; // NOP
1103 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1105 return 0x4E71; // NOP
1107 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1109 return 0x4E71; // NOP
1111 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1113 return 0x4E71; // NOP
1115 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1117 return 0x4E71; // NOP
1119 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1121 return 0x4E71; // NOP
1124 //WriteLog("[RM16] Addr: %08X\n", address);
1125 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1126 // for(int i=0; i<10000; i++)
1127 WriteLog("[M68K] In routine #6!\n");//*/
1128 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1129 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1130 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1132 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1133 gpu_dump_registers();
1134 gpu_dump_disassembly();
1135 // for(int i=0; i<10000; i++)
1136 // WriteLog("[M68K] About to run GPU!\n");
1138 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1139 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1141 if (address == 0x000066A0)
1143 gpu_dump_registers();
1144 gpu_dump_disassembly();
1146 for(int i=0; i<10000; i++)
1147 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1149 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1150 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1151 || address == 0x1AF05E)
1152 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1154 unsigned int retVal = 0;
1156 // Note that the Jaguar only has 2M of RAM, not 4!
1157 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1158 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1159 retVal = GET16(jaguarMainRAM, address);
1160 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1161 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1162 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1163 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1164 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1165 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1166 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1167 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1168 retVal = CDROMReadWord(address, M68K);
1169 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1170 retVal = TOMReadWord(address, M68K);
1171 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1172 retVal = JERRYReadWord(address, M68K);
1174 retVal = jaguar_unknown_readword(address, M68K);
1176 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1177 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1178 //if (address >= 0x2800 && address <= 0x281F)
1179 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1180 //$8B3AE -> Transferred from $F1C010
1181 //$8B5E4 -> Only +1 read at $808AA
1182 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1183 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1186 return MMURead16(address, M68K);
1191 unsigned int m68k_read_memory_32(unsigned int address)
1193 #ifdef ALPINE_FUNCTIONS
1194 // Check if breakpoint on memory is active, and deal with it
1195 if (bpmActive && address == bpmAddress1)
1199 // Musashi does this automagically for you, UAE core does not :-P
1200 address &= 0x00FFFFFF;
1201 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1202 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1203 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));//*/
1205 //WriteLog("--> [RM32]\n");
1207 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1209 return MMURead32(address, M68K);
1214 void m68k_write_memory_8(unsigned int address, unsigned int value)
1216 #ifdef ALPINE_FUNCTIONS
1217 // Check if breakpoint on memory is active, and deal with it
1218 if (bpmActive && address == bpmAddress1)
1222 // Musashi does this automagically for you, UAE core does not :-P
1223 address &= 0x00FFFFFF;
1224 #ifdef CPU_DEBUG_MEMORY
1225 // Note that the Jaguar only has 2M of RAM, not 4!
1226 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1230 if (value > writeMemMax[address])
1231 writeMemMax[address] = value;
1232 if (value < writeMemMin[address])
1233 writeMemMin[address] = value;
1237 /*if (address == 0x4E00)
1238 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1239 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1240 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1241 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1243 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1244 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1246 /*if (address >= 0x53D0 && address <= 0x53FF)
1247 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1248 //Testing AvP on UAE core...
1249 //000075A0: FFFFF80E B6320220 (BITMAP)
1250 /*if (address == 0x75A0 && value == 0xFF)
1251 printf("M68K: (8) Tripwire hit...\n");//*/
1254 // Note that the Jaguar only has 2M of RAM, not 4!
1255 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1256 jaguarMainRAM[address] = value;
1257 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1258 CDROMWriteByte(address, value, M68K);
1259 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1260 TOMWriteByte(address, value, M68K);
1261 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1262 JERRYWriteByte(address, value, M68K);
1264 jaguar_unknown_writebyte(address, value, M68K);
1266 MMUWrite8(address, value, M68K);
1271 void m68k_write_memory_16(unsigned int address, unsigned int value)
1273 #ifdef ALPINE_FUNCTIONS
1274 // Check if breakpoint on memory is active, and deal with it
1275 if (bpmActive && address == bpmAddress1)
1279 // Musashi does this automagically for you, UAE core does not :-P
1280 address &= 0x00FFFFFF;
1281 #ifdef CPU_DEBUG_MEMORY
1282 // Note that the Jaguar only has 2M of RAM, not 4!
1283 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1287 uint8_t hi = value >> 8, lo = value & 0xFF;
1289 if (hi > writeMemMax[address])
1290 writeMemMax[address] = hi;
1291 if (hi < writeMemMin[address])
1292 writeMemMin[address] = hi;
1294 if (lo > writeMemMax[address+1])
1295 writeMemMax[address+1] = lo;
1296 if (lo < writeMemMin[address+1])
1297 writeMemMin[address+1] = lo;
1301 /*if (address == 0x4E00)
1302 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1303 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1304 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1305 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1306 //if (address >= 0xF02200 && address <= 0xF0229F)
1307 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1308 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1309 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1310 /*extern uint32_t totalFrames;
1311 if (address == 0xF02114)
1312 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1313 if (address == 0xF02110)
1314 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1315 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1316 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1318 /*if (address == 0x0100)//64*4)
1319 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1321 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1322 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1323 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1324 || address == 0x1AF05E)
1325 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1327 /*if (address >= 0x53D0 && address <= 0x53FF)
1328 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1329 //Testing AvP on UAE core...
1330 //000075A0: FFFFF80E B6320220 (BITMAP)
1331 /*if (address == 0x75A0 && value == 0xFFFF)
1333 printf("\nM68K: (16) Tripwire hit...\n");
1338 // Note that the Jaguar only has 2M of RAM, not 4!
1339 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1341 /* jaguar_mainRam[address] = value >> 8;
1342 jaguar_mainRam[address + 1] = value & 0xFF;*/
1343 SET16(jaguarMainRAM, address, value);
1345 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1346 CDROMWriteWord(address, value, M68K);
1347 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1348 TOMWriteWord(address, value, M68K);
1349 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1350 JERRYWriteWord(address, value, M68K);
1353 jaguar_unknown_writeword(address, value, M68K);
1354 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1355 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1356 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1357 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1361 MMUWrite16(address, value, M68K);
1366 void m68k_write_memory_32(unsigned int address, unsigned int value)
1368 #ifdef ALPINE_FUNCTIONS
1369 // Check if breakpoint on memory is active, and deal with it
1370 if (bpmActive && address == bpmAddress1)
1374 // Musashi does this automagically for you, UAE core does not :-P
1375 address &= 0x00FFFFFF;
1376 /*if (address == 0x4E00)
1377 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1378 //WriteLog("--> [WM32]\n");
1379 /*if (address == 0x0100)//64*4)
1380 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1381 /*if (address >= 0xF03214 && address < 0xF0321F)
1382 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1383 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1384 /*extern bool doGPUDis;
1385 if (address == 0xF03214 && value == 0x88E30047)
1387 doGPUDis = true;//*/
1388 /* if (address == 0x51136 || address == 0xFB074)
1389 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1390 //Testing AvP on UAE core...
1391 //000075A0: FFFFF80E B6320220 (BITMAP)
1392 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1394 printf("\nM68K: (32) Tripwire hit...\n");
1399 m68k_write_memory_16(address, value >> 16);
1400 m68k_write_memory_16(address + 2, value & 0xFFFF);
1402 MMUWrite32(address, value, M68K);
1407 uint32_t JaguarGetHandler(uint32_t i)
1409 return JaguarReadLong(i * 4);
1413 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1415 uint32_t handler = JaguarGetHandler(i);
1416 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1420 void M68K_show_context(void)
1422 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1424 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1426 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1428 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1432 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1434 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1436 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1440 WriteLog("68K disasm\n");
1441 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1442 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1443 // jaguar_dasm(0x5000, 0x14414);
1445 // WriteLog("\n.......[Cart start]...........\n\n");
1446 // jaguar_dasm(0x192000, 0x1000);//0x200);
1448 WriteLog("..................\n");
1450 if (TOMIRQEnabled(IRQ_VIDEO))
1452 WriteLog("video int: enabled\n");
1453 JaguarDasm(JaguarGetHandler(64), 0x200);
1456 WriteLog("video int: disabled\n");
1458 WriteLog("..................\n");
1460 for(int i=0; i<256; i++)
1462 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1463 uint32_t address = (uint32_t)JaguarGetHandler(i);
1466 WriteLog(".........\n");
1468 WriteLog("$%08X\n", address);
1474 // Unknown read/write byte/word routines
1477 // It's hard to believe that developers would be sloppy with their memory writes, yet in
1478 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
1480 // 807EC4: movea.l #$f1b000, A1
1481 // 807ECA: movea.l #$8129e0, A0
1482 // 807ED0: move.l A0, D0
1483 // 807ED2: move.l #$f1bb94, D1
1484 // 807ED8: sub.l D0, D1
1485 // 807EDA: lsr.l #2, D1
1486 // 807EDC: move.l (A0)+, (A1)+
1487 // 807EDE: dbra D1, 807edc
1489 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
1490 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
1491 // space! (That is, unless the 68K causes a bus error...)
1493 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1495 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1496 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));
1498 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1499 // extern bool finished;
1501 // extern bool doDSPDis;
1508 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1510 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1511 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));
1513 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1514 // extern bool finished;
1516 // extern bool doDSPDis;
1523 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1525 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1526 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1528 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1529 // extern bool finished;
1531 // extern bool doDSPDis;
1539 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1541 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1542 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1544 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1545 // extern bool finished;
1547 // extern bool doDSPDis;
1556 // Disassemble M68K instructions at the given offset
1559 unsigned int m68k_read_disassembler_8(unsigned int address)
1561 return m68k_read_memory_8(address);
1565 unsigned int m68k_read_disassembler_16(unsigned int address)
1567 return m68k_read_memory_16(address);
1571 unsigned int m68k_read_disassembler_32(unsigned int address)
1573 return m68k_read_memory_32(address);
1577 void JaguarDasm(uint32_t offset, uint32_t qt)
1580 static char buffer[2048];//, mem[64];
1581 int pc = offset, oldpc;
1583 for(uint32_t i=0; i<qt; i++)
1586 for(int j=0; j<64; j++)
1587 mem[j^0x01] = jaguar_byte_read(pc + j);
1589 pc += Dasm68000((char *)mem, buffer, 0);
1590 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1592 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1593 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1599 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1601 uint8_t data = 0x00;
1604 // First 2M is mirrored in the $0 - $7FFFFF range
1605 if (offset < 0x800000)
1606 data = jaguarMainRAM[offset & 0x1FFFFF];
1607 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1608 data = jaguarMainROM[offset - 0x800000];
1609 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1610 data = CDROMReadByte(offset, who);
1611 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1612 // data = jaguarBootROM[offset & 0x3FFFF];
1613 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1614 data = jagMemSpace[offset];
1615 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1616 data = TOMReadByte(offset, who);
1617 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1618 data = JERRYReadByte(offset, who);
1620 data = jaguar_unknown_readbyte(offset, who);
1626 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1630 // First 2M is mirrored in the $0 - $7FFFFF range
1631 if (offset < 0x800000)
1633 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1635 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1638 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1640 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1641 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1642 return CDROMReadWord(offset, who);
1643 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1644 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1645 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1646 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1647 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1648 return TOMReadWord(offset, who);
1649 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1650 return JERRYReadWord(offset, who);
1652 return jaguar_unknown_readword(offset, who);
1656 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1658 /* if (offset >= 0x4E00 && offset < 0x4E04)
1659 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1660 //Need to check for writes in the range of $18FA70 + 8000...
1662 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1663 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1667 // First 2M is mirrored in the $0 - $7FFFFF range
1668 if (offset < 0x800000)
1670 jaguarMainRAM[offset & 0x1FFFFF] = data;
1673 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1675 CDROMWriteByte(offset, data, who);
1678 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1680 TOMWriteByte(offset, data, who);
1683 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1685 JERRYWriteByte(offset, data, who);
1689 jaguar_unknown_writebyte(offset, data, who);
1694 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1696 /* if (offset >= 0x4E00 && offset < 0x4E04)
1697 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1698 /*if (offset == 0x0100)//64*4)
1699 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1700 if (offset == 0x0102)//64*4)
1701 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1702 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1703 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1704 //Need to check for writes in the range of $18FA70 + 8000...
1706 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1707 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1708 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1709 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1713 // First 2M is mirrored in the $0 - $7FFFFF range
1714 if (offset <= 0x7FFFFE)
1719 1A 69 F0 ($0000) -> Starfield
1720 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1723 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1732 //This MUST be done by the 68K!
1733 /*if (offset == 0x670C)
1734 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1736 /*extern bool doGPUDis;
1737 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1738 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1739 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1740 doGPUDis = true;//*/
1741 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1742 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1743 if ((data & 0xFF00) != 0x7700)
1744 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1745 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1747 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1748 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1749 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1751 /*extern bool doGPUDis;
1752 if (offset == 0x120216 && who == GPU)
1753 doGPUDis = true;//*/
1754 /*extern uint32_t gpu_pc;
1755 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1757 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1758 uint32_t y = base / 0x300;
1759 uint32_t x = (base - (y * 0x300)) / 2;
1760 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1763 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1765 //if (offset == (0x001E17F8 + 0x34))
1766 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1768 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1769 /*extern uint32_t gpu_pc;
1770 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1772 extern int objectPtr;
1773 // if (offset > 0x148000)
1776 if (starCount > objectPtr)
1779 // if (starCount == 1)
1780 // WriteLog("--> Drawing 1st star...\n");
1782 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1783 // uint32_t y = base / 0x300;
1784 // uint32_t x = (base - (y * 0x300)) / 2;
1785 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1787 //A star of interest...
1788 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1789 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1790 //JWW: Blitter writing echo 77B3 at 0011D022...
1792 //extern bool doGPUDis;
1793 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1796 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1799 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1800 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1802 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1803 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1806 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1808 CDROMWriteWord(offset, data, who);
1811 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1813 TOMWriteWord(offset, data, who);
1816 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1818 JERRYWriteWord(offset, data, who);
1821 // Don't bomb on attempts to write to ROM
1822 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1825 jaguar_unknown_writeword(offset, data, who);
1829 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1830 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1832 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1836 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1837 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1839 /* extern bool doDSPDis;
1840 if (offset < 0x400 && !doDSPDis)
1842 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1845 /*if (offset == 0x0100)//64*4)
1846 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1848 JaguarWriteWord(offset, data >> 16, who);
1849 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1853 void JaguarSetScreenBuffer(uint32_t * buffer)
1855 // This is in TOM, but we set it here...
1856 screenBuffer = buffer;
1860 void JaguarSetScreenPitch(uint32_t pitch)
1862 // This is in TOM, but we set it here...
1863 screenPitch = pitch;
1868 // Jaguar console initialization
1870 void JaguarInit(void)
1872 // For randomizing RAM
1875 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1876 for(uint32_t i=0; i<0x200000; i+=4)
1877 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1879 #ifdef CPU_DEBUG_MEMORY
1880 memset(readMem, 0x00, 0x400000);
1881 memset(writeMemMin, 0xFF, 0x400000);
1882 memset(writeMemMax, 0x00, 0x400000);
1884 // memset(jaguarMainRAM, 0x00, 0x200000);
1885 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1886 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1887 //NOTE: This *doesn't* fix FlipOut...
1888 //Or does it? Hmm...
1889 //Seems to want $01010101... Dunno why. Investigate!
1890 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1891 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1892 lowerField = false; // Reset the lower field flag
1893 //temp, for crappy crap that sux
1894 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1896 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1905 //New timer based code stuffola...
1906 void HalflineCallback(void);
1907 void RenderCallback(void);
1908 void JaguarReset(void)
1910 // Only problem with this approach: It wipes out RAM loaded files...!
1911 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1912 for(uint32_t i=8; i<0x200000; i+=4)
1913 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1915 // New timer base code stuffola...
1916 InitializeEventList();
1917 //Need to change this so it uses the single RAM space and load the BIOS
1918 //into it somewhere...
1919 //Also, have to change this here and in JaguarReadXX() currently
1920 // Only use the system BIOS if it's available...! (it's always available now!)
1921 // AND only if a jaguar cartridge has been inserted.
1922 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1923 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1925 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1927 // WriteLog("jaguar_reset():\n");
1933 m68k_pulse_reset(); // Reset the 68000
1934 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1936 lowerField = false; // Reset the lower field flag
1937 // SetCallbackTime(ScanlineCallback, 63.5555);
1938 // SetCallbackTime(ScanlineCallback, 31.77775);
1939 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1943 void JaguarDone(void)
1945 #ifdef CPU_DEBUG_MEMORY
1946 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1948 for(uint32_t i=0; i<=raPtr; i++)
1950 WriteLog("\t%08X\n", returnAddr[i]);
1951 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1952 jaguar_dasm(returnAddr[i] - 16, 16);
1957 /* int start = 0, end = 0;
1958 bool endTriggered = false, startTriggered = false;
1959 for(int i=0; i<0x400000; i++)
1961 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1963 if (!startTriggered)
1964 startTriggered = true, endTriggered = false, start = i;
1966 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1972 end = i - 1, endTriggered = true, startTriggered = false;
1973 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1980 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1981 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1982 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1983 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
1985 for(int i=-2; i<9; i++)
1986 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
1988 uint32_t address = topOfStack - (4 * 4 * 3);
1990 for(int i=0; i<10; i++)
1992 WriteLog("%06X:", address);
1994 for(int j=0; j<4; j++)
1996 WriteLog(" %08X", JaguarReadLong(address));
2004 /* WriteLog("\nM68000 disassembly at $802288...\n");
2005 jaguar_dasm(0x802288, 3);
2006 WriteLog("\nM68000 disassembly at $802200...\n");
2007 jaguar_dasm(0x802200, 500);
2008 WriteLog("\nM68000 disassembly at $802518...\n");
2009 jaguar_dasm(0x802518, 100);//*/
2011 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2012 jaguar_dasm(0x803F00, 500);
2015 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2016 jaguar_dasm(0x802B00, 500);
2019 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2020 jaguar_dasm(0x809900, 500);
2023 /* WriteLog("\n\nDump of $8093C8:\n\n");
2024 for(int i=0x8093C8; i<0x809900; i+=4)
2025 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2026 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2027 jaguar_dasm(0x90006C, 500);
2029 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2030 jaguar_dasm(0x1AC000, 6000);
2033 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2034 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2035 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2036 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2037 M68K_show_context();
2046 // temp, until debugger is in place
2047 //00802016: jsr $836F1A.l
2048 //0080201C: jsr $836B30.l
2049 //00802022: jsr $836B18.l
2050 //00802028: jsr $8135F0.l
2051 //00813C1E: jsr $813F76.l
2052 //00802038: jsr $836D00.l
2053 //00802098: jsr $8373A4.l
2054 //008020A2: jsr $83E24A.l
2055 //008020BA: jsr $83E156.l
2056 //008020C6: jsr $83E19C.l
2057 //008020E6: jsr $8445E8.l
2058 //008020EC: jsr $838C20.l
2059 //0080211A: jsr $838ED6.l
2060 //00802124: jsr $89CA56.l
2061 //0080212A: jsr $802B48.l
2063 WriteLog("-------------------------------------------\n");
2064 JaguarDasm(0x8445E8, 0x200);
2065 WriteLog("-------------------------------------------\n");
2066 JaguarDasm(0x838C20, 0x200);
2067 WriteLog("-------------------------------------------\n");
2068 JaguarDasm(0x838ED6, 0x200);
2069 WriteLog("-------------------------------------------\n");
2070 JaguarDasm(0x89CA56, 0x200);
2071 WriteLog("-------------------------------------------\n");
2072 JaguarDasm(0x802B48, 0x200);
2073 WriteLog("\n\nM68000 disassembly at $802000...\n");
2074 JaguarDasm(0x802000, 6000);
2077 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2078 JaguarDasm(0x6004, 10000);
2080 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2081 // JaguarDasm(0x802000, 0x1000);
2082 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2083 // JaguarDasm(0x4100, 200);
2084 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2085 // JaguarDasm(0x800800, 0x1000);
2089 // Temp debugging stuff
2091 void DumpMainMemory(void)
2093 FILE * fp = fopen("./memdump.bin", "wb");
2098 fwrite(jaguarMainRAM, 1, 0x200000, fp);
2103 uint8_t * GetRamPtr(void)
2105 return jaguarMainRAM;
2110 // New Jaguar execution stack
2111 // This executes 1 frame's worth of code.
2114 void JaguarExecuteNew(void)
2120 double timeToNextEvent = GetTimeToNextEvent();
2121 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2123 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2126 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2134 #define USE_CORRECT_PAL_TIMINGS
2135 // A lot of confusion comes from here...
2136 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
2137 // of whether the display is interlaced or not. The only difference with an
2138 // interlaced display is that the high bit of VC will be set when the lower
2139 // field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
2140 // regardless of whether it's in interlace mode or not.
2141 // NB2: Seems it doens't always, not sure what the constraint is...)
2143 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2144 // rendering two fields that are slighty vertically offset from each other.
2145 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2146 // is rendered in this mode so that each field, when overlaid on each other,
2147 // will yield the final picture at the full resolution for the full frame.
2149 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2150 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2151 // it will be half this number for a half frame. BUT, since we're counting
2152 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
2154 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2155 // Half line times are, naturally, half of this. :-P
2156 void HalflineCallback(void)
2158 //OK, this is hardwired to run in NTSC, and for who knows how long.
2159 //Need to fix this so that it does a half-line in the correct amount of time
2160 //and number of lines, depending on which mode we're in. [FIXED]
2161 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2162 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2163 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2164 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2167 #ifdef USE_CORRECT_PAL_TIMINGS
2168 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2169 // So we cut the number of half-lines in a frame in half. :-P
2170 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2172 if ((vc & 0x7FF) >= numHalfLines)
2174 if ((vc & 0x7FF) >= vp)
2178 // lowerField = !lowerField;
2180 // If we're rendering the lower field, set the high bit (#12, counting
2186 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
2187 TOMWriteWord(0xF00006, vc, JAGUAR);
2189 //This is a crappy kludge, but maybe it'll work for now...
2190 //Maybe it's not so bad, since the IRQ happens on a scanline boundary...
2191 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
2193 // We don't have to worry about autovectors & whatnot because the Jaguar
2194 // tells you through its HW registers who sent the interrupt...
2195 TOMSetPendingVideoInt();
2199 TOMExecHalfline(vc, true);
2201 //Change this to VBB???
2202 //Doesn't seem to matter (at least for Flip Out & I-War)
2203 if ((vc & 0x7FF) == 0)
2210 #ifdef USE_CORRECT_PAL_TIMINGS
2211 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2213 // SetCallbackTime(HalflineCallback, 63.5555);
2214 SetCallbackTime(HalflineCallback, 31.77775);
2219 // This isn't currently used, but maybe it should be...
2221 Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
2222 handles all the rest, so this isn't needed. :-P
2224 void RenderCallback(void)
2226 // SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
2227 SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time