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