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