Add native Crystal exploration port and reference tooling
Checks / web (push) Canceled after 0s

This commit is contained in:
Sébastien QUEROL committed 2026-09-23 09:23:29 +02:00
1 parent 2127f5f459
commit 8b80d05ca2
56 files changed
+6910 -1

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
/** Bounds-checked access to the user's cartridge. No CPU or hardware state. */
export class RomReader {
constructor(readonly bytes: Uint8Array) {}
byte(offset: number): number {
this.check(offset, 1);
return this.bytes[offset];
}
word(offset: number): number {
return this.byte(offset) | (this.byte(offset + 1) << 8);
}
slice(offset: number, length: number): Uint8Array {
this.check(offset, length);
return this.bytes.slice(offset, offset + length);
}
address(bank: number, address: number): number {
if (
!Number.isInteger(bank) ||
bank < 0 ||
bank >= this.bytes.length / 0x4000 ||
!Number.isInteger(address) ||
address < 0 ||
address >= 0x8000
) {
throw new Error("Invalid ROM bank or address.");
}
const offset =
address < 0x4000 ? address : bank * 0x4000 + address - 0x4000;
this.check(offset, 1);
return offset;
}
near(pointer: number, bank: number): number {
return this.address(bank, this.word(pointer));
}
far(pointer: number): number {
return this.near(pointer + 1, this.byte(pointer));
}
bank(offset: number): number {
this.check(offset, 1);
return Math.floor(offset / 0x4000);
}
private check(offset: number, length: number) {
if (
!Number.isInteger(offset) ||
!Number.isInteger(length) ||
offset < 0 ||
length < 0 ||
offset + length > this.bytes.length
) {
throw new Error(
"Cartridge data is truncated or contains an invalid pointer.",
);
}
}
}