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