Added a specific breakpoint for the M68K illegal instruction exception
[clinton/Virtual-Jaguar-Rx.git] / src / jaguar.cpp
1 //
2 // JAGUAR.CPP
3 //
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. :-)
9 //
10 // JLH = James Hammons
11 // JPM = Jean-Paul Mari
12 //
13 // WHO WHEN WHAT
14 // --- ---------- -----------------------------------------------------------
15 // JLH 11/25/2009 Major rewrite of memory subsystem and handlers
16 // JPM 09/04/2018 Added the new Models and BIOS handler
17 // JPM 10/13/2018 Added breakpoints features
18 //
19
20
21 #define NEWMODELSBIOSHANDLER // New Jaguar models and bios usage handler
22
23
24 #include "jaguar.h"
25 #include <QApplication>
26 #include <QMessageBox>
27 #include <time.h>
28 #include <SDL.h>
29 #include "SDL_opengl.h"
30 #include "blitter.h"
31 #include "cdrom.h"
32 #include "dac.h"
33 #include "dsp.h"
34 #include "eeprom.h"
35 #include "event.h"
36 #include "foooked.h"
37 #include "gpu.h"
38 #include "jerry.h"
39 #include "joystick.h"
40 #include "log.h"
41 #include "m68000/m68kinterface.h"
42 //#include "memory.h"
43 #include "memtrack.h"
44 #include "mmu.h"
45 #include "settings.h"
46 #include "tom.h"
47 //#include "debugger/BreakpointsWin.h"
48 #ifdef NEWMODELSBIOSHANDLER
49 #include "modelsBIOS.h"
50 #endif
51
52 #define CPU_DEBUG
53 //Do this in makefile??? Yes! Could, but it's easier to define here...
54 //#define LOG_UNMAPPED_MEMORY_ACCESSES
55 //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS
56 //#define ABORT_ON_ILLEGAL_INSTRUCTIONS
57 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
58 #define CPU_DEBUG_MEMORY
59 //#define LOG_CD_BIOS_CALLS
60 #define CPU_DEBUG_TRACING
61 #define ALPINE_FUNCTIONS
62
63 // Private function prototypes
64
65 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
66 unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
67 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
68 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
69 void M68K_show_context(void);
70 #if 0
71 void M68K_Debughalt(void);
72 #endif
73
74 // External variables
75
76 #ifdef CPU_DEBUG_MEMORY
77 extern bool startMemLog; // Set by "e" key
78 extern int effect_start;
79 extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6;
80 #endif
81
82 // Really, need to include memory.h for this, but it might interfere with some stuff...
83 extern uint8_t jagMemSpace[];
84
85 // Internal variables
86
87 uint32_t jaguar_active_memory_dumps = 0;
88
89 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
90 bool jaguarCartInserted = false;
91 bool lowerField = false;
92
93 #ifdef CPU_DEBUG_MEMORY
94 uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
95 uint8_t readMem[0x400000];
96 uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
97 #endif
98
99 uint32_t pcQueue[0x400];
100 uint32_t a0Queue[0x400];
101 uint32_t a1Queue[0x400];
102 uint32_t a2Queue[0x400];
103 uint32_t a3Queue[0x400];
104 uint32_t a4Queue[0x400];
105 uint32_t a5Queue[0x400];
106 uint32_t a6Queue[0x400];
107 uint32_t a7Queue[0x400];
108 uint32_t d0Queue[0x400];
109 uint32_t d1Queue[0x400];
110 uint32_t d2Queue[0x400];
111 uint32_t d3Queue[0x400];
112 uint32_t d4Queue[0x400];
113 uint32_t d5Queue[0x400];
114 uint32_t d6Queue[0x400];
115 uint32_t d7Queue[0x400];
116 uint32_t srQueue[0x400];
117 uint32_t pcQPtr = 0;
118 bool startM68KTracing = false;
119
120 // Breakpoint on memory access vars (exported)
121 bool bpmActive = false;
122 bool bpmSaveActive = false;
123 size_t bpmHitCounts;
124 uint32_t bpmAddress1;
125 S_BrkInfo *brkInfo;
126 size_t brkNbr;
127
128
129 //
130 // Callback function to detect illegal instructions
131 //
132 void GPUDumpDisassembly(void);
133 void GPUDumpRegisters(void);
134 static bool start = false;
135
136 void M68KInstructionHook(void)
137 {
138 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
139 // Temp, for comparing...
140 {
141 /* static char buffer[2048];//, mem[64];
142 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
143 printf("%08X: %s\n", m68kPC, buffer);//*/
144 }
145 //JaguarDasm(m68kPC, 1);
146 //Testing Hover Strike...
147 #if 0
148 //Dasm(regs.pc, 1);
149 static int hitCount = 0;
150 static int inRoutine = 0;
151 static int instSeen;
152
153 //if (regs.pc == 0x80340A)
154 if (m68kPC == 0x803416)
155 {
156 hitCount++;
157 inRoutine = 1;
158 instSeen = 0;
159 printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1));
160 }
161 else if (m68kPC == 0x803422)
162 {
163 inRoutine = 0;
164 printf("(%i instructions)\n", instSeen);
165 }
166
167 if (inRoutine)
168 instSeen++;
169 #endif
170
171 // For code tracing...
172 #ifdef CPU_DEBUG_TRACING
173 if (startM68KTracing)
174 {
175 static char buffer[2048];
176
177 m68k_disassemble(buffer, m68kPC, 0, 1);
178 WriteLog("%06X: %s\n", m68kPC, buffer);
179 }
180 #endif
181
182 // For tracebacks...
183 // Ideally, we'd save all the registers as well...
184 pcQueue[pcQPtr] = m68kPC;
185 a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
186 a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
187 a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
188 a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
189 a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
190 a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
191 a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
192 a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
193 d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
194 d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
195 d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
196 d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
197 d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
198 d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
199 d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
200 d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
201 srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR);
202 pcQPtr++;
203 pcQPtr &= 0x3FF;
204
205 if (m68kPC & 0x01) // Oops! We're fetching an odd address!
206 {
207 WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
208
209 static char buffer[2048];
210 for(int i=0; i<0x400; i++)
211 {
212 // WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
213 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]);
214 m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0, 1);//M68K_CPU_TYPE_68000);
215 WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
216 }
217 WriteLog("\n");
218
219 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
220 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
221 for(int i=0; i<10; i++)
222 WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4)));
223 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
224 M68K_show_context();
225 LogDone();
226 exit(0);
227 }
228
229 // Disassemble everything
230 /* {
231 static char buffer[2048];
232 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
233 WriteLog("%08X: %s", m68kPC, buffer);
234 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
235 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
236 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
237 }//*/
238 /* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB)
239 {
240 static char buffer[2048];
241 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
242 WriteLog("%08X: %s", m68kPC, buffer);
243 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n",
244 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
245 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
246 }//*/
247 /* if (m68kPC == 0x8D0E48 && effect_start5)
248 {
249 WriteLog("\nM68K: At collision detection code. Exiting!\n\n");
250 GPUDumpRegisters();
251 GPUDumpDisassembly();
252 log_done();
253 exit(0);
254 }//*/
255 /* uint16_t opcode = JaguarReadWord(m68kPC);
256 if (opcode == 0x4E75) // RTS
257 {
258 if (startMemLog)
259 // WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)));
260 {
261 uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7));
262 bool found = false;
263 if (raPtr != 0xFFFFFFFF)
264 {
265 for(uint32_t i=0; i<=raPtr; i++)
266 {
267 if (returnAddr[i] == addr)
268 {
269 found = true;
270 break;
271 }
272 }
273 }
274
275 if (!found)
276 returnAddr[++raPtr] = addr;
277 }
278 }//*/
279
280 //Flip Out! debugging...
281 //805F46, 806486
282 /*
283 00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
284 00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
285 00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
286 00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
287
288 0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
289
290 0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
291 0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
292 00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
293 00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
294 00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
295 0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
296 00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000
297 */
298 /* static char buffer[2048];
299 //if (m68kPC > 0x805F48) start = true;
300 //if (m68kPC > 0x806486) start = true;
301 //if (m68kPC == 0x805FEE) start = true;
302 //if (m68kPC == 0x80600C)// start = true;
303 if (m68kPC == 0x802058) start = true;
304 //{
305 // GPUDumpRegisters();
306 // GPUDumpDisassembly();
307 //
308 // M68K_show_context();
309 // log_done();
310 // exit(0);
311 //}
312 if (start)
313 {
314 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
315 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));
316 }//*/
317
318 /* if (m68kPC == 0x803F16)
319 {
320 WriteLog("M68K: Registers found at $803F16:\n");
321 WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
322 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
323 WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
324 WriteLog("\n");
325 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
326 WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
327 }*/
328 //Looks like the DSP is supposed to return $12345678 when it finishes its validation routine...
329 // !!! Investigate !!!
330 /*extern bool doDSPDis;
331 static bool disgo = false;
332 if (m68kPC == 0x50222)
333 {
334 // CD BIOS hacking
335 // WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K));
336 // DSPWriteLong(0xF1B000, 0x12345678, M68K);
337 // disgo = true;
338 }
339 if (m68kPC == 0x5000)
340 // doDSPDis = true;
341 disgo = true;
342 if (disgo)
343 {
344 static char buffer[2048];
345 m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
346 WriteLog("%08X: %s", m68kPC, buffer);
347 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
348 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
349 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
350 }//*/
351 /* if (m68kPC == 0x82E1A)
352 {
353 static char buffer[2048];
354 m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000);
355 WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer);
356 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
357 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
358 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
359 }//*/
360 /* if (m68kPC == 0x82E58)
361 WriteLog("--> [Routine end]\n");
362 if (m68kPC == 0x80004)
363 {
364 WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
365 // m68k_set_reg(M68K_REG_D2, 0x12345678);
366 }//*/
367
368 #ifdef LOG_CD_BIOS_CALLS
369 /*
370 CD_init:: -> $3000
371 BIOS_VER:: -> $3004
372 CD_mode:: -> $3006
373 CD_ack:: -> $300C
374 CD_jeri:: -> $3012
375 CD_spin:: -> $3018
376 CD_stop:: -> $301E
377 CD_mute:: -> $3024
378 CD_umute:: -> $302A
379 CD_paus:: -> $3030
380 CD_upaus:: -> $3036
381 CD_read:: -> $303C
382 CD_uread:: -> $3042
383 CD_setup:: -> $3048
384 CD_ptr:: -> $304E
385 CD_osamp:: -> $3054
386 CD_getoc:: -> $305A
387 CD_initm:: -> $3060
388 CD_initf:: -> $3066
389 CD_switch:: -> $306C
390 */
391 if (m68kPC == 0x3000)
392 WriteLog("M68K: CD_init\n");
393 else if (m68kPC == 0x3006 + (6 * 0))
394 WriteLog("M68K: CD_mode\n");
395 else if (m68kPC == 0x3006 + (6 * 1))
396 WriteLog("M68K: CD_ack\n");
397 else if (m68kPC == 0x3006 + (6 * 2))
398 WriteLog("M68K: CD_jeri\n");
399 else if (m68kPC == 0x3006 + (6 * 3))
400 WriteLog("M68K: CD_spin\n");
401 else if (m68kPC == 0x3006 + (6 * 4))
402 WriteLog("M68K: CD_stop\n");
403 else if (m68kPC == 0x3006 + (6 * 5))
404 WriteLog("M68K: CD_mute\n");
405 else if (m68kPC == 0x3006 + (6 * 6))
406 WriteLog("M68K: CD_umute\n");
407 else if (m68kPC == 0x3006 + (6 * 7))
408 WriteLog("M68K: CD_paus\n");
409 else if (m68kPC == 0x3006 + (6 * 8))
410 WriteLog("M68K: CD_upaus\n");
411 else if (m68kPC == 0x3006 + (6 * 9))
412 WriteLog("M68K: CD_read\n");
413 else if (m68kPC == 0x3006 + (6 * 10))
414 WriteLog("M68K: CD_uread\n");
415 else if (m68kPC == 0x3006 + (6 * 11))
416 WriteLog("M68K: CD_setup\n");
417 else if (m68kPC == 0x3006 + (6 * 12))
418 WriteLog("M68K: CD_ptr\n");
419 else if (m68kPC == 0x3006 + (6 * 13))
420 WriteLog("M68K: CD_osamp\n");
421 else if (m68kPC == 0x3006 + (6 * 14))
422 WriteLog("M68K: CD_getoc\n");
423 else if (m68kPC == 0x3006 + (6 * 15))
424 WriteLog("M68K: CD_initm\n");
425 else if (m68kPC == 0x3006 + (6 * 16))
426 WriteLog("M68K: CD_initf\n");
427 else if (m68kPC == 0x3006 + (6 * 17))
428 WriteLog("M68K: CD_switch\n");
429
430 if (m68kPC >= 0x3000 && m68kPC <= 0x306C)
431 WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
432 m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
433 m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
434 #endif
435
436 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
437 if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000))
438 {
439 #ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
440 if (m68k_read_memory_16(m68kPC) == 0x4AFC)
441 {
442 // This is a kludge to let homebrew programs work properly (i.e., let the other processors
443 // keep going even when the 68K dumped back to the debugger or what have you).
444 //dis no wok right!
445 // m68k_set_reg(M68K_REG_PC, m68kPC - 2);
446 // Try setting the vector to the illegal instruction...
447 //This doesn't work right either! Do something else! Quick!
448 // SET32(jaguar_mainRam, 0x10, m68kPC);
449
450 return;
451 }
452 #endif
453
454 WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC);
455 uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
456 WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack));
457 uint32_t address = topOfStack - (4 * 4 * 3);
458
459 for(int i=0; i<10; i++)
460 {
461 WriteLog("%06X:", address);
462
463 for(int j=0; j<4; j++)
464 {
465 WriteLog(" %08X", JaguarReadLong(address));
466 address += 4;
467 }
468
469 WriteLog("\n");
470 }
471
472 WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
473 M68K_show_context();
474
475 //temp
476 // WriteLog("\n\n68K disasm\n\n");
477 // jaguar_dasm(0x802000, 0x50C);
478 // WriteLog("\n\n");
479 //endoftemp
480
481 LogDone();
482 exit(0);
483 }//*/
484 #endif
485 }
486
487 #if 0
488 Now here be dragons...
489 Here is how memory ranges are defined in the CoJag driver.
490 Note that we only have to be concerned with 3 entities read/writing anything:
491 The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
492 checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
493 things that are entirely internal to those modules. This way we should be able to get a handle on all
494 this crap which is currently scattered over Hell's Half Acre(tm).
495
496 Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
497 is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone.
498
499 /*************************************
500 *
501 * Main CPU memory handlers
502 *
503 *************************************/
504
505 static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 )
506 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1)
507 AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base)
508 AM_RANGE(0xa00000, 0xa1ffff) AM_RAM
509 AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
510 AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w)
511 AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w)
512 AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w)
513 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2)
514 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
515 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
516 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2)
517 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
518 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
519 AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3)
520 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
521 AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02
522 AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03
523 // AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04
524 AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05
525 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
526 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
527 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4)
528 ADDRESS_MAP_END
529
530 /*************************************
531 *
532 * GPU memory handlers
533 *
534 *************************************/
535
536 static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 )
537 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
538 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
539 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
540 AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w)
541 AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w)
542 AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2)
543 AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w)
544 AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w)
545 AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3)
546 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
547 ADDRESS_MAP_END
548
549 /*************************************
550 *
551 * DSP memory handlers
552 *
553 *************************************/
554
555 static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 )
556 AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1)
557 AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8)
558 AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9)
559 AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w)
560 AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w)
561 AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w)
562 AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4)
563 AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom)
564 ADDRESS_MAP_END
565 */
566 #endif
567
568 //#define EXPERIMENTAL_MEMORY_HANDLING
569 // Experimental memory mappage...
570 // Dunno if this is a good approach or not, but it seems to make better
571 // sense to have all this crap in one spot intstead of scattered all over
572 // the place the way it is now.
573 #ifdef EXPERIMENTAL_MEMORY_HANDLING
574 // Needed defines...
575 #define NEW_TIMER_SYSTEM
576
577 /*
578 uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
579 uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
580 uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
581 uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
582 bool BIOSLoaded = false;
583 bool CDBIOSLoaded = false;
584
585 uint8_t cdRAM[0x100];
586 uint8_t tomRAM[0x4000];
587 uint8_t jerryRAM[0x10000];
588 static uint16_t eeprom_ram[64];
589
590 // NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all)
591 */
592
593 enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
594
595 // M68K Memory map/handlers
596 uint32_t {
597 { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
598 { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
599 // Note that this is really memory mapped I/O region...
600 // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM },
601 { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W
602 { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W
603 { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W
604 { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W
605 { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W
606 { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A
607 { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B
608 { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24)
609 { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data
610 { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old)
611 { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface
612
613 { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM },
614
615 // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW },
616 { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler },
617 { 0xF00052, 0xF00053, MM_IO, tomTimerDivider },
618 { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other...
619 { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well
620 //What about LBUF writes???
621 { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL
622 { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER
623 { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM
624
625 { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW },
626
627 /*
628 EEPROM:
629 { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO }
630 { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR }
631 { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ }
632
633 JOYSTICK:
634 { 0xF14000, 0xF14003, MM_IO, joystickFoo }
635 0 = pad0/1 button values (4 bits each), RO(?)
636 1 = pad0/1 index value (4 bits each), WO
637 2 = unused, RO
638 3 = NTSC/PAL, certain button states, RO
639
640 JOYSTICK $F14000 Read/Write
641 15.....8 7......0
642 Read fedcba98 7654321q f-1 Signals J15 to J1
643 q Cartridge EEPROM output data
644 Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs
645 0 = disable J7-J0 outputs
646 x don't care
647 m Audio mute
648 0 = Audio muted (reset state)
649 1 = Audio enabled
650 7-4 J7-J4 outputs (port 2)
651 3-0 J3-J0 outputs (port 1)
652 JOYBUTS $F14002 Read Only
653 15.....8 7......0
654 Read xxxxxxxx rrdv3210 x don't care
655 r Reserved
656 d Reserved
657 v 1 = NTSC Video hardware
658 0 = PAL Video hardware
659 3-2 Button inputs B3 & B2 (port 2)
660 1-0 Button inputs B1 & B0 (port 1)
661
662 J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
663 J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11
664 0 0 0 0
665 0 0 0 1
666 0 0 1 0
667 0 0 1 1
668 0 1 0 0
669 0 1 0 1
670 0 1 1 0
671 0 1 1 1 Row 3 C3 Option # 9 6 3
672 1 0 0 0
673 1 0 0 1
674 1 0 1 0
675 1 0 1 1 Row 2 C2 C 0 8 5 2
676 1 1 0 0
677 1 1 0 1 Row 1 C1 B * 7 4 1
678 1 1 1 0 Row 0 Pause A Up Down Left Right
679 1 1 1 1
680
681 0 bit read in any position means that button is pressed.
682 C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
683 */
684 };
685
686 void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/)
687 {
688 // Not sure, but I think the system only has 24 address bits...
689 address &= 0x00FFFFFF;
690
691 // RAM ($000000 - $3FFFFF) 4M
692 if (address <= 0x3FFFFF)
693 jaguarMainRAM[address] = byte;
694 // hole ($400000 - $7FFFFF) 4M
695 else if (address <= 0x7FFFFF)
696 ; // Do nothing
697 // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes
698 else if (address <= 0xDFFEFF)
699 ; // Do nothing
700 // CDROM ($DFFF00 - $DFFFFF) 256 bytes
701 else if (address <= 0xDFFFFF)
702 {
703 cdRAM[address & 0xFF] = byte;
704 #ifdef CDROM_LOG
705 if ((address & 0xFF) < 12 * 4)
706 WriteLog("[%s] ", BReg[(address & 0xFF) / 4]);
707 WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
708 #endif
709 }
710 // BIOS ROM ($E00000 - $E3FFFF) 256K
711 else if (address <= 0xE3FFFF)
712 ; // Do nothing
713 // hole ($E40000 - $EFFFFF) 768K
714 else if (address <= 0xEFFFFF)
715 ; // Do nothing
716 // TOM ($F00000 - $F0FFFF) 64K
717 else if (address <= 0xF0FFFF)
718 // ; // Do nothing
719 {
720 if (address == 0xF00050)
721 {
722 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8);
723 TOMResetPIT();
724 return;
725 }
726 else if (address == 0xF00051)
727 {
728 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte;
729 TOMResetPIT();
730 return;
731 }
732 else if (address == 0xF00052)
733 {
734 tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8);
735 TOMResetPIT();
736 return;
737 }
738 else if (address == 0xF00053)
739 {
740 tomTimerDivider = (tomTimerDivider & 0xFF00) | byte;
741 TOMResetPIT();
742 return;
743 }
744 else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B)
745 {
746 // Writing to one CLUT writes to the other
747 address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
748 tomRAM[address] = tomRAM[address + 0x200] = byte;
749 return;
750 }
751 //What about LBUF writes???
752 else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL
753 {
754 GPUWriteByte(address, byte, who);
755 return;
756 }
757 else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER
758 {
759 BlitterWriteByte(address, byte, who);
760 return;
761 }
762 else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM
763 {
764 GPUWriteByte(address, byte, who);
765 return;
766 }
767
768 tomRAM[address & 0x3FFF] = byte;
769 }
770 // JERRY ($F10000 - $F1FFFF) 64K
771 else if (address <= 0xF1FFFF)
772 // ; // Do nothing
773 {
774 #ifdef JERRY_DEBUG
775 WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address);
776 #endif
777 if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20))
778 {
779 DSPWriteByte(address, byte, who);
780 return;
781 }
782 else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000))
783 {
784 DSPWriteByte(address, byte, who);
785 return;
786 }
787 // SCLK ($F1A150--8 bits wide)
788 //NOTE: This should be taken care of in DAC...
789 else if ((address >= 0xF1A152) && (address <= 0xF1A153))
790 {
791 // WriteLog("JERRY: Writing %02X to SCLK...\n", data);
792 if ((address & 0x03) == 2)
793 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8);
794 else
795 JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte;
796
797 JERRYI2SInterruptTimer = -1;
798 #ifndef NEW_TIMER_SYSTEM
799 jerry_i2s_exec(0);
800 #else
801 RemoveCallback(JERRYI2SCallback);
802 JERRYI2SCallback();
803 #endif
804 // return;
805 }
806 // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
807 else if (address >= 0xF1A148 && address <= 0xF1A157)
808 {
809 DACWriteByte(address, byte, who);
810 return;
811 }
812 else if (address >= 0xF10000 && address <= 0xF10007)
813 {
814 #ifndef NEW_TIMER_SYSTEM
815 switch (address & 0x07)
816 {
817 case 0:
818 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8);
819 JERRYResetPIT1();
820 break;
821 case 1:
822 JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte;
823 JERRYResetPIT1();
824 break;
825 case 2:
826 JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8);
827 JERRYResetPIT1();
828 break;
829 case 3:
830 JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte;
831 JERRYResetPIT1();
832 break;
833 case 4:
834 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8);
835 JERRYResetPIT2();
836 break;
837 case 5:
838 JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte;
839 JERRYResetPIT2();
840 break;
841 case 6:
842 JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8);
843 JERRYResetPIT2();
844 break;
845 case 7:
846 JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte;
847 JERRYResetPIT2();
848 }
849 #else
850 WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address);
851 #endif
852 return;
853 }
854 /* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
855 {
856 clock_byte_write(offset, byte);
857 return;
858 }//*/
859 // JERRY -> 68K interrupt enables/latches (need to be handled!)
860 else if (address >= 0xF10020 && address <= 0xF10023)
861 {
862 WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address);
863 }
864 /* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
865 {
866 anajoy_byte_write(offset, byte);
867 return;
868 }*/
869 else if ((address >= 0xF14000) && (address <= 0xF14003))
870 {
871 JoystickWriteByte(address, byte);
872 EepromWriteByte(address, byte);
873 return;
874 }
875 else if ((address >= 0xF14004) && (address <= 0xF1A0FF))
876 {
877 EepromWriteByte(address, byte);
878 return;
879 }
880 //Need to protect write attempts to Wavetable ROM (F1D000-FFF)
881 else if (address >= 0xF1D000 && address <= 0xF1DFFF)
882 return;
883
884 jerryRAM[address & 0xFFFF] = byte;
885 }
886 // hole ($F20000 - $FFFFFF) 1M - 128K
887 else
888 ; // Do nothing
889 }
890
891
892 void WriteWord(uint32_t adddress, uint16_t word)
893 {
894 }
895
896
897 void WriteDWord(uint32_t adddress, uint32_t dword)
898 {
899 }
900
901
902 uint8_t ReadByte(uint32_t adddress)
903 {
904 }
905
906
907 uint16_t ReadWord(uint32_t adddress)
908 {
909 }
910
911
912 uint32_t ReadDWord(uint32_t adddress)
913 {
914 }
915 #endif
916
917
918 void ShowM68KContext(void)
919 {
920 printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
921
922 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
923 {
924 printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
925
926 if (i == M68K_REG_D3 || i == M68K_REG_D7)
927 printf("\n");
928 }
929
930 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
931 {
932 printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
933
934 if (i == M68K_REG_A3 || i == M68K_REG_A7)
935 printf("\n");
936 }
937
938 uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
939 uint32_t disPC = currpc - 30;
940 char buffer[128];
941
942 do
943 {
944 uint32_t oldpc = disPC;
945 disPC += m68k_disassemble(buffer, disPC, 0, 1);
946 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
947 }
948 while (disPC < (currpc + 10));
949 }
950
951
952 //
953 // Custom UAE 68000 read/write/IRQ functions
954 //
955
956 #if 0
957 IRQs:
958 =-=-=
959
960 IPL Name Vector Control
961 ---------+---------------+---------------+---------------
962 2 VBLANK IRQ $100 INT1 bit #0
963 2 GPU IRQ $100 INT1 bit #1
964 2 HBLANK IRQ $100 INT1 bit #2
965 2 Timer IRQ $100 INT1 bit #3
966
967 Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
968 and are therefore indistinguishable.
969
970 A typical way to install a LEVEL2 handler for the 68000 would be
971 something like this, you gotta supply "last_line" and "handler".
972 Note that the interrupt is auto vectored thru $100 (not $68)
973
974
975 V_AUTO = $100
976 VI = $F004E
977 INT1 = $F00E0
978 INT2 = $F00E2
979
980 IRQS_HANDLED=$909 ;; VBLANK and TIMER
981
982 move.w #$2700,sr ;; no IRQs please
983 move.l #handler,V_AUTO ;; install our routine
984
985 move.w #last_line,VI ;; scanline where IRQ should occur
986 ;; should be 'odd' BTW
987 move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
988 move.w #$2100,sr ;; enable IRQs on the 68K
989 ...
990
991 handler:
992 move.w d0,-(a7)
993 move.w INT1,d0
994 btst.b #0,d0
995 bne.b .no_blank
996
997 ...
998
999 .no_blank:
1000 btst.b #3,d0
1001 beq.b .no_timer
1002
1003 ...
1004
1005 .no_timer:
1006 move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
1007 move.w #0,INT2 ; let GPU run again
1008 move.w (a7)+,d0
1009 rte
1010
1011 As you can see, if you have multiple INT1 interrupts coming in,
1012 you need to check the lower byte of INT1, to see which interrupt
1013 happened.
1014 #endif
1015 int irq_ack_handler(int level)
1016 {
1017 #ifdef CPU_DEBUG_TRACING
1018 if (startM68KTracing)
1019 {
1020 WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1021 }
1022 #endif
1023
1024 // Tracing the IPL lines on the Jaguar schematic yields the following:
1025 // IPL1 is connected to INTL on TOM (OUT to 68K)
1026 // IPL0-2 are also tied to Vcc via 4.7K resistors!
1027 // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
1028 // There doesn't seem to be any other path to IPL0 or 2 on the schematic,
1029 // which means that *all* IRQs to the 68K are routed thru TOM at level 2.
1030 // Which means they're all maskable.
1031
1032 // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work
1033 // OK...
1034 // They aren't, and this causes problems with a, err, specific ROM. :-D
1035
1036 if (level == 2)
1037 {
1038 m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
1039 return 64; // Set user interrupt #0
1040 }
1041
1042 return M68K_INT_ACK_AUTOVECTOR;
1043 }
1044
1045
1046 #if 0
1047 void M68K_Debughalt(void)
1048 {
1049 M68KDebugHalt();
1050 }
1051 #endif
1052
1053
1054 // M68000 breakpoints initialisations
1055 void m68k_brk_init(void)
1056 {
1057 brkNbr = 0;
1058 brkInfo = NULL;
1059 }
1060
1061
1062 // Reset the M68000 breakpoints structures
1063 void m68k_brk_reset(void)
1064 {
1065 // Reset the breakpoints
1066 free(brkInfo);
1067 brkInfo = NULL;
1068 brkNbr = 0;
1069 }
1070
1071
1072 // Delete a M68000 breakpoint (starting from 1)
1073 void m68k_brk_del(unsigned int NumBrk)
1074 {
1075 // Remove the breakpoint
1076 memset((void *)(brkInfo + (NumBrk - 1)), 0, sizeof(S_BrkInfo));
1077 }
1078
1079
1080 // Add a M68000 breakpoint
1081 // return true if breakpoint has been added, and false if breakpoint already exists
1082 unsigned int m68k_brk_add(void *PtrInfo)
1083 {
1084 S_BrkInfo *Ptr = NULL;
1085
1086 // Check if breakpoint already exists
1087 for (size_t i = 0; i < brkNbr; i++)
1088 {
1089 if (brkInfo[i].Used)
1090 {
1091 if (brkInfo[i].Adr == ((S_BrkInfo *)PtrInfo)->Adr)
1092 {
1093 return false;
1094 }
1095 }
1096 }
1097
1098 // Look for an available breakpoint
1099 for (size_t i = 0; i < brkNbr, Ptr; i++)
1100 {
1101 if (!brkInfo[i].Used)
1102 {
1103 Ptr = &brkInfo[i];
1104 }
1105 }
1106
1107 // Add a breakpoint
1108 if (!Ptr)
1109 {
1110 brkInfo = (S_BrkInfo *)realloc(brkInfo, (++brkNbr * sizeof(S_BrkInfo)));
1111 Ptr = &brkInfo[brkNbr - 1];
1112 }
1113
1114 // Transfert the breakpoint information and init the activities
1115 memcpy((void *)Ptr, PtrInfo, sizeof(S_BrkInfo));
1116 Ptr->HitCounts = 0;
1117 return (Ptr->Active = Ptr->Used = true);
1118 }
1119
1120
1121 // Check if breakpoint has been reached
1122 unsigned int m68k_brk_check(unsigned int adr)
1123 {
1124 // Check if BPM has been reached
1125 if ((adr == bpmAddress1) && bpmActive)
1126 {
1127 bpmHitCounts++;
1128 return true;
1129 }
1130 else
1131 {
1132 // Check user breakpoints
1133 for (size_t i = 0; i < brkNbr; i++)
1134 {
1135 if (brkInfo[i].Used && brkInfo[i].Active)
1136 {
1137 if (brkInfo[i].Adr == adr)
1138 {
1139 brkInfo[i].HitCounts++;
1140 return true;
1141 }
1142 }
1143 }
1144 }
1145
1146 // No breakpoint found
1147 return false;
1148 }
1149
1150
1151 // Disable the M68000 breakpoints
1152 void m68k_brk_disable(void)
1153 {
1154 // reset active for the breakpoints
1155 for (size_t i = 0; i < brkNbr; i++)
1156 {
1157 brkInfo[i].Active = 0;
1158 }
1159 }
1160
1161
1162 // Reset the M68000 breakpoints
1163 void m68k_brk_hitcounts_reset(void)
1164 {
1165 // reset hit counts for the breakpoints
1166 for (size_t i = 0; i < brkNbr; i++)
1167 {
1168 brkInfo[i].HitCounts = 0;
1169 }
1170 }
1171
1172
1173 // Close the M68000 breakpoints structures
1174 void m68k_brk_close(void)
1175 {
1176 free(brkInfo);
1177 }
1178
1179
1180 // Read 1 byte from address
1181 // Check if address reaches a breakpoint
1182 unsigned int m68k_read_memory_8(unsigned int address)
1183 {
1184 #ifdef ALPINE_FUNCTIONS
1185 // Check if breakpoint on memory is active, and deal with it
1186 if (!startM68KTracing && m68k_brk_check(address))
1187 {
1188 M68KDebugHalt();
1189 }
1190 #endif
1191
1192 // Musashi does this automagically for you, UAE core does not :-P
1193 address &= 0x00FFFFFF;
1194 #ifdef CPU_DEBUG_MEMORY
1195 // Note that the Jaguar only has 2M of RAM, not 4!
1196 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1197 {
1198 if (startMemLog)
1199 readMem[address] = 1;
1200 }
1201 #endif
1202 //WriteLog("[RM8] Addr: %08X\n", address);
1203 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1204 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1205 || address == 0x1AF05E)
1206 WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/
1207 #ifndef USE_NEW_MMU
1208 unsigned int retVal = 0;
1209
1210 // Note that the Jaguar only has 2M of RAM, not 4!
1211 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 1)))
1212 {
1213 retVal = jaguarMainRAM[address];
1214 }
1215 // else if ((address >= 0x800000) && (address <= 0xDFFFFF))
1216 else
1217 {
1218 if ((address >= 0x800000) && (address <= 0xDFFEFF))
1219 {
1220 retVal = jaguarMainROM[address - 0x800000];
1221 }
1222 else
1223 {
1224 if ((address >= 0xE00000) && (address <= 0xE3FFFF))
1225 {
1226 // retVal = jaguarBootROM[address - 0xE00000];
1227 // retVal = jaguarDevBootROM1[address - 0xE00000];
1228 retVal = jagMemSpace[address];
1229 }
1230 else
1231 {
1232 if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1233 {
1234 retVal = CDROMReadByte(address);
1235 }
1236 else
1237 {
1238 if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1239 {
1240 retVal = TOMReadByte(address, M68K);
1241 }
1242 else
1243 {
1244 if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1245 {
1246 retVal = JERRYReadByte(address, M68K);
1247 }
1248 else
1249 {
1250 retVal = jaguar_unknown_readbyte(address, M68K);
1251 }
1252 }
1253 }
1254 }
1255 }
1256 }
1257
1258 //if (address >= 0x2800 && address <= 0x281F)
1259 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1260 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1261 // WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1262 return retVal;
1263 #else
1264 return MMURead8(address, M68K);
1265 #endif
1266 }
1267
1268
1269 /*
1270 void gpu_dump_disassembly(void);
1271 void gpu_dump_registers(void);
1272 */
1273
1274 unsigned int m68k_read_memory_16(unsigned int address)
1275 {
1276 #ifdef ALPINE_FUNCTIONS
1277 // Check if breakpoint on memory is active, and deal with it
1278 if (!startM68KTracing && m68k_brk_check(address))
1279 {
1280 M68KDebugHalt();
1281 }
1282 #endif
1283
1284 // Musashi does this automagically for you, UAE core does not :-P
1285 address &= 0x00FFFFFF;
1286 #ifdef CPU_DEBUG_MEMORY
1287 /* if ((address >= 0x000000) && (address <= 0x3FFFFE))
1288 {
1289 if (startMemLog)
1290 readMem[address] = 1, readMem[address + 1] = 1;
1291 }//*/
1292 /* if (effect_start && (address >= 0x8064FC && address <= 0x806501))
1293 {
1294 return 0x4E71; // NOP
1295 }
1296 if (effect_start2 && (address >= 0x806502 && address <= 0x806507))
1297 {
1298 return 0x4E71; // NOP
1299 }
1300 if (effect_start3 && (address >= 0x806512 && address <= 0x806517))
1301 {
1302 return 0x4E71; // NOP
1303 }
1304 if (effect_start4 && (address >= 0x806524 && address <= 0x806527))
1305 {
1306 return 0x4E71; // NOP
1307 }
1308 if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection!
1309 {
1310 return 0x4E71; // NOP
1311 }
1312 if (effect_start6 && (address >= 0x806544 && address <= 0x806547))
1313 {
1314 return 0x4E71; // NOP
1315 }//*/
1316 #endif
1317 //WriteLog("[RM16] Addr: %08X\n", address);
1318 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA)
1319 // for(int i=0; i<10000; i++)
1320 WriteLog("[M68K] In routine #6!\n");//*/
1321 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4
1322 //if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2
1323 /*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3
1324 {
1325 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1326 gpu_dump_registers();
1327 gpu_dump_disassembly();
1328 // for(int i=0; i<10000; i++)
1329 // WriteLog("[M68K] About to run GPU!\n");
1330 }//*/
1331 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1332 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8)
1333 {
1334 if (address == 0x000066A0)
1335 {
1336 gpu_dump_registers();
1337 gpu_dump_disassembly();
1338 }
1339 for(int i=0; i<10000; i++)
1340 WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address));
1341 }//*/
1342 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1343 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1344 || address == 0x1AF05E)
1345 WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/
1346 #ifndef USE_NEW_MMU
1347 unsigned int retVal = 0;
1348
1349 // Note that the Jaguar only has 2M of RAM, not 4!
1350 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 2)))
1351 {
1352 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
1353 retVal = GET16(jaguarMainRAM, address);
1354 }
1355 // else if ((address >= 0x800000) && (address <= 0xDFFFFE))
1356 else
1357 {
1358 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1359 {
1360 // Memory Track reading...
1361 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1362 {
1363 retVal = MTReadWord(address);
1364 }
1365 else
1366 {
1367 retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
1368 }
1369 }
1370 else
1371 {
1372 if ((address >= 0xE00000) && (address <= 0xE3FFFE))
1373 {
1374 // retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
1375 // retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
1376 retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
1377 }
1378 else
1379 {
1380 if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1381 {
1382 retVal = CDROMReadWord(address, M68K);
1383 }
1384 else
1385 {
1386 if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1387 {
1388 retVal = TOMReadWord(address, M68K);
1389 }
1390 else
1391 {
1392 if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1393 {
1394 retVal = JERRYReadWord(address, M68K);
1395 }
1396 else
1397 {
1398 retVal = jaguar_unknown_readword(address, M68K);
1399 }
1400 }
1401 }
1402 }
1403 }
1404 }
1405
1406 //if (address >= 0xF1B000 && address <= 0xF1CFFF)
1407 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1408 //if (address >= 0x2800 && address <= 0x281F)
1409 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1410 //$8B3AE -> Transferred from $F1C010
1411 //$8B5E4 -> Only +1 read at $808AA
1412 //if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16)
1413 // WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC));
1414 return retVal;
1415 #else
1416 return MMURead16(address, M68K);
1417 #endif
1418 }
1419
1420
1421 // Alert message in case of exception vector request
1422 bool m68k_read_exception_vector(unsigned int address, char *text)
1423 {
1424 QString msg;
1425 QMessageBox msgBox;
1426
1427 msg.sprintf("$%06x: %s", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], text);
1428 msgBox.setText(msg);
1429 msgBox.setStandardButtons(QMessageBox::Abort);
1430 msgBox.setDefaultButton(QMessageBox::Abort);
1431 msgBox.exec();
1432 return M68KDebugHalt();
1433 }
1434
1435
1436 // Read 4 bytes from memory
1437 unsigned int m68k_read_memory_32(unsigned int address)
1438 {
1439 #ifdef ALPINE_FUNCTIONS
1440 // Check if breakpoint on memory is active, and deal with it
1441 if (!startM68KTracing && m68k_brk_check(address))
1442 {
1443 M68KDebugHalt();
1444 }
1445 #endif
1446
1447 // Musashi does this automagically for you, UAE core does not :-P
1448 address &= 0x00FFFFFF;
1449 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1450 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1451 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));//*/
1452
1453 //WriteLog("--> [RM32]\n");
1454 #ifndef USE_NEW_MMU
1455 //uint32_t retVal = 0;
1456
1457 // check exception vectors access
1458 if ((address >= 0x8) && (address <= 0x7c))
1459 {
1460 switch (address)
1461 {
1462 case 0x10:
1463 m68k_read_exception_vector(address, "Illegal instruction");
1464 break;
1465 }
1466 }
1467 else
1468 {
1469 // check ROM or Memory Track access
1470 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1471 {
1472 // Memory Track reading...
1473 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1474 {
1475 return MTReadLong(address);
1476 }
1477 else
1478 {
1479 return GET32(jaguarMainROM, address - 0x800000);
1480 }
1481 }
1482 }
1483
1484 // return value from memory
1485 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1486 #else
1487 return MMURead32(address, M68K);
1488 #endif
1489 }
1490
1491
1492 // Alert message in case of writing to unknown memory location
1493 bool m68k_write_unknown_alert(unsigned int address, char *bits, unsigned int value)
1494 {
1495 QString msg;
1496 QMessageBox msgBox;
1497
1498 msg.sprintf("$%06x: Writing at this unknown memory location $%06x with a (%s bits) value of $%0x", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], address, bits, value);
1499 msgBox.setText(msg);
1500 msgBox.setStandardButtons(QMessageBox::Abort);
1501 msgBox.setDefaultButton(QMessageBox::Abort);
1502 msgBox.exec();
1503 return M68KDebugHalt();
1504 }
1505
1506
1507 // Alert message in case of writing to cartridge/ROM memory location
1508 bool m68k_write_cartridge_alert(unsigned int address, char *bits, unsigned int value)
1509 {
1510 if (!M68KDebugHaltStatus())
1511 {
1512 QString msg;
1513 QMessageBox msgBox;
1514
1515 msg.sprintf("$%06x: Writing at this ROM cartridge location $%06x with a (%s bits) value of $%0x", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], address, bits, value);
1516 msgBox.setText(msg);
1517
1518 msgBox.setInformativeText("Do you want to continue?");
1519 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1520 msgBox.setDefaultButton(QMessageBox::No);
1521
1522 int retVal = msgBox.exec();
1523
1524 if (retVal == QMessageBox::Yes)
1525 {
1526 return false;
1527 }
1528 else
1529 {
1530 return M68KDebugHalt();
1531 }
1532 }
1533 else
1534 {
1535 return 1;
1536 }
1537 }
1538
1539
1540 // Check memory write location
1541 // BPM & cartridge/ROM detections
1542 bool m68k_write_memory_check(unsigned int address, char *bits, unsigned int value)
1543 {
1544 unsigned int address1;
1545
1546 #ifdef ALPINE_FUNCTIONS
1547 // Check if breakpoint on memory is active, and deal with it
1548 if (!M68KDebugHaltStatus() && bpmActive && (address == bpmAddress1))
1549 {
1550 return M68KDebugHalt();
1551 }
1552 else
1553 #endif
1554 {
1555 // Rom writing authorisation detection
1556 if (!vjs.allowWritesToROM)
1557 {
1558 // Calcul the end address
1559 if (strstr(bits, "32"))
1560 {
1561 address1 = address + 3;
1562 }
1563 else
1564 {
1565 if (strstr(bits, "16"))
1566 {
1567 address1 = address + 1;
1568 }
1569 else
1570 {
1571 address1 = address;
1572 }
1573 }
1574
1575 // Rom writing detection
1576 if ((address >= 0x800000) && (address1 < 0xDFFF00))
1577 {
1578 return m68k_write_cartridge_alert(address, bits, value);
1579 }
1580 }
1581
1582 return false;
1583 }
1584 }
1585
1586
1587 // Memory write location on 8 bits
1588 void m68k_write_memory_8(unsigned int address, unsigned int value)
1589 {
1590 // Check memory write location on 8 bits
1591 if (!m68k_write_memory_check(address, "8", value))
1592 {
1593 // Musashi does this automagically for you, UAE core does not :-P
1594 //address &= 0x00FFFFFF;
1595 #ifdef CPU_DEBUG_MEMORY
1596 // Note that the Jaguar only has 2M of RAM, not 4!
1597 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1598 {
1599 if (startMemLog)
1600 {
1601 if (value > writeMemMax[address])
1602 writeMemMax[address] = value;
1603 if (value < writeMemMin[address])
1604 writeMemMin[address] = value;
1605 }
1606 }
1607 #endif
1608 /*if (address == 0x4E00)
1609 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1610 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1611 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1612 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1613 /*if (effect_start)
1614 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1615 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1616 //$53D0
1617 /*if (address >= 0x53D0 && address <= 0x53FF)
1618 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1619 //Testing AvP on UAE core...
1620 //000075A0: FFFFF80E B6320220 (BITMAP)
1621 /*if (address == 0x75A0 && value == 0xFF)
1622 printf("M68K: (8) Tripwire hit...\n");//*/
1623
1624 #ifndef USE_NEW_MMU
1625 // Note that the Jaguar only has 2M of RAM, not 4!
1626 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 1)))
1627 {
1628 jaguarMainRAM[address] = value;
1629 }
1630 else
1631 {
1632 if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1633 {
1634 CDROMWriteByte(address, value, M68K);
1635 }
1636 else
1637 {
1638 if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1639 {
1640 TOMWriteByte(address, value, M68K);
1641 }
1642 else
1643 {
1644 if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1645 {
1646 JERRYWriteByte(address, value, M68K);
1647 }
1648 else
1649 {
1650 if ((address >= 0x800000) && (address <= 0xDFFEFF))
1651 {
1652 jagMemSpace[address] = (uint8_t)value;
1653 }
1654 else
1655 {
1656 jaguar_unknown_writebyte(address, value, M68K);
1657 }
1658 }
1659 }
1660 }
1661 }
1662 #else
1663 MMUWrite8(address, value, M68K);
1664 #endif
1665 }
1666 }
1667
1668
1669 // Memory write location on 16 bits
1670 void m68k_write_memory_16(unsigned int address, unsigned int value)
1671 {
1672 // Check memory write location on 16 bits
1673 if (!m68k_write_memory_check(address, "16", value))
1674 {
1675 // Musashi does this automagically for you, UAE core does not :-P
1676 //address &= 0x00FFFFFF;
1677 #ifdef CPU_DEBUG_MEMORY
1678 // Note that the Jaguar only has 2M of RAM, not 4!
1679 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1680 {
1681 if (startMemLog)
1682 {
1683 uint8_t hi = value >> 8, lo = value & 0xFF;
1684
1685 if (hi > writeMemMax[address])
1686 writeMemMax[address] = hi;
1687 if (hi < writeMemMin[address])
1688 writeMemMin[address] = hi;
1689
1690 if (lo > writeMemMax[address + 1])
1691 writeMemMax[address + 1] = lo;
1692 if (lo < writeMemMin[address + 1])
1693 writeMemMin[address + 1] = lo;
1694 }
1695 }
1696 #endif
1697 /*if (address == 0x4E00)
1698 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1699 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1700 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1701 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1702 //if (address >= 0xF02200 && address <= 0xF0229F)
1703 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1704 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1705 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1706 /*extern uint32_t totalFrames;
1707 if (address == 0xF02114)
1708 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1709 if (address == 0xF02110)
1710 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1711 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1712 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1713
1714 /*if (address == 0x0100)//64*4)
1715 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1716 /*if (effect_start)
1717 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1718 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1719 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1720 || address == 0x1AF05E)
1721 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1722 //$53D0
1723 /*if (address >= 0x53D0 && address <= 0x53FF)
1724 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1725 //Testing AvP on UAE core...
1726 //000075A0: FFFFF80E B6320220 (BITMAP)
1727 /*if (address == 0x75A0 && value == 0xFFFF)
1728 {
1729 printf("\nM68K: (16) Tripwire hit...\n");
1730 ShowM68KContext();
1731 }//*/
1732
1733 #ifndef USE_NEW_MMU
1734 // Note that the Jaguar only has 2M of RAM, not 4!
1735 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 2)))
1736 {
1737 /* jaguar_mainRam[address] = value >> 8;
1738 jaguar_mainRam[address + 1] = value & 0xFF;*/
1739 SET16(jaguarMainRAM, address, value);
1740 }
1741 else
1742 {
1743 // Memory Track device writes....
1744 if ((address >= 0x800000) && (address <= 0x87FFFE))
1745 {
1746 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1747 {
1748 MTWriteWord(address, value);
1749 return;
1750 }
1751 }
1752
1753 if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1754 {
1755 CDROMWriteWord(address, value, M68K);
1756 }
1757 else
1758 {
1759 if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1760 {
1761 TOMWriteWord(address, value, M68K);
1762 }
1763 else
1764 {
1765 if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1766 {
1767 JERRYWriteWord(address, value, M68K);
1768 }
1769 else
1770 {
1771 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1772 {
1773 SET16(jagMemSpace, address, value);
1774 }
1775 else
1776 {
1777 jaguar_unknown_writeword(address, value, M68K);
1778 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1779 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n", m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
1780 #endif
1781 }
1782 }
1783 }
1784 }
1785 }
1786 #else
1787 MMUWrite16(address, value, M68K);
1788 #endif
1789 }
1790 }
1791
1792
1793 // Memory write location on 32 bits
1794 void m68k_write_memory_32(unsigned int address, unsigned int value)
1795 {
1796 // Check memory write location on 32 bits
1797 if (!m68k_write_memory_check(address, "32", value))
1798 {
1799 // Musashi does this automagically for you, UAE core does not :-P
1800 //address &= 0x00FFFFFF;
1801 /*if (address == 0x4E00)
1802 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1803 //WriteLog("--> [WM32]\n");
1804 /*if (address == 0x0100)//64*4)
1805 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1806 /*if (address >= 0xF03214 && address < 0xF0321F)
1807 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1808 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1809 /*extern bool doGPUDis;
1810 if (address == 0xF03214 && value == 0x88E30047)
1811 // start = true;
1812 doGPUDis = true;//*/
1813 /* if (address == 0x51136 || address == 0xFB074)
1814 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1815 //Testing AvP on UAE core...
1816 //000075A0: FFFFF80E B6320220 (BITMAP)
1817 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1818 {
1819 printf("\nM68K: (32) Tripwire hit...\n");
1820 ShowM68KContext();
1821 }//*/
1822
1823 #ifndef USE_NEW_MMU
1824 m68k_write_memory_16(address, value >> 16);
1825 m68k_write_memory_16(address + 2, value & 0xFFFF);
1826 #else
1827 MMUWrite32(address, value, M68K);
1828 #endif
1829 }
1830 }
1831
1832
1833 uint32_t JaguarGetHandler(uint32_t i)
1834 {
1835 return JaguarReadLong(i * 4);
1836 }
1837
1838
1839 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1840 {
1841 uint32_t handler = JaguarGetHandler(i);
1842 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1843 }
1844
1845
1846 void M68K_show_context(void)
1847 {
1848 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1849
1850 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1851 {
1852 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1853
1854 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1855 WriteLog("\n");
1856 }
1857
1858 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1859 {
1860 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1861
1862 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1863 WriteLog("\n");
1864 }
1865
1866 WriteLog("68K disasm\n");
1867 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1868 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1869 // jaguar_dasm(0x5000, 0x14414);
1870
1871 // WriteLog("\n.......[Cart start]...........\n\n");
1872 // jaguar_dasm(0x192000, 0x1000);//0x200);
1873
1874 WriteLog("..................\n");
1875
1876 if (TOMIRQEnabled(IRQ_VIDEO))
1877 {
1878 WriteLog("video int: enabled\n");
1879 JaguarDasm(JaguarGetHandler(64), 0x200);
1880 }
1881 else
1882 WriteLog("video int: disabled\n");
1883
1884 WriteLog("..................\n");
1885
1886 for(int i=0; i<256; i++)
1887 {
1888 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1889 uint32_t address = (uint32_t)JaguarGetHandler(i);
1890
1891 if (address == 0)
1892 WriteLog(".........\n");
1893 else
1894 WriteLog("$%08X\n", address);
1895 }
1896 }
1897
1898
1899 //
1900 // Unknown read/write byte/word routines
1901 //
1902
1903 // It's hard to believe that developers would be sloppy with their memory
1904 // writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1905 // has the following code:
1906 //
1907 // 807EC4: movea.l #$f1b000, A1
1908 // 807ECA: movea.l #$8129e0, A0
1909 // 807ED0: move.l A0, D0
1910 // 807ED2: move.l #$f1bb94, D1
1911 // 807ED8: sub.l D0, D1
1912 // 807EDA: lsr.l #2, D1
1913 // 807EDC: move.l (A0)+, (A1)+
1914 // 807EDE: dbra D1, 807edc
1915 //
1916 // The problem is at $807ED0--instead of putting A0 into D0, they really meant
1917 // to put A1 in. This mistake causes it to try and overwrite approximately
1918 // $700000 worth of address space! (That is, unless the 68K causes a bus
1919 // error...)
1920
1921 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1922 {
1923 m68k_write_unknown_alert(address, "8", data);
1924 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1925 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));
1926 #endif
1927 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1928 // extern bool finished;
1929 finished = true;
1930 // extern bool doDSPDis;
1931 if (who == DSP)
1932 doDSPDis = true;
1933 #endif
1934 }
1935
1936
1937 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1938 {
1939 m68k_write_unknown_alert(address, "16", data);
1940 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1941 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));
1942 #endif
1943 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1944 // extern bool finished;
1945 finished = true;
1946 // extern bool doDSPDis;
1947 if (who == DSP)
1948 doDSPDis = true;
1949 #endif
1950 }
1951
1952
1953 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1954 {
1955 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1956 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1957 #endif
1958 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1959 // extern bool finished;
1960 finished = true;
1961 // extern bool doDSPDis;
1962 if (who == DSP)
1963 doDSPDis = true;
1964 #endif
1965 return 0xFF;
1966 }
1967
1968
1969 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1970 {
1971 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1972 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1973 #endif
1974 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1975 // extern bool finished;
1976 finished = true;
1977 // extern bool doDSPDis;
1978 if (who == DSP)
1979 doDSPDis = true;
1980 #endif
1981 return 0xFFFF;
1982 }
1983
1984
1985 //
1986 // Disassemble M68K instructions at the given offset
1987 //
1988
1989 unsigned int m68k_read_disassembler_8(unsigned int address)
1990 {
1991 return m68k_read_memory_8(address);
1992 }
1993
1994
1995 unsigned int m68k_read_disassembler_16(unsigned int address)
1996 {
1997 return m68k_read_memory_16(address);
1998 }
1999
2000
2001 unsigned int m68k_read_disassembler_32(unsigned int address)
2002 {
2003 return m68k_read_memory_32(address);
2004 }
2005
2006
2007 void JaguarDasm(uint32_t offset, uint32_t qt)
2008 {
2009 #ifdef CPU_DEBUG
2010 static char buffer[2048];//, mem[64];
2011 int pc = offset, oldpc;
2012
2013 for(uint32_t i=0; i<qt; i++)
2014 {
2015 /* oldpc = pc;
2016 for(int j=0; j<64; j++)
2017 mem[j^0x01] = jaguar_byte_read(pc + j);
2018
2019 pc += Dasm68000((char *)mem, buffer, 0);
2020 WriteLog("%08X: %s\n", oldpc, buffer);//*/
2021 oldpc = pc;
2022 pc += m68k_disassemble(buffer, pc, 0, 1);//M68K_CPU_TYPE_68000);
2023 WriteLog("%08X: %s\n", oldpc, buffer);//*/
2024 }
2025 #endif
2026 }
2027
2028
2029 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2030 {
2031 uint8_t data = 0x00;
2032 offset &= 0xFFFFFF;
2033
2034 // First 2M is mirrored in the $0 - $7FFFFF range
2035 if (offset < 0x800000)
2036 data = jaguarMainRAM[offset & (vjs.DRAM_size - 1)];
2037 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2038 data = jaguarMainROM[offset - 0x800000];
2039 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2040 data = CDROMReadByte(offset, who);
2041 else if ((offset >= 0xE00000) && (offset < 0xE40000))
2042 // data = jaguarBootROM[offset & 0x3FFFF];
2043 // data = jaguarDevBootROM1[offset & 0x3FFFF];
2044 data = jagMemSpace[offset];
2045 else if ((offset >= 0xF00000) && (offset < 0xF10000))
2046 data = TOMReadByte(offset, who);
2047 else if ((offset >= 0xF10000) && (offset < 0xF20000))
2048 data = JERRYReadByte(offset, who);
2049 else
2050 data = jaguar_unknown_readbyte(offset, who);
2051
2052 return data;
2053 }
2054
2055
2056 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2057 {
2058 offset &= 0xFFFFFF;
2059
2060 // First 2M is mirrored in the $0 - $7FFFFF range
2061 if (offset < 0x800000)
2062 {
2063 return (jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] << 8) | jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)];
2064 }
2065 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2066 {
2067 offset -= 0x800000;
2068 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
2069 }
2070 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
2071 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
2072 return CDROMReadWord(offset, who);
2073 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
2074 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
2075 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
2076 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
2077 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
2078 return TOMReadWord(offset, who);
2079 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
2080 return JERRYReadWord(offset, who);
2081
2082 return jaguar_unknown_readword(offset, who);
2083 }
2084
2085
2086 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
2087 {
2088 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2089 {
2090 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
2091 }//*/
2092 /* if (offset >= 0x4E00 && offset < 0x4E04)
2093 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2094 //Need to check for writes in the range of $18FA70 + 8000...
2095 /*if (effect_start)
2096 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2097 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2098
2099 offset &= 0xFFFFFF;
2100
2101 // First 2M is mirrored in the $0 - $7FFFFF range
2102 if (offset < 0x800000)
2103 {
2104 jaguarMainRAM[offset & (vjs.DRAM_size - 1)] = data;
2105 return;
2106 }
2107 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2108 {
2109 CDROMWriteByte(offset, data, who);
2110 return;
2111 }
2112 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
2113 {
2114 TOMWriteByte(offset, data, who);
2115 return;
2116 }
2117 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
2118 {
2119 JERRYWriteByte(offset, data, who);
2120 return;
2121 }
2122
2123 jaguar_unknown_writebyte(offset, data, who);
2124 }
2125
2126
2127 uint32_t starCount;
2128 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
2129 {
2130 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2131 {
2132 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
2133 WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
2134 }//*/
2135 /* if (offset >= 0x4E00 && offset < 0x4E04)
2136 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2137 /*if (offset == 0x0100)//64*4)
2138 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
2139 if (offset == 0x0102)//64*4)
2140 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
2141 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
2142 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
2143 //Need to check for writes in the range of $18FA70 + 8000...
2144 /*if (effect_start)
2145 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2146 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2147 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
2148 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
2149
2150 offset &= 0xFFFFFF;
2151
2152 // First 2M is mirrored in the $0 - $7FFFFF range
2153 if (offset <= 0x7FFFFE)
2154 {
2155 /*
2156 GPU Table (CD BIOS)
2157
2158 1A 69 F0 ($0000) -> Starfield
2159 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
2160 1A 79 F0 ($0002)
2161 1A 88 C0 ($0003)
2162 1A 8F E8 ($0004) -> "Jaguar" small color logo?
2163 1A 95 20 ($0005)
2164 1A 9F 08 ($0006)
2165 1A A1 38 ($0007)
2166 1A AB 38 ($0008)
2167 1A B3 C8 ($0009)
2168 1A B9 C0 ($000A)
2169 */
2170
2171 //This MUST be done by the 68K!
2172 /*if (offset == 0x670C)
2173 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
2174
2175 /*extern bool doGPUDis;
2176 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
2177 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2178 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
2179 doGPUDis = true;//*/
2180 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2181 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
2182 if ((data & 0xFF00) != 0x7700)
2183 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2184 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
2185 return;//*/
2186 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
2187 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2188 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
2189 return;//*/
2190 /*extern bool doGPUDis;
2191 if (offset == 0x120216 && who == GPU)
2192 doGPUDis = true;//*/
2193 /*extern uint32_t gpu_pc;
2194 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2195 {
2196 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2197 uint32_t y = base / 0x300;
2198 uint32_t x = (base - (y * 0x300)) / 2;
2199 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2200 }//*/
2201 /*
2202 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
2203 */
2204 //if (offset == (0x001E17F8 + 0x34))
2205 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
2206 data = 0xFE3C;//*/
2207 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
2208 /*extern uint32_t gpu_pc;
2209 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2210 {
2211 extern int objectPtr;
2212 // if (offset > 0x148000)
2213 // return;
2214 starCount++;
2215 if (starCount > objectPtr)
2216 return;
2217
2218 // if (starCount == 1)
2219 // WriteLog("--> Drawing 1st star...\n");
2220 //
2221 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2222 // uint32_t y = base / 0x300;
2223 // uint32_t x = (base - (y * 0x300)) / 2;
2224 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2225
2226 //A star of interest...
2227 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
2228 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
2229 //JWW: Blitter writing echo 77B3 at 0011D022...
2230 }//*/
2231 //extern bool doGPUDis;
2232 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
2233 {
2234 // doGPUDis = true;
2235 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
2236 // LogBlit();
2237 }
2238 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
2239 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
2240
2241 jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] = data >> 8;
2242 jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)] = data & 0xFF;
2243 return;
2244 }
2245 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
2246 {
2247 CDROMWriteWord(offset, data, who);
2248 return;
2249 }
2250 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
2251 {
2252 TOMWriteWord(offset, data, who);
2253 return;
2254 }
2255 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
2256 {
2257 JERRYWriteWord(offset, data, who);
2258 return;
2259 }
2260 // Don't bomb on attempts to write to ROM
2261 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
2262 return;
2263
2264 jaguar_unknown_writeword(offset, data, who);
2265 }
2266
2267
2268 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2269 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2270 {
2271 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
2272 }
2273
2274
2275 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2276 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
2277 {
2278 /* extern bool doDSPDis;
2279 if (offset < 0x400 && !doDSPDis)
2280 {
2281 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
2282 doDSPDis = true;
2283 }//*/
2284 /*if (offset == 0x0100)//64*4)
2285 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
2286
2287 JaguarWriteWord(offset, data >> 16, who);
2288 JaguarWriteWord(offset+2, data & 0xFFFF, who);
2289 }
2290
2291
2292 void JaguarSetScreenBuffer(uint32_t * buffer)
2293 {
2294 // This is in TOM, but we set it here...
2295 screenBuffer = buffer;
2296 }
2297
2298
2299 void JaguarSetScreenPitch(uint32_t pitch)
2300 {
2301 // This is in TOM, but we set it here...
2302 screenPitch = pitch;
2303 }
2304
2305
2306 //
2307 // Jaguar console initialization
2308 //
2309 void JaguarInit(void)
2310 {
2311 // For randomizing RAM
2312 srand((unsigned int)time(NULL));
2313
2314 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
2315 for(uint32_t i=0; i<vjs.DRAM_size; i+=4)
2316 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
2317
2318 #ifdef CPU_DEBUG_MEMORY
2319 memset(readMem, 0x00, 0x400000);
2320 memset(writeMemMin, 0xFF, 0x400000);
2321 memset(writeMemMax, 0x00, 0x400000);
2322 #endif
2323 // memset(jaguarMainRAM, 0x00, 0x200000);
2324 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
2325 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
2326 //NOTE: This *doesn't* fix FlipOut...
2327 //Or does it? Hmm...
2328 //Seems to want $01010101... Dunno why. Investigate!
2329 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
2330 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
2331 lowerField = false; // Reset the lower field flag
2332 //temp, for crappy crap that sux
2333 memset(jaguarMainRAM + 0x804, 0xFF, 4);
2334
2335 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
2336 GPUInit();
2337 DSPInit();
2338 TOMInit();
2339 JERRYInit();
2340 CDROMInit();
2341 m68k_brk_init();
2342 }
2343
2344
2345 //New timer based code stuffola...
2346 void HalflineCallback(void);
2347 void RenderCallback(void);
2348 void JaguarReset(void)
2349 {
2350 // Only problem with this approach: It wipes out RAM loaded files...!
2351 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
2352 for (uint32_t i = 8; i < vjs.DRAM_size; i += 4)
2353 {
2354 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
2355 }
2356
2357 // New timer base code stuffola...
2358 InitializeEventList();
2359 //Need to change this so it uses the single RAM space and load the BIOS
2360 //into it somewhere...
2361 //Also, have to change this here and in JaguarReadXX() currently
2362 // Only use the system BIOS if it's available...! (it's always available now!)
2363 // AND only if a jaguar cartridge has been inserted.
2364 #ifndef NEWMODELSBIOSHANDLER
2365 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine && !vjs.softTypeDebugger)
2366 {
2367 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
2368 #else
2369 if (vjs.useJaguarBIOS && jaguarCartInserted)
2370 {
2371 SetBIOS();
2372 #endif
2373 }
2374 else
2375 {
2376 SET32(jaguarMainRAM, 4, jaguarRunAddress);
2377 }
2378
2379 // WriteLog("jaguar_reset():\n");
2380 TOMReset();
2381 JERRYReset();
2382 GPUReset();
2383 DSPReset();
2384 CDROMReset();
2385 m68k_pulse_reset(); // Reset the 68000
2386 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
2387 lowerField = false; // Reset the lower field flag
2388 // SetCallbackTime(ScanlineCallback, 63.5555);
2389 // SetCallbackTime(ScanlineCallback, 31.77775);
2390 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2391 }
2392
2393
2394 void JaguarDone(void)
2395 {
2396 #ifdef CPU_DEBUG_MEMORY
2397 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
2398
2399 for(uint32_t i=0; i<=raPtr; i++)
2400 {
2401 WriteLog("\t%08X\n", returnAddr[i]);
2402 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
2403 jaguar_dasm(returnAddr[i] - 16, 16);
2404 WriteLog("\n");
2405 }
2406 WriteLog("\n");//*/
2407
2408 /* int start = 0, end = 0;
2409 bool endTriggered = false, startTriggered = false;
2410 for(int i=0; i<0x400000; i++)
2411 {
2412 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
2413 {
2414 if (!startTriggered)
2415 startTriggered = true, endTriggered = false, start = i;
2416
2417 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
2418 }
2419 else
2420 {
2421 if (!endTriggered)
2422 {
2423 end = i - 1, endTriggered = true, startTriggered = false;
2424 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
2425 }
2426 }
2427 }
2428 WriteLog("\n");//*/
2429 #endif
2430 //#ifdef CPU_DEBUG
2431 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
2432 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
2433 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
2434 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2435 #if 0
2436 for(int i=-2; i<9; i++)
2437 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2438 #else
2439 uint32_t address = topOfStack - (4 * 4 * 3);
2440
2441 for(int i=0; i<10; i++)
2442 {
2443 WriteLog("%06X:", address);
2444
2445 for(int j=0; j<4; j++)
2446 {
2447 WriteLog(" %08X", JaguarReadLong(address));
2448 address += 4;
2449 }
2450
2451 WriteLog("\n");
2452 }
2453 #endif
2454
2455 /* WriteLog("\nM68000 disassembly at $802288...\n");
2456 jaguar_dasm(0x802288, 3);
2457 WriteLog("\nM68000 disassembly at $802200...\n");
2458 jaguar_dasm(0x802200, 500);
2459 WriteLog("\nM68000 disassembly at $802518...\n");
2460 jaguar_dasm(0x802518, 100);//*/
2461
2462 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2463 jaguar_dasm(0x803F00, 500);
2464 WriteLog("\n");//*/
2465
2466 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2467 jaguar_dasm(0x802B00, 500);
2468 WriteLog("\n");//*/
2469
2470 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2471 jaguar_dasm(0x809900, 500);
2472 WriteLog("\n");//*/
2473 //8099F8
2474 /* WriteLog("\n\nDump of $8093C8:\n\n");
2475 for(int i=0x8093C8; i<0x809900; i+=4)
2476 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2477 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2478 jaguar_dasm(0x90006C, 500);
2479 WriteLog("\n");//*/
2480 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2481 jaguar_dasm(0x1AC000, 6000);
2482 WriteLog("\n");//*/
2483
2484 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2485 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2486 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2487 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2488 M68K_show_context();
2489 //#endif
2490
2491 CDROMDone();
2492 GPUDone();
2493 DSPDone();
2494 TOMDone();
2495 JERRYDone();
2496 m68k_brk_close();
2497
2498 // temp, until debugger is in place
2499 //00802016: jsr $836F1A.l
2500 //0080201C: jsr $836B30.l
2501 //00802022: jsr $836B18.l
2502 //00802028: jsr $8135F0.l
2503 //00813C1E: jsr $813F76.l
2504 //00802038: jsr $836D00.l
2505 //00802098: jsr $8373A4.l
2506 //008020A2: jsr $83E24A.l
2507 //008020BA: jsr $83E156.l
2508 //008020C6: jsr $83E19C.l
2509 //008020E6: jsr $8445E8.l
2510 //008020EC: jsr $838C20.l
2511 //0080211A: jsr $838ED6.l
2512 //00802124: jsr $89CA56.l
2513 //0080212A: jsr $802B48.l
2514 #if 0
2515 WriteLog("-------------------------------------------\n");
2516 JaguarDasm(0x8445E8, 0x200);
2517 WriteLog("-------------------------------------------\n");
2518 JaguarDasm(0x838C20, 0x200);
2519 WriteLog("-------------------------------------------\n");
2520 JaguarDasm(0x838ED6, 0x200);
2521 WriteLog("-------------------------------------------\n");
2522 JaguarDasm(0x89CA56, 0x200);
2523 WriteLog("-------------------------------------------\n");
2524 JaguarDasm(0x802B48, 0x200);
2525 WriteLog("\n\nM68000 disassembly at $802000...\n");
2526 JaguarDasm(0x802000, 6000);
2527 WriteLog("\n");//*/
2528 #endif
2529 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2530 JaguarDasm(0x6004, 10000);
2531 WriteLog("\n");//*/
2532 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2533 // JaguarDasm(0x802000, 0x1000);
2534 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2535 // JaguarDasm(0x4100, 200);
2536 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2537 // JaguarDasm(0x800800, 0x1000);
2538 }
2539
2540
2541 // Temp debugging stuff
2542
2543 void DumpMainMemory(void)
2544 {
2545 FILE * fp = fopen("./memdump.bin", "wb");
2546
2547 if (fp == NULL)
2548 return;
2549
2550 fwrite(jaguarMainRAM, 1, vjs.DRAM_size, fp);
2551 fclose(fp);
2552 }
2553
2554
2555 uint8_t * GetRamPtr(void)
2556 {
2557 return jaguarMainRAM;
2558 }
2559
2560
2561 //
2562 // New Jaguar execution stack
2563 // This executes 1 frame's worth of code.
2564 //
2565 bool frameDone;
2566 void JaguarExecuteNew(void)
2567 {
2568 frameDone = false;
2569
2570 do
2571 {
2572 double timeToNextEvent = GetTimeToNextEvent();
2573 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2574
2575 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2576
2577 if (vjs.GPUEnabled)
2578 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2579
2580 HandleNextEvent();
2581 }
2582 while (!frameDone);
2583 }
2584
2585
2586 // Step over function
2587 void JaguarStepOver(int depth)
2588 {
2589 bool exit;
2590 //bool case55 = false;
2591 //uint32_t m68kSR;
2592
2593 if (!depth)
2594 {
2595 exit = true;
2596 }
2597 else
2598 {
2599 exit = false;
2600 }
2601
2602 do
2603 {
2604 JaguarStepInto();
2605
2606 switch (M68KGetCurrentOpcodeFamily())
2607 {
2608 // rts
2609 case 49:
2610 //if (depth)
2611 {
2612 //if (!--depth)
2613 {
2614 exit = true;
2615 }
2616 //exit = false;
2617 }
2618 break;
2619
2620 #if 0
2621 // bcc
2622 case 55:
2623 if (!depth)
2624 {
2625 //m68kSR = m68k_get_reg(NULL, M68K_REG_SR);
2626 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x4)
2627 {
2628 exit = true;
2629 }
2630 else
2631 {
2632 exit = false;
2633 }
2634 }
2635 break;
2636 #endif
2637
2638 // bsr & jsr
2639 case 54:
2640 case 52:
2641 JaguarStepOver(depth+1);
2642 //if (depth)
2643 //{
2644 // exit = false;
2645 //}
2646 break;
2647
2648 default:
2649 //if (case55)
2650 //{
2651 // exit = true;
2652 //}
2653 break;
2654 }
2655 }
2656 while (!exit);
2657
2658 #ifdef _MSC_VER
2659 #pragma message("Warning: !!! Need to verify the Jaguar Step Over function !!!")
2660 #else
2661 #warning "!!! Need to verify the Jaguar Step Over function !!!"
2662 #endif // _MSC_VER
2663 }
2664
2665
2666 // Step into function
2667 void JaguarStepInto(void)
2668 {
2669 // double timeToNextEvent = GetTimeToNextEvent();
2670
2671 m68k_execute(USEC_TO_M68K_CYCLES(0));
2672 // m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2673
2674 if (vjs.GPUEnabled)
2675 GPUExec(USEC_TO_RISC_CYCLES(0));
2676
2677 // HandleNextEvent();
2678 #ifdef _MSC_VER
2679 #pragma message("Warning: !!! Need to verify the Jaguar Step Into function !!!")
2680 #else
2681 #warning "!!! Need to verify the Jaguar Step Into function !!!"
2682 #endif // _MSC_VER
2683 }
2684
2685
2686 //
2687 // The thing to keep in mind is that the VC is advanced every HALF line,
2688 // regardless of whether the display is interlaced or not. The only difference
2689 // with an interlaced display is that the high bit of VC will be set when the
2690 // lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2691 // lower field, regardless of whether it's in interlace mode or not.
2692 // NB2: Seems it doesn't always, not sure what the constraint is...)
2693 //
2694 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2695 // rendering two fields that are slighty vertically offset from each other.
2696 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2697 // is rendered in this mode so that each field, when overlaid on each other,
2698 // will yield the final picture at the full resolution for the full frame.
2699 //
2700 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2701 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2702 // it will be half this number for a half frame. BUT, since we're counting
2703 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2704 // PAL.
2705 //
2706 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2707 // Half line times are, naturally, half of this. :-P
2708 //
2709 void HalflineCallback(void)
2710 {
2711 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2712 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2713 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2714 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2715 vc++;
2716
2717 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2718 // So we cut the number of half-lines in a frame in half. :-P
2719 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2720
2721 if ((vc & 0x7FF) >= numHalfLines)
2722 {
2723 lowerField = !lowerField;
2724 // If we're rendering the lower field, set the high bit (#11, counting
2725 // from 0) of VC
2726 vc = (lowerField ? 0x0800 : 0x0000);
2727 }
2728
2729 //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2730 TOMWriteWord(0xF00006, vc, JAGUAR);
2731
2732 // Time for Vertical Interrupt?
2733 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2734 {
2735 // We don't have to worry about autovectors & whatnot because the Jaguar
2736 // tells you through its HW registers who sent the interrupt...
2737 TOMSetPendingVideoInt();
2738 m68k_set_irq(2);
2739 }
2740
2741 TOMExecHalfline(vc, true);
2742
2743 //Change this to VBB???
2744 //Doesn't seem to matter (at least for Flip Out & I-War)
2745 if ((vc & 0x7FF) == 0)
2746 // if (vc == vbb)
2747 {
2748 JoystickExec();
2749 frameDone = true;
2750 }//*/
2751
2752 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2753 }
2754