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