]> Shamusworld >> Repos - virtualjaguar/blob - src/file.cpp
Added missing headers for win32, code cleanup for file detection code.
[virtualjaguar] / src / file.cpp
1 //
2 // FILE.CPP
3 //
4 // File support
5 // by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  01/16/2010  Created this log ;-)
13 // JLH  02/28/2010  Added functions to look inside .ZIP files and handle contents
14 //
15
16 #include "file.h"
17
18 #include <stdarg.h>
19 #include <string.h>
20 #include "crc32.h"
21 #include "eeprom.h"
22 #include "jaguar.h"
23 #include "log.h"
24 #include "memory.h"
25 #include "universalhdr.h"
26 #include "unzip.h"
27 #include "zlib.h"
28
29 // Private function prototypes
30
31 static int gzfilelength(gzFile gd);
32 static bool CheckExtension(const char * filename, const char * ext);
33 //static int ParseFileType(uint8 header1, uint8 header2, uint32 size);
34
35 // Private variables/enums
36
37
38 //
39 // Generic ROM loading
40 //
41 uint32 JaguarLoadROM(uint8 * rom, char * path)
42 {
43 // We really should have some kind of sanity checking for the ROM size here to prevent
44 // a buffer overflow... !!! FIX !!!
45 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
46         uint32 romSize = 0;
47
48         WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
49         char * ext = strrchr(path, '.');
50
51         // No filename extension == YUO FAIL IT (it is loading the file).
52         // This is naive, but it works. But should probably come up with something a little
53         // more robust, to prevent problems with dopes trying to exploit this.
54         if (ext == NULL)
55         {
56                 WriteLog("FAILED!\n");
57                 return 0;
58         }
59
60         WriteLog("Succeeded in finding extension (%s)!\n", ext);
61         WriteLog("VJ: Loading \"%s\"...", path);
62
63         if (strcasecmp(ext, ".zip") == 0)
64         {
65                 // Handle ZIP file loading here...
66                 WriteLog("(ZIPped)...");
67
68                 uint8_t * buffer = NULL;
69                 romSize = GetFileFromZIP(path, FT_SOFTWARE, buffer);
70
71                 if (romSize == 0)
72                 {
73                         WriteLog("Failed!\n");
74                         return 0;
75                 }
76
77                 memcpy(rom, buffer, romSize);
78                 delete[] buffer;
79         }
80         else
81         {
82                 // Handle gzipped files transparently [Adam Green]...
83
84                 gzFile fp = gzopen(path, "rb");
85
86                 if (fp == NULL)
87                 {
88                         WriteLog("Failed!\n");
89                         return 0;
90                 }
91
92                 romSize = gzfilelength(fp);
93                 gzseek(fp, 0, SEEK_SET);
94                 gzread(fp, rom, romSize);
95                 gzclose(fp);
96         }
97
98         WriteLog("OK (%i bytes)\n", romSize);
99
100         return romSize;
101 }
102
103 //
104 // Jaguar file loading
105 //
106 bool JaguarLoadFileOld(char * path)
107 {
108         jaguarROMSize = JaguarLoadROM(jaguarMainROM, path);
109
110         if (jaguarROMSize == 0)
111         {
112 //                      WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
113                 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
114 #warning "!!! Need error dialog here !!!"
115 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
116 //              log_done();
117 //              exit(0);
118                 return false;                                                           // This is a start...
119         }
120
121         jaguarMainROMCRC32 = crc32_calcCheckSum(jaguarMainROM, jaguarROMSize);
122         WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32);
123         EepromInit();
124
125         jaguarRunAddress = 0x802000;
126
127         char * ext = strrchr(path, '.');                                // Get the file's extension for non-cartridge checking
128
129 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
130 #warning "!!! Need more robust file type checking in JaguarLoadROM() !!!"
131         if (strcasecmp(ext, ".rom") == 0)
132         {
133                 // File extension ".ROM": Alpine image that loads/runs at $802000
134                 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarROMSize);
135
136                 for(int i=jaguarROMSize-1; i>=0; i--)
137                         jaguarMainROM[0x2000 + i] = jaguarMainROM[i];
138
139                 memset(jaguarMainROM, 0xFF, 0x2000);
140 /*              memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
141                 memset(jaguar_mainRom, 0xFF, 0x600000);
142                 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
143                 memset(jaguar_mainRam, 0x00, 0x400000);*/
144
145 /*
146 Stubulator ROM vectors...
147 handler 001 at $00E00008
148 handler 002 at $00E008DE
149 handler 003 at $00E008E2
150 handler 004 at $00E008E6
151 handler 005 at $00E008EA
152 handler 006 at $00E008EE
153 handler 007 at $00E008F2
154 handler 008 at $00E0054A
155 handler 009 at $00E008FA
156 handler 010 at $00000000
157 handler 011 at $00000000
158 handler 012 at $00E008FE
159 handler 013 at $00E00902
160 handler 014 at $00E00906
161 handler 015 at $00E0090A
162 handler 016 at $00E0090E
163 handler 017 at $00E00912
164 handler 018 at $00E00916
165 handler 019 at $00E0091A
166 handler 020 at $00E0091E
167 handler 021 at $00E00922
168 handler 022 at $00E00926
169 handler 023 at $00E0092A
170 handler 024 at $00E0092E
171 handler 025 at $00E0107A
172 handler 026 at $00E0107A
173 handler 027 at $00E0107A
174 handler 028 at $00E008DA
175 handler 029 at $00E0107A
176 handler 030 at $00E0107A
177 handler 031 at $00E0107A
178 handler 032 at $00000000
179
180 Let's try setting up the illegal instruction vector for a stubulated jaguar...
181 */
182 /*              SET32(jaguar_mainRam, 0x08, 0x00E008DE);
183                 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
184                 SET32(jaguar_mainRam, 0x10, 0x00E008E6);        // <-- Should be here (it is)...
185                 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
186
187                 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
188                 // This kludge works! Yeah!
189                 SET32(jaguarMainRAM, 0x10, 0x00001000);
190                 SET16(jaguarMainRAM, 0x1000, 0x60FE);           // Here: bra Here
191         }
192         else if (strcasecmp(ext, ".abs") == 0)
193         {
194                 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
195
196 /*
197 ABS Format sleuthing (LBUGDEMO.ABS):
198
199 000000  60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
200 000010  12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
201 000020  00 00 40 00
202
203 DRI-format file detected...
204 Text segment size = 0x0000050c bytes
205 Data segment size = 0x000462c0 bytes
206 BSS Segment size = 0x00000428 bytes
207 Symbol Table size = 0x000012a6 bytes
208 Absolute Address for text segment = 0x00802000
209 Absolute Address for data segment = 0x0080250c
210 Absolute Address for BSS segment = 0x00004000
211
212 (CRZDEMO.ABS):
213 000000  01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
214 000010  00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
215 000020  00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
216
217 000030  2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
218 000040  00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
219 000050  00 00 00 00 00 00 00 20
220 000058  2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
221 000068  00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
222 000078  00 00 00 00 00 00 00 40
223 000080  2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
224 000090  00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
225 0000a0  00 00 00 00 00 00 00 80
226
227 Header size is $A8 bytes...
228
229 BSD/COFF format file detected...
230 3 sections specified
231 Symbol Table offset = 230160                            ($00038310)
232 Symbol Table contains 1339 symbol entries       ($0000053B)
233 The additional header size is 28 bytes          ($001C)
234 Magic Number for RUN_HDR = 0x00000107
235 Text Segment Size = 7632                                        ($00001DD0)
236 Data Segment Size = 222360                                      ($00036498)
237 BSS Segment Size = 428928                                       ($00068B80)
238 Starting Address for executable = 0x00802000
239 Start of Text Segment = 0x00802000
240 Start of Data Segment = 0x00803dd0
241 */
242                 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1B)
243                 {
244                         uint32 loadAddress = GET32(jaguarMainROM, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
245                                 codeSize = GET32(jaguarMainROM, 0x02) + GET32(jaguarMainROM, 0x06);
246                         WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
247
248                         if (loadAddress < 0x800000)
249                                 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x24, codeSize);
250                         else
251                         {
252                                 for(int i=codeSize-1; i>=0; i--)
253                                         jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0x24];
254 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
255                                 memset(jaguar_mainRom, 0xFF, 0x600000);
256                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
257                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
258                         }
259
260                         jaguarRunAddress = loadAddress;
261                 }
262                 else if (jaguarMainROM[0] == 0x01 && jaguarMainROM[1] == 0x50)
263                 {
264                         uint32 loadAddress = GET32(jaguarMainROM, 0x28), runAddress = GET32(jaguarMainROM, 0x24),
265                                 codeSize = GET32(jaguarMainROM, 0x18) + GET32(jaguarMainROM, 0x1C);
266                         WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
267
268                         if (loadAddress < 0x800000)
269                                 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0xA8, codeSize);
270                         else
271                         {
272                                 for(int i=codeSize-1; i>=0; i--)
273                                         jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0xA8];
274 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
275                                 memset(jaguar_mainRom, 0xFF, 0x600000);
276                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
277                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
278                         }
279
280                         jaguarRunAddress = runAddress;
281                 }
282                 else
283                 {
284                         WriteLog("GUI: Couldn't find correct ABS/COF format: %02X %02X\n", jaguarMainROM[0], jaguarMainROM[1]);
285                         return false;
286                 }
287         }
288         else if (strcasecmp(ext, ".jag") == 0)
289         {
290                 // File extension ".JAG": Atari server file with header
291 //NOTE: The bytes 'JAGR' should also be at position $1C...
292 //      Also, there's *always* a $601A header at position $00...
293                 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1A)
294                 {
295                         uint32 loadAddress = GET32(jaguarMainROM, 0x22), runAddress = GET32(jaguarMainROM, 0x2A);
296 //This is not always right! Especially when converted via bin2jag1!!!
297 //We should have access to the length of the furshlumiger file that was loaded anyway!
298 //Now, we do! ;-)
299 //                      uint32 progLength = GET32(jaguar_mainRom, 0x02);
300 //jaguarRomSize
301 //jaguarRunAddress
302 //                      WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
303 //                      memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
304                         WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarROMSize - 0x2E);
305                         memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x2E, jaguarROMSize - 0x2E);
306 //              SET32(jaguar_mainRam, 4, runAddress);
307                         jaguarRunAddress = runAddress;
308                 }
309                 else
310                         return false;
311         }
312         // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
313
314         return true;
315 }
316
317 //
318 // Jaguar file loading (second stab at it...)
319 // We do a more intelligent file analysis here instead of relying on (possible false)
320 // file extensions which people don't seem to give two shits about anyway. :-(
321 //
322 bool JaguarLoadFile(char * path)
323 {
324 // NOTE: We can further clean this up by fixing JaguarLoadROM to load to a buffer
325 //       instead of assuming it goes into our ROM space.
326         jaguarROMSize = JaguarLoadROM(jaguarMainROM, path);
327
328         if (jaguarROMSize == 0)
329         {
330 //                      WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
331                 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
332 #warning "!!! Need error dialog here !!!"
333 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
334                 return false;                                                           // This is a start...
335         }
336
337         jaguarMainROMCRC32 = crc32_calcCheckSum(jaguarMainROM, jaguarROMSize);
338         WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32);
339 // TODO: Check for EEPROM file in ZIP file. If there is no EEPROM in the user's EEPROM
340 //       directory, copy the one from the ZIP file, if it exists.
341         EepromInit();
342         jaguarRunAddress = 0x802000;                                    // For non-BIOS runs, this is true
343         int fileType = ParseFileType(jaguarMainROM[0], jaguarMainROM[1], jaguarROMSize);
344
345         if (fileType == JST_ROM)
346                 return true;
347         else if (fileType == JST_ALPINE)
348         {
349                 // File extension ".ROM": Alpine image that loads/runs at $802000
350                 WriteLog("GUI: Setting up Alpine ROM... Run address: 00802000, length: %08X\n", jaguarROMSize);
351
352                 for(int i=jaguarROMSize-1; i>=0; i--)
353                         jaguarMainROM[0x2000 + i] = jaguarMainROM[i];
354
355                 memset(jaguarMainROM, 0xFF, 0x2000);
356
357 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
358                 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
359                 // This kludge works! Yeah!
360                 SET32(jaguarMainRAM, 0x10, 0x00001000);
361                 SET16(jaguarMainRAM, 0x1000, 0x60FE);           // Here: bra Here
362                 return true;
363         }
364         else if (fileType == JST_ABS_TYPE1)
365         {
366                 uint32 loadAddress = GET32(jaguarMainROM, 0x16),
367                         codeSize = GET32(jaguarMainROM, 0x02) + GET32(jaguarMainROM, 0x06);
368                 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
369
370                 if (loadAddress < 0x800000)
371                         memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x24, codeSize);
372                 else
373                 {
374                         for(int i=codeSize-1; i>=0; i--)
375                                 jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0x24];
376                 }
377
378                 jaguarRunAddress = loadAddress;
379                 return true;
380         }
381         else if (fileType == JST_ABS_TYPE2)
382         {
383                 uint32 loadAddress = GET32(jaguarMainROM, 0x28), runAddress = GET32(jaguarMainROM, 0x24),
384                         codeSize = GET32(jaguarMainROM, 0x18) + GET32(jaguarMainROM, 0x1C);
385                 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
386
387                 if (loadAddress < 0x800000)
388                         memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0xA8, codeSize);
389                 else
390                 {
391                         for(int i=codeSize-1; i>=0; i--)
392                                 jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0xA8];
393                 }
394
395                 jaguarRunAddress = runAddress;
396                 return true;
397         }
398         else if (fileType == JST_JAGSERVER)
399         {
400                 uint32 loadAddress = GET32(jaguarMainROM, 0x22), runAddress = GET32(jaguarMainROM, 0x2A);
401                 WriteLog("GUI: Setting up homebrew (Jag Server)... Run address: %08X, length: %08X\n", runAddress, jaguarROMSize - 0x2E);
402                 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x2E, jaguarROMSize - 0x2E);
403                 jaguarRunAddress = runAddress;
404                 return true;
405         }
406
407         // We can assume we have JST_NONE at this point. :-P
408         // TODO: Add a dialog box that tells the user that they're trying to feed VJ a bogus file.
409         return false;
410 }
411
412 //
413 // Get the length of a (possibly) gzipped file
414 //
415 static int gzfilelength(gzFile gd)
416 {
417    int size = 0, length = 0;
418    unsigned char buffer[0x10000];
419
420    gzrewind(gd);
421
422    do
423    {
424       // Read in chunks until EOF
425       size = gzread(gd, buffer, 0x10000);
426
427       if (size <= 0)
428         break;
429
430       length += size;
431    }
432    while (!gzeof(gd));
433
434    gzrewind(gd);
435    return length;
436 }
437
438 //
439 // Compare extension to passed in filename. If equal, return true; otherwise false.
440 //
441 static bool CheckExtension(const char * filename, const char * ext)
442 {
443         const char * filenameExt = strrchr(filename, '.');      // Get the file's extension (if any)
444         return (strcasecmp(filenameExt, ext) == 0 ? true : false);
445 }
446
447 //
448 // Get file from .ZIP
449 // Returns the size of the file inside the .ZIP file that we're looking at
450 // NOTE: If the thing we're looking for is found, it allocates it in the passed in buffer.
451 //       Which means we have to deallocate it later.
452 //
453 uint32 GetFileFromZIP(const char * zipFile, FileType type, uint8 * &buffer)
454 {
455 // NOTE: We could easily check for this by discarding anything that's larger than the RAM/ROM
456 //       size of the Jaguar console.
457 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
458         const char ftStrings[5][32] = { "Software", "EEPROM", "Label", "Box Art", "Controller Overlay" };
459         ZIP * zip = openzip(0, 0, zipFile);
460
461         if (zip == NULL)
462         {
463                 WriteLog("FILE: Could not open file '%s'!\n", zipFile);
464                 return 0;
465         }
466
467         zipent * ze;
468         bool found = false;
469
470         // The order is here is important: If the file is found, we need to short-circuit the
471         // readzip() call because otherwise, 'ze' will be pointing to the wrong file!
472         while (!found && readzip(zip))
473         {
474                 ze = &zip->ent;
475
476                 // Here we simply rely on the file extension to tell the truth, but we know
477                 // that extensions lie like sons-a-bitches. So this is naive, we need to do
478                 // something a little more robust to keep bad things from happening here.
479 #warning "!!! Checking for image by extension can be fooled !!!"
480                 if ((type == FT_LABEL) && (CheckExtension(ze->name, ".png") || CheckExtension(ze->name, ".jpg") || CheckExtension(ze->name, ".gif")))
481                 {
482                         found = true;
483                         WriteLog("FILE: Found image file '%s'.\n", ze->name);
484                 }
485
486                 if ((type == FT_SOFTWARE) && (CheckExtension(ze->name, ".j64") || CheckExtension(ze->name, ".rom") || CheckExtension(ze->name, ".abs") || CheckExtension(ze->name, ".cof")))
487                 {
488                         found = true;
489                         WriteLog("FILE: Found software file '%s'.\n", ze->name);
490                 }
491
492                 if ((type == FT_EEPROM) && (CheckExtension(ze->name, ".eep") || CheckExtension(ze->name, ".eeprom")))
493                 {
494                         found = true;
495                         WriteLog("FILE: Found EEPROM file '%s'.\n", ze->name);
496                 }
497         }
498
499         uint32 fileSize = 0;
500
501         if (found)
502         {
503                 WriteLog("FILE: Uncompressing...");
504 // Insert file size sanity check here...
505                 buffer = new uint8[ze->uncompressed_size];
506
507                 if (readuncompresszip(zip, ze, (char *)buffer) == 0)
508                 {
509                         fileSize = ze->uncompressed_size;
510                         WriteLog("success! (%u bytes)\n", fileSize);
511                 }
512                 else
513                 {
514                         delete[] buffer;
515                         buffer = NULL;
516                         WriteLog("FAILED!\n");
517                 }
518         }
519         else
520                 // Didn't find what we're looking for...
521                 WriteLog("FILE: Failed to find file of type %s...\n", ftStrings[type]);
522
523         closezip(zip);
524         return fileSize;
525 }
526
527 //
528 // Parse the file type based upon file size and/or headers.
529 //
530 uint32 ParseFileType(uint8 header1, uint8 header2, uint32 size)
531 {
532         // If the file size is divisible by 1M, we probably have an regular ROM.
533         // We can also check our CRC32 against the internal ROM database to be sure.
534         if ((size % 1048576) == 0)
535                 return JST_ROM;
536
537         // If the file size + 8192 bytes is divisible by 1M, we probably have an
538         // Alpine format ROM.
539         if (((size + 8192) % 1048576) == 0)
540                 return JST_ALPINE;
541
542         // So much for low hanging fruit. Now try some other types.
543
544         // ABS/COFF type 1
545         if (header1 == 0x60 && header2 == 0x1B)
546                 return JST_ABS_TYPE1;
547
548         // ABS/COFF type 2
549         if (header1 == 0x01 && header2 == 0x50)
550                 return JST_ABS_TYPE2;
551
552         // Jag Server
553         if (header1 == 0x60 && header2 == 0x1A)
554                 return JST_JAGSERVER;
555
556         // Headerless crap
557         return JST_NONE;
558 }
559
560 //
561 // Check for universal header
562 //
563 bool HasUniversalHeader(uint8 * rom, uint32 romSize)
564 {
565         // Sanity check
566         if (romSize < 8192)
567                 return false;
568
569         for(int i=0; i<8192; i++)
570                 if (rom[i] != universalCartHeader[i])
571                         return false;
572
573         return true;
574 }
575
576 #if 0
577 // Misc. doco
578
579 /*
580 Stubulator ROM vectors...
581 handler 001 at $00E00008
582 handler 002 at $00E008DE
583 handler 003 at $00E008E2
584 handler 004 at $00E008E6
585 handler 005 at $00E008EA
586 handler 006 at $00E008EE
587 handler 007 at $00E008F2
588 handler 008 at $00E0054A
589 handler 009 at $00E008FA
590 handler 010 at $00000000
591 handler 011 at $00000000
592 handler 012 at $00E008FE
593 handler 013 at $00E00902
594 handler 014 at $00E00906
595 handler 015 at $00E0090A
596 handler 016 at $00E0090E
597 handler 017 at $00E00912
598 handler 018 at $00E00916
599 handler 019 at $00E0091A
600 handler 020 at $00E0091E
601 handler 021 at $00E00922
602 handler 022 at $00E00926
603 handler 023 at $00E0092A
604 handler 024 at $00E0092E
605 handler 025 at $00E0107A
606 handler 026 at $00E0107A
607 handler 027 at $00E0107A
608 handler 028 at $00E008DA
609 handler 029 at $00E0107A
610 handler 030 at $00E0107A
611 handler 031 at $00E0107A
612 handler 032 at $00000000
613
614 Let's try setting up the illegal instruction vector for a stubulated jaguar...
615
616                 SET32(jaguar_mainRam, 0x08, 0x00E008DE);
617                 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
618                 SET32(jaguar_mainRam, 0x10, 0x00E008E6);        // <-- Should be here (it is)...
619                 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
620
621 /*
622 ABS Format sleuthing (LBUGDEMO.ABS):
623
624 000000  60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
625 000010  12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
626 000020  00 00 40 00
627
628 DRI-format file detected...
629 Text segment size = 0x0000050c bytes
630 Data segment size = 0x000462c0 bytes
631 BSS Segment size = 0x00000428 bytes
632 Symbol Table size = 0x000012a6 bytes
633 Absolute Address for text segment = 0x00802000
634 Absolute Address for data segment = 0x0080250c
635 Absolute Address for BSS segment = 0x00004000
636
637 (CRZDEMO.ABS):
638 000000  01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
639 000010  00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
640 000020  00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
641
642 000030  2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
643 000040  00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
644 000050  00 00 00 00 00 00 00 20
645 000058  2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
646 000068  00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
647 000078  00 00 00 00 00 00 00 40
648 000080  2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
649 000090  00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
650 0000a0  00 00 00 00 00 00 00 80
651
652 Header size is $A8 bytes...
653
654 BSD/COFF format file detected...
655 3 sections specified
656 Symbol Table offset = 230160                            ($00038310)
657 Symbol Table contains 1339 symbol entries       ($0000053B)
658 The additional header size is 28 bytes          ($001C)
659 Magic Number for RUN_HDR = 0x00000107
660 Text Segment Size = 7632                                        ($00001DD0)
661 Data Segment Size = 222360                                      ($00036498)
662 BSS Segment Size = 428928                                       ($00068B80)
663 Starting Address for executable = 0x00802000
664 Start of Text Segment = 0x00802000
665 Start of Data Segment = 0x00803dd0
666 */
667 #endif