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:
@@ -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[];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ import { Offcanvas } from "bootstrap";
|
||||
import { VirtualMachine, VirtualMachineUI } from ".";
|
||||
import { DeviceRef, VM } from "ic10emu_wasm";
|
||||
|
||||
|
||||
|
||||
|
||||
class VMDeviceUI {
|
||||
ui: VirtualMachineUI;
|
||||
summary: HTMLDivElement;
|
||||
|
||||
@@ -357,7 +357,7 @@ class VMRegistersUI {
|
||||
});
|
||||
}
|
||||
}
|
||||
this.updateAliases();
|
||||
// this.updateAliases();
|
||||
}
|
||||
|
||||
updateAliases() {
|
||||
|
||||
90
www/src/js/virtual_machine/registers.ts
Normal file
90
www/src/js/virtual_machine/registers.ts
Normal 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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
82
www/src/js/virtual_machine/stack.ts
Normal file
82
www/src/js/virtual_machine/stack.ts
Normal 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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user