From 41a9e6da86e4dcce8963b618ee755bc3bff6f632 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 8 Apr 2024 01:55:15 -0700 Subject: [PATCH] Registers and stack pages are back (still need to hook for changing values) Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- ic10emu_wasm/src/types.ts | 84 +++++++++++---------- www/src/js/virtual_machine/base_device.ts | 87 ++++++++++++++++++++++ www/src/js/virtual_machine/controls.ts | 85 ++++++--------------- www/src/js/virtual_machine/device.ts | 3 + www/src/js/virtual_machine/index.ts | 2 +- www/src/js/virtual_machine/registers.ts | 90 +++++++++++++++++++++++ www/src/js/virtual_machine/stack.ts | 82 +++++++++++++++++++++ www/src/js/virtual_machine/ui.ts | 30 +++++++- 8 files changed, 358 insertions(+), 105 deletions(-) create mode 100644 www/src/js/virtual_machine/registers.ts create mode 100644 www/src/js/virtual_machine/stack.ts diff --git a/ic10emu_wasm/src/types.ts b/ic10emu_wasm/src/types.ts index af96e6b..12f6b2f 100644 --- a/ic10emu_wasm/src/types.ts +++ b/ic10emu_wasm/src/types.ts @@ -1,6 +1,6 @@ export type FieldType = "Read" | "Write" | "ReadWrite"; -export interface LogicField { +export interface LogicField { field_type: FieldType; value: number; } @@ -49,17 +49,51 @@ export type Reagents = Map>; export type Connection = { CableNetwork: number } | "Other"; -export type Alias = - | { RegisterSpec: { indirection: number; target: number } } - | { - DeviceSpec: { - device: - | "Db" - | { Numbered: number } - | { Indirect: { indirection: number; target: number } }; - }; - connection: number | undefined; - }; +export type RegisterSpec = { + RegisterSpec: { indirection: number; target: number }; +}; +export type DeviceSpec = { + DeviceSpec: { + device: + | "Db" + | { Numbered: number } + | { Indirect: { indirection: number; target: number } }; + }; + connection: number | undefined; +}; +export type LogicType = { LogicType: string }; +export type SlotLogicType = { SlotLogicType: string }; +export type BatchMode = { BatchMode: string }; +export type ReagentMode = { ReagentMode: string }; +export type Identifier = { Identifier: { name: string } }; + +export type NumberFloat = { Float: number }; +export type NumberBinary = { Binary: number }; +export type NumberHexadecimal = { Hexadecimal: number }; +export type NumberConstant = { Constant: number }; +export type NumberString = { String: string }; +export type NumberEnum = { Enum: number }; + +export type NumberOperand = { + Number: + | NumberFloat + | NumberBinary + | NumberHexadecimal + | NumberConstant + | NumberString + | NumberEnum; +}; +export type Operand = + | RegisterSpec + | DeviceSpec + | NumberOperand + | LogicType + | SlotLogicType + | BatchMode + | ReagentMode + | Identifier; + +export type Alias = RegisterSpec | DeviceSpec; export type Aliases = Map; @@ -67,32 +101,6 @@ export type Defines = Map; export type Pins = (number | undefined)[]; -export type Operand = - | { RegisterSpec: { indirection: number; target: number } } - | { - DeviceSpec: { - device: - | "Db" - | { Numbered: number } - | { Indirect: { indirection: number; target: number } }; - }; - connection: number | undefined; - } - | { - Number: - | { Float: number } - | { Binary: number } - | { Hexadecimal: number } - | { Constant: number } - | { String: string } - | { Enum: number }; - } - | { LogicType: string } - | { SlotLogicType: string } - | { BatchMode: string } - | { ReagentMode: string } - | { Identifier: { name: string } }; - export interface Instruction { instruction: string; operands: Operand[]; diff --git a/www/src/js/virtual_machine/base_device.ts b/www/src/js/virtual_machine/base_device.ts index 9536045..8dbd710 100644 --- a/www/src/js/virtual_machine/base_device.ts +++ b/www/src/js/virtual_machine/base_device.ts @@ -6,6 +6,12 @@ import { Reagents, Slot, Connection, + ICError, + Registers, + Stack, + Aliases, + Defines, + Pins, } from "ic10emu_wasm"; import { structuralEqual } from "../utils"; @@ -20,6 +26,15 @@ export class VMBaseDevice extends BaseElement { @state() accessor slots: Slot[]; @state() accessor reagents: Reagents; @state() accessor connections: Connection[]; + @state() accessor icIP: number; + @state() accessor icOpCount: number; + @state() accessor icState: string; + @state() accessor errors: ICError[]; + @state() accessor registers: Registers | null; + @state() accessor stack: Stack | null; + @state() accessor aliases: Aliases | null; + @state() accessor defines: Defines | null; + @state() accessor pins: Pins | null; constructor() { super(); @@ -74,5 +89,77 @@ export class VMBaseDevice extends BaseElement { if (!structuralEqual(this.connections, connections)) { this.connections = connections; } + this.updateIC(); + } + + updateIC() { + const ip = this.device.ip!; + if (this.icIP !== ip) { + this.icIP = ip; + } + const opCount = this.device.instructionCount!; + if (this.icOpCount !== opCount) { + this.icOpCount = opCount; + } + const state = this.device.state!; + if (this.icState !== state) { + this.icState = state; + } + const errors = this.device.program!.errors ?? null; + if (!structuralEqual(this.errors, errors)) { + this.errors = errors; + } + const registers = this.device.registers ?? null; + if (!structuralEqual(this.registers, registers)) { + this.registers = registers; + } + const stack = this.device.stack ?? null; + if (!structuralEqual(this.stack, stack)) { + this.stack = stack; + } + const aliases = this.device.aliases ?? null; + if (!structuralEqual(this.aliases, aliases)) { + this.aliases = aliases; + } + const defines = this.device.defines ?? null; + if (!structuralEqual(this.defines, defines)) { + this.defines = defines; + } + const pins = this.device.pins ?? null; + if(!structuralEqual(this.pins, pins)) { + this.pins = pins; + } } } + +export class VMActiveIC extends VMBaseDevice { + + constructor() { + super(); + this.deviceID = window.App!.session.activeIC; + } + + connectedCallback(): void { + const root = super.connectedCallback(); + window.VM?.addEventListener( + "vm-run-ic", + this._handleDeviceModified.bind(this), + ); + window.App?.session.addEventListener( + "session-active-ic", + this._handleActiveIC.bind(this), + ); + this.updateIC(); + return root; + } + + _handleActiveIC(e: CustomEvent) { + const id = e.detail; + if (this.deviceID !== id) { + this.deviceID = id; + this.device = window.VM!.devices.get(this.deviceID)!; + } + this.updateDevice(); + } + +} diff --git a/www/src/js/virtual_machine/controls.ts b/www/src/js/virtual_machine/controls.ts index e345095..fc38c9e 100644 --- a/www/src/js/virtual_machine/controls.ts +++ b/www/src/js/virtual_machine/controls.ts @@ -1,8 +1,7 @@ import { html, css } from "lit"; -import { customElement, property, query, state } from "lit/decorators.js"; +import { customElement } from "lit/decorators.js"; import { defaultCss } from "../components"; -import { DeviceRef, ICError } from "ic10emu_wasm"; -import { VMBaseDevice } from "./base_device"; +import { VMActiveIC } from "./base_device"; import { structuralEqual } from "../utils"; import "@shoelace-style/shoelace/dist/components/card/card.js"; @@ -13,12 +12,7 @@ import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js"; import "@shoelace-style/shoelace/dist/components/divider/divider.js"; @customElement("vm-ic-controls") -export class VMICControls extends VMBaseDevice { - @state() accessor icIP: number; - @state() accessor icOpCount: number; - @state() accessor icState: string; - @state() accessor errors: ICError[]; - +export class VMICControls extends VMActiveIC { static styles = [ ...defaultCss, css` @@ -27,7 +21,7 @@ export class VMICControls extends VMBaseDevice { .card { margin-left: 1rem; margin-right: 1rem; - margin-top: 1rem; + margin-top: 0.5rem; } .controls { display: flex; @@ -54,55 +48,6 @@ export class VMICControls extends VMBaseDevice { this.deviceID = window.App!.session.activeIC; } - connectedCallback(): void { - const root = super.connectedCallback(); - window.VM?.addEventListener( - "vm-run-ic", - this._handleDeviceModified.bind(this), - ); - window.App?.session.addEventListener( - "session-active-ic", - this._handleActiveIC.bind(this), - ); - this.updateIC(); - return root; - } - - _handleActiveIC(e: CustomEvent) { - const id = e.detail; - if (this.deviceID !== id) { - this.deviceID = id; - this.device = window.VM!.devices.get(this.deviceID)!; - } - this.updateDevice(); - } - - updateIC() { - const ip = this.device.ip!; - if (this.icIP !== ip) { - this.icIP = ip; - } - const opCount = this.device.instructionCount!; - if (this.icOpCount !== opCount) { - this.icOpCount = opCount; - } - const state = this.device.state!; - if (this.icState !== state) { - this.icState = state; - } - const errors = this.device.program!.errors; - if (!structuralEqual(this.errors, errors)) { - this.errors = errors; - } - } - - updateDevice(): void { - super.updateDevice(); - this.updateIC(); - } - - protected firstUpdated(): void {} - protected render() { return html` @@ -111,13 +56,21 @@ export class VMICControls extends VMBaseDevice { - + Run - + Step - + Reset { if (val === Number.NEGATIVE_INFINITY || val === Number.POSITIVE_INFINITY || Number.isNaN(val)) { return "text"; } else { return "number"; } }; + const displayVal = (val: number) => { + if (Number.POSITIVE_INFINITY === val) { + return "∞"; + } else if (Number.NEGATIVE_INFINITY === val) { + return "-∞"; + } else { + return val.toString(); + } + }; + const validation = + "[-+]?(([0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?)|((\\.[0-9]+)([eE][+-]?[0-9]+)?)|([iI][nN][fF][iI][nN][iI][tT][yY]))"; + const registerAliases: [string, number][] = ( + ( + [...(this.aliases ?? [])].filter( + ([_alias, target]) => + "RegisterSpec" in target && target.RegisterSpec.indirection === 0, + ) as [string, RegisterSpec][] + ).map(([alias, target]) => [alias, target.RegisterSpec.target]) as [ + string, + number, + ][] + ).concat(VMICRegisters.defaultAliases); + return html` + +
+ ${this.registers?.map((val, index) => { + const aliases = registerAliases + .filter(([_alias, target]) => index === target) + .map(([alias, _target]) => alias); + return html` + r${index} + ${aliases.join(", ")} + `; + })} +
+
+ `; + } +} diff --git a/www/src/js/virtual_machine/stack.ts b/www/src/js/virtual_machine/stack.ts new file mode 100644 index 0000000..b859a40 --- /dev/null +++ b/www/src/js/virtual_machine/stack.ts @@ -0,0 +1,82 @@ +import { html, css } from "lit"; +import { customElement } from "lit/decorators.js"; +import { defaultCss } from "../components"; +import { VMActiveIC } from "./base_device"; + +import "@shoelace-style/shoelace/dist/components/card/card.js"; +import "@shoelace-style/shoelace/dist/components/icon/icon.js"; +import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js"; +import "@shoelace-style/shoelace/dist/components/input/input.js"; +import { RegisterSpec } from "ic10emu_wasm"; + +@customElement("vm-ic-stack") +export class VMICStack extends VMActiveIC { + static styles = [ + ...defaultCss, + css` + :host { + } + .card { + --padding: 0.5rem; + --sl-input-font-size-small: 0.75em; + } + .card-body { + display: flex; + flex-flow: row wrap; + max-height: 15rem; + overflow-y: auto; + } + .stack-input { + width: 8rem; + } + .stack-pointer::part(prefix) { + background: rgb(121, 82, 179); + } + sl-input::part(prefix) { + padding-right: 0.25rem; + } + `, + ]; + + constructor() { + super(); + } + + protected render() { + const displayVal = (val: number) => { + if (Number.POSITIVE_INFINITY === val) { + return "∞"; + } else if (Number.NEGATIVE_INFINITY === val) { + return "-∞"; + } else { + return val.toString(); + } + }; + const validation = + "[-+]?(([0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?)|((\\.[0-9]+)([eE][+-]?[0-9]+)?)|([iI][nN][fF][iI][nN][iI][tT][yY]))"; + const sp = this.registers![16]; + + + return html` + +
+ ${this.stack?.map((val, index) => { + return html` + + ${index} + + `; + })} +
+
+ `; + } +} diff --git a/www/src/js/virtual_machine/ui.ts b/www/src/js/virtual_machine/ui.ts index 31cf7f7..ee30988 100644 --- a/www/src/js/virtual_machine/ui.ts +++ b/www/src/js/virtual_machine/ui.ts @@ -1,17 +1,43 @@ import { HTMLTemplateResult, html, css } from "lit"; import { customElement, property, query } from "lit/decorators.js"; import { BaseElement, defaultCss } from "../components"; +import "@shoelace-style/shoelace/dist/components/details/details.js"; -import "./controls.ts"; +import "./controls"; +import "./registers"; +import "./stack"; @customElement("vm-ui") export class VMUI extends BaseElement { + static styles = [ + ...defaultCss, + css` + sl-details { + margin-left: 1rem; + margin-right: 1rem; + } + sl-details::part(header) { + padding: 0.3rem; + } + sl-details::part(content) { + padding: 0.5rem; + } + `, + ]; constructor() { super(); } protected render() { - return html``; + return html` + + + + + + + + `; } }