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