Merge branch 'develop' of https://github.com/djipi/Virtual-Jaguar-Rx into develop
[clinton/Virtual-Jaguar-Rx.git] / src / jaguar.cpp
CommitLineData
cf76e892
JPM
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
ed31b999 11// JPM = Jean-Paul Mari
cf76e892
JPM
12//
13// WHO WHEN WHAT
14// --- ---------- -----------------------------------------------------------
15// JLH 11/25/2009 Major rewrite of memory subsystem and handlers
ed31b999 16// JPM 09/04/2018 Added the new Models and BIOS handler
1081a838 17// JPM 10/13/2018 Added breakpoints features
cf76e892
JPM
18//
19
20
ed31b999
JPM
21#define NEWMODELSBIOSHANDLER // New Jaguar models and bios usage handler
22
23
cf76e892 24#include "jaguar.h"
eb20f274
JPM
25#include <QApplication>
26#include <QMessageBox>
cf76e892
JPM
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"
1081a838 47//#include "debugger/BreakpointsWin.h"
ed31b999
JPM
48#ifdef NEWMODELSBIOSHANDLER
49#include "modelsBIOS.h"
50#endif
cf76e892
JPM
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
65unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN);
66unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN);
67void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN);
68void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN);
69void M68K_show_context(void);
70#if 0
71void M68K_Debughalt(void);
72#endif
73
74// External variables
75
76#ifdef CPU_DEBUG_MEMORY
77extern bool startMemLog; // Set by "e" key
78extern int effect_start;
79extern 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...
83extern uint8_t jagMemSpace[];
84
85// Internal variables
86
87uint32_t jaguar_active_memory_dumps = 0;
88
89uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
90bool jaguarCartInserted = false;
91bool lowerField = false;
92
93#ifdef CPU_DEBUG_MEMORY
94uint8_t writeMemMax[0x400000], writeMemMin[0x400000];
95uint8_t readMem[0x400000];
96uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF;
97#endif
98
99uint32_t pcQueue[0x400];
100uint32_t a0Queue[0x400];
101uint32_t a1Queue[0x400];
102uint32_t a2Queue[0x400];
103uint32_t a3Queue[0x400];
104uint32_t a4Queue[0x400];
105uint32_t a5Queue[0x400];
106uint32_t a6Queue[0x400];
107uint32_t a7Queue[0x400];
108uint32_t d0Queue[0x400];
109uint32_t d1Queue[0x400];
110uint32_t d2Queue[0x400];
111uint32_t d3Queue[0x400];
112uint32_t d4Queue[0x400];
113uint32_t d5Queue[0x400];
114uint32_t d6Queue[0x400];
115uint32_t d7Queue[0x400];
116uint32_t srQueue[0x400];
117uint32_t pcQPtr = 0;
118bool startM68KTracing = false;
119
120// Breakpoint on memory access vars (exported)
121bool bpmActive = false;
122bool bpmSaveActive = false;
1081a838 123size_t bpmHitCounts;
cf76e892 124uint32_t bpmAddress1;
1081a838
JPM
125S_BrkInfo *brkInfo;
126size_t brkNbr;
cf76e892
JPM
127
128
129//
130// Callback function to detect illegal instructions
131//
132void GPUDumpDisassembly(void);
133void GPUDumpRegisters(void);
134static bool start = false;
135
136void 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);
149static int hitCount = 0;
150static int inRoutine = 0;
151static int instSeen;
152
153//if (regs.pc == 0x80340A)
154if (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}
161else if (m68kPC == 0x803422)
162{
163 inRoutine = 0;
164 printf("(%i instructions)\n", instSeen);
165}
166
167if (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/*
28300805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000
28400805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8
28500805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA
28600805FEC: bne 805fe2 D0=00100010, A0=0009C6FA
287
2880080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8
289
2900012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC
2910012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000
29200123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000
29300123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
29400123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
2950012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000
29600123174: 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;
303if (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/*
370CD_init:: -> $3000
371BIOS_VER:: -> $3004
372CD_mode:: -> $3006
373CD_ack:: -> $300C
374CD_jeri:: -> $3012
375CD_spin:: -> $3018
376CD_stop:: -> $301E
377CD_mute:: -> $3024
378CD_umute:: -> $302A
379CD_paus:: -> $3030
380CD_upaus:: -> $3036
381CD_read:: -> $303C
382CD_uread:: -> $3042
383CD_setup:: -> $3048
384CD_ptr:: -> $304E
385CD_osamp:: -> $3054
386CD_getoc:: -> $305A
387CD_initm:: -> $3060
388CD_initf:: -> $3066
389CD_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
488Now here be dragons...
489Here is how memory ranges are defined in the CoJag driver.
490Note that we only have to be concerned with 3 entities read/writing anything:
491The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory
492checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than
493things that are entirely internal to those modules. This way we should be able to get a handle on all
494this crap which is currently scattered over Hell's Half Acre(tm).
495
496Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there
497is 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
505static 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)
528ADDRESS_MAP_END
529
530/*************************************
531 *
532 * GPU memory handlers
533 *
534 *************************************/
535
536static 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)
547ADDRESS_MAP_END
548
549/*************************************
550 *
551 * DSP memory handlers
552 *
553 *************************************/
554
555static 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)
564ADDRESS_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/*
578uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM
579uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM
580uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this!
581uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM
582bool BIOSLoaded = false;
583bool CDBIOSLoaded = false;
584
585uint8_t cdRAM[0x100];
586uint8_t tomRAM[0x4000];
587uint8_t jerryRAM[0x10000];
588static 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
593enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO };
594
595// M68K Memory map/handlers
596uint32_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
640JOYSTICK $F14000 Read/Write
641 15.....8 7......0
642Read fedcba98 7654321q f-1 Signals J15 to J1
643 q Cartridge EEPROM output data
644Write 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)
652JOYBUTS $F14002 Read Only
653 15.....8 7......0
654Read 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
662J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15
663J3 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
6810 bit read in any position means that button is pressed.
682C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached.
683*/
684};
685
686void 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
850WriteLog("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 {
862WriteLog("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
892void WriteWord(uint32_t adddress, uint16_t word)
893{
894}
895
896
897void WriteDWord(uint32_t adddress, uint32_t dword)
898{
899}
900
901
902uint8_t ReadByte(uint32_t adddress)
903{
904}
905
906
907uint16_t ReadWord(uint32_t adddress)
908{
909}
910
911
912uint32_t ReadDWord(uint32_t adddress)
913{
914}
915#endif
916
917
918void 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
957IRQs:
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
991handler:
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
1015int 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
1047void M68K_Debughalt(void)
1048{
1049 M68KDebugHalt();
1050}
1051#endif
1052
1053
1081a838
JPM
1054// M68000 breakpoints initialisations
1055void m68k_brk_init(void)
1056{
1057 brkNbr = 0;
1058 brkInfo = NULL;
1059}
1060
1061
1062// Reset the M68000 breakpoints structures
1063void 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)
1073void 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
1082unsigned 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
1122unsigned 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
1152void 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
1163void 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
1174void m68k_brk_close(void)
1175{
1176 free(brkInfo);
1177}
1178
1179
1180// Read 1 byte from address
1181// Check if address reaches a breakpoint
cf76e892
JPM
1182unsigned 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
1081a838 1186 if (!startM68KTracing && m68k_brk_check(address))
a8c13b4d 1187 {
cf76e892 1188 M68KDebugHalt();
a8c13b4d 1189 }
cf76e892
JPM
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)))
a8c13b4d 1212 {
cf76e892 1213 retVal = jaguarMainRAM[address];
a8c13b4d 1214 }
cf76e892 1215// else if ((address >= 0x800000) && (address <= 0xDFFFFF))
cf76e892 1216 else
a8c13b4d
JPM
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 }
cf76e892
JPM
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/*
1270void gpu_dump_disassembly(void);
1271void gpu_dump_registers(void);
1272*/
1273
1274unsigned 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
1081a838 1278 if (!startM68KTracing && m68k_brk_check(address))
cf76e892
JPM
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)))
a8c13b4d
JPM
1351 {
1352 // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
cf76e892 1353 retVal = GET16(jaguarMainRAM, address);
a8c13b4d 1354 }
cf76e892 1355// else if ((address >= 0x800000) && (address <= 0xDFFFFE))
a8c13b4d 1356 else
cf76e892 1357 {
a8c13b4d 1358 if ((address >= 0x800000) && (address <= 0xDFFEFE))
cf76e892 1359 {
a8c13b4d
JPM
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 }
cf76e892
JPM
1369 }
1370 else
a8c13b4d
JPM
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 }
cf76e892 1404 }
cf76e892
JPM
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
f6eb33e6
JPM
1421// Alert message in case of exception vector request
1422bool m68k_read_exception_vector(unsigned int address, char *text)
1423{
1424 QString msg;
1425 QMessageBox msgBox;
1426
1427 msg.sprintf("$%06x: %s", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], text);
1428 msgBox.setText(msg);
1429 msgBox.setStandardButtons(QMessageBox::Abort);
1430 msgBox.setDefaultButton(QMessageBox::Abort);
1431 msgBox.exec();
1432 return M68KDebugHalt();
1433}
1434
1435
1436// Read 4 bytes from memory
cf76e892
JPM
1437unsigned int m68k_read_memory_32(unsigned int address)
1438{
1439#ifdef ALPINE_FUNCTIONS
1440 // Check if breakpoint on memory is active, and deal with it
1081a838 1441 if (!startM68KTracing && m68k_brk_check(address))
a8c13b4d 1442 {
cf76e892 1443 M68KDebugHalt();
a8c13b4d 1444 }
cf76e892
JPM
1445#endif
1446
1447 // Musashi does this automagically for you, UAE core does not :-P
1448 address &= 0x00FFFFFF;
1449//; So, it seems that it stores the returned DWORD at $51136 and $FB074.
1450/* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
1451 WriteLog("[RM32 PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
1452
1453//WriteLog("--> [RM32]\n");
1454#ifndef USE_NEW_MMU
f6eb33e6 1455 //uint32_t retVal = 0;
cf76e892 1456
f6eb33e6
JPM
1457 // check exception vectors access
1458 if ((address >= 0x8) && (address <= 0x7c))
cf76e892 1459 {
f6eb33e6 1460 switch (address)
a8c13b4d 1461 {
f6eb33e6
JPM
1462 case 0x10:
1463 m68k_read_exception_vector(address, "Illegal instruction");
1464 break;
a8c13b4d 1465 }
f6eb33e6
JPM
1466 }
1467 else
1468 {
1469 // check ROM or Memory Track access
1470 if ((address >= 0x800000) && (address <= 0xDFFEFE))
a8c13b4d 1471 {
f6eb33e6
JPM
1472 // Memory Track reading...
1473 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1474 {
1475 return MTReadLong(address);
1476 }
1477 else
1478 {
1479 return GET32(jaguarMainROM, address - 0x800000);
1480 }
a8c13b4d 1481 }
cf76e892
JPM
1482 }
1483
f6eb33e6 1484 // return value from memory
cf76e892
JPM
1485 return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
1486#else
1487 return MMURead32(address, M68K);
1488#endif
1489}
1490
1491
f04df4f1 1492// Alert message in case of writing to unknown memory location
a8c13b4d
JPM
1493bool m68k_write_unknown_alert(unsigned int address, char *bits, unsigned int value)
1494{
1495 QString msg;
1496 QMessageBox msgBox;
1497
1498 msg.sprintf("$%06x: Writing at this unknown memory location $%06x with a (%s bits) value of $%0x", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], address, bits, value);
1499 msgBox.setText(msg);
f04df4f1
JPM
1500 msgBox.setStandardButtons(QMessageBox::Abort);
1501 msgBox.setDefaultButton(QMessageBox::Abort);
a8c13b4d
JPM
1502 msgBox.exec();
1503 return M68KDebugHalt();
1504}
1505
1506
f04df4f1 1507// Alert message in case of writing to cartridge/ROM memory location
a8c13b4d 1508bool m68k_write_cartridge_alert(unsigned int address, char *bits, unsigned int value)
eb20f274 1509{
f04df4f1
JPM
1510 if (!M68KDebugHaltStatus())
1511 {
1512 QString msg;
1513 QMessageBox msgBox;
a8c13b4d 1514
f04df4f1
JPM
1515 msg.sprintf("$%06x: Writing at this ROM cartridge location $%06x with a (%s bits) value of $%0x", pcQueue[pcQPtr ? (pcQPtr - 1) : 0x3FF], address, bits, value);
1516 msgBox.setText(msg);
eb20f274 1517
eb20f274 1518 msgBox.setInformativeText("Do you want to continue?");
f04df4f1
JPM
1519 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1520 msgBox.setDefaultButton(QMessageBox::No);
eb20f274 1521
f04df4f1 1522 int retVal = msgBox.exec();
eb20f274 1523
f04df4f1
JPM
1524 if (retVal == QMessageBox::Yes)
1525 {
1526 return false;
1527 }
1528 else
1529 {
1530 return M68KDebugHalt();
1531 }
eb20f274
JPM
1532 }
1533 else
1534 {
f04df4f1 1535 return 1;
eb20f274
JPM
1536 }
1537}
1538
1539
f04df4f1
JPM
1540// Check memory write location
1541// BPM & cartridge/ROM detections
a8c13b4d
JPM
1542bool m68k_write_memory_check(unsigned int address, char *bits, unsigned int value)
1543{
f04df4f1
JPM
1544 unsigned int address1;
1545
a8c13b4d
JPM
1546#ifdef ALPINE_FUNCTIONS
1547 // Check if breakpoint on memory is active, and deal with it
f04df4f1 1548 if (!M68KDebugHaltStatus() && bpmActive && (address == bpmAddress1))
a8c13b4d
JPM
1549 {
1550 return M68KDebugHalt();
1551 }
1552 else
1553#endif
1554 {
1555 // Rom writing authorisation detection
f04df4f1 1556 if (!vjs.allowWritesToROM)
a8c13b4d 1557 {
f04df4f1
JPM
1558 // Calcul the end address
1559 if (strstr(bits, "32"))
1560 {
1561 address1 = address + 3;
1562 }
1563 else
1564 {
1565 if (strstr(bits, "16"))
1566 {
1567 address1 = address + 1;
1568 }
1569 else
1570 {
1571 address1 = address;
1572 }
1573 }
1574
1575 // Rom writing detection
1576 if ((address >= 0x800000) && (address1 < 0xDFFF00))
1577 {
1578 return m68k_write_cartridge_alert(address, bits, value);
1579 }
a8c13b4d 1580 }
f04df4f1
JPM
1581
1582 return false;
a8c13b4d
JPM
1583 }
1584}
1585
1586
f04df4f1 1587// Memory write location on 8 bits
cf76e892
JPM
1588void m68k_write_memory_8(unsigned int address, unsigned int value)
1589{
f04df4f1
JPM
1590 // Check memory write location on 8 bits
1591 if (!m68k_write_memory_check(address, "8", value))
eb20f274 1592 {
f04df4f1
JPM
1593 // Musashi does this automagically for you, UAE core does not :-P
1594 //address &= 0x00FFFFFF;
cf76e892
JPM
1595#ifdef CPU_DEBUG_MEMORY
1596 // Note that the Jaguar only has 2M of RAM, not 4!
f04df4f1 1597 if ((address >= 0x000000) && (address <= 0x1FFFFF))
cf76e892 1598 {
f04df4f1
JPM
1599 if (startMemLog)
1600 {
1601 if (value > writeMemMax[address])
1602 writeMemMax[address] = value;
1603 if (value < writeMemMin[address])
1604 writeMemMin[address] = value;
1605 }
cf76e892 1606 }
cf76e892 1607#endif
f04df4f1
JPM
1608 /*if (address == 0x4E00)
1609 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1610 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1611 // WriteLog("M68K: Writing %02X at %08X\n", value, address);
1612 //WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1613 /*if (effect_start)
1614 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1615 WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/
1616 //$53D0
1617 /*if (address >= 0x53D0 && address <= 0x53FF)
1618 printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1619 //Testing AvP on UAE core...
1620 //000075A0: FFFFF80E B6320220 (BITMAP)
1621 /*if (address == 0x75A0 && value == 0xFF)
1622 printf("M68K: (8) Tripwire hit...\n");//*/
cf76e892
JPM
1623
1624#ifndef USE_NEW_MMU
f04df4f1
JPM
1625 // Note that the Jaguar only has 2M of RAM, not 4!
1626 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 1)))
a8c13b4d 1627 {
f04df4f1 1628 jaguarMainRAM[address] = value;
a8c13b4d
JPM
1629 }
1630 else
1631 {
f04df4f1 1632 if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
a8c13b4d 1633 {
f04df4f1 1634 CDROMWriteByte(address, value, M68K);
a8c13b4d
JPM
1635 }
1636 else
1637 {
f04df4f1 1638 if ((address >= 0xF00000) && (address <= 0xF0FFFF))
a8c13b4d 1639 {
f04df4f1 1640 TOMWriteByte(address, value, M68K);
a8c13b4d
JPM
1641 }
1642 else
1643 {
f04df4f1
JPM
1644 if ((address >= 0xF10000) && (address <= 0xF1FFFF))
1645 {
1646 JERRYWriteByte(address, value, M68K);
1647 }
1648 else
1649 {
1650 if ((address >= 0x800000) && (address <= 0xDFFEFF))
1651 {
1652 jagMemSpace[address] = (uint8_t)value;
1653 }
1654 else
1655 {
1656 jaguar_unknown_writebyte(address, value, M68K);
1657 }
1658 }
a8c13b4d
JPM
1659 }
1660 }
1661 }
cf76e892 1662#else
f04df4f1 1663 MMUWrite8(address, value, M68K);
cf76e892 1664#endif
f04df4f1 1665 }
cf76e892
JPM
1666}
1667
1668
f04df4f1 1669// Memory write location on 16 bits
cf76e892
JPM
1670void m68k_write_memory_16(unsigned int address, unsigned int value)
1671{
f04df4f1
JPM
1672 // Check memory write location on 16 bits
1673 if (!m68k_write_memory_check(address, "16", value))
a8c13b4d 1674 {
f04df4f1
JPM
1675 // Musashi does this automagically for you, UAE core does not :-P
1676 //address &= 0x00FFFFFF;
cf76e892
JPM
1677#ifdef CPU_DEBUG_MEMORY
1678 // Note that the Jaguar only has 2M of RAM, not 4!
f04df4f1 1679 if ((address >= 0x000000) && (address <= 0x1FFFFE))
cf76e892 1680 {
f04df4f1
JPM
1681 if (startMemLog)
1682 {
1683 uint8_t hi = value >> 8, lo = value & 0xFF;
cf76e892 1684
f04df4f1
JPM
1685 if (hi > writeMemMax[address])
1686 writeMemMax[address] = hi;
1687 if (hi < writeMemMin[address])
1688 writeMemMin[address] = hi;
cf76e892 1689
f04df4f1
JPM
1690 if (lo > writeMemMax[address + 1])
1691 writeMemMax[address + 1] = lo;
1692 if (lo < writeMemMin[address + 1])
1693 writeMemMin[address + 1] = lo;
1694 }
cf76e892 1695 }
cf76e892 1696#endif
f04df4f1
JPM
1697 /*if (address == 0x4E00)
1698 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1699 //if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F))
1700 // WriteLog("M68K: Writing %04X at %08X\n", value, address);
1701 //WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);
1702 //if (address >= 0xF02200 && address <= 0xF0229F)
1703 // WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address);
1704 //if (address >= 0x0E75D0 && address <= 0x0E75E7)
1705 // WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));
1706 /*extern uint32_t totalFrames;
1707 if (address == 0xF02114)
1708 WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));
1709 if (address == 0xF02110)
1710 WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/
1711 //if (address >= 0xF03B00 && address <= 0xF03DFF)
1712 // WriteLog("M68K: Writing %04X to %08X...\n", value, address);
1713
1714 /*if (address == 0x0100)//64*4)
1715 WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/
1716 /*if (effect_start)
1717 if (address >= 0x18FA70 && address < (0x18FA70 + 8000))
1718 WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/
1719 /* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076
1720 || address == 0x1AF05E)
1721 WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1722 //$53D0
1723 /*if (address >= 0x53D0 && address <= 0x53FF)
1724 printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1725 //Testing AvP on UAE core...
1726 //000075A0: FFFFF80E B6320220 (BITMAP)
1727 /*if (address == 0x75A0 && value == 0xFFFF)
1728 {
1729 printf("\nM68K: (16) Tripwire hit...\n");
1730 ShowM68KContext();
1731 }//*/
cf76e892
JPM
1732
1733#ifndef USE_NEW_MMU
f04df4f1
JPM
1734 // Note that the Jaguar only has 2M of RAM, not 4!
1735 if ((address >= 0x000000) && (address <= (vjs.DRAM_size - 2)))
a8c13b4d 1736 {
f04df4f1
JPM
1737 /* jaguar_mainRam[address] = value >> 8;
1738 jaguar_mainRam[address + 1] = value & 0xFF;*/
1739 SET16(jaguarMainRAM, address, value);
a8c13b4d
JPM
1740 }
1741 else
1742 {
f04df4f1
JPM
1743 // Memory Track device writes....
1744 if ((address >= 0x800000) && (address <= 0x87FFFE))
1745 {
1746 if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
1747 {
1748 MTWriteWord(address, value);
1749 return;
1750 }
1751 }
1752
a8c13b4d
JPM
1753 if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
1754 {
1755 CDROMWriteWord(address, value, M68K);
1756 }
1757 else
1758 {
1759 if ((address >= 0xF00000) && (address <= 0xF0FFFE))
1760 {
1761 TOMWriteWord(address, value, M68K);
1762 }
1763 else
1764 {
1765 if ((address >= 0xF10000) && (address <= 0xF1FFFE))
1766 {
1767 JERRYWriteWord(address, value, M68K);
1768 }
1769 else
1770 {
f04df4f1
JPM
1771 if ((address >= 0x800000) && (address <= 0xDFFEFE))
1772 {
1773 SET16(jagMemSpace, address, value);
1774 }
1775 else
1776 {
1777 jaguar_unknown_writeword(address, value, M68K);
cf76e892 1778#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
f04df4f1 1779 WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n", m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1));
cf76e892 1780#endif
f04df4f1 1781 }
a8c13b4d
JPM
1782 }
1783 }
1784 }
1785 }
cf76e892 1786#else
f04df4f1 1787 MMUWrite16(address, value, M68K);
cf76e892 1788#endif
f04df4f1 1789 }
cf76e892
JPM
1790}
1791
1792
f04df4f1 1793// Memory write location on 32 bits
cf76e892
JPM
1794void m68k_write_memory_32(unsigned int address, unsigned int value)
1795{
f04df4f1
JPM
1796 // Check memory write location on 32 bits
1797 if (!m68k_write_memory_check(address, "32", value))
1798 {
1799 // Musashi does this automagically for you, UAE core does not :-P
1800 //address &= 0x00FFFFFF;
1801 /*if (address == 0x4E00)
1802 WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
1803 //WriteLog("--> [WM32]\n");
1804 /*if (address == 0x0100)//64*4)
1805 WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/
1806 /*if (address >= 0xF03214 && address < 0xF0321F)
1807 WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/
1808 //M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)...
1809 /*extern bool doGPUDis;
1810 if (address == 0xF03214 && value == 0x88E30047)
1811 // start = true;
1812 doGPUDis = true;//*/
1813 /* if (address == 0x51136 || address == 0xFB074)
1814 WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
1815 //Testing AvP on UAE core...
1816 //000075A0: FFFFF80E B6320220 (BITMAP)
1817 /*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
1818 {
1819 printf("\nM68K: (32) Tripwire hit...\n");
1820 ShowM68KContext();
1821 }//*/
cf76e892
JPM
1822
1823#ifndef USE_NEW_MMU
f04df4f1
JPM
1824 m68k_write_memory_16(address, value >> 16);
1825 m68k_write_memory_16(address + 2, value & 0xFFFF);
cf76e892 1826#else
f04df4f1 1827 MMUWrite32(address, value, M68K);
cf76e892 1828#endif
f04df4f1 1829 }
cf76e892
JPM
1830}
1831
1832
1833uint32_t JaguarGetHandler(uint32_t i)
1834{
1835 return JaguarReadLong(i * 4);
1836}
1837
1838
1839bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
1840{
1841 uint32_t handler = JaguarGetHandler(i);
1842 return (handler && (handler != 0xFFFFFFFF) ? true : false);
1843}
1844
1845
1846void M68K_show_context(void)
1847{
1848 WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
1849
1850 for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
1851 {
1852 WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
1853
1854 if (i == M68K_REG_D3 || i == M68K_REG_D7)
1855 WriteLog("\n");
1856 }
1857
1858 for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
1859 {
1860 WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
1861
1862 if (i == M68K_REG_A3 || i == M68K_REG_A7)
1863 WriteLog("\n");
1864 }
1865
1866 WriteLog("68K disasm\n");
1867// jaguar_dasm(s68000readPC()-0x1000,0x20000);
1868 JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
1869// jaguar_dasm(0x5000, 0x14414);
1870
1871// WriteLog("\n.......[Cart start]...........\n\n");
1872// jaguar_dasm(0x192000, 0x1000);//0x200);
1873
1874 WriteLog("..................\n");
1875
1876 if (TOMIRQEnabled(IRQ_VIDEO))
1877 {
1878 WriteLog("video int: enabled\n");
1879 JaguarDasm(JaguarGetHandler(64), 0x200);
1880 }
1881 else
1882 WriteLog("video int: disabled\n");
1883
1884 WriteLog("..................\n");
1885
1886 for(int i=0; i<256; i++)
1887 {
1888 WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
1889 uint32_t address = (uint32_t)JaguarGetHandler(i);
1890
1891 if (address == 0)
1892 WriteLog(".........\n");
1893 else
1894 WriteLog("$%08X\n", address);
1895 }
1896}
1897
1898
1899//
1900// Unknown read/write byte/word routines
1901//
1902
1903// It's hard to believe that developers would be sloppy with their memory
1904// writes, yet in some cases the developers screwed up royal. E.g., Club Drive
1905// has the following code:
1906//
1907// 807EC4: movea.l #$f1b000, A1
1908// 807ECA: movea.l #$8129e0, A0
1909// 807ED0: move.l A0, D0
1910// 807ED2: move.l #$f1bb94, D1
1911// 807ED8: sub.l D0, D1
1912// 807EDA: lsr.l #2, D1
1913// 807EDC: move.l (A0)+, (A1)+
1914// 807EDE: dbra D1, 807edc
1915//
1916// The problem is at $807ED0--instead of putting A0 into D0, they really meant
1917// to put A1 in. This mistake causes it to try and overwrite approximately
1918// $700000 worth of address space! (That is, unless the 68K causes a bus
1919// error...)
1920
1921void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1922{
a8c13b4d 1923 m68k_write_unknown_alert(address, "8", data);
cf76e892
JPM
1924#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1925 WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1926#endif
1927#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1928// extern bool finished;
1929 finished = true;
1930// extern bool doDSPDis;
1931 if (who == DSP)
1932 doDSPDis = true;
1933#endif
1934}
1935
1936
1937void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
1938{
a8c13b4d 1939 m68k_write_unknown_alert(address, "16", data);
cf76e892
JPM
1940#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1941 WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1942#endif
1943#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1944// extern bool finished;
1945 finished = true;
1946// extern bool doDSPDis;
1947 if (who == DSP)
1948 doDSPDis = true;
1949#endif
1950}
1951
1952
1953unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
1954{
1955#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1956 WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1957#endif
1958#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1959// extern bool finished;
1960 finished = true;
1961// extern bool doDSPDis;
1962 if (who == DSP)
1963 doDSPDis = true;
1964#endif
1965 return 0xFF;
1966}
1967
1968
1969unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
1970{
1971#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
1972 WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC));
1973#endif
1974#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS
1975// extern bool finished;
1976 finished = true;
1977// extern bool doDSPDis;
1978 if (who == DSP)
1979 doDSPDis = true;
1980#endif
1981 return 0xFFFF;
1982}
1983
1984
1985//
1986// Disassemble M68K instructions at the given offset
1987//
1988
1989unsigned int m68k_read_disassembler_8(unsigned int address)
1990{
1991 return m68k_read_memory_8(address);
1992}
1993
1994
1995unsigned int m68k_read_disassembler_16(unsigned int address)
1996{
1997 return m68k_read_memory_16(address);
1998}
1999
2000
2001unsigned int m68k_read_disassembler_32(unsigned int address)
2002{
2003 return m68k_read_memory_32(address);
2004}
2005
2006
2007void JaguarDasm(uint32_t offset, uint32_t qt)
2008{
2009#ifdef CPU_DEBUG
2010 static char buffer[2048];//, mem[64];
2011 int pc = offset, oldpc;
2012
2013 for(uint32_t i=0; i<qt; i++)
2014 {
2015/* oldpc = pc;
2016 for(int j=0; j<64; j++)
2017 mem[j^0x01] = jaguar_byte_read(pc + j);
2018
2019 pc += Dasm68000((char *)mem, buffer, 0);
2020 WriteLog("%08X: %s\n", oldpc, buffer);//*/
2021 oldpc = pc;
2022 pc += m68k_disassemble(buffer, pc, 0, 1);//M68K_CPU_TYPE_68000);
2023 WriteLog("%08X: %s\n", oldpc, buffer);//*/
2024 }
2025#endif
2026}
2027
2028
2029uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2030{
2031 uint8_t data = 0x00;
2032 offset &= 0xFFFFFF;
2033
2034 // First 2M is mirrored in the $0 - $7FFFFF range
2035 if (offset < 0x800000)
2036 data = jaguarMainRAM[offset & (vjs.DRAM_size - 1)];
2037 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2038 data = jaguarMainROM[offset - 0x800000];
2039 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2040 data = CDROMReadByte(offset, who);
2041 else if ((offset >= 0xE00000) && (offset < 0xE40000))
2042// data = jaguarBootROM[offset & 0x3FFFF];
2043// data = jaguarDevBootROM1[offset & 0x3FFFF];
2044 data = jagMemSpace[offset];
2045 else if ((offset >= 0xF00000) && (offset < 0xF10000))
2046 data = TOMReadByte(offset, who);
2047 else if ((offset >= 0xF10000) && (offset < 0xF20000))
2048 data = JERRYReadByte(offset, who);
2049 else
2050 data = jaguar_unknown_readbyte(offset, who);
2051
2052 return data;
2053}
2054
2055
2056uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2057{
2058 offset &= 0xFFFFFF;
2059
2060 // First 2M is mirrored in the $0 - $7FFFFF range
2061 if (offset < 0x800000)
2062 {
2063 return (jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] << 8) | jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)];
2064 }
2065 else if ((offset >= 0x800000) && (offset < 0xDFFF00))
2066 {
2067 offset -= 0x800000;
2068 return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
2069 }
2070// else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
2071 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
2072 return CDROMReadWord(offset, who);
2073 else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
2074// return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF];
2075// return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF];
2076 return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
2077 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
2078 return TOMReadWord(offset, who);
2079 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
2080 return JERRYReadWord(offset, who);
2081
2082 return jaguar_unknown_readword(offset, who);
2083}
2084
2085
2086void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
2087{
2088/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2089 {
2090 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
2091 }//*/
2092/* if (offset >= 0x4E00 && offset < 0x4E04)
2093 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2094//Need to check for writes in the range of $18FA70 + 8000...
2095/*if (effect_start)
2096 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2097 WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
2098
2099 offset &= 0xFFFFFF;
2100
2101 // First 2M is mirrored in the $0 - $7FFFFF range
2102 if (offset < 0x800000)
2103 {
2104 jaguarMainRAM[offset & (vjs.DRAM_size - 1)] = data;
2105 return;
2106 }
2107 else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
2108 {
2109 CDROMWriteByte(offset, data, who);
2110 return;
2111 }
2112 else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
2113 {
2114 TOMWriteByte(offset, data, who);
2115 return;
2116 }
2117 else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
2118 {
2119 JERRYWriteByte(offset, data, who);
2120 return;
2121 }
2122
2123 jaguar_unknown_writebyte(offset, data, who);
2124}
2125
2126
2127uint32_t starCount;
2128void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
2129{
2130/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
2131 {
2132 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
2133 WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
2134 }//*/
2135/* if (offset >= 0x4E00 && offset < 0x4E04)
2136 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2137/*if (offset == 0x0100)//64*4)
2138 WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data);
2139if (offset == 0x0102)//64*4)
2140 WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/
2141//TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!)
2142// PLUS, you would handle this in the GPU/DSP WriteLong code! Not here!
2143//Need to check for writes in the range of $18FA70 + 8000...
2144/*if (effect_start)
2145 if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000))
2146 WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
2147/*if (offset >= 0x2C00 && offset <= 0x2CFF)
2148 WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/
2149
2150 offset &= 0xFFFFFF;
2151
2152 // First 2M is mirrored in the $0 - $7FFFFF range
2153 if (offset <= 0x7FFFFE)
2154 {
2155/*
2156GPU Table (CD BIOS)
2157
21581A 69 F0 ($0000) -> Starfield
21591A 73 C8 ($0001) -> Final clearing blit & bitmap blit?
21601A 79 F0 ($0002)
21611A 88 C0 ($0003)
21621A 8F E8 ($0004) -> "Jaguar" small color logo?
21631A 95 20 ($0005)
21641A 9F 08 ($0006)
21651A A1 38 ($0007)
21661A AB 38 ($0008)
21671A B3 C8 ($0009)
21681A B9 C0 ($000A)
2169*/
2170
2171//This MUST be done by the 68K!
2172/*if (offset == 0x670C)
2173 WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/
2174
2175/*extern bool doGPUDis;
2176//if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522
2177if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2178//if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU)
2179 doGPUDis = true;//*/
2180/*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP)
2181 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);
2182if ((data & 0xFF00) != 0x7700)
2183 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2184/*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU)
2185 return;//*/
2186/*if ((data & 0xFF00) != 0x7700 && who == GPU)
2187 WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/
2188/*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU)
2189 return;//*/
2190/*extern bool doGPUDis;
2191if (offset == 0x120216 && who == GPU)
2192 doGPUDis = true;//*/
2193/*extern uint32_t gpu_pc;
2194if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2195{
2196 uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2197 uint32_t y = base / 0x300;
2198 uint32_t x = (base - (y * 0x300)) / 2;
2199 WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2200}//*/
2201/*
2202JWW: Writing starfield star 775E at 0011F650 (555984/1447)
2203*/
2204//if (offset == (0x001E17F8 + 0x34))
2205/*if (who == GPU && offset == (0x001E17F8 + 0x34))
2206 data = 0xFE3C;//*/
2207// WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/
2208/*extern uint32_t gpu_pc;
2209if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
2210{
2211 extern int objectPtr;
2212// if (offset > 0x148000)
2213// return;
2214 starCount++;
2215 if (starCount > objectPtr)
2216 return;
2217
2218// if (starCount == 1)
2219// WriteLog("--> Drawing 1st star...\n");
2220//
2221// uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000);
2222// uint32_t y = base / 0x300;
2223// uint32_t x = (base - (y * 0x300)) / 2;
2224// WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L"));
2225
2226//A star of interest...
2227//-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s]
2228//1st trail +3(x), -1(y) -> 272, 154 -> 0011D020
2229//JWW: Blitter writing echo 77B3 at 0011D022...
2230}//*/
2231//extern bool doGPUDis;
2232/*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU)
2233{
2234// doGPUDis = true;
2235 WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset);
2236// LogBlit();
2237}
2238if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
2239 WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
2240
2241 jaguarMainRAM[(offset+0) & (vjs.DRAM_size - 1)] = data >> 8;
2242 jaguarMainRAM[(offset+1) & (vjs.DRAM_size - 1)] = data & 0xFF;
2243 return;
2244 }
2245 else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
2246 {
2247 CDROMWriteWord(offset, data, who);
2248 return;
2249 }
2250 else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
2251 {
2252 TOMWriteWord(offset, data, who);
2253 return;
2254 }
2255 else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
2256 {
2257 JERRYWriteWord(offset, data, who);
2258 return;
2259 }
2260 // Don't bomb on attempts to write to ROM
2261 else if (offset >= 0x800000 && offset <= 0xEFFFFF)
2262 return;
2263
2264 jaguar_unknown_writeword(offset, data, who);
2265}
2266
2267
2268// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2269uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
2270{
2271 return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
2272}
2273
2274
2275// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
2276void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
2277{
2278/* extern bool doDSPDis;
2279 if (offset < 0x400 && !doDSPDis)
2280 {
2281 WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]);
2282 doDSPDis = true;
2283 }//*/
2284/*if (offset == 0x0100)//64*4)
2285 WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/
2286
2287 JaguarWriteWord(offset, data >> 16, who);
2288 JaguarWriteWord(offset+2, data & 0xFFFF, who);
2289}
2290
2291
2292void JaguarSetScreenBuffer(uint32_t * buffer)
2293{
2294 // This is in TOM, but we set it here...
2295 screenBuffer = buffer;
2296}
2297
2298
2299void JaguarSetScreenPitch(uint32_t pitch)
2300{
2301 // This is in TOM, but we set it here...
2302 screenPitch = pitch;
2303}
2304
2305
2306//
2307// Jaguar console initialization
2308//
2309void JaguarInit(void)
2310{
2311 // For randomizing RAM
2312 srand((unsigned int)time(NULL));
2313
2314 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
2315 for(uint32_t i=0; i<vjs.DRAM_size; i+=4)
2316 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
2317
2318#ifdef CPU_DEBUG_MEMORY
2319 memset(readMem, 0x00, 0x400000);
2320 memset(writeMemMin, 0xFF, 0x400000);
2321 memset(writeMemMax, 0x00, 0x400000);
2322#endif
2323// memset(jaguarMainRAM, 0x00, 0x200000);
2324// memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
2325// memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
2326//NOTE: This *doesn't* fix FlipOut...
2327//Or does it? Hmm...
2328//Seems to want $01010101... Dunno why. Investigate!
2329// memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
2330// memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
2331 lowerField = false; // Reset the lower field flag
2332//temp, for crappy crap that sux
2333memset(jaguarMainRAM + 0x804, 0xFF, 4);
2334
2335 m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
2336 GPUInit();
2337 DSPInit();
2338 TOMInit();
2339 JERRYInit();
2340 CDROMInit();
1081a838 2341 m68k_brk_init();
cf76e892
JPM
2342}
2343
2344
2345//New timer based code stuffola...
2346void HalflineCallback(void);
2347void RenderCallback(void);
2348void JaguarReset(void)
2349{
2350 // Only problem with this approach: It wipes out RAM loaded files...!
2351 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
ed31b999
JPM
2352 for (uint32_t i = 8; i < vjs.DRAM_size; i += 4)
2353 {
cf76e892 2354 *((uint32_t *)(&jaguarMainRAM[i])) = rand();
ed31b999 2355 }
cf76e892
JPM
2356
2357 // New timer base code stuffola...
2358 InitializeEventList();
2359//Need to change this so it uses the single RAM space and load the BIOS
2360//into it somewhere...
2361//Also, have to change this here and in JaguarReadXX() currently
2362 // Only use the system BIOS if it's available...! (it's always available now!)
2363 // AND only if a jaguar cartridge has been inserted.
ed31b999 2364#ifndef NEWMODELSBIOSHANDLER
cf76e892 2365 if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine && !vjs.softTypeDebugger)
ed31b999 2366 {
cf76e892 2367 memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
ed31b999
JPM
2368#else
2369 if (vjs.useJaguarBIOS && jaguarCartInserted)
2370 {
2371 SetBIOS();
2372#endif
2373 }
cf76e892 2374 else
ed31b999 2375 {
cf76e892 2376 SET32(jaguarMainRAM, 4, jaguarRunAddress);
ed31b999 2377 }
cf76e892
JPM
2378
2379// WriteLog("jaguar_reset():\n");
2380 TOMReset();
2381 JERRYReset();
2382 GPUReset();
2383 DSPReset();
2384 CDROMReset();
2385 m68k_pulse_reset(); // Reset the 68000
2386 WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
cf76e892
JPM
2387 lowerField = false; // Reset the lower field flag
2388// SetCallbackTime(ScanlineCallback, 63.5555);
2389// SetCallbackTime(ScanlineCallback, 31.77775);
2390 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2391}
2392
2393
2394void JaguarDone(void)
2395{
2396#ifdef CPU_DEBUG_MEMORY
2397/* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n");
2398
2399 for(uint32_t i=0; i<=raPtr; i++)
2400 {
2401 WriteLog("\t%08X\n", returnAddr[i]);
2402 WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16);
2403 jaguar_dasm(returnAddr[i] - 16, 16);
2404 WriteLog("\n");
2405 }
2406 WriteLog("\n");//*/
2407
2408/* int start = 0, end = 0;
2409 bool endTriggered = false, startTriggered = false;
2410 for(int i=0; i<0x400000; i++)
2411 {
2412 if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00)
2413 {
2414 if (!startTriggered)
2415 startTriggered = true, endTriggered = false, start = i;
2416
2417 WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]);
2418 }
2419 else
2420 {
2421 if (!endTriggered)
2422 {
2423 end = i - 1, endTriggered = true, startTriggered = false;
2424 WriteLog("\tMemory range accessed: %06X - %06X\n", start, end);
2425 }
2426 }
2427 }
2428 WriteLog("\n");//*/
2429#endif
2430//#ifdef CPU_DEBUG
2431// for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
2432// WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
2433 int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7);
2434 WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack));
2435#if 0
2436 for(int i=-2; i<9; i++)
2437 WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4)));
2438#else
2439 uint32_t address = topOfStack - (4 * 4 * 3);
2440
2441 for(int i=0; i<10; i++)
2442 {
2443 WriteLog("%06X:", address);
2444
2445 for(int j=0; j<4; j++)
2446 {
2447 WriteLog(" %08X", JaguarReadLong(address));
2448 address += 4;
2449 }
2450
2451 WriteLog("\n");
2452 }
2453#endif
2454
2455/* WriteLog("\nM68000 disassembly at $802288...\n");
2456 jaguar_dasm(0x802288, 3);
2457 WriteLog("\nM68000 disassembly at $802200...\n");
2458 jaguar_dasm(0x802200, 500);
2459 WriteLog("\nM68000 disassembly at $802518...\n");
2460 jaguar_dasm(0x802518, 100);//*/
2461
2462/* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n");
2463 jaguar_dasm(0x803F00, 500);
2464 WriteLog("\n");//*/
2465
2466/* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n");
2467 jaguar_dasm(0x802B00, 500);
2468 WriteLog("\n");//*/
2469
2470/* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n");
2471 jaguar_dasm(0x809900, 500);
2472 WriteLog("\n");//*/
2473//8099F8
2474/* WriteLog("\n\nDump of $8093C8:\n\n");
2475 for(int i=0x8093C8; i<0x809900; i+=4)
2476 WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/
2477/* WriteLog("\n\nM68000 disassembly at $90006C...\n");
2478 jaguar_dasm(0x90006C, 500);
2479 WriteLog("\n");//*/
2480/* WriteLog("\n\nM68000 disassembly at $1AC000...\n");
2481 jaguar_dasm(0x1AC000, 6000);
2482 WriteLog("\n");//*/
2483
2484// WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
2485 WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
2486 WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
2487 && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
2488 M68K_show_context();
2489//#endif
2490
2491 CDROMDone();
2492 GPUDone();
2493 DSPDone();
2494 TOMDone();
2495 JERRYDone();
1081a838 2496 m68k_brk_close();
cf76e892
JPM
2497
2498 // temp, until debugger is in place
2499//00802016: jsr $836F1A.l
2500//0080201C: jsr $836B30.l
2501//00802022: jsr $836B18.l
2502//00802028: jsr $8135F0.l
2503//00813C1E: jsr $813F76.l
2504//00802038: jsr $836D00.l
2505//00802098: jsr $8373A4.l
2506//008020A2: jsr $83E24A.l
2507//008020BA: jsr $83E156.l
2508//008020C6: jsr $83E19C.l
2509//008020E6: jsr $8445E8.l
2510//008020EC: jsr $838C20.l
2511//0080211A: jsr $838ED6.l
2512//00802124: jsr $89CA56.l
2513//0080212A: jsr $802B48.l
2514#if 0
2515 WriteLog("-------------------------------------------\n");
2516 JaguarDasm(0x8445E8, 0x200);
2517 WriteLog("-------------------------------------------\n");
2518 JaguarDasm(0x838C20, 0x200);
2519 WriteLog("-------------------------------------------\n");
2520 JaguarDasm(0x838ED6, 0x200);
2521 WriteLog("-------------------------------------------\n");
2522 JaguarDasm(0x89CA56, 0x200);
2523 WriteLog("-------------------------------------------\n");
2524 JaguarDasm(0x802B48, 0x200);
2525 WriteLog("\n\nM68000 disassembly at $802000...\n");
2526 JaguarDasm(0x802000, 6000);
2527 WriteLog("\n");//*/
2528#endif
2529/* WriteLog("\n\nM68000 disassembly at $6004...\n");
2530 JaguarDasm(0x6004, 10000);
2531 WriteLog("\n");//*/
2532// WriteLog("\n\nM68000 disassembly at $802000...\n");
2533// JaguarDasm(0x802000, 0x1000);
2534// WriteLog("\n\nM68000 disassembly at $4100...\n");
2535// JaguarDasm(0x4100, 200);
2536// WriteLog("\n\nM68000 disassembly at $800800...\n");
2537// JaguarDasm(0x800800, 0x1000);
2538}
2539
2540
2541// Temp debugging stuff
2542
2543void DumpMainMemory(void)
2544{
2545 FILE * fp = fopen("./memdump.bin", "wb");
2546
2547 if (fp == NULL)
2548 return;
2549
2550 fwrite(jaguarMainRAM, 1, vjs.DRAM_size, fp);
2551 fclose(fp);
2552}
2553
2554
2555uint8_t * GetRamPtr(void)
2556{
2557 return jaguarMainRAM;
2558}
2559
2560
2561//
2562// New Jaguar execution stack
2563// This executes 1 frame's worth of code.
2564//
2565bool frameDone;
2566void JaguarExecuteNew(void)
2567{
2568 frameDone = false;
2569
2570 do
2571 {
2572 double timeToNextEvent = GetTimeToNextEvent();
2573//WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
2574
2575 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2576
2577 if (vjs.GPUEnabled)
2578 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
2579
2580 HandleNextEvent();
2581 }
2582 while (!frameDone);
2583}
2584
2585
2586// Step over function
2587void JaguarStepOver(int depth)
2588{
2589 bool exit;
2590 //bool case55 = false;
2591 //uint32_t m68kSR;
2592
2593 if (!depth)
2594 {
2595 exit = true;
2596 }
2597 else
2598 {
2599 exit = false;
2600 }
2601
2602 do
2603 {
2604 JaguarStepInto();
2605
2606 switch (M68KGetCurrentOpcodeFamily())
2607 {
2608 // rts
2609 case 49:
2610 //if (depth)
2611 {
2612 //if (!--depth)
2613 {
2614 exit = true;
2615 }
2616 //exit = false;
2617 }
2618 break;
2619
2620#if 0
2621 // bcc
2622 case 55:
2623 if (!depth)
2624 {
2625 //m68kSR = m68k_get_reg(NULL, M68K_REG_SR);
2626 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x4)
2627 {
2628 exit = true;
2629 }
2630 else
2631 {
2632 exit = false;
2633 }
2634 }
2635 break;
2636#endif
2637
2638 // bsr & jsr
2639 case 54:
2640 case 52:
2641 JaguarStepOver(depth+1);
2642 //if (depth)
2643 //{
2644 // exit = false;
2645 //}
2646 break;
2647
2648 default:
2649 //if (case55)
2650 //{
2651 // exit = true;
2652 //}
2653 break;
2654 }
2655 }
2656 while (!exit);
2657
2658#ifdef _MSC_VER
2659#pragma message("Warning: !!! Need to verify the Jaguar Step Over function !!!")
2660#else
2661 #warning "!!! Need to verify the Jaguar Step Over function !!!"
2662#endif // _MSC_VER
2663}
2664
2665
2666// Step into function
2667void JaguarStepInto(void)
2668{
2669 // double timeToNextEvent = GetTimeToNextEvent();
2670
2671 m68k_execute(USEC_TO_M68K_CYCLES(0));
2672// m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
2673
2674 if (vjs.GPUEnabled)
2675 GPUExec(USEC_TO_RISC_CYCLES(0));
2676
2677// HandleNextEvent();
2678#ifdef _MSC_VER
2679#pragma message("Warning: !!! Need to verify the Jaguar Step Into function !!!")
2680#else
2681#warning "!!! Need to verify the Jaguar Step Into function !!!"
2682#endif // _MSC_VER
2683}
2684
2685
2686//
2687// The thing to keep in mind is that the VC is advanced every HALF line,
2688// regardless of whether the display is interlaced or not. The only difference
2689// with an interlaced display is that the high bit of VC will be set when the
2690// lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
2691// lower field, regardless of whether it's in interlace mode or not.
2692// NB2: Seems it doesn't always, not sure what the constraint is...)
2693//
2694// Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
2695// rendering two fields that are slighty vertically offset from each other.
2696// Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
2697// is rendered in this mode so that each field, when overlaid on each other,
2698// will yield the final picture at the full resolution for the full frame.
2699//
2700// We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
2701// Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
2702// it will be half this number for a half frame. BUT, since we're counting
2703// HALF lines, we double this number and we're back at 525 for NTSC, 625 for
2704// PAL.
2705//
2706// Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
2707// Half line times are, naturally, half of this. :-P
2708//
2709void HalflineCallback(void)
2710{
2711 uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
2712 uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
2713 uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
2714// uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
2715 vc++;
2716
2717 // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
2718 // So we cut the number of half-lines in a frame in half. :-P
2719 uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
2720
2721 if ((vc & 0x7FF) >= numHalfLines)
2722 {
2723 lowerField = !lowerField;
2724 // If we're rendering the lower field, set the high bit (#11, counting
2725 // from 0) of VC
2726 vc = (lowerField ? 0x0800 : 0x0000);
2727 }
2728
2729//WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
2730 TOMWriteWord(0xF00006, vc, JAGUAR);
2731
2732 // Time for Vertical Interrupt?
2733 if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
2734 {
2735 // We don't have to worry about autovectors & whatnot because the Jaguar
2736 // tells you through its HW registers who sent the interrupt...
2737 TOMSetPendingVideoInt();
2738 m68k_set_irq(2);
2739 }
2740
2741 TOMExecHalfline(vc, true);
2742
2743//Change this to VBB???
2744//Doesn't seem to matter (at least for Flip Out & I-War)
2745 if ((vc & 0x7FF) == 0)
2746// if (vc == vbb)
2747 {
2748 JoystickExec();
2749 frameDone = true;
2750 }//*/
2751
2752 SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
2753}
2754