Registers and stack pages are back

(still need to hook for changing values)

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-04-08 01:55:15 -07:00
parent b609b2e94b
commit 41a9e6da86
8 changed files with 358 additions and 105 deletions

View File

@@ -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<string, Map<number, number>>;
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<string, Alias>;
@@ -67,32 +101,6 @@ export type Defines = Map<string, number>;
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[];

View File

@@ -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();
}
}

View File

@@ -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`
<sl-card class="card">
@@ -111,13 +56,21 @@ export class VMICControls extends VMBaseDevice {
<sl-tooltip
content="Run the active IC through one tick (128 operations)"
>
<sl-button size="small" variant="primary" @click=${this._handleRunClick}>
<sl-button
size="small"
variant="primary"
@click=${this._handleRunClick}
>
<span>Run</span>
<sl-icon name="play" label="Run" slot="prefix"></sl-icon>
</sl-button>
</sl-tooltip>
<sl-tooltip content="Run the active IC through a single operations">
<sl-button size="small" variant="success" @click=${this._handleStepClick}>
<sl-button
size="small"
variant="success"
@click=${this._handleStepClick}
>
<span>Step</span>
<sl-icon
name="chevron-bar-right"
@@ -127,7 +80,11 @@ export class VMICControls extends VMBaseDevice {
</sl-button>
</sl-tooltip>
<sl-tooltip content="Reset the active IC">
<sl-button size="small" variant="warning" @click=${this._handleResetClick}>
<sl-button
size="small"
variant="warning"
@click=${this._handleResetClick}
>
<span>Reset</span>
<sl-icon
name="arrow-clockwise"
@@ -182,9 +139,9 @@ export class VMICControls extends VMBaseDevice {
window.VM?.run();
}
_handleStepClick() {
window.VM?.step()
window.VM?.step();
}
_handleResetClick() {
window.VM?.reset()
window.VM?.reset();
}
}

View File

@@ -2,6 +2,9 @@ import { Offcanvas } from "bootstrap";
import { VirtualMachine, VirtualMachineUI } from ".";
import { DeviceRef, VM } from "ic10emu_wasm";
class VMDeviceUI {
ui: VirtualMachineUI;
summary: HTMLDivElement;

View File

@@ -357,7 +357,7 @@ class VMRegistersUI {
});
}
}
this.updateAliases();
// this.updateAliases();
}
updateAliases() {

View File

@@ -0,0 +1,90 @@
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-registers")
export class VMICRegisters 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: 8rem;
overflow-y: auto;
}
.reg-input {
width: 10rem;
}
`,
];
static defaultAliases: [string, number][] = [
["sp", 16],
["ra", 17],
];
constructor() {
super();
}
protected render() {
// const inputTypeFromVal = (val: number) => { 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`
<sl-card class="card">
<div class="card-body">
${this.registers?.map((val, index) => {
const aliases = registerAliases
.filter(([_alias, target]) => index === target)
.map(([alias, _target]) => alias);
return html` <sl-input
type="text"
value="${displayVal(val)}"
pattern="${validation}"
size="small"
class="reg-input"
>
<span slot="prefix">r${index}</span>
<span slot="suffix">${aliases.join(", ")}</span>
</sl-input>`;
})}
</div>
</sl-card>
`;
}
}

View File

@@ -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`
<sl-card class="card">
<div class="card-body">
${this.stack?.map((val, index) => {
return html` <sl-input
type="text"
value="${displayVal(val)}"
pattern="${validation}"
size="small"
class="stack-input ${sp === index ? "stack-pointer" : "" }"
>
<span
slot="prefix"
>
${index}
</span>
</sl-input>`;
})}
</div>
</sl-card>
`;
}
}

View File

@@ -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`<vm-ic-controls>`;
return html`
<vm-ic-controls></vm-ic-controls>
<sl-details summary="Registers">
<vm-ic-registers></vm-ic-registers>
</sl-details>
<sl-details summary="Stack">
<vm-ic-stack></vm-ic-stack>
</sl-details>
`;
}
}