Likely overzealous numeric type enforcement.
This commit is contained in:
parent
e7cb198123
commit
0764614b66
5
TODO
5
TODO
|
@ -1,5 +1,4 @@
|
||||||
Add screen (VRAM?)
|
Add screen (VRAM?)
|
||||||
|
- Bank switching
|
||||||
Live memory and register editing (Probably should pause autostep when it reaches the cell you're modifying)
|
Live memory and register editing (Probably should pause autostep when it reaches the cell you're modifying)
|
||||||
Draw lines between registers and memory when used
|
HCF flames
|
||||||
|
|
||||||
Save binary button
|
|
|
@ -22,6 +22,7 @@
|
||||||
<button type="button" id="step_button">Step</button>
|
<button type="button" id="step_button">Step</button>
|
||||||
<label for="binary_upload" class="button">Load Binary</label>
|
<label for="binary_upload" class="button">Load Binary</label>
|
||||||
<input id="binary_upload" name="binary_upload" id="binary_upload" style="display: none" type="file" />
|
<input id="binary_upload" name="binary_upload" id="binary_upload" style="display: none" type="file" />
|
||||||
|
<button type="button" id="save_button">Save</button>
|
||||||
<input type="range" name="" id="delay_range" min="0" max="1500" />
|
<input type="range" name="" id="delay_range" min="0" max="1500" />
|
||||||
</div>
|
</div>
|
||||||
<span id="cycles"></span>
|
<span id="cycles"></span>
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
||||||
import { byte_array_to_js_source, format_hex, u8 } from "./etc";
|
import { byte_array_to_js_source, format_hex } from "./etc";
|
||||||
import { EventHandler } from "./eventHandler";
|
import { EventHandler } from "./eventHandler";
|
||||||
import { Instruction, ISA } from "./instructionSet";
|
import { Instruction, ISA } from "./instructionSet";
|
||||||
|
import { m256, u8 } from "./num";
|
||||||
|
|
||||||
export type TempInstrState = {
|
export type TempInstrState = {
|
||||||
pos: u8;
|
pos: u8;
|
||||||
params_found: number;
|
params_found: number;
|
||||||
instr: Instruction;
|
instr: Instruction;
|
||||||
params: Uint8Array;
|
params: Array<u8>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Computer {
|
export class Computer {
|
||||||
private memory = new Uint8Array(256);
|
private memory = new Array<u8>(256);
|
||||||
private registers = new Uint8Array(8);
|
private registers = new Array<u8>(256);
|
||||||
private call_stack: Array<u8> = [];
|
private call_stack: Array<u8> = [];
|
||||||
private program_counter: u8 = 0;
|
private program_counter: u8 = 0;
|
||||||
|
private bank: u8 = 0;
|
||||||
private current_instr: TempInstrState | null = null;
|
private current_instr: TempInstrState | null = null;
|
||||||
events: CpuEventHandler = new EventHandler<CpuEvent>() as CpuEventHandler;
|
events: CpuEventHandler = new EventHandler<CpuEvent>() as CpuEventHandler;
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ export class Computer {
|
||||||
pos: this.program_counter,
|
pos: this.program_counter,
|
||||||
instr: parsed_instruction,
|
instr: parsed_instruction,
|
||||||
params_found: 0,
|
params_found: 0,
|
||||||
params: new Uint8Array(parsed_instruction.params.length),
|
params: new Array<u8>(parsed_instruction.params.length),
|
||||||
};
|
};
|
||||||
this.events.dispatch(CpuEvent.InstructionParsed, {
|
this.events.dispatch(CpuEvent.InstructionParsed, {
|
||||||
pos: this.program_counter,
|
pos: this.program_counter,
|
||||||
|
@ -126,10 +128,14 @@ export class Computer {
|
||||||
return this.call_stack.pop() ?? null;
|
return this.call_stack.pop() ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBank(bank_no: u8): void {
|
||||||
|
this.bank = bank_no;
|
||||||
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
this.events.dispatch(CpuEvent.Reset, null);
|
this.events.dispatch(CpuEvent.Reset, null);
|
||||||
this.memory = new Uint8Array(256);
|
this.memory = new Array<u8>(256);
|
||||||
this.registers = new Uint8Array(8);
|
this.registers = new Array<u8>(8);
|
||||||
this.call_stack = [];
|
this.call_stack = [];
|
||||||
this.current_instr = null;
|
this.current_instr = null;
|
||||||
this.program_counter = 0;
|
this.program_counter = 0;
|
||||||
|
@ -144,19 +150,23 @@ export class Computer {
|
||||||
|
|
||||||
load_memory(program: Array<u8>): void {
|
load_memory(program: Array<u8>): void {
|
||||||
console.log(byte_array_to_js_source(program));
|
console.log(byte_array_to_js_source(program));
|
||||||
const max_loop = Math.min(this.memory.length, program.length);
|
const max_loop: u8 = Math.min(255, program.length) as u8;
|
||||||
for (let i = 0; i < max_loop; i++) {
|
for (let i: u8 = 0; i < 255; i++) {
|
||||||
// Don't fire event if no change is made
|
// Don't fire event if no change is made
|
||||||
if (this.memory[i] === program[i]) continue;
|
if (this.memory[i] === program[i]) continue;
|
||||||
|
|
||||||
this.memory[i] = program[i];
|
this.memory[i] = program[i];
|
||||||
this.events.dispatch(CpuEvent.MemoryChanged, { address: i, value: program[i] });
|
this.events.dispatch(CpuEvent.MemoryChanged, { address: i as u8, value: program[i] });
|
||||||
}
|
}
|
||||||
this.program_counter = 0;
|
this.program_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dump_memory(): Array<u8> {
|
||||||
|
return this.memory;
|
||||||
|
}
|
||||||
|
|
||||||
private step_forward(): void {
|
private step_forward(): void {
|
||||||
this.program_counter = (this.program_counter + 1) % 256;
|
this.program_counter = m256(this.program_counter + 1);
|
||||||
this.events.dispatch(CpuEvent.ProgramCounterChanged, { counter: this.program_counter });
|
this.events.dispatch(CpuEvent.ProgramCounterChanged, { counter: this.program_counter });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { UiEventHandler } from "./events";
|
import { u8 } from "./num";
|
||||||
|
|
||||||
// The u8 type represents an unsigned 8bit integer: byte. It does not add any safety, other than as a hint to the programmer.
|
// The u8 type represents an unsigned 8bit integer: byte. It does not add any safety, other than as a hint to the programmer.
|
||||||
// export type u8 = 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255;
|
|
||||||
export type u8 = number;
|
// export type u8 = number;
|
||||||
|
|
||||||
// Jquery lite
|
// Jquery lite
|
||||||
export const $ = (s: string): HTMLElement => document.getElementById(s) as HTMLElement;
|
export const $ = (s: string): HTMLElement => document.getElementById(s) as HTMLElement;
|
||||||
|
|
||||||
export const format_hex = (n: number): string => n.toString(16).toUpperCase().padStart(2, "0");
|
export const format_hex = (n: u8): string => n.toString(16).toUpperCase().padStart(2, "0");
|
||||||
|
|
||||||
export const byte_array_to_js_source = (a: Array<u8>): string => {
|
export const byte_array_to_js_source = (a: Array<u8>): string => {
|
||||||
let str = "[";
|
let str = "[";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { u8 } from "./etc";
|
|
||||||
import { EventHandler } from "./eventHandler";
|
import { EventHandler } from "./eventHandler";
|
||||||
import { Instruction, ParameterType } from "./instructionSet";
|
import { Instruction, ParameterType } from "./instructionSet";
|
||||||
|
import { u8 } from "./num.js";
|
||||||
|
|
||||||
export enum CpuEvent {
|
export enum CpuEvent {
|
||||||
MemoryChanged,
|
MemoryChanged,
|
||||||
|
|
54
src/index.ts
54
src/index.ts
|
@ -3,29 +3,13 @@ import { $ } from "./etc";
|
||||||
import { ISA } from "./instructionSet";
|
import { ISA } from "./instructionSet";
|
||||||
import { generate_isa } from "./isaGenerator";
|
import { generate_isa } from "./isaGenerator";
|
||||||
import { UI } from "./ui";
|
import { UI } from "./ui";
|
||||||
|
import { u8 } from "./num";
|
||||||
|
|
||||||
import "./style.scss";
|
import "./style.scss";
|
||||||
|
|
||||||
function main(): void {
|
function main(): void {
|
||||||
// const program = [
|
const program: Array<u8> = [
|
||||||
// 0x2f, 0x00, 0xf0, 0x20, 0x07, 0x00, 0x50, 0x05, 0x06, 0x07, 0x11, 0x00, 0x05, 0xfe, 0x07, 0x30, 0x00, 0x10, 0x03,
|
0x2f, 0x00, 0xf0, 0x20, 0x07, 0x00, 0x50, 0x05, 0x06, 0x07, 0x11, 0x00, 0x05, 0xfe, 0x07, 0x30, 0x00, 0x10, 0x03,
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
|
|
||||||
// 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x00, 0x00, 0x00,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const program = [
|
|
||||||
0x01, 0x00, 0x01, 0x00, 0xa0, 0x10, 0xff, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xa1,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
@ -41,6 +25,23 @@ function main(): void {
|
||||||
0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x00, 0x00, 0x00,
|
0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x00, 0x00, 0x00,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// const program = [
|
||||||
|
// 0x01, 0x00, 0x01, 0x00, 0xa0, 0x10, 0xff, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xa1,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
|
||||||
|
// 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x00, 0x00, 0x00,
|
||||||
|
// ];
|
||||||
|
|
||||||
const computer = new Computer();
|
const computer = new Computer();
|
||||||
|
|
||||||
const ui = new UI();
|
const ui = new UI();
|
||||||
|
@ -68,7 +69,7 @@ function main(): void {
|
||||||
const data = e.target.result;
|
const data = e.target.result;
|
||||||
if (data instanceof ArrayBuffer) {
|
if (data instanceof ArrayBuffer) {
|
||||||
const view = new Uint8Array(data);
|
const view = new Uint8Array(data);
|
||||||
const array = [...view];
|
const array = [...view] as Array<u8>;
|
||||||
ui.stop_auto();
|
ui.stop_auto();
|
||||||
computer.reset();
|
computer.reset();
|
||||||
computer.load_memory(array);
|
computer.load_memory(array);
|
||||||
|
@ -79,6 +80,19 @@ function main(): void {
|
||||||
});
|
});
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("save_button").addEventListener("click", () => {
|
||||||
|
const memory = computer.dump_memory();
|
||||||
|
const buffer = new Uint8Array(memory);
|
||||||
|
const blob = new Blob([buffer], { type: "application/octet-stream" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.download = "bin.bin";
|
||||||
|
link.style.display = "none";
|
||||||
|
link.click();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { CpuEvent, CpuEventHandler } from "./events";
|
import { CpuEvent, CpuEventHandler } from "./events";
|
||||||
import { format_hex, u8 } from "./etc";
|
import { format_hex } from "./etc";
|
||||||
|
import { isU3, m256, u1, u3, u8 } from "./num";
|
||||||
|
|
||||||
export enum ParamType {
|
export enum ParamType {
|
||||||
Const,
|
Const,
|
||||||
|
@ -37,10 +38,11 @@ interface GenericComputer {
|
||||||
setMemory: (address: u8, value: u8) => void;
|
setMemory: (address: u8, value: u8) => void;
|
||||||
setProgramCounter: (address: u8) => void;
|
setProgramCounter: (address: u8) => void;
|
||||||
getProgramCounter: () => u8;
|
getProgramCounter: () => u8;
|
||||||
getRegister: (number: u8) => u8;
|
getRegister: (number: u3) => u8;
|
||||||
setRegister: (number: u8, value: u8) => void;
|
setRegister: (number: u3, value: u8) => void;
|
||||||
pushCallStack: (address: u8) => boolean;
|
pushCallStack: (address: u8) => boolean;
|
||||||
popCallStack: () => u8 | null;
|
popCallStack: () => u8 | null;
|
||||||
|
setBank: (bank_no: u1) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AfterExecutionComputerAction {
|
interface AfterExecutionComputerAction {
|
||||||
|
@ -55,7 +57,7 @@ export interface Instruction {
|
||||||
readonly params: Array<ParameterType>;
|
readonly params: Array<ParameterType>;
|
||||||
readonly execute: (
|
readonly execute: (
|
||||||
computer_reference: GenericComputer,
|
computer_reference: GenericComputer,
|
||||||
parameters: Uint8Array,
|
parameters: Array<u8>,
|
||||||
a: AfterExecutionComputerAction
|
a: AfterExecutionComputerAction
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
@ -104,10 +106,13 @@ ISA.insertInstruction(0x10, {
|
||||||
ISA.insertInstruction(0x20, {
|
ISA.insertInstruction(0x20, {
|
||||||
name: "LoadToRegister",
|
name: "LoadToRegister",
|
||||||
desc: "Sets the byte in register (P1) to be the contents of memory cell at address in register (P2)",
|
desc: "Sets the byte in register (P1) to be the contents of memory cell at address in register (P2)",
|
||||||
params: [new RegisParam("Set this register to"), new MemorParam("the byte held in this memory address")],
|
params: [new RegisParam("Set this register to"), new RegisParam("the byte held in this memory address")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no, mem_address] = p;
|
const [register_no, register_2] = p;
|
||||||
c.setRegister(register_no, c.getMemory(c.getRegister(mem_address)));
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
|
if (!isU3(register_2)) throw new Error("TODO");
|
||||||
|
|
||||||
|
c.setRegister(register_no, c.getMemory(c.getRegister(register_2)));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,6 +122,7 @@ ISA.insertInstruction(0x21, {
|
||||||
params: [new RegisParam("Write the byte in this register"), new MemorParam("To this memory address")],
|
params: [new RegisParam("Write the byte in this register"), new MemorParam("To this memory address")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no, mem_address] = p;
|
const [register_no, mem_address] = p;
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
c.setMemory(mem_address, c.getRegister(register_no));
|
c.setMemory(mem_address, c.getRegister(register_no));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -127,6 +133,7 @@ ISA.insertInstruction(0x2f, {
|
||||||
params: [new RegisParam("Set this register"), new ConstParam("to this constant")],
|
params: [new RegisParam("Set this register"), new ConstParam("to this constant")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no, value] = p;
|
const [register_no, value] = p;
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
c.setRegister(register_no, value);
|
c.setRegister(register_no, value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -137,6 +144,7 @@ ISA.insertInstruction(0x11, {
|
||||||
params: [new ConstParam("Set program counter to this constant"), new RegisParam("if this register's 1 bit is set")],
|
params: [new ConstParam("Set program counter to this constant"), new RegisParam("if this register's 1 bit is set")],
|
||||||
execute(c, p, a) {
|
execute(c, p, a) {
|
||||||
const [new_address, check_register_no] = p;
|
const [new_address, check_register_no] = p;
|
||||||
|
if (!isU3(check_register_no)) throw new Error("TODO");
|
||||||
if (c.getRegister(check_register_no) % 2 === 1) {
|
if (c.getRegister(check_register_no) % 2 === 1) {
|
||||||
c.setProgramCounter(new_address);
|
c.setProgramCounter(new_address);
|
||||||
a.noStep();
|
a.noStep();
|
||||||
|
@ -150,8 +158,9 @@ ISA.insertInstruction(0x30, {
|
||||||
params: [new RegisParam("register to be incremented")],
|
params: [new RegisParam("register to be incremented")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const register_no = p[0];
|
const register_no = p[0];
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
const current_value = c.getRegister(register_no);
|
const current_value = c.getRegister(register_no);
|
||||||
const new_value = (current_value + 1) % 256;
|
const new_value = m256(current_value + 1);
|
||||||
c.setRegister(register_no, new_value);
|
c.setRegister(register_no, new_value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -162,12 +171,13 @@ ISA.insertInstruction(0x31, {
|
||||||
params: [new RegisParam("register to be decremented")],
|
params: [new RegisParam("register to be decremented")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const register_no = p[0];
|
const register_no = p[0];
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
const current_value = c.getRegister(register_no);
|
const current_value = c.getRegister(register_no);
|
||||||
let new_value = current_value - 1;
|
let new_value = current_value - 1;
|
||||||
if (new_value === -1) {
|
if (new_value === -1) {
|
||||||
new_value = 255;
|
new_value = 255;
|
||||||
}
|
}
|
||||||
c.setRegister(register_no, new_value);
|
c.setRegister(register_no, new_value as u8);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -177,7 +187,9 @@ ISA.insertInstruction(0x40, {
|
||||||
params: [new RegisParam("set this register to"), new RegisParam("it's sum with the value in this register")],
|
params: [new RegisParam("set this register to"), new RegisParam("it's sum with the value in this register")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no_1, register_no_2] = p;
|
const [register_no_1, register_no_2] = p;
|
||||||
const new_value = (c.getRegister(register_no_1) + c.getRegister(register_no_2)) % 256;
|
if (!isU3(register_no_1)) throw new Error("TODO");
|
||||||
|
if (!isU3(register_no_2)) throw new Error("TODO");
|
||||||
|
const new_value = m256(c.getRegister(register_no_1) + c.getRegister(register_no_2));
|
||||||
c.setRegister(register_no_1, new_value);
|
c.setRegister(register_no_1, new_value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -192,6 +204,9 @@ ISA.insertInstruction(0x50, {
|
||||||
],
|
],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no_1, register_no_2, register_no_3] = p;
|
const [register_no_1, register_no_2, register_no_3] = p;
|
||||||
|
if (!isU3(register_no_1)) throw new Error("TODO");
|
||||||
|
if (!isU3(register_no_2)) throw new Error("TODO");
|
||||||
|
if (!isU3(register_no_3)) throw new Error("TODO");
|
||||||
const truth = c.getRegister(register_no_2) === c.getRegister(register_no_3) ? 0x01 : 0x00;
|
const truth = c.getRegister(register_no_2) === c.getRegister(register_no_3) ? 0x01 : 0x00;
|
||||||
c.setRegister(register_no_1, truth);
|
c.setRegister(register_no_1, truth);
|
||||||
},
|
},
|
||||||
|
@ -203,6 +218,7 @@ ISA.insertInstruction(0xfe, {
|
||||||
params: [new RegisParam("Register to print from")],
|
params: [new RegisParam("Register to print from")],
|
||||||
execute(c, p, a) {
|
execute(c, p, a) {
|
||||||
const register_no = p[0];
|
const register_no = p[0];
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
const asciiByte = c.getRegister(register_no);
|
const asciiByte = c.getRegister(register_no);
|
||||||
|
|
||||||
const char = String.fromCharCode(asciiByte);
|
const char = String.fromCharCode(asciiByte);
|
||||||
|
@ -216,8 +232,10 @@ ISA.insertInstruction(0x48, {
|
||||||
params: [new RegisParam(""), new RegisParam("")],
|
params: [new RegisParam(""), new RegisParam("")],
|
||||||
execute(c, p) {
|
execute(c, p) {
|
||||||
const [register_no_1, register_no_2] = p;
|
const [register_no_1, register_no_2] = p;
|
||||||
|
if (!isU3(register_no_1)) throw new Error("TODO");
|
||||||
|
if (!isU3(register_no_2)) throw new Error("TODO");
|
||||||
const new_value = c.getRegister(register_no_1) & c.getMemory(register_no_2);
|
const new_value = c.getRegister(register_no_1) & c.getMemory(register_no_2);
|
||||||
c.setRegister(register_no_1, new_value);
|
c.setRegister(register_no_1, new_value as u8);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -227,6 +245,7 @@ ISA.insertInstruction(0xff, {
|
||||||
params: [new RegisParam("Register to print from")],
|
params: [new RegisParam("Register to print from")],
|
||||||
execute(c, p, a) {
|
execute(c, p, a) {
|
||||||
const register_no = p[0];
|
const register_no = p[0];
|
||||||
|
if (!isU3(register_no)) throw new Error("TODO");
|
||||||
const byte = c.getRegister(register_no);
|
const byte = c.getRegister(register_no);
|
||||||
|
|
||||||
a.dispatch(CpuEvent.Print, byte.toString(10));
|
a.dispatch(CpuEvent.Print, byte.toString(10));
|
||||||
|
@ -239,6 +258,8 @@ ISA.insertInstruction(0xfd, {
|
||||||
params: [new RegisParam("Upper 8 bits of number"), new RegisParam("Lower 8 bits of number")],
|
params: [new RegisParam("Upper 8 bits of number"), new RegisParam("Lower 8 bits of number")],
|
||||||
execute(c, p, a) {
|
execute(c, p, a) {
|
||||||
const [upper_register_no, lower_register_no] = p;
|
const [upper_register_no, lower_register_no] = p;
|
||||||
|
if (!isU3(upper_register_no)) throw new Error("TODO");
|
||||||
|
if (!isU3(lower_register_no)) throw new Error("TODO");
|
||||||
const upper = c.getRegister(upper_register_no);
|
const upper = c.getRegister(upper_register_no);
|
||||||
const lower = c.getRegister(lower_register_no);
|
const lower = c.getRegister(lower_register_no);
|
||||||
const sum = upper * 16 * 16 + lower;
|
const sum = upper * 16 * 16 + lower;
|
||||||
|
@ -282,8 +303,14 @@ ISA.insertInstruction(0xa1, {
|
||||||
throw new Error("TODO handle this");
|
throw new Error("TODO handle this");
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setProgramCounter(new_address + 1);
|
c.setProgramCounter(m256(new_address + 1));
|
||||||
|
|
||||||
a.noStep();
|
a.noStep();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
ISA.insertInstruction(0xb1, {
|
||||||
|
name: "Set bank",
|
||||||
|
desc: "Selects which bank of memory to write and read to",
|
||||||
|
params: [new ConstParam("Bank number")],
|
||||||
|
execute(c, p, a) {},
|
||||||
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { format_hex, u8 } from "./etc";
|
import { format_hex } from "./etc";
|
||||||
import { Instruction, InstructionSet } from "./instructionSet";
|
import { Instruction, InstructionSet } from "./instructionSet";
|
||||||
|
import { u8 } from "./num.js";
|
||||||
|
|
||||||
export function generate_isa(iset: InstructionSet): string {
|
export function generate_isa(iset: InstructionSet): string {
|
||||||
const instructions: Array<[u8, Instruction]> = [];
|
const instructions: Array<[u8, Instruction]> = [];
|
||||||
|
|
307
src/num.ts
Normal file
307
src/num.ts
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
export type u8 =
|
||||||
|
| 0
|
||||||
|
| 1
|
||||||
|
| 2
|
||||||
|
| 3
|
||||||
|
| 4
|
||||||
|
| 5
|
||||||
|
| 6
|
||||||
|
| 7
|
||||||
|
| 8
|
||||||
|
| 9
|
||||||
|
| 10
|
||||||
|
| 11
|
||||||
|
| 12
|
||||||
|
| 13
|
||||||
|
| 14
|
||||||
|
| 15
|
||||||
|
| 16
|
||||||
|
| 17
|
||||||
|
| 18
|
||||||
|
| 19
|
||||||
|
| 20
|
||||||
|
| 21
|
||||||
|
| 22
|
||||||
|
| 23
|
||||||
|
| 24
|
||||||
|
| 25
|
||||||
|
| 26
|
||||||
|
| 27
|
||||||
|
| 28
|
||||||
|
| 29
|
||||||
|
| 30
|
||||||
|
| 31
|
||||||
|
| 32
|
||||||
|
| 33
|
||||||
|
| 34
|
||||||
|
| 35
|
||||||
|
| 36
|
||||||
|
| 37
|
||||||
|
| 38
|
||||||
|
| 39
|
||||||
|
| 40
|
||||||
|
| 41
|
||||||
|
| 42
|
||||||
|
| 43
|
||||||
|
| 44
|
||||||
|
| 45
|
||||||
|
| 46
|
||||||
|
| 47
|
||||||
|
| 48
|
||||||
|
| 49
|
||||||
|
| 50
|
||||||
|
| 51
|
||||||
|
| 52
|
||||||
|
| 53
|
||||||
|
| 54
|
||||||
|
| 55
|
||||||
|
| 56
|
||||||
|
| 57
|
||||||
|
| 58
|
||||||
|
| 59
|
||||||
|
| 60
|
||||||
|
| 61
|
||||||
|
| 62
|
||||||
|
| 63
|
||||||
|
| 64
|
||||||
|
| 65
|
||||||
|
| 66
|
||||||
|
| 67
|
||||||
|
| 68
|
||||||
|
| 69
|
||||||
|
| 70
|
||||||
|
| 71
|
||||||
|
| 72
|
||||||
|
| 73
|
||||||
|
| 74
|
||||||
|
| 75
|
||||||
|
| 76
|
||||||
|
| 77
|
||||||
|
| 78
|
||||||
|
| 79
|
||||||
|
| 80
|
||||||
|
| 81
|
||||||
|
| 82
|
||||||
|
| 83
|
||||||
|
| 84
|
||||||
|
| 85
|
||||||
|
| 86
|
||||||
|
| 87
|
||||||
|
| 88
|
||||||
|
| 89
|
||||||
|
| 90
|
||||||
|
| 91
|
||||||
|
| 92
|
||||||
|
| 93
|
||||||
|
| 94
|
||||||
|
| 95
|
||||||
|
| 96
|
||||||
|
| 97
|
||||||
|
| 98
|
||||||
|
| 99
|
||||||
|
| 100
|
||||||
|
| 101
|
||||||
|
| 102
|
||||||
|
| 103
|
||||||
|
| 104
|
||||||
|
| 105
|
||||||
|
| 106
|
||||||
|
| 107
|
||||||
|
| 108
|
||||||
|
| 109
|
||||||
|
| 110
|
||||||
|
| 111
|
||||||
|
| 112
|
||||||
|
| 113
|
||||||
|
| 114
|
||||||
|
| 115
|
||||||
|
| 116
|
||||||
|
| 117
|
||||||
|
| 118
|
||||||
|
| 119
|
||||||
|
| 120
|
||||||
|
| 121
|
||||||
|
| 122
|
||||||
|
| 123
|
||||||
|
| 124
|
||||||
|
| 125
|
||||||
|
| 126
|
||||||
|
| 127
|
||||||
|
| 128
|
||||||
|
| 129
|
||||||
|
| 130
|
||||||
|
| 131
|
||||||
|
| 132
|
||||||
|
| 133
|
||||||
|
| 134
|
||||||
|
| 135
|
||||||
|
| 136
|
||||||
|
| 137
|
||||||
|
| 138
|
||||||
|
| 139
|
||||||
|
| 140
|
||||||
|
| 141
|
||||||
|
| 142
|
||||||
|
| 143
|
||||||
|
| 144
|
||||||
|
| 145
|
||||||
|
| 146
|
||||||
|
| 147
|
||||||
|
| 148
|
||||||
|
| 149
|
||||||
|
| 150
|
||||||
|
| 151
|
||||||
|
| 152
|
||||||
|
| 153
|
||||||
|
| 154
|
||||||
|
| 155
|
||||||
|
| 156
|
||||||
|
| 157
|
||||||
|
| 158
|
||||||
|
| 159
|
||||||
|
| 160
|
||||||
|
| 161
|
||||||
|
| 162
|
||||||
|
| 163
|
||||||
|
| 164
|
||||||
|
| 165
|
||||||
|
| 166
|
||||||
|
| 167
|
||||||
|
| 168
|
||||||
|
| 169
|
||||||
|
| 170
|
||||||
|
| 171
|
||||||
|
| 172
|
||||||
|
| 173
|
||||||
|
| 174
|
||||||
|
| 175
|
||||||
|
| 176
|
||||||
|
| 177
|
||||||
|
| 178
|
||||||
|
| 179
|
||||||
|
| 180
|
||||||
|
| 181
|
||||||
|
| 182
|
||||||
|
| 183
|
||||||
|
| 184
|
||||||
|
| 185
|
||||||
|
| 186
|
||||||
|
| 187
|
||||||
|
| 188
|
||||||
|
| 189
|
||||||
|
| 190
|
||||||
|
| 191
|
||||||
|
| 192
|
||||||
|
| 193
|
||||||
|
| 194
|
||||||
|
| 195
|
||||||
|
| 196
|
||||||
|
| 197
|
||||||
|
| 198
|
||||||
|
| 199
|
||||||
|
| 200
|
||||||
|
| 201
|
||||||
|
| 202
|
||||||
|
| 203
|
||||||
|
| 204
|
||||||
|
| 205
|
||||||
|
| 206
|
||||||
|
| 207
|
||||||
|
| 208
|
||||||
|
| 209
|
||||||
|
| 210
|
||||||
|
| 211
|
||||||
|
| 212
|
||||||
|
| 213
|
||||||
|
| 214
|
||||||
|
| 215
|
||||||
|
| 216
|
||||||
|
| 217
|
||||||
|
| 218
|
||||||
|
| 219
|
||||||
|
| 220
|
||||||
|
| 221
|
||||||
|
| 222
|
||||||
|
| 223
|
||||||
|
| 224
|
||||||
|
| 225
|
||||||
|
| 226
|
||||||
|
| 227
|
||||||
|
| 228
|
||||||
|
| 229
|
||||||
|
| 230
|
||||||
|
| 231
|
||||||
|
| 232
|
||||||
|
| 233
|
||||||
|
| 234
|
||||||
|
| 235
|
||||||
|
| 236
|
||||||
|
| 237
|
||||||
|
| 238
|
||||||
|
| 239
|
||||||
|
| 240
|
||||||
|
| 241
|
||||||
|
| 242
|
||||||
|
| 243
|
||||||
|
| 244
|
||||||
|
| 245
|
||||||
|
| 246
|
||||||
|
| 247
|
||||||
|
| 248
|
||||||
|
| 249
|
||||||
|
| 250
|
||||||
|
| 251
|
||||||
|
| 252
|
||||||
|
| 253
|
||||||
|
| 254
|
||||||
|
| 255;
|
||||||
|
|
||||||
|
export type u1 = 0 | 1;
|
||||||
|
export type u2 = 0 | 1 | 2 | 3;
|
||||||
|
export type u3 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||||
|
export type u4 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
|
||||||
|
|
||||||
|
export const m256 = (number: number): u8 => (number % 256) as u8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a number is a u3 type (unsigned 3-bit integer).
|
||||||
|
* Does not check for non integers
|
||||||
|
*
|
||||||
|
* @param n - Input number to be checked
|
||||||
|
* @returns true or false
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function isU3(n: number): n is u3 {
|
||||||
|
if (n < 8 && n >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Determines whether a number is a u4 type (unsigned 4-bit integer).
|
||||||
|
* Does not check for non integers
|
||||||
|
*
|
||||||
|
* @param n - Input number to be checked
|
||||||
|
* @returns true or false
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function isU4(n: number): n is u4 {
|
||||||
|
if (n < 16 && n >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Determines whether a number is a u8 type (unsigned 8-bit integer).
|
||||||
|
* Does not check for non integers
|
||||||
|
*
|
||||||
|
* @param n - Input number to be checked
|
||||||
|
* @returns true or false
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function isU8(n: number): n is u8 {
|
||||||
|
if (n < 256 && n >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -7,16 +7,26 @@ pre {
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--Border: Yellow;
|
--Border: #ffff00;
|
||||||
--mem-instruction: greenyellow;
|
// --mem-instruction: #adff2f;
|
||||||
--mem-register: Purple;
|
// --mem-register: #800080;
|
||||||
--mem-constant: lightgray;
|
// --mem-constant: #d3d3d3;
|
||||||
--mem-memory: lightgray;
|
// --mem-memory: #d3d3d3;
|
||||||
--mem-invalid: red;
|
// --mem-invalid: #ff0000;
|
||||||
|
// --mem-instruction: #2f962a;
|
||||||
|
// --mem-register: #dc21d1;
|
||||||
|
// --mem-constant: #d3d3d3;
|
||||||
|
// --mem-memory: #4d86f0;
|
||||||
|
// --mem-invalid: #bf2e2e;
|
||||||
|
--mem-instruction: #3af78f;
|
||||||
|
--mem-memory: #ff26a8;
|
||||||
|
--mem-register: #9e0ef7;
|
||||||
|
--mem-constant: #19f7f0;
|
||||||
|
--mem-invalid: #bf2e2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
color: gray;
|
color: #808080;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
@ -63,7 +73,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#printout {
|
#printout {
|
||||||
border: 4px dashed yellow;
|
border: 4px dashed var(--Border);
|
||||||
grid-area: printout;
|
grid-area: printout;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
@ -77,7 +87,7 @@ body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
border: 5px dashed yellow;
|
border: 5px dashed var(--Border);
|
||||||
#expl_box {
|
#expl_box {
|
||||||
padding-inline: 20px;
|
padding-inline: 20px;
|
||||||
padding-block-start: 10px;
|
padding-block-start: 10px;
|
||||||
|
@ -128,13 +138,10 @@ body {
|
||||||
.program_counter {
|
.program_counter {
|
||||||
outline: 3px solid orange;
|
outline: 3px solid orange;
|
||||||
}
|
}
|
||||||
.instruction_argument {
|
.instruction_argument,
|
||||||
outline: 3px dashed purple;
|
|
||||||
}
|
|
||||||
.current_instruction {
|
.current_instruction {
|
||||||
outline: 3px dashed greenyellow;
|
outline: 3px dashed var(--color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.invalid {
|
.invalid {
|
||||||
&::after {
|
&::after {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
43
src/ui.ts
43
src/ui.ts
|
@ -1,5 +1,5 @@
|
||||||
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
||||||
import { $, el, format_hex, u8 } from "./etc";
|
import { $, el, format_hex } from "./etc";
|
||||||
import { EventHandler } from "./eventHandler";
|
import { EventHandler } from "./eventHandler";
|
||||||
import { InstructionExplainer } from "./ui/instructionExplainer";
|
import { InstructionExplainer } from "./ui/instructionExplainer";
|
||||||
import { MemoryView } from "./ui/memoryView";
|
import { MemoryView } from "./ui/memoryView";
|
||||||
|
@ -75,57 +75,16 @@ export class UI {
|
||||||
}
|
}
|
||||||
|
|
||||||
init_events(cpu_events: CpuEventHandler): void {
|
init_events(cpu_events: CpuEventHandler): void {
|
||||||
cpu_events.listen(CpuEvent.MemoryChanged, ({ address, value }) => {
|
|
||||||
this.memory.set_cell_value(address, value);
|
|
||||||
});
|
|
||||||
cpu_events.listen(CpuEvent.RegisterChanged, ({ register_no, value }) => {
|
cpu_events.listen(CpuEvent.RegisterChanged, ({ register_no, value }) => {
|
||||||
this.register_cells[register_no].textContent = format_hex(value);
|
this.register_cells[register_no].textContent = format_hex(value);
|
||||||
});
|
});
|
||||||
cpu_events.listen(CpuEvent.ProgramCounterChanged, ({ counter }) => {
|
|
||||||
this.memory.set_program_counter(counter);
|
|
||||||
});
|
|
||||||
cpu_events.listen(CpuEvent.Print, (char) => {
|
cpu_events.listen(CpuEvent.Print, (char) => {
|
||||||
this.printout.textContent = (this.printout.textContent ?? "") + char;
|
this.printout.textContent = (this.printout.textContent ?? "") + char;
|
||||||
});
|
});
|
||||||
cpu_events.listen(CpuEvent.Reset, () => {
|
|
||||||
this.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.frequencyIndicator.init_cpu_events(cpu_events);
|
this.frequencyIndicator.init_cpu_events(cpu_events);
|
||||||
this.memory.init_cpu_events(cpu_events);
|
this.memory.init_cpu_events(cpu_events);
|
||||||
this.instruction_explainer.init_cpu_events(cpu_events);
|
this.instruction_explainer.init_cpu_events(cpu_events);
|
||||||
|
|
||||||
cpu_events.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
|
||||||
this.memory.add_cell_class(pos, "instruction_argument");
|
|
||||||
this.instruction_explainer.add_param(param, pos, code);
|
|
||||||
const t = param.type;
|
|
||||||
this.memory.remove_cell_class(pos, "constant", "register", "memory", "instruction", "invalid");
|
|
||||||
let name: string = "";
|
|
||||||
if (t === ParamType.Const) {
|
|
||||||
name = "constant";
|
|
||||||
} else if (t === ParamType.Memory) {
|
|
||||||
name = "memory";
|
|
||||||
} else if (t === ParamType.Register) {
|
|
||||||
name = "register";
|
|
||||||
} else {
|
|
||||||
throw new Error("unreachable");
|
|
||||||
}
|
|
||||||
this.memory.add_cell_class(pos, name);
|
|
||||||
});
|
|
||||||
cpu_events.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
|
||||||
this.instruction_explainer.add_instruction(instr, pos, code);
|
|
||||||
|
|
||||||
this.memory.remove_all_cell_class("instruction_argument");
|
|
||||||
this.memory.remove_all_cell_class("current_instruction");
|
|
||||||
this.memory.add_cell_class(pos, "current_instruction");
|
|
||||||
this.memory.remove_cell_class(pos, "constant", "register", "memory", "invalid");
|
|
||||||
this.memory.add_cell_class(pos, "instruction");
|
|
||||||
});
|
|
||||||
cpu_events.listen(CpuEvent.InvalidParsed, ({ code, pos }) => {
|
|
||||||
this.memory.remove_cell_class(pos, "constant", "register", "memory", "instruction");
|
|
||||||
this.memory.add_cell_class(pos, "invalid");
|
|
||||||
this.instruction_explainer.add_invalid(pos, code);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
|
|
|
@ -13,6 +13,7 @@ export class frequencyIndicator implements UiComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
start(): void {
|
start(): void {
|
||||||
|
this.last_time = performance.now();
|
||||||
if (this.running !== null) {
|
if (this.running !== null) {
|
||||||
throw new Error("Tried starting frequencyIndicator twice!");
|
throw new Error("Tried starting frequencyIndicator twice!");
|
||||||
}
|
}
|
||||||
|
@ -26,10 +27,15 @@ export class frequencyIndicator implements UiComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
update_indicator(): void {
|
update_indicator(): void {
|
||||||
if (this.last_value !== this.count) {
|
const new_time = performance.now();
|
||||||
this.element.textContent = `${this.count}hz`;
|
const dt = (new_time - this.last_time) / 1000 || 1;
|
||||||
this.last_value = this.count;
|
const value = Math.round(this.count / dt);
|
||||||
|
|
||||||
|
if (this.last_value !== value) {
|
||||||
|
this.element.textContent = `${value}hz`;
|
||||||
|
this.last_value = value;
|
||||||
}
|
}
|
||||||
|
this.last_time = new_time;
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +50,7 @@ export class frequencyIndicator implements UiComponent {
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.last_value = 0;
|
this.last_value = 0;
|
||||||
}
|
}
|
||||||
init_cpu_events(c: CpuEventHandler) {
|
init_cpu_events(c: CpuEventHandler): void {
|
||||||
c.listen(CpuEvent.ClockCycle, () => {
|
c.listen(CpuEvent.ClockCycle, () => {
|
||||||
this.count += 1;
|
this.count += 1;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { el, format_hex, u8 } from "../etc";
|
import { el, format_hex } from "../etc";
|
||||||
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
|
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
|
||||||
import { Instruction, ParamType, ParameterType } from "../instructionSet";
|
import { Instruction, ParamType, ParameterType } from "../instructionSet";
|
||||||
|
import { u8 } from "../num";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { UiComponent } from "./uiComponent";
|
||||||
|
|
||||||
export class InstructionExplainer implements UiComponent {
|
export class InstructionExplainer implements UiComponent {
|
||||||
|
@ -41,13 +42,23 @@ export class InstructionExplainer implements UiComponent {
|
||||||
this.add_box(format_hex(byte), param.desc, name);
|
this.add_box(format_hex(byte), param.desc, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_invalid(pos: u8, byte: u8) {
|
add_invalid(pos: u8, byte: u8): void {
|
||||||
this.reset();
|
this.reset();
|
||||||
this.add_box(format_hex(byte), "Invalid Instruction", "invalid");
|
this.add_box(format_hex(byte), "Invalid Instruction", "invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
init_events(eh: UiEventHandler): void {}
|
init_events(eh: UiEventHandler): void {}
|
||||||
init_cpu_events(c: CpuEventHandler) {}
|
init_cpu_events(c: CpuEventHandler): void {
|
||||||
|
c.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
||||||
|
this.add_param(param, pos, code);
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
||||||
|
this.add_instruction(instr, pos, code);
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.InvalidParsed, ({ code, pos }) => {
|
||||||
|
this.add_invalid(pos, code);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
this.element.innerHTML = "";
|
this.element.innerHTML = "";
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { el, format_hex, u8 } from "../etc";
|
import { el, format_hex } from "../etc";
|
||||||
import { CpuEventHandler, UiEventHandler } from "../events";
|
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
|
||||||
|
import { ParamType } from "../instructionSet";
|
||||||
|
import { u8 } from "../num.js";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { UiComponent } from "./uiComponent";
|
||||||
|
|
||||||
export enum CellTag {
|
|
||||||
ProgramCounter = "program_counter",
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemoryCell = {
|
type MemoryCell = {
|
||||||
el: HTMLElement;
|
el: HTMLElement;
|
||||||
};
|
};
|
||||||
|
@ -74,5 +72,39 @@ export class MemoryView implements UiComponent {
|
||||||
init_events(eh: UiEventHandler): void {
|
init_events(eh: UiEventHandler): void {
|
||||||
this;
|
this;
|
||||||
}
|
}
|
||||||
init_cpu_events(c: CpuEventHandler) {}
|
init_cpu_events(c: CpuEventHandler): void {
|
||||||
|
c.listen(CpuEvent.MemoryChanged, ({ address, value }) => {
|
||||||
|
this.set_cell_value(address, value);
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.ProgramCounterChanged, ({ counter }) => {
|
||||||
|
this.set_program_counter(counter);
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
||||||
|
this.add_cell_class(pos, "instruction_argument");
|
||||||
|
const t = param.type;
|
||||||
|
this.remove_cell_class(pos, "constant", "register", "memory", "instruction", "invalid");
|
||||||
|
let name: string = "";
|
||||||
|
if (t === ParamType.Const) {
|
||||||
|
name = "constant";
|
||||||
|
} else if (t === ParamType.Memory) {
|
||||||
|
name = "memory";
|
||||||
|
} else if (t === ParamType.Register) {
|
||||||
|
name = "register";
|
||||||
|
} else {
|
||||||
|
throw new Error("unreachable");
|
||||||
|
}
|
||||||
|
this.add_cell_class(pos, name);
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
||||||
|
this.remove_all_cell_class("instruction_argument");
|
||||||
|
this.remove_all_cell_class("current_instruction");
|
||||||
|
this.add_cell_class(pos, "current_instruction");
|
||||||
|
this.remove_cell_class(pos, "constant", "register", "memory", "invalid");
|
||||||
|
this.add_cell_class(pos, "instruction");
|
||||||
|
});
|
||||||
|
c.listen(CpuEvent.InvalidParsed, ({ code, pos }) => {
|
||||||
|
this.remove_cell_class(pos, "constant", "register", "memory", "instruction");
|
||||||
|
this.add_cell_class(pos, "invalid");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { u8 } from "../etc";
|
|
||||||
import { CpuEventHandler, UiEventHandler } from "../events";
|
import { CpuEventHandler, UiEventHandler } from "../events";
|
||||||
|
|
||||||
export interface UiComponent {
|
export interface UiComponent {
|
||||||
|
|
Loading…
Reference in a new issue