-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
small refactoring, implemented jmp in Tracer.ts
- Loading branch information
Showing
15 changed files
with
316 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import {Addr, Byteable, Endian, MB_8} from "./core.ts"; | ||
|
||
/** | ||
* Contiguous, fixed-sized 0-based Memory with {@link Endian Endianness}. | ||
*/ | ||
interface Memory<T extends Endian> { | ||
|
||
writeable(): boolean; | ||
|
||
executable(): boolean; | ||
|
||
/** | ||
* Read from the offset a 16 bit word in the right {@link Endian Endianness}. | ||
* @param byteOffset | ||
*/ | ||
read16(byteOffset: Addr): number; | ||
|
||
|
||
read8(byteOffset: Addr): number; | ||
|
||
/** | ||
* Gets the {@link Endian endianness}. | ||
*/ | ||
endianness(): T; | ||
|
||
getLength(): number; | ||
|
||
submatch(seq: Uint8Array, atOffset: number): boolean; | ||
|
||
contains(location: Addr): boolean; | ||
} | ||
|
||
/** | ||
* Represents a contiguous, {@link Endian} Memory, backed by an array. | ||
*/ | ||
class ArrayMemory<T extends Endian> implements Memory<T>, Byteable { | ||
/** Arbitrary size, plenty for retro computers. */ | ||
private static MAX: number = MB_8; | ||
private readonly _bytes: number[]; | ||
private readonly endian: T; | ||
private readonly _writeable: boolean; | ||
private readonly _executable: boolean; | ||
|
||
/** | ||
* Construct with an array of values or a desired size. | ||
* | ||
* @param bytes if a size, must be sensible, if an array, we use that. | ||
* @param endian byte order for word interpretation. | ||
* @param writeable whether this memory is marked as writeable by user code (does not imply immutable) | ||
* @param executable whether this memory is marked as executable for user code | ||
*/ | ||
constructor(bytes: number | number[], endian: T, writeable = true, executable = true) { | ||
this._writeable = writeable; | ||
this._executable = executable; | ||
if (typeof bytes === "number") { | ||
if (bytes < 0 || bytes > ArrayMemory.MAX) { | ||
throw Error(`Memory size ${bytes} is not supported`); | ||
} | ||
this._bytes = new Array<number>(bytes); | ||
// arbitrary conspicuous (0b1010 = 0xa = 10) double-endian fill constant to aid debugging | ||
this._bytes.fill(0b1010); | ||
} else { | ||
if (bytes.length > ArrayMemory.MAX) { | ||
throw Error(`Memory size ${bytes.length} is greater than maximum ${ArrayMemory.MAX}`); | ||
} | ||
this._bytes = bytes; | ||
} | ||
this.endian = endian; | ||
} | ||
|
||
static zeroes<T extends Endian>(size: number, endian: T, writeable: boolean, executable: boolean): ArrayMemory<T> { | ||
return new ArrayMemory(Array(size).fill(0), endian, writeable, executable); | ||
} | ||
|
||
executable = (): boolean => this._executable; | ||
|
||
writeable = (): boolean => this._writeable; | ||
|
||
getLength = (): number => this._bytes.length; | ||
|
||
getBytes = () => this._bytes; | ||
|
||
submatch(seq: Uint8Array, atOffset: number): boolean { | ||
if (seq.length + atOffset <= this._bytes.length && seq.length > 0) { | ||
for (let i = 0; i < seq.length; i++) { | ||
if (seq[i] !== this._bytes[i + atOffset]) { | ||
return false; | ||
} | ||
} | ||
// sequence has matched at offset | ||
return true; | ||
} else { | ||
console.log("Sequence length out of range (" + seq.length + ") for memory size " + this._bytes.length); | ||
return false; | ||
} | ||
} | ||
|
||
read16(byteOffset: Addr) { | ||
// last possible word offset must fit word | ||
const lastWordAddress = this._bytes.length - 2; | ||
if (byteOffset < 0 || byteOffset > lastWordAddress) { | ||
throw Error("offset out of range for word read"); | ||
} | ||
return this.endian.twoBytesToWord([this._bytes[byteOffset], this._bytes[byteOffset + 1]]); | ||
} | ||
|
||
read8(byteOffset: Addr): number { | ||
if (!this.contains(byteOffset)) { | ||
throw Error("offset out of range for vector read"); | ||
} | ||
return this._bytes[byteOffset]; | ||
} | ||
|
||
endianness = (): T => this.endian; | ||
|
||
contains = (location: Addr) => location >= 0 && location < this._bytes.length; | ||
|
||
/** | ||
* Loads the given data to the given address. | ||
* @param data | ||
* @param location | ||
*/ | ||
load(data: number[], location: Addr) { | ||
if (data.length + location > this._bytes.length) { | ||
throw Error(`Not enough room to load ${data.length} bytes at ${location}`); | ||
} | ||
data.forEach((b, index) => { | ||
this._bytes[index + location] = b; | ||
}) | ||
} | ||
} | ||
|
||
export {ArrayMemory}; | ||
export {type Memory}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,50 @@ | ||
export enum OpSemantics { | ||
IS_UNCONDITIONAL_JUMP, // will modify PC | ||
IS_CONDITIONAL_JUMP, // may modify PC | ||
IS_BREAK, // legit break | ||
IS_JAM, // illegal break | ||
IS_ILLEGAL, // undocumented but may execute | ||
IS_STORE, // modifies memory | ||
IS_RETURN, // return from subroutine or interrupt | ||
} | ||
|
||
export class Op { | ||
mnemonic: string; | ||
description: string; | ||
/** mnemonic category */ | ||
cat: string; | ||
private readonly _isJump: boolean; | ||
private semantics: OpSemantics[] = []; | ||
|
||
|
||
constructor(mnemonic: string, description: string, cat: string, isJump = false) { | ||
constructor(mnemonic: string, description: string, cat: string, semantics: OpSemantics[] = []) { | ||
this.semantics = semantics; | ||
this.mnemonic = mnemonic; | ||
this.description = description; | ||
this.cat = cat; | ||
this._isJump = isJump; | ||
} | ||
|
||
get isJump(): boolean { | ||
return this._isJump; | ||
/** | ||
* Returns true only if this {@see Op} has the given semantics. | ||
* @param semantics | ||
*/ | ||
has(semantics: OpSemantics): boolean { | ||
return this.semantics.includes(semantics); | ||
} | ||
|
||
/** | ||
* Returns true only if this {@see Op} has all the given semantics. | ||
* @param semantics | ||
*/ | ||
all(semantics: OpSemantics[]): boolean { | ||
return semantics.every(s => this.semantics.includes(s)); | ||
} | ||
|
||
/** | ||
* Returns true only if this {@see Op} has at least one of the given semantics. | ||
* @param semantics | ||
*/ | ||
any(semantics: OpSemantics[]): boolean { | ||
return semantics.some(s => this.semantics.includes(s)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.