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];
100 uint32_t srQueue[0x400];
102 bool startM68KTracing = false;
104 // Breakpoint on memory access vars (exported)
105 bool bpmActive = false;
106 uint32_t bpmAddress1;
110 // Callback function to detect illegal instructions
112 void GPUDumpDisassembly(void);
113 void GPUDumpRegisters(void);
114 static bool start = false;
116 void M68KInstructionHook(void)
118 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
119 // Temp, for comparing...
121 /* static char buffer[2048];//, mem[64];
122 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
123 printf("%08X: %s\n", m68kPC, buffer);//*/
125 //JaguarDasm(m68kPC, 1);
126 //Testing Hover Strike...
129 static int hitCount = 0;
130 static int inRoutine = 0;
133 //if (regs.pc == 0x80340A)
134 if (m68kPC == 0x803416)
139 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
141 else if (m68kPC == 0x803422)
144 printf("(%i instructions)\n", instSeen);
151 // For code tracing...
152 #ifdef CPU_DEBUG_TRACING
153 if (startM68KTracing)
155 static char buffer[2048];
157 m68k_disassemble(buffer, m68kPC, 0);
158 WriteLog("%06X: %s\n", m68kPC, buffer);
163 // Ideally, we'd save all the registers as well...
164 pcQueue[pcQPtr] = m68kPC;
165 a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
166 a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
167 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
168 a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
169 a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
170 a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
171 a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
172 a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
173 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
174 d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
175 d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
176 d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
177 d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
178 d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
179 d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
180 d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
181 srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR);
185 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
187 WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
189 static char buffer[2048];
190 for(int i=0; i<0x400; i++)
192 // WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
193 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]);
194 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
195 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
199 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
200 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
201 for(int i=0; i<10; i++)
202 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
203 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
209 // Disassemble everything
211 static char buffer[2048];
212 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
213 WriteLog("%08X: %s", m68kPC, buffer);
214 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
215 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
216 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
218 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
220 static char buffer[2048];
221 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
222 WriteLog("%08X: %s", m68kPC, buffer);
223 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
224 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
225 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
227 /* if (m68kPC == 0x8D0E48 && effect_start5)
229 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
231 GPUDumpDisassembly();
235 /* uint16_t opcode = JaguarReadWord(m68kPC);
236 if (opcode == 0x4E75) // RTS
239 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
241 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
243 if (raPtr != 0xFFFFFFFF)
245 for(uint32_t i=0; i<=raPtr; i++)
247 if (returnAddr[i] == addr)
256 returnAddr[++raPtr] = addr;
260 //Flip Out! debugging...
263 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
264 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
265 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
266 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
268 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
270 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
271 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
272 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
273 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
274 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
275 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
276 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
278 /* static char buffer[2048];
279 //if (m68kPC > 0x805F48) start = true;
280 //if (m68kPC > 0x806486) start = true;
281 //if (m68kPC == 0x805FEE) start = true;
282 //if (m68kPC == 0x80600C)// start = true;
283 if (m68kPC == 0x802058) start = true;
285 // GPUDumpRegisters();
286 // GPUDumpDisassembly();
288 // M68K_show_context();
294 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
295 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));
298 /* if (m68kPC == 0x803F16)
300 WriteLog("M68K: Registers found at $803F16:\n");
301 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
302 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
303 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
305 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
306 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
308 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
309 // !!! Investigate !!!
310 /*extern bool doDSPDis;
311 static bool disgo = false;
312 if (m68kPC == 0x50222)
315 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
316 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
319 if (m68kPC == 0x5000)
324 static char buffer[2048];
325 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
326 WriteLog("%08X: %s", m68kPC, buffer);
327 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
328 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
329 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
331 /* if (m68kPC == 0x82E1A)
333 static char buffer[2048];
334 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
335 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
336 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
337 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
338 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
340 /* if (m68kPC == 0x82E58)
341 WriteLog("--> [Routine end]\n");
342 if (m68kPC == 0x80004)
344 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
345 // m68k_set_reg(M68K_REG_D2, 0x12345678);
348 #ifdef LOG_CD_BIOS_CALLS
371 if (m68kPC == 0x3000)
372 WriteLog("M68K: CD_init\n");
373 else if (m68kPC == 0x3006 + (6 * 0))
374 WriteLog("M68K: CD_mode\n");
375 else if (m68kPC == 0x3006 + (6 * 1))
376 WriteLog("M68K: CD_ack\n");
377 else if (m68kPC == 0x3006 + (6 * 2))
378 WriteLog("M68K: CD_jeri\n");
379 else if (m68kPC == 0x3006 + (6 * 3))
380 WriteLog("M68K: CD_spin\n");
381 else if (m68kPC == 0x3006 + (6 * 4))
382 WriteLog("M68K: CD_stop\n");
383 else if (m68kPC == 0x3006 + (6 * 5))
384 WriteLog("M68K: CD_mute\n");
385 else if (m68kPC == 0x3006 + (6 * 6))
386 WriteLog("M68K: CD_umute\n");
387 else if (m68kPC == 0x3006 + (6 * 7))
388 WriteLog("M68K: CD_paus\n");
389 else if (m68kPC == 0x3006 + (6 * 8))
390 WriteLog("M68K: CD_upaus\n");
391 else if (m68kPC == 0x3006 + (6 * 9))
392 WriteLog("M68K: CD_read\n");
393 else if (m68kPC == 0x3006 + (6 * 10))
394 WriteLog("M68K: CD_uread\n");
395 else if (m68kPC == 0x3006 + (6 * 11))
396 WriteLog("M68K: CD_setup\n");
397 else if (m68kPC == 0x3006 + (6 * 12))
398 WriteLog("M68K: CD_ptr\n");
399 else if (m68kPC == 0x3006 + (6 * 13))
400 WriteLog("M68K: CD_osamp\n");
401 else if (m68kPC == 0x3006 + (6 * 14))
402 WriteLog("M68K: CD_getoc\n");
403 else if (m68kPC == 0x3006 + (6 * 15))
404 WriteLog("M68K: CD_initm\n");
405 else if (m68kPC == 0x3006 + (6 * 16))
406 WriteLog("M68K: CD_initf\n");
407 else if (m68kPC == 0x3006 + (6 * 17))
408 WriteLog("M68K: CD_switch\n");
410 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
411 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
412 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
413 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
416 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
417 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
419 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
420 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
422 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
423 // keep going even when the 68K dumped back to the debugger or what have you).
425 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
426 // Try setting the vector to the illegal instruction...
427 //This doesn't work right either! Do something else! Quick!
428 // SET32(jaguar_mainRam, 0x10, m68kPC);
434 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
435 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
436 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
437 uint32_t address = topOfStack - (4 * 4 * 3);
439 for(int i=0; i<10; i++)
441 WriteLog("%06X:", address);
443 for(int j=0; j<4; j++)
445 WriteLog(" %08X", JaguarReadLong(address));
452 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
456 // WriteLog("\n\n68K disasm\n\n");
457 // jaguar_dasm(0x802000, 0x50C);
468 Now here be dragons...
469 Here is how memory ranges are defined in the CoJag driver.
470 Note that we only have to be concerned with 3 entities read/writing anything:
471 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
472 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
473 things that are entirely internal to those modules. This way we should be able to get a handle on all
474 this crap which is currently scattered over Hell's Half Acre(tm).
476 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
477 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
479 /*************************************
481 * Main CPU memory handlers
483 *************************************/
485 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
486 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
487 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
488 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
489 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
490 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
491 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
492 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
493 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
494 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
495 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
496 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
497 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
498 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
499 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
500 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
501 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
502 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
503 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
504 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
505 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
506 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
507 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
510 /*************************************
512 * GPU memory handlers
514 *************************************/
516 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
517 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
518 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
519 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
520 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
521 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
522 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
523 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
524 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
525 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
526 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
529 /*************************************
531 * DSP memory handlers
533 *************************************/
535 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
536 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
537 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
538 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
539 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
540 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
541 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
542 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
543 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
548 //#define EXPERIMENTAL_MEMORY_HANDLING
549 // Experimental memory mappage...
550 // Dunno if this is a good approach or not, but it seems to make better
551 // sense to have all this crap in one spot intstead of scattered all over
552 // the place the way it is now.
553 #ifdef EXPERIMENTAL_MEMORY_HANDLING
555 #define NEW_TIMER_SYSTEM
558 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
559 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
560 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
561 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
562 bool BIOSLoaded = false;
563 bool CDBIOSLoaded = false;
565 uint8_t cdRAM[0x100];
566 uint8_t tomRAM[0x4000];
567 uint8_t jerryRAM[0x10000];
568 static uint16_t eeprom_ram[64];
570 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
573 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
575 // M68K Memory map/handlers
577 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
578 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
579 // Note that this is really memory mapped I/O region...
580 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
581 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
582 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
583 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
584 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
585 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
586 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
587 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
588 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
589 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
590 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
591 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
593 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
595 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
596 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
597 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
598 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
599 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
600 //What about LBUF writes???
601 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
602 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
603 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
605 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
609 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
610 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
611 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
614 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
615 0 = pad0/1 button values (4 bits each), RO(?)
616 1 = pad0/1 index value (4 bits each), WO
618 3 = NTSC/PAL, certain button states, RO
620 JOYSTICK $F14000 Read/Write
622 Read fedcba98 7654321q f-1 Signals J15 to J1
623 q Cartridge EEPROM output data
624 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
625 0 = disable J7-J0 outputs
628 0 = Audio muted (reset state)
630 7-4 J7-J4 outputs (port 2)
631 3-0 J3-J0 outputs (port 1)
632 JOYBUTS $F14002 Read Only
634 Read xxxxxxxx rrdv3210 x don't care
637 v 1 = NTSC Video hardware
638 0 = PAL Video hardware
639 3-2 Button inputs B3 & B2 (port 2)
640 1-0 Button inputs B1 & B0 (port 1)
642 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
643 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
651 0 1 1 1 Row 3 C3 Option # 9 6 3
655 1 0 1 1 Row 2 C2 C 0 8 5 2
657 1 1 0 1 Row 1 C1 B * 7 4 1
658 1 1 1 0 Row 0 Pause A Up Down Left Right
661 0 bit read in any position means that button is pressed.
662 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
666 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
668 // Not sure, but I think the system only has 24 address bits...
669 address &= 0x00FFFFFF;
671 // RAM ($000000 - $3FFFFF) 4M
672 if (address <= 0x3FFFFF)
673 jaguarMainRAM[address] = byte;
674 // hole ($400000 - $7FFFFF) 4M
675 else if (address <= 0x7FFFFF)
677 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
678 else if (address <= 0xDFFEFF)
680 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
681 else if (address <= 0xDFFFFF)
683 cdRAM[address & 0xFF] = byte;
685 if ((address & 0xFF) < 12 * 4)
686 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
687 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
690 // BIOS ROM ($E00000 - $E3FFFF) 256K
691 else if (address <= 0xE3FFFF)
693 // hole ($E40000 - $EFFFFF) 768K
694 else if (address <= 0xEFFFFF)
696 // TOM ($F00000 - $F0FFFF) 64K
697 else if (address <= 0xF0FFFF)
700 if (address == 0xF00050)
702 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
706 else if (address == 0xF00051)
708 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
712 else if (address == 0xF00052)
714 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
718 else if (address == 0xF00053)
720 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
724 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
726 // Writing to one CLUT writes to the other
727 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
728 tomRAM[address] = tomRAM[address + 0x200] = byte;
731 //What about LBUF writes???
732 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
734 GPUWriteByte(address, byte, who);
737 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
739 BlitterWriteByte(address, byte, who);
742 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
744 GPUWriteByte(address, byte, who);
748 tomRAM[address & 0x3FFF] = byte;
750 // JERRY ($F10000 - $F1FFFF) 64K
751 else if (address <= 0xF1FFFF)
755 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
757 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
759 DSPWriteByte(address, byte, who);
762 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
764 DSPWriteByte(address, byte, who);
767 // SCLK ($F1A150--8 bits wide)
768 //NOTE: This should be taken care of in DAC...
769 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
771 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
772 if ((address & 0x03) == 2)
773 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
775 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
777 JERRYI2SInterruptTimer = -1;
778 #ifndef NEW_TIMER_SYSTEM
781 RemoveCallback(JERRYI2SCallback);
786 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
787 else if (address >= 0xF1A148 && address <= 0xF1A157)
789 DACWriteByte(address, byte, who);
792 else if (address >= 0xF10000 && address <= 0xF10007)
794 #ifndef NEW_TIMER_SYSTEM
795 switch (address & 0x07)
798 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
802 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
806 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
810 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
814 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
818 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
822 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
826 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
830 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
834 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
836 clock_byte_write(offset, byte);
839 // JERRY -> 68K interrupt enables/latches (need to be handled!)
840 else if (address >= 0xF10020 && address <= 0xF10023)
842 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
844 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
846 anajoy_byte_write(offset, byte);
849 else if ((address >= 0xF14000) && (address <= 0xF14003))
851 JoystickWriteByte(address, byte);
852 EepromWriteByte(address, byte);
855 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
857 EepromWriteByte(address, byte);
860 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
861 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
864 jerryRAM[address & 0xFFFF] = byte;
866 // hole ($F20000 - $FFFFFF) 1M - 128K
872 void WriteWord(uint32_t adddress, uint16_t word)
877 void WriteDWord(uint32_t adddress, uint32_t dword)
882 uint8_t ReadByte(uint32_t adddress)
887 uint16_t ReadWord(uint32_t adddress)
892 uint32_t ReadDWord(uint32_t adddress)
898 void ShowM68KContext(void)
900 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
902 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
904 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
906 if (i == M68K_REG_D3 || i == M68K_REG_D7)
910 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
912 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
914 if (i == M68K_REG_A3 || i == M68K_REG_A7)
918 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
919 uint32_t disPC = currpc - 30;
924 uint32_t oldpc = disPC;
925 disPC += m68k_disassemble(buffer, disPC, 0);
926 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
928 while (disPC < (currpc + 10));
933 // Custom UAE 68000 read/write/IRQ functions
940 IPL Name Vector Control
941 ---------+---------------+---------------+---------------
942 2 VBLANK IRQ $100 INT1 bit #0
943 2 GPU IRQ $100 INT1 bit #1
944 2 HBLANK IRQ $100 INT1 bit #2
945 2 Timer IRQ $100 INT1 bit #3
947 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
948 and are therefore indistinguishable.
950 A typical way to install a LEVEL2 handler for the 68000 would be
951 something like this, you gotta supply "last_line" and "handler".
952 Note that the interrupt is auto vectored thru $100 (not $68)
960 IRQS_HANDLED=$909 ;; VBLANK and TIMER
962 move.w #$2700,sr ;; no IRQs please
963 move.l #handler,V_AUTO ;; install our routine
965 move.w #last_line,VI ;; scanline where IRQ should occur
966 ;; should be 'odd' BTW
967 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
968 move.w #$2100,sr ;; enable IRQs on the 68K
986 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
987 move.w #0,INT2 ; let GPU run again
991 As you can see, if you have multiple INT1 interrupts coming in,
992 you need to check the lower byte of INT1, to see which interrupt
995 int irq_ack_handler(int level)
997 #ifdef CPU_DEBUG_TRACING
998 if (startM68KTracing)
1000 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1004 // Tracing the IPL lines on the Jaguar schematic yields the following:
1005 // IPL1 is connected to INTL on TOM (OUT to 68K)
1006 // IPL0-2 are also tied to Vcc via 4.7K resistors!
1007 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
1008 // There doesn't seem to be any other path to IPL0 or 2 on the schematic,
1009 // which means that *all* IRQs to the 68K are routed thru TOM at level 2.
1010 // Which means they're all maskable.
1012 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work
1014 // They aren't, and this causes problems with a, err, specific ROM. :-D
1018 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1019 return 64; // Set user interrupt #0
1022 return M68K_INT_ACK_AUTOVECTOR;
1026 //#define USE_NEW_MMU
1028 unsigned int m68k_read_memory_8(unsigned int address)
1030 #ifdef ALPINE_FUNCTIONS
1031 // Check if breakpoint on memory is active, and deal with it
1032 if (bpmActive && address == bpmAddress1)
1036 // Musashi does this automagically for you, UAE core does not :-P
1037 address &= 0x00FFFFFF;
1038 #ifdef CPU_DEBUG_MEMORY
1039 // Note that the Jaguar only has 2M of RAM, not 4!
1040 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1043 readMem[address] = 1;
1046 //WriteLog("[RM8] Addr: %08X\n", address);
1047 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1048 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1049 || address == 0x1AF05E)
1050 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1052 unsigned int retVal = 0;
1054 // Note that the Jaguar only has 2M of RAM, not 4!
1055 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1056 retVal = jaguarMainRAM[address];
1057 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1058 else if ((address >= 0x800000) && (address <= 0xDFFEFF))
1059 retVal = jaguarMainROM[address - 0x800000];
1060 else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1061 // retVal = jaguarBootROM[address - 0xE00000];
1062 // retVal = jaguarDevBootROM1[address - 0xE00000];
1063 retVal = jagMemSpace[address];
1064 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1065 retVal = CDROMReadByte(address);
1066 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1067 retVal = TOMReadByte(address, M68K);
1068 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1069 retVal = JERRYReadByte(address, M68K);
1071 retVal = jaguar_unknown_readbyte(address, M68K);
1073 //if (address >= 0x2800 && address <= 0x281F)
1074 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1075 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1076 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1079 return MMURead8(address, M68K);
1084 void gpu_dump_disassembly(void);
1085 void gpu_dump_registers(void);
1087 unsigned int m68k_read_memory_16(unsigned int address)
1089 #ifdef ALPINE_FUNCTIONS
1090 // Check if breakpoint on memory is active, and deal with it
1091 if (bpmActive && address == bpmAddress1)
1095 // Musashi does this automagically for you, UAE core does not :-P
1096 address &= 0x00FFFFFF;
1097 #ifdef CPU_DEBUG_MEMORY
1098 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1101 readMem[address] = 1, readMem[address + 1] = 1;
1103 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1105 return 0x4E71; // NOP
1107 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1109 return 0x4E71; // NOP
1111 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1113 return 0x4E71; // NOP
1115 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1117 return 0x4E71; // NOP
1119 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1121 return 0x4E71; // NOP
1123 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1125 return 0x4E71; // NOP
1128 //WriteLog("[RM16] Addr: %08X\n", address);
1129 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1130 // for(int i=0; i<10000; i++)
1131 WriteLog("[M68K] In routine #6!\n");//*/
1132 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1133 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1134 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1136 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1137 gpu_dump_registers();
1138 gpu_dump_disassembly();
1139 // for(int i=0; i<10000; i++)
1140 // WriteLog("[M68K] About to run GPU!\n");
1142 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1143 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1145 if (address == 0x000066A0)
1147 gpu_dump_registers();
1148 gpu_dump_disassembly();
1150 for(int i=0; i<10000; i++)
1151 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1153 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1154 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1155 || address == 0x1AF05E)
1156 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1158 unsigned int retVal = 0;
1160 // Note that the Jaguar only has 2M of RAM, not 4!
1161 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1162 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1163 retVal = GET16(jaguarMainRAM, address);
1164 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1165 else if ((address >= 0x800000) && (address <= 0xDFFEFE))
1166 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1167 else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1168 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1169 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1170 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1171 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1172 retVal = CDROMReadWord(address, M68K);
1173 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1174 retVal = TOMReadWord(address, M68K);
1175 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1176 retVal = JERRYReadWord(address, M68K);
1178 retVal = jaguar_unknown_readword(address, M68K);
1180 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1181 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1182 //if (address >= 0x2800 && address <= 0x281F)
1183 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1184 //$8B3AE -> Transferred from $F1C010
1185 //$8B5E4 -> Only +1 read at $808AA
1186 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1187 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1190 return MMURead16(address, M68K);
1195 unsigned int m68k_read_memory_32(unsigned int address)
1197 #ifdef ALPINE_FUNCTIONS
1198 // Check if breakpoint on memory is active, and deal with it
1199 if (bpmActive && address == bpmAddress1)
1203 // Musashi does this automagically for you, UAE core does not :-P
1204 address &= 0x00FFFFFF;
1205 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1206 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1207 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));//*/
1209 //WriteLog("--> [RM32]\n");
1211 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1213 return MMURead32(address, M68K);
1218 void m68k_write_memory_8(unsigned int address, unsigned int value)
1220 #ifdef ALPINE_FUNCTIONS
1221 // Check if breakpoint on memory is active, and deal with it
1222 if (bpmActive && address == bpmAddress1)
1226 // Musashi does this automagically for you, UAE core does not :-P
1227 address &= 0x00FFFFFF;
1228 #ifdef CPU_DEBUG_MEMORY
1229 // Note that the Jaguar only has 2M of RAM, not 4!
1230 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1234 if (value > writeMemMax[address])
1235 writeMemMax[address] = value;
1236 if (value < writeMemMin[address])
1237 writeMemMin[address] = value;
1241 /*if (address == 0x4E00)
1242 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1243 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1244 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1245 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1247 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1248 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1250 /*if (address >= 0x53D0 && address <= 0x53FF)
1251 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1252 //Testing AvP on UAE core...
1253 //000075A0: FFFFF80E B6320220 (BITMAP)
1254 /*if (address == 0x75A0 && value == 0xFF)
1255 printf("M68K: (8) Tripwire hit...\n");//*/
1258 // Note that the Jaguar only has 2M of RAM, not 4!
1259 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1260 jaguarMainRAM[address] = value;
1261 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1262 CDROMWriteByte(address, value, M68K);
1263 else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1264 TOMWriteByte(address, value, M68K);
1265 else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1266 JERRYWriteByte(address, value, M68K);
1268 jaguar_unknown_writebyte(address, value, M68K);
1270 MMUWrite8(address, value, M68K);
1275 void m68k_write_memory_16(unsigned int address, unsigned int value)
1277 #ifdef ALPINE_FUNCTIONS
1278 // Check if breakpoint on memory is active, and deal with it
1279 if (bpmActive && address == bpmAddress1)
1283 // Musashi does this automagically for you, UAE core does not :-P
1284 address &= 0x00FFFFFF;
1285 #ifdef CPU_DEBUG_MEMORY
1286 // Note that the Jaguar only has 2M of RAM, not 4!
1287 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1291 uint8_t hi = value >> 8, lo = value & 0xFF;
1293 if (hi > writeMemMax[address])
1294 writeMemMax[address] = hi;
1295 if (hi < writeMemMin[address])
1296 writeMemMin[address] = hi;
1298 if (lo > writeMemMax[address+1])
1299 writeMemMax[address+1] = lo;
1300 if (lo < writeMemMin[address+1])
1301 writeMemMin[address+1] = lo;
1305 /*if (address == 0x4E00)
1306 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1307 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1308 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1309 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1310 //if (address >= 0xF02200 && address <= 0xF0229F)
1311 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1312 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1313 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1314 /*extern uint32_t totalFrames;
1315 if (address == 0xF02114)
1316 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1317 if (address == 0xF02110)
1318 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1319 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1320 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1322 /*if (address == 0x0100)//64*4)
1323 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1325 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1326 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1327 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1328 || address == 0x1AF05E)
1329 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1331 /*if (address >= 0x53D0 && address <= 0x53FF)
1332 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1333 //Testing AvP on UAE core...
1334 //000075A0: FFFFF80E B6320220 (BITMAP)
1335 /*if (address == 0x75A0 && value == 0xFFFF)
1337 printf("\nM68K: (16) Tripwire hit...\n");
1342 // Note that the Jaguar only has 2M of RAM, not 4!
1343 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1345 /* jaguar_mainRam[address] = value >> 8;
1346 jaguar_mainRam[address + 1] = value & 0xFF;*/
1347 SET16(jaguarMainRAM, address, value);
1349 else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1350 CDROMWriteWord(address, value, M68K);
1351 else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1352 TOMWriteWord(address, value, M68K);
1353 else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1354 JERRYWriteWord(address, value, M68K);
1357 jaguar_unknown_writeword(address, value, M68K);
1358 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1359 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
1360 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
1361 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1365 MMUWrite16(address, value, M68K);
1370 void m68k_write_memory_32(unsigned int address, unsigned int value)
1372 #ifdef ALPINE_FUNCTIONS
1373 // Check if breakpoint on memory is active, and deal with it
1374 if (bpmActive && address == bpmAddress1)
1378 // Musashi does this automagically for you, UAE core does not :-P
1379 address &= 0x00FFFFFF;
1380 /*if (address == 0x4E00)
1381 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1382 //WriteLog("--> [WM32]\n");
1383 /*if (address == 0x0100)//64*4)
1384 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1385 /*if (address >= 0xF03214 && address < 0xF0321F)
1386 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1387 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1388 /*extern bool doGPUDis;
1389 if (address == 0xF03214 && value == 0x88E30047)
1391 doGPUDis = true;//*/
1392 /* if (address == 0x51136 || address == 0xFB074)
1393 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1394 //Testing AvP on UAE core...
1395 //000075A0: FFFFF80E B6320220 (BITMAP)
1396 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1398 printf("\nM68K: (32) Tripwire hit...\n");
1403 m68k_write_memory_16(address, value >> 16);
1404 m68k_write_memory_16(address + 2, value & 0xFFFF);
1406 MMUWrite32(address, value, M68K);
1411 uint32_t JaguarGetHandler(uint32_t i)
1413 return JaguarReadLong(i * 4);
1417 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1419 uint32_t handler = JaguarGetHandler(i);
1420 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1424 void M68K_show_context(void)
1426 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1428 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1430 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1432 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1436 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1438 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1440 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1444 WriteLog("68K disasm\n");
1445 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1446 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1447 // jaguar_dasm(0x5000, 0x14414);
1449 // WriteLog("\n.......[Cart start]...........\n\n");
1450 // jaguar_dasm(0x192000, 0x1000);//0x200);
1452 WriteLog("..................\n");
1454 if (TOMIRQEnabled(IRQ_VIDEO))
1456 WriteLog("video int: enabled\n");
1457 JaguarDasm(JaguarGetHandler(64), 0x200);
1460 WriteLog("video int: disabled\n");
1462 WriteLog("..................\n");
1464 for(int i=0; i<256; i++)
1466 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1467 uint32_t address = (uint32_t)JaguarGetHandler(i);
1470 WriteLog(".........\n");
1472 WriteLog("$%08X\n", address);
1478 // Unknown read/write byte/word routines
1481 // It's hard to believe that developers would be sloppy with their memory
1482 // writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1483 // has the following code:
1485 // 807EC4: movea.l #$f1b000, A1
1486 // 807ECA: movea.l #$8129e0, A0
1487 // 807ED0: move.l A0, D0
1488 // 807ED2: move.l #$f1bb94, D1
1489 // 807ED8: sub.l D0, D1
1490 // 807EDA: lsr.l #2, D1
1491 // 807EDC: move.l (A0)+, (A1)+
1492 // 807EDE: dbra D1, 807edc
1494 // The problem is at $807ED0--instead of putting A0 into D0, they really meant
1495 // to put A1 in. This mistake causes it to try and overwrite approximately
1496 // $700000 worth of address space! (That is, unless the 68K causes a bus
1499 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1501 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1502 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));
1504 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1505 // extern bool finished;
1507 // extern bool doDSPDis;
1514 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1516 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1517 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));
1519 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1520 // extern bool finished;
1522 // extern bool doDSPDis;
1529 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1531 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1532 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1534 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1535 // extern bool finished;
1537 // extern bool doDSPDis;
1545 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1547 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1548 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1550 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1551 // extern bool finished;
1553 // extern bool doDSPDis;
1562 // Disassemble M68K instructions at the given offset
1565 unsigned int m68k_read_disassembler_8(unsigned int address)
1567 return m68k_read_memory_8(address);
1571 unsigned int m68k_read_disassembler_16(unsigned int address)
1573 return m68k_read_memory_16(address);
1577 unsigned int m68k_read_disassembler_32(unsigned int address)
1579 return m68k_read_memory_32(address);
1583 void JaguarDasm(uint32_t offset, uint32_t qt)
1586 static char buffer[2048];//, mem[64];
1587 int pc = offset, oldpc;
1589 for(uint32_t i=0; i<qt; i++)
1592 for(int j=0; j<64; j++)
1593 mem[j^0x01] = jaguar_byte_read(pc + j);
1595 pc += Dasm68000((char *)mem, buffer, 0);
1596 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1598 pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
1599 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1605 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1607 uint8_t data = 0x00;
1610 // First 2M is mirrored in the $0 - $7FFFFF range
1611 if (offset < 0x800000)
1612 data = jaguarMainRAM[offset & 0x1FFFFF];
1613 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1614 data = jaguarMainROM[offset - 0x800000];
1615 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1616 data = CDROMReadByte(offset, who);
1617 else if ((offset >= 0xE00000) && (offset < 0xE40000))
1618 // data = jaguarBootROM[offset & 0x3FFFF];
1619 // data = jaguarDevBootROM1[offset & 0x3FFFF];
1620 data = jagMemSpace[offset];
1621 else if ((offset >= 0xF00000) && (offset < 0xF10000))
1622 data = TOMReadByte(offset, who);
1623 else if ((offset >= 0xF10000) && (offset < 0xF20000))
1624 data = JERRYReadByte(offset, who);
1626 data = jaguar_unknown_readbyte(offset, who);
1632 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1636 // First 2M is mirrored in the $0 - $7FFFFF range
1637 if (offset < 0x800000)
1639 return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
1641 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
1644 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
1646 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
1647 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
1648 return CDROMReadWord(offset, who);
1649 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
1650 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
1651 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
1652 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
1653 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
1654 return TOMReadWord(offset, who);
1655 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
1656 return JERRYReadWord(offset, who);
1658 return jaguar_unknown_readword(offset, who);
1662 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1664 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1666 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
1668 /* if (offset >= 0x4E00 && offset < 0x4E04)
1669 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1670 //Need to check for writes in the range of $18FA70 + 8000...
1672 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1673 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
1677 // First 2M is mirrored in the $0 - $7FFFFF range
1678 if (offset < 0x800000)
1680 jaguarMainRAM[offset & 0x1FFFFF] = data;
1683 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
1685 CDROMWriteByte(offset, data, who);
1688 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
1690 TOMWriteByte(offset, data, who);
1693 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
1695 JERRYWriteByte(offset, data, who);
1699 jaguar_unknown_writebyte(offset, data, who);
1704 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1706 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
1708 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
1709 WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
1711 /* if (offset >= 0x4E00 && offset < 0x4E04)
1712 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1713 /*if (offset == 0x0100)//64*4)
1714 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
1715 if (offset == 0x0102)//64*4)
1716 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
1717 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
1718 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
1719 //Need to check for writes in the range of $18FA70 + 8000...
1721 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
1722 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
1723 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
1724 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
1728 // First 2M is mirrored in the $0 - $7FFFFF range
1729 if (offset <= 0x7FFFFE)
1734 1A 69 F0 ($0000) -> Starfield
1735 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
1738 1A 8F E8 ($0004) -> "Jaguar" small color logo?
1747 //This MUST be done by the 68K!
1748 /*if (offset == 0x670C)
1749 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
1751 /*extern bool doGPUDis;
1752 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
1753 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1754 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
1755 doGPUDis = true;//*/
1756 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
1757 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
1758 if ((data & 0xFF00) != 0x7700)
1759 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1760 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
1762 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
1763 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
1764 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
1766 /*extern bool doGPUDis;
1767 if (offset == 0x120216 && who == GPU)
1768 doGPUDis = true;//*/
1769 /*extern uint32_t gpu_pc;
1770 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1772 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1773 uint32_t y = base / 0x300;
1774 uint32_t x = (base - (y * 0x300)) / 2;
1775 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1778 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
1780 //if (offset == (0x001E17F8 + 0x34))
1781 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
1783 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
1784 /*extern uint32_t gpu_pc;
1785 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
1787 extern int objectPtr;
1788 // if (offset > 0x148000)
1791 if (starCount > objectPtr)
1794 // if (starCount == 1)
1795 // WriteLog("--> Drawing 1st star...\n");
1797 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
1798 // uint32_t y = base / 0x300;
1799 // uint32_t x = (base - (y * 0x300)) / 2;
1800 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
1802 //A star of interest...
1803 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
1804 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
1805 //JWW: Blitter writing echo 77B3 at 0011D022...
1807 //extern bool doGPUDis;
1808 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
1811 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
1814 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
1815 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
1817 jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
1818 jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
1821 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
1823 CDROMWriteWord(offset, data, who);
1826 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
1828 TOMWriteWord(offset, data, who);
1831 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
1833 JERRYWriteWord(offset, data, who);
1836 // Don't bomb on attempts to write to ROM
1837 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
1840 jaguar_unknown_writeword(offset, data, who);
1844 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1845 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1847 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
1851 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
1852 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
1854 /* extern bool doDSPDis;
1855 if (offset < 0x400 && !doDSPDis)
1857 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
1860 /*if (offset == 0x0100)//64*4)
1861 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
1863 JaguarWriteWord(offset, data >> 16, who);
1864 JaguarWriteWord(offset+2, data & 0xFFFF, who);
1868 void JaguarSetScreenBuffer(uint32_t * buffer)
1870 // This is in TOM, but we set it here...
1871 screenBuffer = buffer;
1875 void JaguarSetScreenPitch(uint32_t pitch)
1877 // This is in TOM, but we set it here...
1878 screenPitch = pitch;
1883 // Jaguar console initialization
1885 void JaguarInit(void)
1887 // For randomizing RAM
1890 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1891 for(uint32_t i=0; i<0x200000; i+=4)
1892 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1894 #ifdef CPU_DEBUG_MEMORY
1895 memset(readMem, 0x00, 0x400000);
1896 memset(writeMemMin, 0xFF, 0x400000);
1897 memset(writeMemMax, 0x00, 0x400000);
1899 // memset(jaguarMainRAM, 0x00, 0x200000);
1900 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
1901 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
1902 //NOTE: This *doesn't* fix FlipOut...
1903 //Or does it? Hmm...
1904 //Seems to want $01010101... Dunno why. Investigate!
1905 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
1906 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
1907 lowerField = false; // Reset the lower field flag
1908 //temp, for crappy crap that sux
1909 memset(jaguarMainRAM + 0x804, 0xFF, 4);
1911 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
1920 //New timer based code stuffola...
1921 void HalflineCallback(void);
1922 void RenderCallback(void);
1923 void JaguarReset(void)
1925 // Only problem with this approach: It wipes out RAM loaded files...!
1926 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1927 for(uint32_t i=8; i<0x200000; i+=4)
1928 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
1930 // New timer base code stuffola...
1931 InitializeEventList();
1932 //Need to change this so it uses the single RAM space and load the BIOS
1933 //into it somewhere...
1934 //Also, have to change this here and in JaguarReadXX() currently
1935 // Only use the system BIOS if it's available...! (it's always available now!)
1936 // AND only if a jaguar cartridge has been inserted.
1937 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
1938 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
1940 SET32(jaguarMainRAM, 4, jaguarRunAddress);
1942 // WriteLog("jaguar_reset():\n");
1948 m68k_pulse_reset(); // Reset the 68000
1949 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
1951 lowerField = false; // Reset the lower field flag
1952 // SetCallbackTime(ScanlineCallback, 63.5555);
1953 // SetCallbackTime(ScanlineCallback, 31.77775);
1954 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
1958 void JaguarDone(void)
1960 #ifdef CPU_DEBUG_MEMORY
1961 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
1963 for(uint32_t i=0; i<=raPtr; i++)
1965 WriteLog("\t%08X\n", returnAddr[i]);
1966 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
1967 jaguar_dasm(returnAddr[i] - 16, 16);
1972 /* int start = 0, end = 0;
1973 bool endTriggered = false, startTriggered = false;
1974 for(int i=0; i<0x400000; i++)
1976 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
1978 if (!startTriggered)
1979 startTriggered = true, endTriggered = false, start = i;
1981 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
1987 end = i - 1, endTriggered = true, startTriggered = false;
1988 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
1995 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1996 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1997 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
1998 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2000 for(int i=-2; i<9; i++)
2001 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2003 uint32_t address = topOfStack - (4 * 4 * 3);
2005 for(int i=0; i<10; i++)
2007 WriteLog("%06X:", address);
2009 for(int j=0; j<4; j++)
2011 WriteLog(" %08X", JaguarReadLong(address));
2019 /* WriteLog("\nM68000 disassembly at $802288...\n");
2020 jaguar_dasm(0x802288, 3);
2021 WriteLog("\nM68000 disassembly at $802200...\n");
2022 jaguar_dasm(0x802200, 500);
2023 WriteLog("\nM68000 disassembly at $802518...\n");
2024 jaguar_dasm(0x802518, 100);//*/
2026 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2027 jaguar_dasm(0x803F00, 500);
2030 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2031 jaguar_dasm(0x802B00, 500);
2034 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2035 jaguar_dasm(0x809900, 500);
2038 /* WriteLog("\n\nDump of $8093C8:\n\n");
2039 for(int i=0x8093C8; i<0x809900; i+=4)
2040 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2041 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2042 jaguar_dasm(0x90006C, 500);
2044 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2045 jaguar_dasm(0x1AC000, 6000);
2048 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2049 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2050 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2051 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2052 M68K_show_context();
2061 // temp, until debugger is in place
2062 //00802016: jsr $836F1A.l
2063 //0080201C: jsr $836B30.l
2064 //00802022: jsr $836B18.l
2065 //00802028: jsr $8135F0.l
2066 //00813C1E: jsr $813F76.l
2067 //00802038: jsr $836D00.l
2068 //00802098: jsr $8373A4.l
2069 //008020A2: jsr $83E24A.l
2070 //008020BA: jsr $83E156.l
2071 //008020C6: jsr $83E19C.l
2072 //008020E6: jsr $8445E8.l
2073 //008020EC: jsr $838C20.l
2074 //0080211A: jsr $838ED6.l
2075 //00802124: jsr $89CA56.l
2076 //0080212A: jsr $802B48.l
2078 WriteLog("-------------------------------------------\n");
2079 JaguarDasm(0x8445E8, 0x200);
2080 WriteLog("-------------------------------------------\n");
2081 JaguarDasm(0x838C20, 0x200);
2082 WriteLog("-------------------------------------------\n");
2083 JaguarDasm(0x838ED6, 0x200);
2084 WriteLog("-------------------------------------------\n");
2085 JaguarDasm(0x89CA56, 0x200);
2086 WriteLog("-------------------------------------------\n");
2087 JaguarDasm(0x802B48, 0x200);
2088 WriteLog("\n\nM68000 disassembly at $802000...\n");
2089 JaguarDasm(0x802000, 6000);
2092 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2093 JaguarDasm(0x6004, 10000);
2095 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2096 // JaguarDasm(0x802000, 0x1000);
2097 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2098 // JaguarDasm(0x4100, 200);
2099 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2100 // JaguarDasm(0x800800, 0x1000);
2104 // Temp debugging stuff
2106 void DumpMainMemory(void)
2108 FILE * fp = fopen("./memdump.bin", "wb");
2113 fwrite(jaguarMainRAM, 1, 0x200000, fp);
2118 uint8_t * GetRamPtr(void)
2120 return jaguarMainRAM;
2125 // New Jaguar execution stack
2126 // This executes 1 frame's worth of code.
2129 void JaguarExecuteNew(void)
2135 double timeToNextEvent = GetTimeToNextEvent();
2136 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2138 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2141 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2150 // The thing to keep in mind is that the VC is advanced every HALF line,
2151 // regardless of whether the display is interlaced or not. The only difference
2152 // with an interlaced display is that the high bit of VC will be set when the
2153 // lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2154 // lower field, regardless of whether it's in interlace mode or not.
2155 // NB2: Seems it doesn't always, not sure what the constraint is...)
2157 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2158 // rendering two fields that are slighty vertically offset from each other.
2159 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2160 // is rendered in this mode so that each field, when overlaid on each other,
2161 // will yield the final picture at the full resolution for the full frame.
2163 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2164 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2165 // it will be half this number for a half frame. BUT, since we're counting
2166 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2169 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2170 // Half line times are, naturally, half of this. :-P
2172 void HalflineCallback(void)
2174 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2175 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2176 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2177 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2180 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2181 // So we cut the number of half-lines in a frame in half. :-P
2182 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2184 if ((vc & 0x7FF) >= numHalfLines)
2186 lowerField = !lowerField;
2187 // If we're rendering the lower field, set the high bit (#11, counting
2189 vc = (lowerField ? 0x0800 : 0x0000);
2192 //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2193 TOMWriteWord(0xF00006, vc, JAGUAR);
2195 // Time for Vertical Interrupt?
2196 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2198 // We don't have to worry about autovectors & whatnot because the Jaguar
2199 // tells you through its HW registers who sent the interrupt...
2200 TOMSetPendingVideoInt();
2204 TOMExecHalfline(vc, true);
2206 //Change this to VBB???
2207 //Doesn't seem to matter (at least for Flip Out & I-War)
2208 if ((vc & 0x7FF) == 0)
2215 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));