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