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
11 //
12 // WHO  WHEN        WHAT
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  11/25/2009  Major rewrite of memory subsystem and handlers
15 //
16 #include <string.h>
17 #include <stdlib.h>
18 
19 #include <time.h>
20 
21 #include "jaguar.h"
22 
23 #include "cdrom.h"
24 #include "dsp.h"
25 #include "eeprom.h"
26 #include "event.h"
27 #include "gpu.h"
28 #include "jerry.h"
29 #include "joystick.h"
30 #include "log.h"
31 #include "m68000/m68kinterface.h"
32 #include "memtrack.h"
33 #include "mmu.h"
34 #include "settings.h"
35 #include "tom.h"
36 
37 bool frameDone;
38 uint32_t starCount;
39 
40 #define ALPINE_FUNCTIONS
41 
42 // Private function prototypes
43 
jaguar_unknown_readbyte(unsigned address,uint32_t who)44 unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who)
45 {
46    return 0xFF;
47 }
48 
jaguar_unknown_readword(unsigned address,uint32_t who)49 unsigned jaguar_unknown_readword(unsigned address, uint32_t who)
50 {
51    return 0xFFFF;
52 }
53 
54 // Unknown read/write byte/word routines
55 
56 // It's hard to believe that developers would be sloppy with their memory writes, yet in
57 // some cases the developers screwed up royal. E.g., Club Drive has the following code:
58 //
59 // 807EC4: movea.l #$f1b000, A1
60 // 807ECA: movea.l #$8129e0, A0
61 // 807ED0: move.l  A0, D0
62 // 807ED2: move.l  #$f1bb94, D1
63 // 807ED8: sub.l   D0, D1
64 // 807EDA: lsr.l   #2, D1
65 // 807EDC: move.l  (A0)+, (A1)+
66 // 807EDE: dbra    D1, 807edc
67 //
68 // The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
69 // in. This mistake causes it to try and overwrite approximately $700000 worth of address
70 // space! (That is, unless the 68K causes a bus error...)
71 
jaguar_unknown_writebyte(unsigned address,unsigned data,uint32_t who)72 void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who)
73 {
74 }
75 
jaguar_unknown_writeword(unsigned address,unsigned data,uint32_t who)76 void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who)
77 {
78 }
79 
JaguarGetHandler(uint32_t i)80 uint32_t JaguarGetHandler(uint32_t i)
81 {
82    return JaguarReadLong(i * 4, UNKNOWN);
83 }
84 
85 
JaguarInterruptHandlerIsValid(uint32_t i)86 bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
87 {
88    uint32_t handler = JaguarGetHandler(i);
89    return (handler && (handler != 0xFFFFFFFF) ? true : false);
90 }
91 
M68K_show_context(void)92 void M68K_show_context(void)
93 {
94    unsigned i;
95 
96    WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
97 
98    for(i=M68K_REG_D0; i<=M68K_REG_D7; i++)
99    {
100       WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
101 
102       if (i == M68K_REG_D3 || i == M68K_REG_D7)
103          WriteLog("\n");
104    }
105 
106    for(i=M68K_REG_A0; i<=M68K_REG_A7; i++)
107    {
108       WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
109 
110       if (i == M68K_REG_A3 || i == M68K_REG_A7)
111          WriteLog("\n");
112    }
113 
114    WriteLog("68K disasm\n");
115    JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200);
116 
117    if (TOMIRQEnabled(IRQ_VIDEO))
118    {
119       WriteLog("video int: enabled\n");
120       JaguarDasm(JaguarGetHandler(64), 0x200);
121    }
122    else
123       WriteLog("video int: disabled\n");
124 
125    WriteLog("..................\n");
126 
127    for(i=0; i<256; i++)
128    {
129       uint32_t address;
130 
131       WriteLog("handler %03i at ", i);
132       address = (uint32_t)JaguarGetHandler(i);
133 
134       if (address == 0)
135          WriteLog(".........\n");
136       else
137          WriteLog("$%08X\n", address);
138    }
139 }
140 
141 // External variables
142 
143 // Really, need to include memory.h for this, but it might interfere with some stuff...
144 extern uint8_t jagMemSpace[];
145 
146 // Internal variables
147 
148 uint32_t jaguar_active_memory_dumps = 0;
149 
150 uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
151 
152 bool jaguarCartInserted = false;
153 bool lowerField = false;
154 
155 
156 uint32_t pcQueue[0x400];
157 uint32_t a0Queue[0x400];
158 uint32_t a1Queue[0x400];
159 uint32_t a2Queue[0x400];
160 uint32_t a3Queue[0x400];
161 uint32_t a4Queue[0x400];
162 uint32_t a5Queue[0x400];
163 uint32_t a6Queue[0x400];
164 uint32_t a7Queue[0x400];
165 uint32_t d0Queue[0x400];
166 uint32_t d1Queue[0x400];
167 uint32_t d2Queue[0x400];
168 uint32_t d3Queue[0x400];
169 uint32_t d4Queue[0x400];
170 uint32_t d5Queue[0x400];
171 uint32_t d6Queue[0x400];
172 uint32_t d7Queue[0x400];
173 uint32_t pcQPtr = 0;
174 bool startM68KTracing = false;
175 
176 // Breakpoint on memory access vars (exported)
177 bool bpmActive = false;
178 uint32_t bpmAddress1;
179 
180 
181 /* Callback function to detect illegal instructions */
182 static bool start = false;
183 
M68KInstructionHook(void)184 void M68KInstructionHook(void)
185 {
186    unsigned i;
187    uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
188 
189    // For tracebacks...
190    // Ideally, we'd save all the registers as well...
191    pcQueue[pcQPtr] = m68kPC;
192    a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
193    a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
194    a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
195    a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
196    a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
197    a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
198    a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
199    a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
200    d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
201    d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
202    d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
203    d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
204    d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
205    d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
206    d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
207    d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
208    pcQPtr++;
209    pcQPtr &= 0x3FF;
210 
211    if (m68kPC & 0x01)		// Oops! We're fetching an odd address!
212    {
213       static char buffer[2048];
214       WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
215 
216       for(i=0; i<0x400; i++)
217       {
218          //			WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
219          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]\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]);
220          m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
221          WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
222       }
223       WriteLog("\n");
224 
225       M68K_show_context();
226       LogDone();
227       exit(0);
228    }
229 }
230 
ShowM68KContext(void)231 void ShowM68KContext(void)
232 {
233    unsigned i;
234    uint32_t currpc;
235    uint32_t disPC;
236    char buffer[128];
237 
238    printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
239 
240    for(i=M68K_REG_D0; i<=M68K_REG_D7; i++)
241    {
242       printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
243 
244       if (i == M68K_REG_D3 || i == M68K_REG_D7)
245          printf("\n");
246    }
247 
248    for(i=M68K_REG_A0; i<=M68K_REG_A7; i++)
249    {
250       printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
251 
252       if (i == M68K_REG_A3 || i == M68K_REG_A7)
253          printf("\n");
254    }
255 
256    currpc = m68k_get_reg(NULL, M68K_REG_PC);
257    disPC  = currpc - 30;
258 
259    do
260    {
261       uint32_t oldpc = disPC;
262       disPC += m68k_disassemble(buffer, disPC, 0);
263       printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
264    }
265    while (disPC < (currpc + 10));
266 }
267 
268 
269 /* Custom UAE 68000 read/write/IRQ functions */
270 
irq_ack_handler(int level)271 int irq_ack_handler(int level)
272 {
273    // Tracing the IPL lines on the Jaguar schematic yields the following:
274    // IPL1 is connected to INTL on TOM (OUT to 68K)
275    // IPL0-2 are also tied to Vcc via 4.7K resistors!
276    // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
277    // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
278    // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
279 
280    // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
281    // They aren't, and this causes problems with a, err, specific ROM. :-D
282 
283    if (level == 2)
284    {
285       m68k_set_irq(0);						// Clear the IRQ (NOTE: Without this, the BIOS fails)...
286       return 64;								// Set user interrupt #0
287    }
288 
289    return M68K_INT_ACK_AUTOVECTOR;
290 }
291 
292 
293 //#define USE_NEW_MMU
294 
m68k_read_memory_8(unsigned int address)295 unsigned int m68k_read_memory_8(unsigned int address)
296 {
297 #ifdef ALPINE_FUNCTIONS
298    // Check if breakpoint on memory is active, and deal with it
299    if (bpmActive && address == bpmAddress1)
300       M68KDebugHalt();
301 #endif
302 
303    // Musashi does this automagically for you, UAE core does not :-P
304    address &= 0x00FFFFFF;
305 #ifndef USE_NEW_MMU
306    // Note that the Jaguar only has 2M of RAM, not 4!
307    if ((address >= 0x000000) && (address <= 0x1FFFFF))
308       return jaguarMainRAM[address];
309    else if ((address >= 0x800000) && (address <= 0xDFFEFF))
310       return jaguarMainROM[address - 0x800000];
311    else if ((address >= 0xE00000) && (address <= 0xE3FFFF))
312       return jagMemSpace[address];
313    else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
314       return CDROMReadByte(address, UNKNOWN);
315    else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
316       return TOMReadByte(address, M68K);
317    else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
318       return JERRYReadByte(address, M68K);
319    else
320       return jaguar_unknown_readbyte(address, M68K);
321 
322    return 0;
323 #else
324    return MMURead8(address, M68K);
325 #endif
326 }
327 
328 
329 void gpu_dump_disassembly(void);
330 void gpu_dump_registers(void);
331 
m68k_read_memory_16(unsigned int address)332 unsigned int m68k_read_memory_16(unsigned int address)
333 {
334 #ifdef ALPINE_FUNCTIONS
335    // Check if breakpoint on memory is active, and deal with it
336    if (bpmActive && address == bpmAddress1)
337       M68KDebugHalt();
338 #endif
339 
340    // Musashi does this automagically for you, UAE core does not :-P
341    address &= 0x00FFFFFF;
342 
343 #ifndef USE_NEW_MMU
344    // Note that the Jaguar only has 2M of RAM, not 4!
345    if ((address >= 0x000000) && (address <= 0x1FFFFE))
346       return GET16(jaguarMainRAM, address);
347    else if ((address >= 0x800000) && (address <= 0xDFFEFE))
348    {
349       /* Memory Track reading... */
350       if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
351          return MTReadWord(address);
352       else
353          return (jaguarMainROM[address - 0x800000] << 8)
354             | jaguarMainROM[address - 0x800000 + 1];
355    }
356    else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
357       return (jagMemSpace[address] << 8) | jagMemSpace[address + 1];
358    else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
359       return CDROMReadWord(address, M68K);
360    else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
361       return TOMReadWord(address, M68K);
362    else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
363       return JERRYReadWord(address, M68K);
364 
365    return jaguar_unknown_readword(address, M68K);
366 #else
367    return MMURead16(address, M68K);
368 #endif
369 }
370 
371 
m68k_read_memory_32(unsigned int address)372 unsigned int m68k_read_memory_32(unsigned int address)
373 {
374 #ifdef ALPINE_FUNCTIONS
375    // Check if breakpoint on memory is active, and deal with it
376    if (bpmActive && address == bpmAddress1)
377       M68KDebugHalt();
378 #endif
379 
380    // Musashi does this automagically for you, UAE core does not :-P
381    address &= 0x00FFFFFF;
382 
383 #ifndef USE_NEW_MMU
384    if ((address >= 0x800000) && (address <= 0xDFFEFE))
385    {
386       // Memory Track reading...
387       if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
388          return MTReadLong(address);
389 
390       return GET32(jaguarMainROM, address - 0x800000);
391    }
392 
393    return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
394 #else
395    return MMURead32(address, M68K);
396 #endif
397 }
398 
399 
m68k_write_memory_8(unsigned int address,unsigned int value)400 void m68k_write_memory_8(unsigned int address, unsigned int value)
401 {
402 #ifdef ALPINE_FUNCTIONS
403    // Check if breakpoint on memory is active, and deal with it
404    if (bpmActive && address == bpmAddress1)
405       M68KDebugHalt();
406 #endif
407 
408    // Musashi does this automagically for you, UAE core does not :-P
409    address &= 0x00FFFFFF;
410 
411 #ifndef USE_NEW_MMU
412    // Note that the Jaguar only has 2M of RAM, not 4!
413    if ((address >= 0x000000) && (address <= 0x1FFFFF))
414       jaguarMainRAM[address] = value;
415    else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
416       CDROMWriteByte(address, value, M68K);
417    else if ((address >= 0xF00000) && (address <= 0xF0FFFF))
418       TOMWriteByte(address, value, M68K);
419    else if ((address >= 0xF10000) && (address <= 0xF1FFFF))
420       JERRYWriteByte(address, value, M68K);
421    else
422       jaguar_unknown_writebyte(address, value, M68K);
423 #else
424    MMUWrite8(address, value, M68K);
425 #endif
426 }
427 
428 
m68k_write_memory_16(unsigned int address,unsigned int value)429 void m68k_write_memory_16(unsigned int address, unsigned int value)
430 {
431 #ifdef ALPINE_FUNCTIONS
432    // Check if breakpoint on memory is active, and deal with it
433    if (bpmActive && address == bpmAddress1)
434       M68KDebugHalt();
435 #endif
436 
437    // Musashi does this automagically for you, UAE core does not :-P
438    address &= 0x00FFFFFF;
439 
440 #ifndef USE_NEW_MMU
441    // Note that the Jaguar only has 2M of RAM, not 4!
442    if ((address >= 0x000000) && (address <= 0x1FFFFE))
443    {
444       SET16(jaguarMainRAM, address, value);
445    }
446    /* Memory Track device writes.... */
447    else if ((address >= 0x800000) && (address <= 0x87FFFE))
448    {
449       if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
450          MTWriteWord(address, value);
451    }
452    else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
453       CDROMWriteWord(address, value, M68K);
454    else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
455       TOMWriteWord(address, value, M68K);
456    else if ((address >= 0xF10000) && (address <= 0xF1FFFE))
457       JERRYWriteWord(address, value, M68K);
458    else
459    {
460       jaguar_unknown_writeword(address, value, M68K);
461    }
462 #else
463    MMUWrite16(address, value, M68K);
464 #endif
465 }
466 
467 
m68k_write_memory_32(unsigned int address,unsigned int value)468 void m68k_write_memory_32(unsigned int address, unsigned int value)
469 {
470 #ifdef ALPINE_FUNCTIONS
471    // Check if breakpoint on memory is active, and deal with it
472    if (bpmActive && address == bpmAddress1)
473       M68KDebugHalt();
474 #endif
475 
476    // Musashi does this automagically for you, UAE core does not :-P
477    address &= 0x00FFFFFF;
478 
479 #ifndef USE_NEW_MMU
480    m68k_write_memory_16(address, value >> 16);
481    m68k_write_memory_16(address + 2, value & 0xFFFF);
482 #else
483    MMUWrite32(address, value, M68K);
484 #endif
485 }
486 
487 /* Disassemble M68K instructions at the given offset */
488 
m68k_read_disassembler_8(unsigned int address)489 unsigned int m68k_read_disassembler_8(unsigned int address)
490 {
491    return m68k_read_memory_8(address);
492 }
493 
494 
m68k_read_disassembler_16(unsigned int address)495 unsigned int m68k_read_disassembler_16(unsigned int address)
496 {
497    return m68k_read_memory_16(address);
498 }
499 
500 
m68k_read_disassembler_32(unsigned int address)501 unsigned int m68k_read_disassembler_32(unsigned int address)
502 {
503    return m68k_read_memory_32(address);
504 }
505 
JaguarDasm(uint32_t offset,uint32_t qt)506 void JaguarDasm(uint32_t offset, uint32_t qt)
507 {
508 }
509 
JaguarReadByte(uint32_t offset,uint32_t who)510 uint8_t JaguarReadByte(uint32_t offset, uint32_t who)
511 {
512    offset &= 0xFFFFFF;
513 
514    // First 2M is mirrored in the $0 - $7FFFFF range
515    if (offset < 0x800000)
516       return jaguarMainRAM[offset & 0x1FFFFF];
517    else if ((offset >= 0x800000) && (offset < 0xDFFF00))
518       return jaguarMainROM[offset - 0x800000];
519    else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
520       return CDROMReadByte(offset, who);
521    else if ((offset >= 0xE00000) && (offset < 0xE40000))
522       return jagMemSpace[offset];
523    else if ((offset >= 0xF00000) && (offset < 0xF10000))
524       return TOMReadByte(offset, who);
525    else if ((offset >= 0xF10000) && (offset < 0xF20000))
526       return JERRYReadByte(offset, who);
527    else
528       return jaguar_unknown_readbyte(offset, who);
529 
530    return 0x00;
531 }
532 
JaguarReadWord(uint32_t offset,uint32_t who)533 uint16_t JaguarReadWord(uint32_t offset, uint32_t who)
534 {
535    offset &= 0xFFFFFF;
536 
537    // First 2M is mirrored in the $0 - $7FFFFF range
538    if (offset < 0x800000)
539       return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
540    else if ((offset >= 0x800000) && (offset < 0xDFFF00))
541    {
542       offset -= 0x800000;
543       return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1];
544    }
545    //	else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00))
546    else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE))
547       return CDROMReadWord(offset, who);
548    else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE))
549       return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1];
550    else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE))
551       return TOMReadWord(offset, who);
552    else if ((offset >= 0xF10000) && (offset <= 0xF1FFFE))
553       return JERRYReadWord(offset, who);
554 
555    return jaguar_unknown_readword(offset, who);
556 }
557 
558 
JaguarWriteByte(uint32_t offset,uint8_t data,uint32_t who)559 void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who)
560 {
561    offset &= 0xFFFFFF;
562 
563    // First 2M is mirrored in the $0 - $7FFFFF range
564    if (offset < 0x800000)
565    {
566       jaguarMainRAM[offset & 0x1FFFFF] = data;
567       return;
568    }
569    else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
570    {
571       CDROMWriteByte(offset, data, who);
572       return;
573    }
574    else if ((offset >= 0xF00000) && (offset <= 0xF0FFFF))
575    {
576       TOMWriteByte(offset, data, who);
577       return;
578    }
579    else if ((offset >= 0xF10000) && (offset <= 0xF1FFFF))
580    {
581       JERRYWriteByte(offset, data, who);
582       return;
583    }
584 
585    jaguar_unknown_writebyte(offset, data, who);
586 }
587 
588 
JaguarWriteWord(uint32_t offset,uint16_t data,uint32_t who)589 void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who)
590 {
591    offset &= 0xFFFFFF;
592 
593    // First 2M is mirrored in the $0 - $7FFFFF range
594    if (offset <= 0x7FFFFE)
595    {
596       jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
597       jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
598       return;
599    }
600    else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
601    {
602       CDROMWriteWord(offset, data, who);
603       return;
604    }
605    else if (offset >= 0xF00000 && offset <= 0xF0FFFE)
606    {
607       TOMWriteWord(offset, data, who);
608       return;
609    }
610    else if (offset >= 0xF10000 && offset <= 0xF1FFFE)
611    {
612       JERRYWriteWord(offset, data, who);
613       return;
614    }
615    // Don't bomb on attempts to write to ROM
616    else if (offset >= 0x800000 && offset <= 0xEFFFFF)
617       return;
618 
619    jaguar_unknown_writeword(offset, data, who);
620 }
621 
622 
623 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
JaguarReadLong(uint32_t offset,uint32_t who)624 uint32_t JaguarReadLong(uint32_t offset, uint32_t who)
625 {
626    return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
627 }
628 
629 
630 // We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
JaguarWriteLong(uint32_t offset,uint32_t data,uint32_t who)631 void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who)
632 {
633    JaguarWriteWord(offset, data >> 16, who);
634    JaguarWriteWord(offset+2, data & 0xFFFF, who);
635 }
636 
637 
JaguarSetScreenBuffer(uint32_t * buffer)638 void JaguarSetScreenBuffer(uint32_t * buffer)
639 {
640    // This is in TOM, but we set it here...
641    screenBuffer = buffer;
642 }
643 
644 
JaguarSetScreenPitch(uint32_t pitch)645 void JaguarSetScreenPitch(uint32_t pitch)
646 {
647    // This is in TOM, but we set it here...
648    screenPitch = pitch;
649 }
650 
651 /* Jaguar console initialization */
JaguarInit(void)652 void JaguarInit(void)
653 {
654    unsigned i;
655    // For randomizing RAM
656    srand(time(NULL));
657 
658    // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
659    for(i=0; i<0x200000; i+=4)
660       *((uint32_t *)(&jaguarMainRAM[i])) = rand();
661 
662    lowerField = false;							// Reset the lower field flag
663    memset(jaguarMainRAM + 0x804, 0xFF, 4);
664 
665    m68k_pulse_reset();							// Need to do this so UAE disasm doesn't segfault on exit
666    GPUInit();
667    DSPInit();
668    TOMInit();
669    JERRYInit();
670    CDROMInit();
671 
672 }
673 
674 /* New timer based code stuffola... */
675 
676 // The thing to keep in mind is that the VC is advanced every HALF line, regardless
677 // of whether the display is interlaced or not. The only difference with an
678 // interlaced display is that the high bit of VC will be set when the lower
679 // field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
680 // regardless of whether it's in interlace mode or not.
681 // NB2: Seems it doens't always, not sure what the constraint is...)
682 //
683 // Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
684 // rendering two fields that are slighty vertically offset from each other.
685 // Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
686 // is rendered in this mode so that each field, when overlaid on each other,
687 // will yield the final picture at the full resolution for the full frame.
688 //
689 // We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
690 // Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
691 // it will be half this number for a half frame. BUT, since we're counting
692 // HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
693 //
694 // Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
695 // Half line times are, naturally, half of this. :-P
HalflineCallback(void)696 void HalflineCallback(void)
697 {
698    uint16_t numHalfLines;
699    uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
700    uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
701    uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
702    vc++;
703 
704    // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
705    // So we cut the number of half-lines in a frame in half. :-P
706    numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
707 
708    if ((vc & 0x7FF) >= numHalfLines)
709    {
710       lowerField = !lowerField;
711       // If we're rendering the lower field, set the high bit (#11, counting
712       // from 0) of VC
713       vc = (lowerField ? 0x0800 : 0x0000);
714    }
715 
716    //WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
717    TOMWriteWord(0xF00006, vc, JAGUAR);
718 
719    // Time for Vertical Interrupt?
720    if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
721    {
722       // We don't have to worry about autovectors & whatnot because the Jaguar
723       // tells you through its HW registers who sent the interrupt...
724       TOMSetPendingVideoInt();
725       m68k_set_irq(2);
726    }
727 
728    TOMExecHalfline(vc, true);
729 
730    //Change this to VBB???
731    //Doesn't seem to matter (at least for Flip Out & I-War)
732    if ((vc & 0x7FF) == 0)
733    {
734       JoystickExec();
735       frameDone = true;
736    }
737 
738    SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0), EVENT_MAIN);
739 }
740 
JaguarReset(void)741 void JaguarReset(void)
742 {
743    unsigned i;
744 
745    // Only problem with this approach: It wipes out RAM loaded files...!
746    // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
747    for(i=8; i<0x200000; i+=4)
748       *((uint32_t *)(&jaguarMainRAM[i])) = rand();
749 
750    // New timer base code stuffola...
751    InitializeEventList();
752    //Need to change this so it uses the single RAM space and load the BIOS
753    //into it somewhere...
754    //Also, have to change this here and in JaguarReadXX() currently
755    // Only use the system BIOS if it's available...! (it's always available now!)
756    // AND only if a jaguar cartridge has been inserted.
757    if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine)
758       memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8);
759    else
760       SET32(jaguarMainRAM, 4, jaguarRunAddress);
761 
762    //	WriteLog("jaguar_reset():\n");
763    TOMReset();
764    JERRYReset();
765    GPUReset();
766    DSPReset();
767    CDROMReset();
768    m68k_pulse_reset();								// Reset the 68000
769    WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
770 
771    lowerField = false;								// Reset the lower field flag
772    SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0), EVENT_MAIN);
773 }
774 
775 
JaguarDone(void)776 void JaguarDone(void)
777 {
778    WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
779    WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO))
780             && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
781    M68K_show_context();
782 
783    CDROMDone();
784    GPUDone();
785    DSPDone();
786    TOMDone();
787    JERRYDone();
788 }
789 
GetRamPtr(void)790 uint8_t * GetRamPtr(void)
791 {
792    return jaguarMainRAM;
793 }
794 
795 
796 /* New Jaguar execution stack
797  * This executes 1 frame's worth of code. */
JaguarExecuteNew(void)798 void JaguarExecuteNew(void)
799 {
800    frameDone = false;
801 
802    do
803    {
804       double timeToNextEvent = GetTimeToNextEvent(EVENT_MAIN);
805       m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
806       GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
807       HandleNextEvent(EVENT_MAIN);
808    } while(!frameDone);
809 }
810