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