Merge pull request #18 from djipi/release/R4
[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 unsigned int m68k_read_memory_32(unsigned int address)
1422 {
1423 #ifdef ALPINE_FUNCTIONS
1424 // Check if breakpoint on memory is active, and deal with it
1425 if (!startM68KTracing && m68k_brk_check(address))
1426 {
1427 M68KDebugHalt();
1428 }
1429 #endif
1430
1431 // Musashi does this automagically for you, UAE core does not :-P
1432 address &= 0x00FFFFFF;
1433 //; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1434 /* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1435 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));//*/
1436
1437 //WriteLog("--> [RM32]\n");
1438 #ifndef USE_NEW_MMU
1439 uint32_t retVal = 0;
1440
1441 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1442 {
1443 // Memory Track reading...
1444 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1445 {
1446 retVal = MTReadLong(address);
1447 }
1448 else
1449 {
1450 retVal = GET32(jaguarMainROM, address - 0x800000);
1451 }
1452
1453 return retVal;
1454 }
1455
1456 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1457 #else
1458 return MMURead32(address, M68K);
1459 #endif
1460 }
1461
1462
1463 // Alert message in case of writing to unknown memory location
1464 bool m68k_write_unknown_alert(unsigned int address, char *bits, unsigned int value)
1465 {
1466 QString msg;
1467 QMessageBox msgBox;
1468
1469 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);
1470 msgBox.setText(msg);
1471 msgBox.setStandardButtons(QMessageBox::Abort);
1472 msgBox.setDefaultButton(QMessageBox::Abort);
1473 msgBox.exec();
1474 return M68KDebugHalt();
1475 }
1476
1477
1478 // Alert message in case of writing to cartridge/ROM memory location
1479 bool m68k_write_cartridge_alert(unsigned int address, char *bits, unsigned int value)
1480 {
1481 if (!M68KDebugHaltStatus())
1482 {
1483 QString msg;
1484 QMessageBox msgBox;
1485
1486 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);
1487 msgBox.setText(msg);
1488
1489 msgBox.setInformativeText("Do you want to continue?");
1490 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1491 msgBox.setDefaultButton(QMessageBox::No);
1492
1493 int retVal = msgBox.exec();
1494
1495 if (retVal == QMessageBox::Yes)
1496 {
1497 return false;
1498 }
1499 else
1500 {
1501 return M68KDebugHalt();
1502 }
1503 }
1504 else
1505 {
1506 return 1;
1507 }
1508 }
1509
1510
1511 // Check memory write location
1512 // BPM & cartridge/ROM detections
1513 bool m68k_write_memory_check(unsigned int address, char *bits, unsigned int value)
1514 {
1515 unsigned int address1;
1516
1517 #ifdef ALPINE_FUNCTIONS
1518 // Check if breakpoint on memory is active, and deal with it
1519 if (!M68KDebugHaltStatus() && bpmActive && (address == bpmAddress1))
1520 {
1521 return M68KDebugHalt();
1522 }
1523 else
1524 #endif
1525 {
1526 // Rom writing authorisation detection
1527 if (!vjs.allowWritesToROM)
1528 {
1529 // Calcul the end address
1530 if (strstr(bits, "32"))
1531 {
1532 address1 = address + 3;
1533 }
1534 else
1535 {
1536 if (strstr(bits, "16"))
1537 {
1538 address1 = address + 1;
1539 }
1540 else
1541 {
1542 address1 = address;
1543 }
1544 }
1545
1546 // Rom writing detection
1547 if ((address >= 0x800000) && (address1 < 0xDFFF00))
1548 {
1549 return m68k_write_cartridge_alert(address, bits, value);
1550 }
1551 }
1552
1553 return false;
1554 }
1555 }
1556
1557
1558 // Memory write location on 8 bits
1559 void m68k_write_memory_8(unsigned int address, unsigned int value)
1560 {
1561 // Check memory write location on 8 bits
1562 if (!m68k_write_memory_check(address, "8", value))
1563 {
1564 // Musashi does this automagically for you, UAE core does not :-P
1565 //address &= 0x00FFFFFF;
1566 #ifdef CPU_DEBUG_MEMORY
1567 // Note that the Jaguar only has 2M of RAM, not 4!
1568 if ((address >= 0x000000) && (address <= 0x1FFFFF))
1569 {
1570 if (startMemLog)
1571 {
1572 if (value > writeMemMax[address])
1573 writeMemMax[address] = value;
1574 if (value < writeMemMin[address])
1575 writeMemMin[address] = value;
1576 }
1577 }
1578 #endif
1579 /*if (address == 0x4E00)
1580 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1581 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1582 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1583 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1584 /*if (effect_start)
1585 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1586 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1587 //$53D0
1588 /*if (address >= 0x53D0 && address <= 0x53FF)
1589 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1590 //Testing AvP on UAE core...
1591 //000075A0: FFFFF80E B6320220 (BITMAP)
1592 /*if (address == 0x75A0 && value == 0xFF)
1593 printf("M68K: (8) Tripwire hit...\n");//*/
1594
1595 #ifndef USE_NEW_MMU
1596 // Note that the Jaguar only has 2M of RAM, not 4!
1597 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 1)))
1598 {
1599 jaguarMainRAM[address] = value;
1600 }
1601 else
1602 {
1603 if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
1604 {
1605 CDROMWriteByte(address, value, M68K);
1606 }
1607 else
1608 {
1609 if ((address >= 0xF00000) && (address <= 0xF0FFFF))
1610 {
1611 TOMWriteByte(address, value, M68K);
1612 }
1613 else
1614 {
1615 if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1616 {
1617 JERRYWriteByte(address, value, M68K);
1618 }
1619 else
1620 {
1621 if ((address >= 0x800000) && (address <= 0xDFFEFF))
1622 {
1623 jagMemSpace[address] = (uint8_t)value;
1624 }
1625 else
1626 {
1627 jaguar_unknown_writebyte(address, value, M68K);
1628 }
1629 }
1630 }
1631 }
1632 }
1633 #else
1634 MMUWrite8(address, value, M68K);
1635 #endif
1636 }
1637 }
1638
1639
1640 // Memory write location on 16 bits
1641 void m68k_write_memory_16(unsigned int address, unsigned int value)
1642 {
1643 // Check memory write location on 16 bits
1644 if (!m68k_write_memory_check(address, "16", value))
1645 {
1646 // Musashi does this automagically for you, UAE core does not :-P
1647 //address &= 0x00FFFFFF;
1648 #ifdef CPU_DEBUG_MEMORY
1649 // Note that the Jaguar only has 2M of RAM, not 4!
1650 if ((address >= 0x000000) && (address <= 0x1FFFFE))
1651 {
1652 if (startMemLog)
1653 {
1654 uint8_t hi = value >> 8, lo = value & 0xFF;
1655
1656 if (hi > writeMemMax[address])
1657 writeMemMax[address] = hi;
1658 if (hi < writeMemMin[address])
1659 writeMemMin[address] = hi;
1660
1661 if (lo > writeMemMax[address + 1])
1662 writeMemMax[address + 1] = lo;
1663 if (lo < writeMemMin[address + 1])
1664 writeMemMin[address + 1] = lo;
1665 }
1666 }
1667 #endif
1668 /*if (address == 0x4E00)
1669 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1670 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1671 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1672 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1673 //if (address >= 0xF02200 && address <= 0xF0229F)
1674 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1675 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1676 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1677 /*extern uint32_t totalFrames;
1678 if (address == 0xF02114)
1679 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1680 if (address == 0xF02110)
1681 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1682 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1683 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1684
1685 /*if (address == 0x0100)//64*4)
1686 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1687 /*if (effect_start)
1688 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1689 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1690 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1691 || address == 0x1AF05E)
1692 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1693 //$53D0
1694 /*if (address >= 0x53D0 && address <= 0x53FF)
1695 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1696 //Testing AvP on UAE core...
1697 //000075A0: FFFFF80E B6320220 (BITMAP)
1698 /*if (address == 0x75A0 && value == 0xFFFF)
1699 {
1700 printf("\nM68K: (16) Tripwire hit...\n");
1701 ShowM68KContext();
1702 }//*/
1703
1704 #ifndef USE_NEW_MMU
1705 // Note that the Jaguar only has 2M of RAM, not 4!
1706 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 2)))
1707 {
1708 /* jaguar_mainRam[address] = value >> 8;
1709 jaguar_mainRam[address + 1] = value & 0xFF;*/
1710 SET16(jaguarMainRAM, address, value);
1711 }
1712 else
1713 {
1714 // Memory Track device writes....
1715 if ((address >= 0x800000) && (address <= 0x87FFFE))
1716 {
1717 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1718 {
1719 MTWriteWord(address, value);
1720 return;
1721 }
1722 }
1723
1724 if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1725 {
1726 CDROMWriteWord(address, value, M68K);
1727 }
1728 else
1729 {
1730 if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1731 {
1732 TOMWriteWord(address, value, M68K);
1733 }
1734 else
1735 {
1736 if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1737 {
1738 JERRYWriteWord(address, value, M68K);
1739 }
1740 else
1741 {
1742 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1743 {
1744 SET16(jagMemSpace, address, value);
1745 }
1746 else
1747 {
1748 jaguar_unknown_writeword(address, value, M68K);
1749 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1750 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));
1751 #endif
1752 }
1753 }
1754 }
1755 }
1756 }
1757 #else
1758 MMUWrite16(address, value, M68K);
1759 #endif
1760 }
1761 }
1762
1763
1764 // Memory write location on 32 bits
1765 void m68k_write_memory_32(unsigned int address, unsigned int value)
1766 {
1767 // Check memory write location on 32 bits
1768 if (!m68k_write_memory_check(address, "32", value))
1769 {
1770 // Musashi does this automagically for you, UAE core does not :-P
1771 //address &= 0x00FFFFFF;
1772 /*if (address == 0x4E00)
1773 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1774 //WriteLog("--> [WM32]\n");
1775 /*if (address == 0x0100)//64*4)
1776 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1777 /*if (address >= 0xF03214 && address < 0xF0321F)
1778 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1779 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1780 /*extern bool doGPUDis;
1781 if (address == 0xF03214 && value == 0x88E30047)
1782 // start = true;
1783 doGPUDis = true;//*/
1784 /* if (address == 0x51136 || address == 0xFB074)
1785 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1786 //Testing AvP on UAE core...
1787 //000075A0: FFFFF80E B6320220 (BITMAP)
1788 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1789 {
1790 printf("\nM68K: (32) Tripwire hit...\n");
1791 ShowM68KContext();
1792 }//*/
1793
1794 #ifndef USE_NEW_MMU
1795 m68k_write_memory_16(address, value >> 16);
1796 m68k_write_memory_16(address + 2, value & 0xFFFF);
1797 #else
1798 MMUWrite32(address, value, M68K);
1799 #endif
1800 }
1801 }
1802
1803
1804 uint32_t JaguarGetHandler(uint32_t i)
1805 {
1806 return JaguarReadLong(i * 4);
1807 }
1808
1809
1810 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1811 {
1812 uint32_t handler = JaguarGetHandler(i);
1813 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1814 }
1815
1816
1817 void M68K_show_context(void)
1818 {
1819 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1820
1821 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1822 {
1823 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1824
1825 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1826 WriteLog("\n");
1827 }
1828
1829 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1830 {
1831 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1832
1833 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1834 WriteLog("\n");
1835 }
1836
1837 WriteLog("68K disasm\n");
1838 // jaguar_dasm(s68000readPC()-0x1000,0x20000);
1839 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1840 // jaguar_dasm(0x5000, 0x14414);
1841
1842 // WriteLog("\n.......[Cart start]...........\n\n");
1843 // jaguar_dasm(0x192000, 0x1000);//0x200);
1844
1845 WriteLog("..................\n");
1846
1847 if (TOMIRQEnabled(IRQ_VIDEO))
1848 {
1849 WriteLog("video int: enabled\n");
1850 JaguarDasm(JaguarGetHandler(64), 0x200);
1851 }
1852 else
1853 WriteLog("video int: disabled\n");
1854
1855 WriteLog("..................\n");
1856
1857 for(int i=0; i<256; i++)
1858 {
1859 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1860 uint32_t address = (uint32_t)JaguarGetHandler(i);
1861
1862 if (address == 0)
1863 WriteLog(".........\n");
1864 else
1865 WriteLog("$%08X\n", address);
1866 }
1867 }
1868
1869
1870 //
1871 // Unknown read/write byte/word routines
1872 //
1873
1874 // It's hard to believe that developers would be sloppy with their memory
1875 // writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1876 // has the following code:
1877 //
1878 // 807EC4: movea.l #$f1b000, A1
1879 // 807ECA: movea.l #$8129e0, A0
1880 // 807ED0: move.l A0, D0
1881 // 807ED2: move.l #$f1bb94, D1
1882 // 807ED8: sub.l D0, D1
1883 // 807EDA: lsr.l #2, D1
1884 // 807EDC: move.l (A0)+, (A1)+
1885 // 807EDE: dbra D1, 807edc
1886 //
1887 // The problem is at $807ED0--instead of putting A0 into D0, they really meant
1888 // to put A1 in. This mistake causes it to try and overwrite approximately
1889 // $700000 worth of address space! (That is, unless the 68K causes a bus
1890 // error...)
1891
1892 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1893 {
1894 m68k_write_unknown_alert(address, "8", data);
1895 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1896 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));
1897 #endif
1898 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1899 // extern bool finished;
1900 finished = true;
1901 // extern bool doDSPDis;
1902 if (who == DSP)
1903 doDSPDis = true;
1904 #endif
1905 }
1906
1907
1908 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1909 {
1910 m68k_write_unknown_alert(address, "16", data);
1911 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1912 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));
1913 #endif
1914 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1915 // extern bool finished;
1916 finished = true;
1917 // extern bool doDSPDis;
1918 if (who == DSP)
1919 doDSPDis = true;
1920 #endif
1921 }
1922
1923
1924 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1925 {
1926 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1927 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1928 #endif
1929 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1930 // extern bool finished;
1931 finished = true;
1932 // extern bool doDSPDis;
1933 if (who == DSP)
1934 doDSPDis = true;
1935 #endif
1936 return 0xFF;
1937 }
1938
1939
1940 unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1941 {
1942 #ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1943 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1944 #endif
1945 #ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1946 // extern bool finished;
1947 finished = true;
1948 // extern bool doDSPDis;
1949 if (who == DSP)
1950 doDSPDis = true;
1951 #endif
1952 return 0xFFFF;
1953 }
1954
1955
1956 //
1957 // Disassemble M68K instructions at the given offset
1958 //
1959
1960 unsigned int m68k_read_disassembler_8(unsigned int address)
1961 {
1962 return m68k_read_memory_8(address);
1963 }
1964
1965
1966 unsigned int m68k_read_disassembler_16(unsigned int address)
1967 {
1968 return m68k_read_memory_16(address);
1969 }
1970
1971
1972 unsigned int m68k_read_disassembler_32(unsigned int address)
1973 {
1974 return m68k_read_memory_32(address);
1975 }
1976
1977
1978 void JaguarDasm(uint32_t offset, uint32_t qt)
1979 {
1980 #ifdef CPU_DEBUG
1981 static char buffer[2048];//, mem[64];
1982 int pc = offset, oldpc;
1983
1984 for(uint32_t i=0; i<qt; i++)
1985 {
1986 /* oldpc = pc;
1987 for(int j=0; j<64; j++)
1988 mem[j^0x01] = jaguar_byte_read(pc + j);
1989
1990 pc += Dasm68000((char *)mem, buffer, 0);
1991 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1992 oldpc = pc;
1993 pc += m68k_disassemble(buffer, pc, 0, 1);//M68K_CPU_TYPE_68000);
1994 WriteLog("%08X: %s\n", oldpc, buffer);//*/
1995 }
1996 #endif
1997 }
1998
1999
2000 uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2001 {
2002 uint8_t data = 0x00;
2003 offset &= 0xFFFFFF;
2004
2005 // First 2M is mirrored in the $0 - $7FFFFF range
2006 if (offset < 0x800000)
2007 data = jaguarMainRAM[offset & (vjs.DRAM_size - 1)];
2008 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2009 data = jaguarMainROM[offset - 0x800000];
2010 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2011 data = CDROMReadByte(offset, who);
2012 else if ((offset >= 0xE00000) && (offset < 0xE40000))
2013 // data = jaguarBootROM[offset & 0x3FFFF];
2014 // data = jaguarDevBootROM1[offset & 0x3FFFF];
2015 data = jagMemSpace[offset];
2016 else if ((offset >= 0xF00000) && (offset < 0xF10000))
2017 data = TOMReadByte(offset, who);
2018 else if ((offset >= 0xF10000) && (offset < 0xF20000))
2019 data = JERRYReadByte(offset, who);
2020 else
2021 data = jaguar_unknown_readbyte(offset, who);
2022
2023 return data;
2024 }
2025
2026
2027 uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2028 {
2029 offset &= 0xFFFFFF;
2030
2031 // First 2M is mirrored in the $0 - $7FFFFF range
2032 if (offset < 0x800000)
2033 {
2034 return (jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] << 8) | jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)];
2035 }
2036 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2037 {
2038 offset -= 0x800000;
2039 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
2040 }
2041 // else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
2042 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
2043 return CDROMReadWord(offset, who);
2044 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
2045 // return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
2046 // return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
2047 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
2048 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
2049 return TOMReadWord(offset, who);
2050 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
2051 return JERRYReadWord(offset, who);
2052
2053 return jaguar_unknown_readword(offset, who);
2054 }
2055
2056
2057 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
2058 {
2059 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2060 {
2061 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
2062 }//*/
2063 /* if (offset >= 0x4E00 && offset < 0x4E04)
2064 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2065 //Need to check for writes in the range of $18FA70 + 8000...
2066 /*if (effect_start)
2067 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2068 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2069
2070 offset &= 0xFFFFFF;
2071
2072 // First 2M is mirrored in the $0 - $7FFFFF range
2073 if (offset < 0x800000)
2074 {
2075 jaguarMainRAM[offset & (vjs.DRAM_size - 1)] = data;
2076 return;
2077 }
2078 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2079 {
2080 CDROMWriteByte(offset, data, who);
2081 return;
2082 }
2083 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
2084 {
2085 TOMWriteByte(offset, data, who);
2086 return;
2087 }
2088 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
2089 {
2090 JERRYWriteByte(offset, data, who);
2091 return;
2092 }
2093
2094 jaguar_unknown_writebyte(offset, data, who);
2095 }
2096
2097
2098 uint32_t starCount;
2099 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
2100 {
2101 /* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2102 {
2103 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
2104 WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
2105 }//*/
2106 /* if (offset >= 0x4E00 && offset < 0x4E04)
2107 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2108 /*if (offset == 0x0100)//64*4)
2109 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
2110 if (offset == 0x0102)//64*4)
2111 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
2112 //TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
2113 // PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
2114 //Need to check for writes in the range of $18FA70 + 8000...
2115 /*if (effect_start)
2116 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2117 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2118 /*if (offset >= 0x2C00 && offset <= 0x2CFF)
2119 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
2120
2121 offset &= 0xFFFFFF;
2122
2123 // First 2M is mirrored in the $0 - $7FFFFF range
2124 if (offset <= 0x7FFFFE)
2125 {
2126 /*
2127 GPU Table (CD BIOS)
2128
2129 1A 69 F0 ($0000) -> Starfield
2130 1A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
2131 1A 79 F0 ($0002)
2132 1A 88 C0 ($0003)
2133 1A 8F E8 ($0004) -> "Jaguar" small color logo?
2134 1A 95 20 ($0005)
2135 1A 9F 08 ($0006)
2136 1A A1 38 ($0007)
2137 1A AB 38 ($0008)
2138 1A B3 C8 ($0009)
2139 1A B9 C0 ($000A)
2140 */
2141
2142 //This MUST be done by the 68K!
2143 /*if (offset == 0x670C)
2144 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
2145
2146 /*extern bool doGPUDis;
2147 //if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
2148 if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2149 //if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
2150 doGPUDis = true;//*/
2151 /*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2152 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
2153 if ((data & 0xFF00) != 0x7700)
2154 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2155 /*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
2156 return;//*/
2157 /*if ((data & 0xFF00) != 0x7700 && who == GPU)
2158 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2159 /*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
2160 return;//*/
2161 /*extern bool doGPUDis;
2162 if (offset == 0x120216 && who == GPU)
2163 doGPUDis = true;//*/
2164 /*extern uint32_t gpu_pc;
2165 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2166 {
2167 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2168 uint32_t y = base / 0x300;
2169 uint32_t x = (base - (y * 0x300)) / 2;
2170 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2171 }//*/
2172 /*
2173 JWW: Writing starfield star 775E at 0011F650 (555984/1447)
2174 */
2175 //if (offset == (0x001E17F8 + 0x34))
2176 /*if (who == GPU && offset == (0x001E17F8 + 0x34))
2177 data = 0xFE3C;//*/
2178 // WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
2179 /*extern uint32_t gpu_pc;
2180 if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2181 {
2182 extern int objectPtr;
2183 // if (offset > 0x148000)
2184 // return;
2185 starCount++;
2186 if (starCount > objectPtr)
2187 return;
2188
2189 // if (starCount == 1)
2190 // WriteLog("--> Drawing 1st star...\n");
2191 //
2192 // uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2193 // uint32_t y = base / 0x300;
2194 // uint32_t x = (base - (y * 0x300)) / 2;
2195 // WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2196
2197 //A star of interest...
2198 //-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
2199 //1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
2200 //JWW: Blitter writing echo 77B3 at 0011D022...
2201 }//*/
2202 //extern bool doGPUDis;
2203 /*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
2204 {
2205 // doGPUDis = true;
2206 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
2207 // LogBlit();
2208 }
2209 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
2210 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
2211
2212 jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] = data >> 8;
2213 jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)] = data & 0xFF;
2214 return;
2215 }
2216 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
2217 {
2218 CDROMWriteWord(offset, data, who);
2219 return;
2220 }
2221 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
2222 {
2223 TOMWriteWord(offset, data, who);
2224 return;
2225 }
2226 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
2227 {
2228 JERRYWriteWord(offset, data, who);
2229 return;
2230 }
2231 // Don't bomb on attempts to write to ROM
2232 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
2233 return;
2234
2235 jaguar_unknown_writeword(offset, data, who);
2236 }
2237
2238
2239 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2240 uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2241 {
2242 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
2243 }
2244
2245
2246 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2247 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
2248 {
2249 /* extern bool doDSPDis;
2250 if (offset < 0x400 && !doDSPDis)
2251 {
2252 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
2253 doDSPDis = true;
2254 }//*/
2255 /*if (offset == 0x0100)//64*4)
2256 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
2257
2258 JaguarWriteWord(offset, data >> 16, who);
2259 JaguarWriteWord(offset+2, data & 0xFFFF, who);
2260 }
2261
2262
2263 void JaguarSetScreenBuffer(uint32_t * buffer)
2264 {
2265 // This is in TOM, but we set it here...
2266 screenBuffer = buffer;
2267 }
2268
2269
2270 void JaguarSetScreenPitch(uint32_t pitch)
2271 {
2272 // This is in TOM, but we set it here...
2273 screenPitch = pitch;
2274 }
2275
2276
2277 //
2278 // Jaguar console initialization
2279 //
2280 void JaguarInit(void)
2281 {
2282 // For randomizing RAM
2283 srand((unsigned int)time(NULL));
2284
2285 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
2286 for(uint32_t i=0; i<vjs.DRAM_size; i+=4)
2287 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
2288
2289 #ifdef CPU_DEBUG_MEMORY
2290 memset(readMem, 0x00, 0x400000);
2291 memset(writeMemMin, 0xFF, 0x400000);
2292 memset(writeMemMax, 0x00, 0x400000);
2293 #endif
2294 // memset(jaguarMainRAM, 0x00, 0x200000);
2295 // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
2296 // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
2297 //NOTE: This *doesn't* fix FlipOut...
2298 //Or does it? Hmm...
2299 //Seems to want $01010101... Dunno why. Investigate!
2300 // memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
2301 // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
2302 lowerField = false; // Reset the lower field flag
2303 //temp, for crappy crap that sux
2304 memset(jaguarMainRAM + 0x804, 0xFF, 4);
2305
2306 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
2307 GPUInit();
2308 DSPInit();
2309 TOMInit();
2310 JERRYInit();
2311 CDROMInit();
2312 m68k_brk_init();
2313 }
2314
2315
2316 //New timer based code stuffola...
2317 void HalflineCallback(void);
2318 void RenderCallback(void);
2319 void JaguarReset(void)
2320 {
2321 // Only problem with this approach: It wipes out RAM loaded files...!
2322 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
2323 for (uint32_t i = 8; i < vjs.DRAM_size; i += 4)
2324 {
2325 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
2326 }
2327
2328 // New timer base code stuffola...
2329 InitializeEventList();
2330 //Need to change this so it uses the single RAM space and load the BIOS
2331 //into it somewhere...
2332 //Also, have to change this here and in JaguarReadXX() currently
2333 // Only use the system BIOS if it's available...! (it's always available now!)
2334 // AND only if a jaguar cartridge has been inserted.
2335 #ifndef NEWMODELSBIOSHANDLER
2336 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine && !vjs.softTypeDebugger)
2337 {
2338 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
2339 #else
2340 if (vjs.useJaguarBIOS && jaguarCartInserted)
2341 {
2342 SetBIOS();
2343 #endif
2344 }
2345 else
2346 {
2347 SET32(jaguarMainRAM, 4, jaguarRunAddress);
2348 }
2349
2350 // WriteLog("jaguar_reset():\n");
2351 TOMReset();
2352 JERRYReset();
2353 GPUReset();
2354 DSPReset();
2355 CDROMReset();
2356 m68k_pulse_reset(); // Reset the 68000
2357 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
2358 lowerField = false; // Reset the lower field flag
2359 // SetCallbackTime(ScanlineCallback, 63.5555);
2360 // SetCallbackTime(ScanlineCallback, 31.77775);
2361 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2362 }
2363
2364
2365 void JaguarDone(void)
2366 {
2367 #ifdef CPU_DEBUG_MEMORY
2368 /* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
2369
2370 for(uint32_t i=0; i<=raPtr; i++)
2371 {
2372 WriteLog("\t%08X\n", returnAddr[i]);
2373 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
2374 jaguar_dasm(returnAddr[i] - 16, 16);
2375 WriteLog("\n");
2376 }
2377 WriteLog("\n");//*/
2378
2379 /* int start = 0, end = 0;
2380 bool endTriggered = false, startTriggered = false;
2381 for(int i=0; i<0x400000; i++)
2382 {
2383 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
2384 {
2385 if (!startTriggered)
2386 startTriggered = true, endTriggered = false, start = i;
2387
2388 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
2389 }
2390 else
2391 {
2392 if (!endTriggered)
2393 {
2394 end = i - 1, endTriggered = true, startTriggered = false;
2395 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
2396 }
2397 }
2398 }
2399 WriteLog("\n");//*/
2400 #endif
2401 //#ifdef CPU_DEBUG
2402 // for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
2403 // WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
2404 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
2405 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2406 #if 0
2407 for(int i=-2; i<9; i++)
2408 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2409 #else
2410 uint32_t address = topOfStack - (4 * 4 * 3);
2411
2412 for(int i=0; i<10; i++)
2413 {
2414 WriteLog("%06X:", address);
2415
2416 for(int j=0; j<4; j++)
2417 {
2418 WriteLog(" %08X", JaguarReadLong(address));
2419 address += 4;
2420 }
2421
2422 WriteLog("\n");
2423 }
2424 #endif
2425
2426 /* WriteLog("\nM68000 disassembly at $802288...\n");
2427 jaguar_dasm(0x802288, 3);
2428 WriteLog("\nM68000 disassembly at $802200...\n");
2429 jaguar_dasm(0x802200, 500);
2430 WriteLog("\nM68000 disassembly at $802518...\n");
2431 jaguar_dasm(0x802518, 100);//*/
2432
2433 /* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2434 jaguar_dasm(0x803F00, 500);
2435 WriteLog("\n");//*/
2436
2437 /* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2438 jaguar_dasm(0x802B00, 500);
2439 WriteLog("\n");//*/
2440
2441 /* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2442 jaguar_dasm(0x809900, 500);
2443 WriteLog("\n");//*/
2444 //8099F8
2445 /* WriteLog("\n\nDump of $8093C8:\n\n");
2446 for(int i=0x8093C8; i<0x809900; i+=4)
2447 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2448 /* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2449 jaguar_dasm(0x90006C, 500);
2450 WriteLog("\n");//*/
2451 /* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2452 jaguar_dasm(0x1AC000, 6000);
2453 WriteLog("\n");//*/
2454
2455 // WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2456 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2457 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2458 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2459 M68K_show_context();
2460 //#endif
2461
2462 CDROMDone();
2463 GPUDone();
2464 DSPDone();
2465 TOMDone();
2466 JERRYDone();
2467 m68k_brk_close();
2468
2469 // temp, until debugger is in place
2470 //00802016: jsr $836F1A.l
2471 //0080201C: jsr $836B30.l
2472 //00802022: jsr $836B18.l
2473 //00802028: jsr $8135F0.l
2474 //00813C1E: jsr $813F76.l
2475 //00802038: jsr $836D00.l
2476 //00802098: jsr $8373A4.l
2477 //008020A2: jsr $83E24A.l
2478 //008020BA: jsr $83E156.l
2479 //008020C6: jsr $83E19C.l
2480 //008020E6: jsr $8445E8.l
2481 //008020EC: jsr $838C20.l
2482 //0080211A: jsr $838ED6.l
2483 //00802124: jsr $89CA56.l
2484 //0080212A: jsr $802B48.l
2485 #if 0
2486 WriteLog("-------------------------------------------\n");
2487 JaguarDasm(0x8445E8, 0x200);
2488 WriteLog("-------------------------------------------\n");
2489 JaguarDasm(0x838C20, 0x200);
2490 WriteLog("-------------------------------------------\n");
2491 JaguarDasm(0x838ED6, 0x200);
2492 WriteLog("-------------------------------------------\n");
2493 JaguarDasm(0x89CA56, 0x200);
2494 WriteLog("-------------------------------------------\n");
2495 JaguarDasm(0x802B48, 0x200);
2496 WriteLog("\n\nM68000 disassembly at $802000...\n");
2497 JaguarDasm(0x802000, 6000);
2498 WriteLog("\n");//*/
2499 #endif
2500 /* WriteLog("\n\nM68000 disassembly at $6004...\n");
2501 JaguarDasm(0x6004, 10000);
2502 WriteLog("\n");//*/
2503 // WriteLog("\n\nM68000 disassembly at $802000...\n");
2504 // JaguarDasm(0x802000, 0x1000);
2505 // WriteLog("\n\nM68000 disassembly at $4100...\n");
2506 // JaguarDasm(0x4100, 200);
2507 // WriteLog("\n\nM68000 disassembly at $800800...\n");
2508 // JaguarDasm(0x800800, 0x1000);
2509 }
2510
2511
2512 // Temp debugging stuff
2513
2514 void DumpMainMemory(void)
2515 {
2516 FILE * fp = fopen("./memdump.bin", "wb");
2517
2518 if (fp == NULL)
2519 return;
2520
2521 fwrite(jaguarMainRAM, 1, vjs.DRAM_size, fp);
2522 fclose(fp);
2523 }
2524
2525
2526 uint8_t * GetRamPtr(void)
2527 {
2528 return jaguarMainRAM;
2529 }
2530
2531
2532 //
2533 // New Jaguar execution stack
2534 // This executes 1 frame's worth of code.
2535 //
2536 bool frameDone;
2537 void JaguarExecuteNew(void)
2538 {
2539 frameDone = false;
2540
2541 do
2542 {
2543 double timeToNextEvent = GetTimeToNextEvent();
2544 //WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2545
2546 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2547
2548 if (vjs.GPUEnabled)
2549 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2550
2551 HandleNextEvent();
2552 }
2553 while (!frameDone);
2554 }
2555
2556
2557 // Step over function
2558 void JaguarStepOver(int depth)
2559 {
2560 bool exit;
2561 //bool case55 = false;
2562 //uint32_t m68kSR;
2563
2564 if (!depth)
2565 {
2566 exit = true;
2567 }
2568 else
2569 {
2570 exit = false;
2571 }
2572
2573 do
2574 {
2575 JaguarStepInto();
2576
2577 switch (M68KGetCurrentOpcodeFamily())
2578 {
2579 // rts
2580 case 49:
2581 //if (depth)
2582 {
2583 //if (!--depth)
2584 {
2585 exit = true;
2586 }
2587 //exit = false;
2588 }
2589 break;
2590
2591 #if 0
2592 // bcc
2593 case 55:
2594 if (!depth)
2595 {
2596 //m68kSR = m68k_get_reg(NULL, M68K_REG_SR);
2597 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x4)
2598 {
2599 exit = true;
2600 }
2601 else
2602 {
2603 exit = false;
2604 }
2605 }
2606 break;
2607 #endif
2608
2609 // bsr & jsr
2610 case 54:
2611 case 52:
2612 JaguarStepOver(depth+1);
2613 //if (depth)
2614 //{
2615 // exit = false;
2616 //}
2617 break;
2618
2619 default:
2620 //if (case55)
2621 //{
2622 // exit = true;
2623 //}
2624 break;
2625 }
2626 }
2627 while (!exit);
2628
2629 #ifdef _MSC_VER
2630 #pragma message("Warning: !!! Need to verify the Jaguar Step Over function !!!")
2631 #else
2632 #warning "!!! Need to verify the Jaguar Step Over function !!!"
2633 #endif // _MSC_VER
2634 }
2635
2636
2637 // Step into function
2638 void JaguarStepInto(void)
2639 {
2640 // double timeToNextEvent = GetTimeToNextEvent();
2641
2642 m68k_execute(USEC_TO_M68K_CYCLES(0));
2643 // m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2644
2645 if (vjs.GPUEnabled)
2646 GPUExec(USEC_TO_RISC_CYCLES(0));
2647
2648 // HandleNextEvent();
2649 #ifdef _MSC_VER
2650 #pragma message("Warning: !!! Need to verify the Jaguar Step Into function !!!")
2651 #else
2652 #warning "!!! Need to verify the Jaguar Step Into function !!!"
2653 #endif // _MSC_VER
2654 }
2655
2656
2657 //
2658 // The thing to keep in mind is that the VC is advanced every HALF line,
2659 // regardless of whether the display is interlaced or not. The only difference
2660 // with an interlaced display is that the high bit of VC will be set when the
2661 // lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2662 // lower field, regardless of whether it's in interlace mode or not.
2663 // NB2: Seems it doesn't always, not sure what the constraint is...)
2664 //
2665 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2666 // rendering two fields that are slighty vertically offset from each other.
2667 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2668 // is rendered in this mode so that each field, when overlaid on each other,
2669 // will yield the final picture at the full resolution for the full frame.
2670 //
2671 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2672 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2673 // it will be half this number for a half frame. BUT, since we're counting
2674 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2675 // PAL.
2676 //
2677 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2678 // Half line times are, naturally, half of this. :-P
2679 //
2680 void HalflineCallback(void)
2681 {
2682 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2683 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2684 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2685 // uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2686 vc++;
2687
2688 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2689 // So we cut the number of half-lines in a frame in half. :-P
2690 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2691
2692 if ((vc & 0x7FF) >= numHalfLines)
2693 {
2694 lowerField = !lowerField;
2695 // If we're rendering the lower field, set the high bit (#11, counting
2696 // from 0) of VC
2697 vc = (lowerField ? 0x0800 : 0x0000);
2698 }
2699
2700 //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2701 TOMWriteWord(0xF00006, vc, JAGUAR);
2702
2703 // Time for Vertical Interrupt?
2704 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2705 {
2706 // We don't have to worry about autovectors & whatnot because the Jaguar
2707 // tells you through its HW registers who sent the interrupt...
2708 TOMSetPendingVideoInt();
2709 m68k_set_irq(2);
2710 }
2711
2712 TOMExecHalfline(vc, true);
2713
2714 //Change this to VBB???
2715 //Doesn't seem to matter (at least for Flip Out & I-War)
2716 if ((vc & 0x7FF) == 0)
2717 // if (vc == vbb)
2718 {
2719 JoystickExec();
2720 frameDone = true;
2721 }//*/
2722
2723 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2724 }
2725