diff --git a/TODO b/TODO
index 72c4d95..a58b191 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
Add screen (VRAM?)
+- Bank switching
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
-
-Save binary button
\ No newline at end of file
+HCF flames
\ No newline at end of file
diff --git a/index.html b/index.html
index 9fb742b..3ce56be 100644
--- a/index.html
+++ b/index.html
@@ -22,6 +22,7 @@
+
diff --git a/src/computer.ts b/src/computer.ts
index 4c07eaf..682e29b 100644
--- a/src/computer.ts
+++ b/src/computer.ts
@@ -1,20 +1,22 @@
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 { Instruction, ISA } from "./instructionSet";
+import { m256, u8 } from "./num";
export type TempInstrState = {
pos: u8;
params_found: number;
instr: Instruction;
- params: Uint8Array;
+ params: Array;
};
export class Computer {
- private memory = new Uint8Array(256);
- private registers = new Uint8Array(8);
+ private memory = new Array(256);
+ private registers = new Array(256);
private call_stack: Array = [];
private program_counter: u8 = 0;
+ private bank: u8 = 0;
private current_instr: TempInstrState | null = null;
events: CpuEventHandler = new EventHandler() as CpuEventHandler;
@@ -44,7 +46,7 @@ export class Computer {
pos: this.program_counter,
instr: parsed_instruction,
params_found: 0,
- params: new Uint8Array(parsed_instruction.params.length),
+ params: new Array(parsed_instruction.params.length),
};
this.events.dispatch(CpuEvent.InstructionParsed, {
pos: this.program_counter,
@@ -126,10 +128,14 @@ export class Computer {
return this.call_stack.pop() ?? null;
}
+ setBank(bank_no: u8): void {
+ this.bank = bank_no;
+ }
+
reset(): void {
this.events.dispatch(CpuEvent.Reset, null);
- this.memory = new Uint8Array(256);
- this.registers = new Uint8Array(8);
+ this.memory = new Array(256);
+ this.registers = new Array(8);
this.call_stack = [];
this.current_instr = null;
this.program_counter = 0;
@@ -144,19 +150,23 @@ export class Computer {
load_memory(program: Array): void {
console.log(byte_array_to_js_source(program));
- const max_loop = Math.min(this.memory.length, program.length);
- for (let i = 0; i < max_loop; i++) {
+ const max_loop: u8 = Math.min(255, program.length) as u8;
+ for (let i: u8 = 0; i < 255; i++) {
// Don't fire event if no change is made
if (this.memory[i] === program[i]) continue;
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;
}
+ dump_memory(): Array {
+ return this.memory;
+ }
+
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 });
}
}
diff --git a/src/etc.ts b/src/etc.ts
index 47ae339..ffdd553 100644
--- a/src/etc.ts
+++ b/src/etc.ts
@@ -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.
-// 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
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): string => {
let str = "[";
diff --git a/src/events.ts b/src/events.ts
index f2d1251..5e16025 100644
--- a/src/events.ts
+++ b/src/events.ts
@@ -1,6 +1,6 @@
-import { u8 } from "./etc";
import { EventHandler } from "./eventHandler";
import { Instruction, ParameterType } from "./instructionSet";
+import { u8 } from "./num.js";
export enum CpuEvent {
MemoryChanged,
diff --git a/src/index.ts b/src/index.ts
index 4859439..d88c835 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,29 +3,13 @@ import { $ } from "./etc";
import { ISA } from "./instructionSet";
import { generate_isa } from "./isaGenerator";
import { UI } from "./ui";
+import { u8 } from "./num";
import "./style.scss";
function main(): void {
- // const program = [
- // 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,
+ const program: Array = [
+ 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,
@@ -41,6 +25,23 @@ function main(): void {
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 ui = new UI();
@@ -68,7 +69,7 @@ function main(): void {
const data = e.target.result;
if (data instanceof ArrayBuffer) {
const view = new Uint8Array(data);
- const array = [...view];
+ const array = [...view] as Array;
ui.stop_auto();
computer.reset();
computer.load_memory(array);
@@ -79,6 +80,19 @@ function main(): void {
});
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", () => {
diff --git a/src/instructionSet.ts b/src/instructionSet.ts
index 52726da..2af2b42 100644
--- a/src/instructionSet.ts
+++ b/src/instructionSet.ts
@@ -1,5 +1,6 @@
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 {
Const,
@@ -37,10 +38,11 @@ interface GenericComputer {
setMemory: (address: u8, value: u8) => void;
setProgramCounter: (address: u8) => void;
getProgramCounter: () => u8;
- getRegister: (number: u8) => u8;
- setRegister: (number: u8, value: u8) => void;
+ getRegister: (number: u3) => u8;
+ setRegister: (number: u3, value: u8) => void;
pushCallStack: (address: u8) => boolean;
popCallStack: () => u8 | null;
+ setBank: (bank_no: u1) => void;
}
interface AfterExecutionComputerAction {
@@ -55,7 +57,7 @@ export interface Instruction {
readonly params: Array;
readonly execute: (
computer_reference: GenericComputer,
- parameters: Uint8Array,
+ parameters: Array,
a: AfterExecutionComputerAction
) => void;
}
@@ -104,10 +106,13 @@ ISA.insertInstruction(0x10, {
ISA.insertInstruction(0x20, {
name: "LoadToRegister",
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) {
- const [register_no, mem_address] = p;
- c.setRegister(register_no, c.getMemory(c.getRegister(mem_address)));
+ const [register_no, register_2] = p;
+ 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")],
execute(c, p) {
const [register_no, mem_address] = p;
+ if (!isU3(register_no)) throw new Error("TODO");
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")],
execute(c, p) {
const [register_no, value] = p;
+ if (!isU3(register_no)) throw new Error("TODO");
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")],
execute(c, p, a) {
const [new_address, check_register_no] = p;
+ if (!isU3(check_register_no)) throw new Error("TODO");
if (c.getRegister(check_register_no) % 2 === 1) {
c.setProgramCounter(new_address);
a.noStep();
@@ -150,8 +158,9 @@ ISA.insertInstruction(0x30, {
params: [new RegisParam("register to be incremented")],
execute(c, p) {
const register_no = p[0];
+ if (!isU3(register_no)) throw new Error("TODO");
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);
},
});
@@ -162,12 +171,13 @@ ISA.insertInstruction(0x31, {
params: [new RegisParam("register to be decremented")],
execute(c, p) {
const register_no = p[0];
+ if (!isU3(register_no)) throw new Error("TODO");
const current_value = c.getRegister(register_no);
let new_value = current_value - 1;
if (new_value === -1) {
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")],
execute(c, 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);
},
});
@@ -192,6 +204,9 @@ ISA.insertInstruction(0x50, {
],
execute(c, 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;
c.setRegister(register_no_1, truth);
},
@@ -203,6 +218,7 @@ ISA.insertInstruction(0xfe, {
params: [new RegisParam("Register to print from")],
execute(c, p, a) {
const register_no = p[0];
+ if (!isU3(register_no)) throw new Error("TODO");
const asciiByte = c.getRegister(register_no);
const char = String.fromCharCode(asciiByte);
@@ -216,8 +232,10 @@ ISA.insertInstruction(0x48, {
params: [new RegisParam(""), new RegisParam("")],
execute(c, 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);
- 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")],
execute(c, p, a) {
const register_no = p[0];
+ if (!isU3(register_no)) throw new Error("TODO");
const byte = c.getRegister(register_no);
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")],
execute(c, p, a) {
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 lower = c.getRegister(lower_register_no);
const sum = upper * 16 * 16 + lower;
@@ -282,8 +303,14 @@ ISA.insertInstruction(0xa1, {
throw new Error("TODO handle this");
}
- c.setProgramCounter(new_address + 1);
+ c.setProgramCounter(m256(new_address + 1));
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) {},
+});
diff --git a/src/isaGenerator.ts b/src/isaGenerator.ts
index 5a9d630..d14147e 100644
--- a/src/isaGenerator.ts
+++ b/src/isaGenerator.ts
@@ -1,5 +1,6 @@
-import { format_hex, u8 } from "./etc";
+import { format_hex } from "./etc";
import { Instruction, InstructionSet } from "./instructionSet";
+import { u8 } from "./num.js";
export function generate_isa(iset: InstructionSet): string {
const instructions: Array<[u8, Instruction]> = [];
diff --git a/src/num.ts b/src/num.ts
new file mode 100644
index 0000000..d1ec48c
--- /dev/null
+++ b/src/num.ts
@@ -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;
+}
diff --git a/src/style.scss b/src/style.scss
index ea3f147..08758bb 100644
--- a/src/style.scss
+++ b/src/style.scss
@@ -7,16 +7,26 @@ pre {
}
:root {
- --Border: Yellow;
- --mem-instruction: greenyellow;
- --mem-register: Purple;
- --mem-constant: lightgray;
- --mem-memory: lightgray;
- --mem-invalid: red;
+ --Border: #ffff00;
+ // --mem-instruction: #adff2f;
+ // --mem-register: #800080;
+ // --mem-constant: #d3d3d3;
+ // --mem-memory: #d3d3d3;
+ // --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 {
- color: gray;
+ color: #808080;
background-color: black;
font-size: 2.5em;
font-family: monospace;
@@ -63,7 +73,7 @@ body {
}
#printout {
- border: 4px dashed yellow;
+ border: 4px dashed var(--Border);
grid-area: printout;
padding: 10px;
word-wrap: break-word;
@@ -77,7 +87,7 @@ body {
display: flex;
flex-direction: column;
gap: 5px;
- border: 5px dashed yellow;
+ border: 5px dashed var(--Border);
#expl_box {
padding-inline: 20px;
padding-block-start: 10px;
@@ -128,13 +138,10 @@ body {
.program_counter {
outline: 3px solid orange;
}
- .instruction_argument {
- outline: 3px dashed purple;
- }
+ .instruction_argument,
.current_instruction {
- outline: 3px dashed greenyellow;
+ outline: 3px dashed var(--color);
}
-
.invalid {
&::after {
user-select: none;
diff --git a/src/ui.ts b/src/ui.ts
index 4709e19..d1f3eb5 100644
--- a/src/ui.ts
+++ b/src/ui.ts
@@ -1,5 +1,5 @@
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 { InstructionExplainer } from "./ui/instructionExplainer";
import { MemoryView } from "./ui/memoryView";
@@ -75,57 +75,16 @@ export class UI {
}
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 }) => {
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) => {
this.printout.textContent = (this.printout.textContent ?? "") + char;
});
- cpu_events.listen(CpuEvent.Reset, () => {
- this.reset();
- });
this.frequencyIndicator.init_cpu_events(cpu_events);
this.memory.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 {
diff --git a/src/ui/frequencyIndicator.ts b/src/ui/frequencyIndicator.ts
index 3a689d0..b61d013 100644
--- a/src/ui/frequencyIndicator.ts
+++ b/src/ui/frequencyIndicator.ts
@@ -13,6 +13,7 @@ export class frequencyIndicator implements UiComponent {
}
start(): void {
+ this.last_time = performance.now();
if (this.running !== null) {
throw new Error("Tried starting frequencyIndicator twice!");
}
@@ -26,10 +27,15 @@ export class frequencyIndicator implements UiComponent {
}
update_indicator(): void {
- if (this.last_value !== this.count) {
- this.element.textContent = `${this.count}hz`;
- this.last_value = this.count;
+ const new_time = performance.now();
+ const dt = (new_time - this.last_time) / 1000 || 1;
+ 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;
}
@@ -44,7 +50,7 @@ export class frequencyIndicator implements UiComponent {
this.count = 0;
this.last_value = 0;
}
- init_cpu_events(c: CpuEventHandler) {
+ init_cpu_events(c: CpuEventHandler): void {
c.listen(CpuEvent.ClockCycle, () => {
this.count += 1;
});
diff --git a/src/ui/instructionExplainer.ts b/src/ui/instructionExplainer.ts
index ede412e..c3bc75f 100644
--- a/src/ui/instructionExplainer.ts
+++ b/src/ui/instructionExplainer.ts
@@ -1,6 +1,7 @@
-import { el, format_hex, u8 } from "../etc";
+import { el, format_hex } from "../etc";
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
import { Instruction, ParamType, ParameterType } from "../instructionSet";
+import { u8 } from "../num";
import { UiComponent } from "./uiComponent";
export class InstructionExplainer implements UiComponent {
@@ -41,13 +42,23 @@ export class InstructionExplainer implements UiComponent {
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.add_box(format_hex(byte), "Invalid Instruction", "invalid");
}
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 {
this.element.innerHTML = "";
diff --git a/src/ui/memoryView.ts b/src/ui/memoryView.ts
index a1de6e0..616be61 100644
--- a/src/ui/memoryView.ts
+++ b/src/ui/memoryView.ts
@@ -1,11 +1,9 @@
-import { el, format_hex, u8 } from "../etc";
-import { CpuEventHandler, UiEventHandler } from "../events";
+import { el, format_hex } from "../etc";
+import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
+import { ParamType } from "../instructionSet";
+import { u8 } from "../num.js";
import { UiComponent } from "./uiComponent";
-export enum CellTag {
- ProgramCounter = "program_counter",
-}
-
type MemoryCell = {
el: HTMLElement;
};
@@ -74,5 +72,39 @@ export class MemoryView implements UiComponent {
init_events(eh: UiEventHandler): void {
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");
+ });
+ }
}
diff --git a/src/ui/uiComponent.ts b/src/ui/uiComponent.ts
index c7d281e..da43929 100644
--- a/src/ui/uiComponent.ts
+++ b/src/ui/uiComponent.ts
@@ -1,4 +1,3 @@
-import { u8 } from "../etc";
import { CpuEventHandler, UiEventHandler } from "../events";
export interface UiComponent {