// 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 };