Vm working. simple interface built
- still need stack view - still ned to work with devices
This commit is contained in:
@@ -36,6 +36,8 @@ ace.config.setModuleLoader('ace/keyboard/sublime', () => import('ace-code/src/ke
|
||||
ace.config.setModuleLoader('ace/keyboard/vim', () => import('ace-code/src/keyboard/vim.js'));
|
||||
ace.config.setModuleLoader('ace/keyboard/vscode', () => import('ace-code/src/keyboard/vscode.js'));
|
||||
|
||||
ace.config.setModuleLoader('ace/range', () => import('ace-code/src/range'));
|
||||
|
||||
console.log("ace module loaders patched");
|
||||
|
||||
export { ace };
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Mode as IC10Mode } from "./ic10_mode.js";
|
||||
import * as one_dark from "ace-code/src/theme/one_dark";
|
||||
import { AceLanguageClient } from "ace-linters/build/ace-language-client";
|
||||
import { IC10EditorUI } from './ui.js';
|
||||
|
||||
import { Range } from 'ace-code/src/range.js';
|
||||
// to make sure language tools are loaded
|
||||
import _ace_ext_langue_tools from "ace-code/src/ext/language_tools";
|
||||
|
||||
@@ -21,139 +21,173 @@ async function setupLspWorker() {
|
||||
}
|
||||
|
||||
|
||||
function IC10Editor(session_id) {
|
||||
this.mode = new IC10Mode()
|
||||
class IC10Editor {
|
||||
constructor(session_id) {
|
||||
window.Editor = this;
|
||||
this.mode = new IC10Mode();
|
||||
|
||||
this.settings = {
|
||||
keyboard: "ace",
|
||||
cursor: "ace",
|
||||
fontSize: 16,
|
||||
relativeLineNumbers: false,
|
||||
};
|
||||
this.settings = {
|
||||
keyboard: "ace",
|
||||
cursor: "ace",
|
||||
fontSize: 16,
|
||||
relativeLineNumbers: false,
|
||||
};
|
||||
|
||||
this.editor = ace.edit('editor', {
|
||||
mode: this.mode,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
theme: "ace/theme/one_dark",
|
||||
fontSize: "16px",
|
||||
customScrollbar: true,
|
||||
firstLineNumber: 0,
|
||||
printMarginColumn: 52,
|
||||
});
|
||||
this.aceEditor = ace.edit('editor', {
|
||||
mode: this.mode,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
theme: "ace/theme/one_dark",
|
||||
fontSize: "16px",
|
||||
customScrollbar: false,
|
||||
firstLineNumber: 0,
|
||||
printMarginColumn: 52,
|
||||
});
|
||||
|
||||
this.sessions = {};
|
||||
this.sessions[session_id] = this.editor.getSession();
|
||||
this.active_session = session_id;
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
this.sessions = {};
|
||||
this.sessions[session_id] = this.aceEditor.getSession();
|
||||
this.active_session = session_id;
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
this.active_line_markers = {};
|
||||
this.active_line_markers[session_id] = null;
|
||||
|
||||
this.languageProvider = null;
|
||||
this.languageProvider = null;
|
||||
|
||||
this.ui = new IC10EditorUI(this);
|
||||
this.ui = new IC10EditorUI(this);
|
||||
|
||||
const self = this;
|
||||
const self = this;
|
||||
|
||||
App.session.onLoad((session) => {
|
||||
const updated_ids = [];
|
||||
for (const id in session.programs) {
|
||||
updated_ids.push(id);
|
||||
self.createOrSetSession(id, session.programs[id]);
|
||||
App.session.onLoad((session) => {
|
||||
const updated_ids = [];
|
||||
for (const id in session.programs) {
|
||||
updated_ids.push(id);
|
||||
self.createOrSetSession(id, session.programs[id]);
|
||||
}
|
||||
for (const id in self.sessions) {
|
||||
if (!updated_ids.includes(id)) {
|
||||
self.destroySession(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
App.session.loadFromFragment();
|
||||
|
||||
App.session.onActiveLine(session => {
|
||||
for (const id in Object.keys(session.programs)) {
|
||||
const active_line = session.getActiveLine(id);
|
||||
if (typeof active_line !== "undefined") {
|
||||
const marker = self.active_line_markers[id];
|
||||
if (marker) {
|
||||
self.sessions[id].removeMarker(marker);
|
||||
self.active_line_markers[id] = null;
|
||||
|
||||
}
|
||||
self.active_line_markers[id] = self.sessions[id].addMarker(new Range(active_line, 0, active_line, 1), "vm_ic_active_line", "fullLine", true);
|
||||
if (self.active_session == id) {
|
||||
// editor.resize(true);
|
||||
self.aceEditor.scrollToLine(active_line, true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
createOrSetSession(session_id, content) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
this.newSession(session_id);
|
||||
}
|
||||
for (const id in self.sessions) {
|
||||
if (!updated_ids.includes(id)) {
|
||||
self.destroySession(id);
|
||||
this.sessions[session_id].setValue(content);
|
||||
}
|
||||
|
||||
newSession(session_id) {
|
||||
if (this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
this.sessions[session_id] = ace.createEditSession("", this.mode);
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
}
|
||||
|
||||
setupLsp(lsp_worker) {
|
||||
const serverData = {
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: "ic10",
|
||||
type: "webworker",
|
||||
worker: lsp_worker,
|
||||
};
|
||||
// Create a language provider for web worker
|
||||
this.languageProvider = AceLanguageClient.for(serverData);
|
||||
this.languageProvider.registerEditor(this.aceEditor);
|
||||
|
||||
for (const session_id in this.sessions) {
|
||||
let options = this.mode.options ?? {};
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
activateSession(session_id) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
this.aceEditor.setSession(this.sessions[session_id]);
|
||||
this.active_session = session_id;
|
||||
let options = this.mode.options ?? {};
|
||||
if (this.languageProvider !== null) {
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
loadEditorSettings() {
|
||||
const saved_settings = window.localStorage.getItem("editorSettings");
|
||||
if (saved_settings !== null && saved_settings.length > 0) {
|
||||
try {
|
||||
const saved = JSON.parse(saved_settings);
|
||||
const temp = Object.assign({}, this.settings, saved);
|
||||
Object.assign(this.settings, temp);
|
||||
} catch (e) {
|
||||
console.log("error loading editor settings", e);
|
||||
}
|
||||
}
|
||||
})
|
||||
App.session.loadFromFragment();
|
||||
|
||||
}
|
||||
|
||||
IC10Editor.prototype.createOrSetSession = function(session_id, content) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
this.newSession(session_id);
|
||||
}
|
||||
this.sessions[session_id].setValue(content);
|
||||
}
|
||||
|
||||
IC10Editor.prototype.newSession = function(session_id) {
|
||||
if (this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
this.sessions[session_id] = ace.createEditSession("", this.mode);
|
||||
this.bindSession(session_id, this.sessions[session_id]);
|
||||
}
|
||||
|
||||
IC10Editor.prototype.setupLsp = function(lsp_worker) {
|
||||
const serverData = {
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: "ic10",
|
||||
type: "webworker",
|
||||
worker: lsp_worker,
|
||||
};
|
||||
// Create a language provider for web worker
|
||||
this.languageProvider = AceLanguageClient.for(serverData);
|
||||
this.languageProvider.registerEditor(this.editor);
|
||||
|
||||
for (const session_id in this.sessions) {
|
||||
let options = this.mode.options ?? {};
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IC10Editor.prototype.activateSession = function(session_id) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
saveEditorSettings() {
|
||||
const toSave = JSON.stringify(this.settings);
|
||||
window.localStorage.setItem("editorSettings", toSave);
|
||||
}
|
||||
this.editor.setSession(this.sessions[session_id]);
|
||||
let options = this.mode.options ?? {};
|
||||
if (this.languageProvider !== null) {
|
||||
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IC10Editor.prototype.loadEditorSettings = function() {
|
||||
const saved_settings = window.localStorage.getItem("editorSettings");
|
||||
if (saved_settings !== null && saved_settings.length > 0) {
|
||||
try {
|
||||
const saved = JSON.parse(saved_settings);
|
||||
const temp = Object.assign({}, this.settings, saved);
|
||||
Object.assign(this.settings, temp);
|
||||
} catch (e) {
|
||||
console.log("error loading editor settings", e);
|
||||
destroySession(session_id) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
if (!(Object.keys(this.sessions).length > 1)) {
|
||||
return false;
|
||||
}
|
||||
const session = this.sessions[session_id];
|
||||
delete this.sessions[session_id];
|
||||
if (this.active_session = session_id) {
|
||||
this.activateSession(Object.keys(this.sessions)[0]);
|
||||
}
|
||||
session.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
bindSession(session_id, session) {
|
||||
session.on('change', () => {
|
||||
var val = session.getValue();
|
||||
window.App.session.setProgramCode(session_id, val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
IC10Editor.prototype.saveEditorSettings = function() {
|
||||
const toSave = JSON.stringify(this.settings);
|
||||
window.localStorage.setItem("editorSettings", toSave);
|
||||
}
|
||||
|
||||
IC10Editor.prototype.destroySession = function(session_id) {
|
||||
if (!this.sessions.hasOwnProperty(session_id)) {
|
||||
return false;
|
||||
}
|
||||
if (!(Object.keys(this.sessions).length > 1)) {
|
||||
return false;
|
||||
}
|
||||
const session = this.sessions[session_id];
|
||||
delete this.sessions[session_id];
|
||||
if (this.active_session = session_id) {
|
||||
this.activateSession(Object.keys(this.sessions)[0]);
|
||||
}
|
||||
session.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
IC10Editor.prototype.bindSession = function(session_id, session) {
|
||||
session.on('change', () => {
|
||||
var val = session.getValue();
|
||||
window.App.session.setProgramCode(session_id, val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export { IC10Editor, setupLspWorker };
|
||||
|
||||
@@ -107,9 +107,9 @@ export class AsyncStreamQueue {
|
||||
|
||||
async next() {
|
||||
const done = false;
|
||||
console.log(`AsyncStream(${this.tag}) waiting for message`)
|
||||
// console.log(`AsyncStream(${this.tag}) waiting for message`)
|
||||
const value = await this.dequeue();
|
||||
console.log(`AsyncStream(${this.tag}) got message`, decoder.decode(value))
|
||||
// console.log(`AsyncStream(${this.tag}) got message`, decoder.decode(value))
|
||||
return { done, value };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,104 +1,111 @@
|
||||
import { ace } from "./ace";
|
||||
import { Offcanvas } from 'bootstrap';
|
||||
|
||||
function IC10EditorUI(ic10editor) {
|
||||
class IC10EditorUI {
|
||||
|
||||
const self = this;
|
||||
constructor(ic10editor) {
|
||||
|
||||
self.ic10editor = ic10editor;
|
||||
const self = this;
|
||||
|
||||
self.ic10editor.editor.commands.addCommand({
|
||||
name: "showSettingsMenu",
|
||||
description: "Show settings menu",
|
||||
bindKey: { win: "Ctrl-,", mac: "Command-," },
|
||||
exec: (_editor) => {
|
||||
const offCanvas = new Offcanvas(document.getElementById("editorSettings"));
|
||||
offCanvas.toggle();
|
||||
}
|
||||
});
|
||||
self.ic10editor = ic10editor;
|
||||
|
||||
ace.config.loadModule("ace/ext/keyboard_menu", function(module) {
|
||||
console.log("keybinding_menu loaded");
|
||||
module.init(self.ic10editor.editor);
|
||||
})
|
||||
self.ic10editor.aceEditor.commands.addCommand({
|
||||
name: "showSettingsMenu",
|
||||
description: "Show settings menu",
|
||||
bindKey: { win: "Ctrl-,", mac: "Command-," },
|
||||
exec: (_editor) => {
|
||||
const offCanvas = new Offcanvas(document.getElementById("editorSettings"));
|
||||
offCanvas.toggle();
|
||||
}
|
||||
});
|
||||
|
||||
self.ic10editor.loadEditorSettings();
|
||||
self.displayEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
self.reCalcEditorSize();
|
||||
window.addEventListener('resize', (e) => { self.reCalcEditorSize() });
|
||||
ace.config.loadModule("ace/ext/keyboard_menu", function (module) {
|
||||
console.log("keybinding_menu loaded");
|
||||
module.init(self.ic10editor.aceEditor);
|
||||
});
|
||||
|
||||
document.getElementsByName("editorKeybindRadio").forEach((el) => {
|
||||
el.addEventListener('change', (e) => {
|
||||
self.ic10editor.settings.keyboard = e.target.value;
|
||||
self.ic10editor.loadEditorSettings();
|
||||
self.displayEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
self.reCalcEditorSize();
|
||||
window.addEventListener('resize', (e) => { self.reCalcEditorSize(); });
|
||||
|
||||
document.getElementsByName("editorKeybindRadio").forEach((el) => {
|
||||
el.addEventListener('change', (e) => {
|
||||
self.ic10editor.settings.keyboard = e.target.value;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementsByName("editorCursorRadio").forEach((el) => {
|
||||
el.addEventListener('change', (e) => {
|
||||
self.ic10editor.settings.cursor = e.target.value;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
});
|
||||
});
|
||||
document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => {
|
||||
window.App.editorSettings.fontSize = e.target.value;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
})
|
||||
});
|
||||
|
||||
document.getElementsByName("editorCursorRadio").forEach((el) => {
|
||||
el.addEventListener('change', (e) => {
|
||||
self.ic10editor.settings.cursor = e.target.value;
|
||||
});
|
||||
document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => {
|
||||
window.App.editorSettings.relativeLineNumbers = e.target.checked;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
})
|
||||
});
|
||||
document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => {
|
||||
window.App.editorSettings.fontSize = e.target.value;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
});
|
||||
document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => {
|
||||
window.App.editorSettings.relativeLineNumbers = e.target.checked;
|
||||
self.ic10editor.saveEditorSettings();
|
||||
self.updateEditorSettings();
|
||||
})
|
||||
});
|
||||
|
||||
console.log(self.ic10editor.editor.getOption('keyboardHandler'));
|
||||
console.log(self.ic10editor.aceEditor.getOption('keyboardHandler'));
|
||||
|
||||
self.ic10editor.editor.setTheme("ace/theme/one_dark");
|
||||
ace.config.loadModule("ace/ext/statusbar", function(module) {
|
||||
const statusBar = new module.StatusBar(self.ic10editor.editor, document.getElementById("statusBar"));
|
||||
statusBar.updateStatus(self.ic10editor.editor);
|
||||
})
|
||||
self.ic10editor.aceEditor.setTheme("ace/theme/one_dark");
|
||||
ace.config.loadModule("ace/ext/statusbar", function (module) {
|
||||
const statusBar = new module.StatusBar(self.ic10editor.aceEditor, document.getElementById("statusBar"));
|
||||
statusBar.updateStatus(self.ic10editor.aceEditor);
|
||||
});
|
||||
|
||||
self.ic10editor.editor.setAutoScrollEditorIntoView(true);
|
||||
}
|
||||
self.ic10editor.aceEditor.setAutoScrollEditorIntoView(true);
|
||||
|
||||
IC10EditorUI.prototype.updateEditorSettings = function() {
|
||||
const settings = this.ic10editor.settings;
|
||||
const editor = this.ic10editor.editor;
|
||||
if (settings.keyboard === 'ace') {
|
||||
editor.setOption('keyboardHandler', null);
|
||||
} else {
|
||||
editor.setOption('keyboardHandler', `ace/keyboard/${settings.keyboard}`);
|
||||
}
|
||||
editor.setOption('cursorStyle', settings.cursor);
|
||||
editor.setOption('fontSize', `${settings.fontSize}px`);
|
||||
editor.setOption('relativeLineNumbers', settings.relativeLineNumbers);
|
||||
|
||||
updateEditorSettings() {
|
||||
const settings = this.ic10editor.settings;
|
||||
const editor = this.ic10editor.aceEditor;
|
||||
if (settings.keyboard === 'ace') {
|
||||
editor.setOption('keyboardHandler', null);
|
||||
} else {
|
||||
editor.setOption('keyboardHandler', `ace/keyboard/${settings.keyboard}`);
|
||||
}
|
||||
editor.setOption('cursorStyle', settings.cursor);
|
||||
editor.setOption('fontSize', `${settings.fontSize}px`);
|
||||
editor.setOption('relativeLineNumbers', settings.relativeLineNumbers);
|
||||
}
|
||||
|
||||
displayEditorSettings() {
|
||||
const settings = this.ic10editor.settings;
|
||||
document.getElementsByName("editorKeybindRadio").forEach((el) => {
|
||||
el.checked = el.value === settings.keyboard;
|
||||
});
|
||||
document.getElementsByName("editorCursorRadio").forEach((el) => {
|
||||
el.checked = el.value === settings.cursor;
|
||||
});
|
||||
document.getElementById("editorSettingsFontSize").value = settings.fontSize;
|
||||
document.getElementById("editorSettingsRelativeLineNumbers").checked = settings.relativeLineNumbers;
|
||||
}
|
||||
|
||||
reCalcEditorSize() {
|
||||
const editor = this.ic10editor.aceEditor;
|
||||
const navBar = document.getElementById("navBar");
|
||||
const statusBarContainer = document.getElementById("statusBarContainer");
|
||||
|
||||
const correction = navBar.offsetHeight + statusBarContainer.offsetHeight;
|
||||
const editorContainer = document.getElementById("editor");
|
||||
editorContainer.style.height = `calc( 100vh - ${correction}px - 0.5rem)`;
|
||||
editor.resize(true);
|
||||
}
|
||||
}
|
||||
|
||||
IC10EditorUI.prototype.displayEditorSettings = function() {
|
||||
const settings = this.ic10editor.settings;
|
||||
document.getElementsByName("editorKeybindRadio").forEach((el) => {
|
||||
el.checked = el.value === settings.keyboard;
|
||||
});
|
||||
document.getElementsByName("editorCursorRadio").forEach((el) => {
|
||||
el.checked = el.value === settings.cursor;
|
||||
});
|
||||
document.getElementById("editorSettingsFontSize").value = settings.fontSize;
|
||||
document.getElementById("editorSettingsRelativeLineNumbers").checked = settings.relativeLineNumbers;
|
||||
}
|
||||
|
||||
IC10EditorUI.prototype.reCalcEditorSize = function() {
|
||||
const editor = this.ic10editor.editor;
|
||||
const navBar = document.getElementById("navBar");
|
||||
const statusBarContainer = document.getElementById("statusBarContainer");
|
||||
|
||||
const correction = navBar.offsetHeight + statusBarContainer.offsetHeight;
|
||||
const editorContainer = document.getElementById("editor");
|
||||
editorContainer.style.height = `calc( 100vh - ${correction}px - 0.5rem)`;
|
||||
editor.resize(true);
|
||||
}
|
||||
|
||||
export { IC10EditorUI };
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { init } from "ic10emu_wasm";
|
||||
|
||||
import { IC10Editor, setupLspWorker } from "./editor";
|
||||
import { Session } from './session';
|
||||
import { VirtualMachine } from "./virtual_machine";
|
||||
|
||||
const App = {
|
||||
editor: null,
|
||||
vm: null,
|
||||
session: new Session()
|
||||
};
|
||||
|
||||
@@ -20,10 +20,10 @@ function docReady(fn) {
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
docReady(() => {
|
||||
|
||||
App.vm = new VirtualMachine();
|
||||
|
||||
App.editor = new IC10Editor();
|
||||
|
||||
setupLspWorker().then((worker) => {
|
||||
|
||||
@@ -37,7 +37,7 @@ move r2 100000.001
|
||||
# to get their documentation
|
||||
# vvvvvvvvvvvvvvv
|
||||
move r0 HASH("AccessCardBlack")
|
||||
beqz r1 test
|
||||
beqzal r1 test
|
||||
|
||||
# -2045627372 is the crc32 hash of a SolarPanel,
|
||||
# hover it to see the documentation!
|
||||
@@ -45,7 +45,7 @@ beqz r1 test
|
||||
move r1 -2045627372
|
||||
jal test
|
||||
move r1 $FF
|
||||
beqz 0 test
|
||||
beqzal 0 test
|
||||
move r1 %1000
|
||||
yield
|
||||
j main
|
||||
@@ -61,6 +61,9 @@ class Session {
|
||||
this._programs = {};
|
||||
this._save_timeout = 0;
|
||||
this._onLoadCallbacks = [];
|
||||
this._activeSession = 0;
|
||||
this._activeLines = {};
|
||||
this._onActiveLineCallbacks = [];
|
||||
this.loadFromFragment();
|
||||
|
||||
const self = this;
|
||||
@@ -77,6 +80,23 @@ class Session {
|
||||
Object.assign(this._programs, programs);
|
||||
}
|
||||
|
||||
get activeSession() {
|
||||
return this._activeSession;
|
||||
}
|
||||
|
||||
getActiveLine(id) {
|
||||
return this._activeLines[id];
|
||||
}
|
||||
|
||||
setActiveLine(id, line) {
|
||||
this._activeLines[id] = line;
|
||||
this._fireOnActiveLine();
|
||||
}
|
||||
|
||||
set activeLine(line) {
|
||||
this._activeLine = line;
|
||||
}
|
||||
|
||||
setProgramCode(id, code) {
|
||||
this._programs[id] = code;
|
||||
this.save();
|
||||
@@ -93,10 +113,25 @@ class Session {
|
||||
}
|
||||
}
|
||||
|
||||
onActiveLine(callback) {
|
||||
this._onActiveLineCallbacks.push(callback);
|
||||
}
|
||||
|
||||
_fireOnActiveLine() {
|
||||
for (const i in this._onActiveLineCallbacks) {
|
||||
const callback = this._onActiveLineCallbacks[i];
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this._save_timeout) clearTimeout(this._save_timeout);
|
||||
this._save_timeout = setTimeout(() => {
|
||||
this.saveToFragment();
|
||||
if (window.App.vm) {
|
||||
window.App.vm.updateCode();
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
201
www/src/js/virtual_machine/index.js
Normal file
201
www/src/js/virtual_machine/index.js
Normal file
@@ -0,0 +1,201 @@
|
||||
import { init } from "ic10emu_wasm";
|
||||
// import { Card } from 'bootstrap';
|
||||
|
||||
class VirtualMachine {
|
||||
|
||||
constructor() {
|
||||
const vm = init();
|
||||
|
||||
window.VM = this;
|
||||
|
||||
this.ic10vm = vm;
|
||||
this.ui = new VirtualMachineUI(this);
|
||||
|
||||
this.ics = {}
|
||||
const ics = this.ic10vm.ics;
|
||||
for (const id of Object.keys(ics)) {
|
||||
this.ics[id] = this.ic10vm.getDevice(parseInt(id));
|
||||
}
|
||||
this.updateCode()
|
||||
|
||||
|
||||
}
|
||||
|
||||
updateCode() {
|
||||
const progs = window.App.session.programs;
|
||||
for (const id of Object.keys(progs)) {
|
||||
const ic = this.ics[id];
|
||||
const prog = progs[id];
|
||||
if (ic && prog) {
|
||||
console.time(`CompileProgram_${id}`);
|
||||
this.ics[id].setCode(progs[id]);
|
||||
console.timeEnd(`CompileProgram_${id}`);
|
||||
}
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
|
||||
step() {
|
||||
const ic = this.ics[window.App.session.activeSession];
|
||||
if (ic) {
|
||||
try {
|
||||
ic.step();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
run() {
|
||||
const ic = this.ics[window.App.session.activeSession];
|
||||
if (ic) {
|
||||
try {
|
||||
ic.run(false);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
const ic = this.ics[window.App.session.activeSession];
|
||||
if (ic) {
|
||||
ic.reset();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
const ic = this.ics[window.App.session.activeSession];
|
||||
window.App.session.setActiveLine(window.App.session.activeSession, ic.ip);
|
||||
this.ui.update(ic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VirtualMachineUI {
|
||||
constructor(vm) {
|
||||
this.vm = vm
|
||||
this.state = new VMStateUI();
|
||||
this.registers = new VMRegistersUI();
|
||||
this.buildStackDisplay();
|
||||
|
||||
const self = this;
|
||||
|
||||
|
||||
document.getElementById("vmControlRun").addEventListener('click', (_event) => {
|
||||
self.vm.run();
|
||||
}, { capture: true });
|
||||
document.getElementById("vmControlStep").addEventListener('click', (_event) => {
|
||||
self.vm.step();
|
||||
}, { capture: true });
|
||||
document.getElementById("vmControlReset").addEventListener('click', (_event) => {
|
||||
self.vm.reset();
|
||||
}, { capture: true });
|
||||
|
||||
}
|
||||
|
||||
update(ic) {
|
||||
this.state.update(ic);
|
||||
this.registers.update(ic);
|
||||
}
|
||||
|
||||
|
||||
buildStackDisplay() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class VMStateUI {
|
||||
constructor() {
|
||||
const stateDom = document.getElementById("vmActiveICState");
|
||||
|
||||
this.tbl = document.createElement("table");
|
||||
this.tbl.classList.add("table");
|
||||
this.ipRow = this.tbl.insertRow();
|
||||
this.counterRow = this.tbl.insertRow()
|
||||
this.stateRow = this.tbl.insertRow()
|
||||
const ipTh = document.createElement("th");
|
||||
ipTh.appendChild(document.createTextNode("Instruction Pointer"));
|
||||
this.ipRow.appendChild(ipTh);
|
||||
this.instructionPointer = this.ipRow.insertCell();
|
||||
const conuterTh = document.createElement("th");
|
||||
conuterTh.appendChild(document.createTextNode("Last Run Operations"));
|
||||
this.counterRow.appendChild(conuterTh);
|
||||
this.instructionCounter = this.counterRow.insertCell();
|
||||
const stateTh = document.createElement("th");
|
||||
stateTh.appendChild(document.createTextNode("Last State"));
|
||||
this.stateRow.appendChild(stateTh);
|
||||
this.lastState = this.stateRow.insertCell();
|
||||
|
||||
stateDom.appendChild(this.tbl);
|
||||
}
|
||||
|
||||
update(ic) {
|
||||
if (ic) {
|
||||
this.instructionPointer.innerText = ic.ip.toString();
|
||||
this.instructionCounter.innerText = ic.instructionCount.toString();
|
||||
this.lastState.innerText = ic.state.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VMRegistersUI {
|
||||
constructor() {
|
||||
const regDom = document.getElementById("vmActiveRegisters");
|
||||
this.tbl = document.createElement("div");
|
||||
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-start", "align-self-center");
|
||||
this.regCels = [];
|
||||
for (var i = 0; i < 18; i++) {
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("vm_reg_cel");
|
||||
const cell = document.createElement("div");
|
||||
cell.classList.add("input-group", "input-group-sm")
|
||||
// cell.style.width = "30%";
|
||||
const nameLabel = document.createElement("span");
|
||||
nameLabel.innerText = `r${i}`;
|
||||
nameLabel.classList.add("input-group-text")
|
||||
cell.appendChild(nameLabel);
|
||||
const input = document.createElement("input");
|
||||
input.type = "text"
|
||||
input.value = 0;
|
||||
// input.size = 3;
|
||||
// input.style.width = 40;
|
||||
cell.appendChild(input);
|
||||
const aliasesLabel = document.createElement("span");
|
||||
aliasesLabel.classList.add("input-group-text")
|
||||
aliasesLabel.innerText = "\xa0";
|
||||
cell.appendChild(aliasesLabel);
|
||||
if (i == 16 ) {
|
||||
aliasesLabel.innerText = "sp";
|
||||
} else if (i == 17) {
|
||||
aliasesLabel.innerText = "ra";
|
||||
}
|
||||
this.regCels.push({
|
||||
cell,
|
||||
nameLabel,
|
||||
aliasesLabel,
|
||||
input,
|
||||
});
|
||||
container.appendChild(cell);
|
||||
this.tbl.appendChild(container);
|
||||
}
|
||||
regDom.appendChild(this.tbl);
|
||||
}
|
||||
|
||||
update(ic) {
|
||||
if (ic) {
|
||||
const registers = ic.registers;
|
||||
if (registers) {
|
||||
console.log(registers)
|
||||
for (var i = 0; i < registers.length; i++) {
|
||||
this.regCels[i].input.value = registers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { VirtualMachine }
|
||||
Reference in New Issue
Block a user