Include missing ISX decover
This commit is contained in:
parent
4f0b889b74
commit
c62dd833a3
|
@ -0,0 +1,297 @@
|
|||
/* This file is included into vbu.c and cannot be compiled on its own. */
|
||||
#ifdef VBUAPI
|
||||
|
||||
|
||||
|
||||
/********************************* Constants *********************************/
|
||||
|
||||
/* Range types */
|
||||
/*
|
||||
0x41 ('A') 8-bit integer (.db), string
|
||||
0x42 ('B') 8-bit integer (.db), numeric
|
||||
0x43 ('C') Compiled C code
|
||||
0x44 ('D') 16-bit integer (.dd, high byte first)
|
||||
0x45 ('E') 65C816 code (8-bit accumulator, 8-bit index)
|
||||
0x46 ('F') 65C816 code (8-bit accumulator, 16-bit index)
|
||||
0x47 ('G') 65C816 code (16-bit accumulator, 8-bit index)
|
||||
0x48 ('H') 65C816 code (16-bit accumulator, 16-bit index)
|
||||
0x4C ('L') 32-bit integer (.dl SNES, .dw Virtual Boy, low byte first)
|
||||
0x53 ('S') Size reservation, as in .bss allocation (.ds)
|
||||
0x57 ('W') 16-bit integer (.dw SNES, .dh Virtual Boy, low byte first)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
|
||||
/* Skip ISX record type 0x01 */
|
||||
static size_t isx01(uint8_t *bytes, size_t length, size_t src) {
|
||||
/*
|
||||
u8 Type =0x01
|
||||
u8 Bank Cartridge bank number
|
||||
u8 BankHigh Only if Bank >= 0x80
|
||||
u16 Address CPU bus address
|
||||
u16 DataLength Number of bytes in Data
|
||||
u8[] Data Code bytes
|
||||
*/
|
||||
|
||||
/* Bank field is not present */
|
||||
if (src + 2 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Advance to DataLength field */
|
||||
src += bytes[src + 1] >= 0x80 ? 5 : 4;
|
||||
|
||||
/* DataLength field is not present */
|
||||
if (src + 2 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Advance past Data field */
|
||||
return src + 2 + ((uint16_t) bytes[src + 1] << 8 | bytes[src]);
|
||||
}
|
||||
|
||||
/* Decode ISX record type 0x11 */
|
||||
static size_t isx11(uint8_t *bytes, size_t length, size_t src,
|
||||
uint32_t *address, uint32_t *size) {
|
||||
/*
|
||||
u8 Type =0x11
|
||||
u32 Address CPU bus address
|
||||
u32 DataLength Number of bytes in Data
|
||||
u8[] Data Code bytes
|
||||
*/
|
||||
|
||||
/* DataLength field is not present */
|
||||
if (src + 9 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Parse Address and DataLength fields */
|
||||
*address = (uint32_t) bytes[src+4] << 24 | (uint32_t) bytes[src+3] << 16 |
|
||||
(uint32_t) bytes[src+2] << 8 | bytes[src+1];
|
||||
*size = (uint32_t) bytes[src+8] << 24 | (uint32_t) bytes[src+7] << 16 |
|
||||
(uint32_t) bytes[src+6] << 8 | bytes[src+5];
|
||||
|
||||
/* Advance past Data field */
|
||||
return src + 9 + *size;
|
||||
}
|
||||
|
||||
/* Skip ISX range records */
|
||||
static size_t isxRange(uint8_t *bytes,size_t length,size_t src,size_t size) {
|
||||
/*
|
||||
u8 Type =0x03 (SNES) or 0x13 (Virtual Boy)
|
||||
u16 Count Number of ranges
|
||||
Range[] Ranges
|
||||
=== SNES fields ===
|
||||
u8 Bank Cartridge bank number
|
||||
u16 StartAddress Lowest CPU bus address
|
||||
u16 EndAddress Highest CPU bus address
|
||||
u8 RangeType See range types
|
||||
=== Virtual Boy fields ===
|
||||
u32 StartAddress Lowest CPU bus address
|
||||
u32 EndAddress Highest CPU bus address
|
||||
u8 RangeType See range types
|
||||
*/
|
||||
|
||||
/* Count field is not present */
|
||||
if (src + 3 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Advance past Ranges field */
|
||||
return src + 3 + size * ((uint16_t) bytes[src + 2] << 8 | bytes[src + 1]);
|
||||
}
|
||||
|
||||
/* Skip ISX symbol record */
|
||||
static size_t isxSymbol(uint8_t *bytes,size_t length,size_t src,size_t size) {
|
||||
size_t count; /* Number of symbols */
|
||||
size_t x; /* Iterator */
|
||||
|
||||
/*
|
||||
u8 Type =0x04 (SNES) or 0x14 (Virtual Boy)
|
||||
u16 Count Number of symbols
|
||||
Symbol[] Symbols
|
||||
u8 NameLength Number of bytes in Name
|
||||
u8[] Name Symbol name
|
||||
=== SNES fields ===
|
||||
u8 Flags Undocumented
|
||||
u8 Bank Cartridge bank number
|
||||
u16 Address CPU bus address
|
||||
=== Virtual Boy fields ===
|
||||
u16 Flags Undocumented
|
||||
u32 Address CPU bus address
|
||||
*/
|
||||
|
||||
/* Count field is not present */
|
||||
if (src + 3 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Working variables */
|
||||
count = (uint16_t) bytes[src + 2] << 8 | bytes[src + 1];
|
||||
src += 3;
|
||||
|
||||
/* Process all symbols */
|
||||
for (x = 0; x < count; x++) {
|
||||
|
||||
/* NameLength field is not present */
|
||||
if (src > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Advance past remainder of symbol */
|
||||
src += size + bytes[src];
|
||||
|
||||
/* Remainder of symbol is not present */
|
||||
if (src > length)
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
/* Skip ISX system record */
|
||||
static size_t isxSystem(uint8_t *bytes, size_t length, size_t src) {
|
||||
/*
|
||||
u8 Type =0x20, 0x21 or 0x22
|
||||
u32 DataLength Number of bytes in Data
|
||||
u8[] Data Record data
|
||||
*/
|
||||
|
||||
/* DataLength field is not present */
|
||||
if (src + 5 > length)
|
||||
return (size_t) -1;
|
||||
|
||||
/* Advance past Data field */
|
||||
return src + 5 + (
|
||||
(uint32_t) bytes[src + 4] << 24 | (uint32_t) bytes[src + 3] << 16 |
|
||||
(uint32_t) bytes[src + 2] << 8 | bytes[src + 1]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Decode an ISX debugger file to a Virtual Boy ROM */
|
||||
static void* isxFrom(uint8_t *bytes, size_t length, size_t *romLength) {
|
||||
uint32_t addr; /* Code record base address */
|
||||
uint32_t highMin; /* Lowest address in upper half of ROM */
|
||||
uint32_t lowMax; /* Highest address in lower half of ROM */
|
||||
uint8_t *rom; /* Output ROM */
|
||||
uint32_t size; /* Code record size in bytes */
|
||||
size_t src; /* Input position */
|
||||
size_t start; /* Offset of first record */
|
||||
|
||||
/* Error checking */
|
||||
if (length < 3)
|
||||
return NULL;
|
||||
|
||||
/* Working variables */
|
||||
highMin = 0xFFFFFF;
|
||||
lowMax = 0x000000;
|
||||
size = 0;
|
||||
start = strncmp((char *) bytes, "ISX", 3) ? 0 : 32;
|
||||
|
||||
/* First pass: determine the size of the ROM */
|
||||
for (src = start; src < length;) {
|
||||
switch (bytes[src]) {
|
||||
|
||||
case 0x11: /* Code (Virtual Boy) */
|
||||
|
||||
/* Decode record fields */
|
||||
src = isx11(bytes, length, src, &addr, &size);
|
||||
if (src > length)
|
||||
return NULL;
|
||||
|
||||
/* Validate address and data size */
|
||||
addr &= 0x07FFFFFF;
|
||||
if (
|
||||
addr < 0x07000000 ||
|
||||
0x08000000 - addr < size
|
||||
) return NULL;
|
||||
addr &= 0x00FFFFFF;
|
||||
|
||||
/* Requires 16 MiB */
|
||||
if (addr < 0x800000 && addr + size > 0x800000) {
|
||||
highMin = 0x800000;
|
||||
lowMax = 0x7FFFFF;
|
||||
}
|
||||
|
||||
/* Map from top of ROM space */
|
||||
else if (addr & 0x800000) {
|
||||
if (addr < highMin)
|
||||
highMin = addr;
|
||||
}
|
||||
|
||||
/* Map from bottom of ROM space */
|
||||
else {
|
||||
addr += size - 1;
|
||||
if (addr > lowMax)
|
||||
lowMax = addr;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x01: /* Code (SNES) */
|
||||
src = isx01 (bytes, length, src ); break;
|
||||
case 0x03: /* Range (SNES) */
|
||||
src = isxRange (bytes, length, src, 6); break;
|
||||
case 0x04: /* Symbol (SNES) */
|
||||
src = isxSymbol(bytes, length, src, 5); break;
|
||||
case 0x13: /* Range (Virtual Boy) */
|
||||
src = isxRange (bytes, length, src, 9); break;
|
||||
case 0x14: /* Symbol (Virtual Boy) */
|
||||
src = isxSymbol(bytes, length, src, 7); break;
|
||||
case 0x20: /* System (undocumented) */
|
||||
case 0x21: /* System (undocumented) */
|
||||
case 0x22: /* System (undocumented) */
|
||||
src = isxSystem(bytes, length, src ); break;
|
||||
default: /* Invalid record type */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Record contains invalid data */
|
||||
if (src > length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Produce a ROM buffer of minimal size to fit all the code records */
|
||||
for (
|
||||
src = 1;
|
||||
src < lowMax + 0x1000001 - highMin;
|
||||
src <<= 1
|
||||
);
|
||||
rom = VBU_REALLOC(NULL, src);
|
||||
if (rom == NULL)
|
||||
return NULL;
|
||||
*romLength = src;
|
||||
memset(rom, 0x00, src);
|
||||
|
||||
/* Second pass: fill the ROM buffer with the code records */
|
||||
for (src = start; src < length;) {
|
||||
switch (bytes[src]) {
|
||||
|
||||
case 0x11: /* Code (Virtual Boy) */
|
||||
src = isx11(bytes, length, src, &addr, &size);
|
||||
memcpy(&rom[addr & (*romLength-1)], &bytes[src - size], size);
|
||||
break;
|
||||
|
||||
case 0x01: /* Code (SNES) */
|
||||
src = isx01 (bytes, length, src ); break;
|
||||
case 0x03: /* Range (SNES) */
|
||||
src = isxRange (bytes, length, src, 9); break;
|
||||
case 0x04: /* Symbol (SNES) */
|
||||
src = isxSymbol(bytes, length, src, 5); break;
|
||||
case 0x13: /* Range (Virtual Boy) */
|
||||
src = isxRange (bytes, length, src, 12); break;
|
||||
case 0x14: /* Symbol (Virtual Boy) */
|
||||
src = isxSymbol(bytes, length, src, 7); break;
|
||||
case 0x20: /* System (undocumented) */
|
||||
case 0x21: /* System (undocumented) */
|
||||
case 0x22: /* System (undocumented) */
|
||||
src = isxSystem(bytes, length, src ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* VBUAPI */
|
Loading…
Reference in New Issue