178 lines
4.8 KiB
JavaScript
178 lines
4.8 KiB
JavaScript
|
// Debug manager for Intelligent Systems binaries
|
||
|
class ISX {
|
||
|
|
||
|
///////////////////////// Initialization Methods //////////////////////////
|
||
|
|
||
|
// Throws on decoding error
|
||
|
constructor(data) {
|
||
|
|
||
|
// Configure instance fields
|
||
|
this.data = data;
|
||
|
this.offset = 0;
|
||
|
this.ranges = [];
|
||
|
this.symbols = [];
|
||
|
this.codes = [];
|
||
|
|
||
|
// Skip any header that may be present
|
||
|
if (data.length >= 32 && this.readInt(3) == 0x585349)
|
||
|
this.offset = 32;
|
||
|
else this.offset = 0;
|
||
|
|
||
|
// Process all records
|
||
|
while (this.offset < this.data.length) {
|
||
|
switch (this.readInt(1)) {
|
||
|
|
||
|
// Virtual Boy records
|
||
|
case 0x11: this.code (); break;
|
||
|
case 0x13: this.range (); break;
|
||
|
case 0x14: this.symbol(); break;
|
||
|
|
||
|
// System records
|
||
|
case 0x20:
|
||
|
case 0x21:
|
||
|
case 0x22:
|
||
|
let length = this.readInt(4);
|
||
|
this.offset += length;
|
||
|
break;
|
||
|
|
||
|
// Other records
|
||
|
default: throw "ISX decode error";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Cleanup instance fields
|
||
|
delete this.data;
|
||
|
delete this.decoder;
|
||
|
delete this.offset;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////// Public Methods //////////////////////////////
|
||
|
|
||
|
// Produce a .vb format ROM file from the ISX code segments
|
||
|
toROM() {
|
||
|
let head = 0x00000000;
|
||
|
let tail = 0x01000000;
|
||
|
|
||
|
// Inspect all code segments
|
||
|
for (let code of this.codes) {
|
||
|
let start = code.address & 0x00FFFFFF;
|
||
|
let end = start + code.data.length;
|
||
|
|
||
|
// Segment begins in the first half of ROM
|
||
|
if (start < 0x00800000) {
|
||
|
|
||
|
// Segment ends in the second half of ROM
|
||
|
if (end > 0x00800000) {
|
||
|
head = tail = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Segment ends in the first half of ROM
|
||
|
else if (end > head)
|
||
|
head = end;
|
||
|
}
|
||
|
|
||
|
// Segment begins in the second half of ROM
|
||
|
else if (start < tail)
|
||
|
tail = start;
|
||
|
}
|
||
|
|
||
|
// Prepare the output buffer
|
||
|
let min = head + 0x01000000 - tail;
|
||
|
let size = 1;
|
||
|
for (; size < min; size <<= 1);
|
||
|
let rom = new Uint8Array(size);
|
||
|
|
||
|
// Output all code segments
|
||
|
for (let code of this.codes) {
|
||
|
let dest = code.address & rom.length - 1;
|
||
|
for (let src = 0; src < code.data.length; src++, dest++)
|
||
|
rom[dest] = code.data[src];
|
||
|
}
|
||
|
|
||
|
return rom;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////// Private Methods /////////////////////////////
|
||
|
|
||
|
// Process a code record
|
||
|
code() {
|
||
|
let address = this.readInt(4);
|
||
|
let length = this.readInt(4);
|
||
|
let data = this.readBytes(length);
|
||
|
if (
|
||
|
length == 0 ||
|
||
|
length > 0x01000000 ||
|
||
|
(address & 0x07000000) != 0x07000000 ||
|
||
|
(address & 0x07000000) + length > 0x08000000
|
||
|
) throw "ISX decode error";
|
||
|
this.codes.push({
|
||
|
address: address,
|
||
|
data : data
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Process a range record
|
||
|
range() {
|
||
|
let count = this.readInt(2);
|
||
|
while (count--) {
|
||
|
let start = this.readInt(4);
|
||
|
let end = this.readInt(4);
|
||
|
let type = this.readInt(1);
|
||
|
this.ranges.push({
|
||
|
end : end,
|
||
|
start: start,
|
||
|
type : type
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Process a symbol record
|
||
|
symbol() {
|
||
|
let count = this.readInt(2);
|
||
|
while (count--) {
|
||
|
let length = this.readInt(1);
|
||
|
let name = this.readString(length);
|
||
|
let flags = this.readInt(2);
|
||
|
let address = this.readInt(4);
|
||
|
this.symbols.push({
|
||
|
address: address,
|
||
|
flags : flags,
|
||
|
name : name
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read a byte buffer
|
||
|
readBytes(size) {
|
||
|
if (this.offset + size > this.data.length)
|
||
|
throw "ISX decode error";
|
||
|
let ret = this.data.slice(this.offset, this.offset + size);
|
||
|
this.offset += size;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
// Read an integer
|
||
|
readInt(size) {
|
||
|
if (this.offset + size > this.data.length)
|
||
|
throw "ISX decode error";
|
||
|
let ret = new Uint32Array(1);
|
||
|
for (let shift = 0; size > 0; size--, shift += 8)
|
||
|
ret[0] |= this.data[this.offset++] << shift;
|
||
|
return ret[0];
|
||
|
}
|
||
|
|
||
|
// Read a text string
|
||
|
readString(size) {
|
||
|
return (this.decoder = this.decoder || new TextDecoder()
|
||
|
).decode(this.readBytes(size));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
export { ISX };
|