Webpack copy. add windows
This commit is contained in:
parent
8a38dded92
commit
1f6a95c253
194
package-lock.json
generated
194
package-lock.json
generated
|
@ -7,6 +7,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"css-loader": "^6.10.0",
|
"css-loader": "^6.10.0",
|
||||||
"eslint": "^8.44.0",
|
"eslint": "^8.44.0",
|
||||||
"sass": "^1.71.0",
|
"sass": "^1.71.0",
|
||||||
|
@ -262,6 +263,18 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@sindresorhus/merge-streams": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.56.2",
|
"version": "8.56.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||||
|
@ -753,6 +766,45 @@
|
||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ajv-formats": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ajv": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats/node_modules/ajv": {
|
||||||
|
"version": "8.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||||
|
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/ajv-keywords": {
|
"node_modules/ajv-keywords": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||||
|
@ -1028,6 +1080,127 @@
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/copy-webpack-plugin": {
|
||||||
|
"version": "12.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz",
|
||||||
|
"integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"glob-parent": "^6.0.1",
|
||||||
|
"globby": "^14.0.0",
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"schema-utils": "^4.2.0",
|
||||||
|
"serialize-javascript": "^6.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"webpack": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/ajv": {
|
||||||
|
"version": "8.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||||
|
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/ajv-keywords": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.8.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/globby": {
|
||||||
|
"version": "14.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz",
|
||||||
|
"integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@sindresorhus/merge-streams": "^2.1.0",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"ignore": "^5.2.4",
|
||||||
|
"path-type": "^5.0.0",
|
||||||
|
"slash": "^5.1.0",
|
||||||
|
"unicorn-magic": "^0.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/path-type": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/schema-utils": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.9",
|
||||||
|
"ajv": "^8.9.0",
|
||||||
|
"ajv-formats": "^2.1.1",
|
||||||
|
"ajv-keywords": "^5.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/copy-webpack-plugin/node_modules/slash": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -2474,6 +2647,15 @@
|
||||||
"node": ">= 10.13.0"
|
"node": ">= 10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.8",
|
"version": "1.22.8",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
|
@ -2985,6 +3167,18 @@
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/unicorn-magic": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"css-loader": "^6.10.0",
|
"css-loader": "^6.10.0",
|
||||||
"eslint": "^8.44.0",
|
"eslint": "^8.44.0",
|
||||||
"sass": "^1.71.0",
|
"sass": "^1.71.0",
|
||||||
|
|
|
@ -72,6 +72,12 @@ export enum UiEvent {
|
||||||
// Ui Events
|
// Ui Events
|
||||||
EditOn,
|
EditOn,
|
||||||
EditOff,
|
EditOff,
|
||||||
|
ConsoleOn,
|
||||||
|
ConsoleOff,
|
||||||
|
ExplainerOn,
|
||||||
|
ExplainerOff,
|
||||||
|
VideoOn,
|
||||||
|
VideoOff,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UiEventMap {
|
interface UiEventMap {
|
||||||
|
|
BIN
src/include/explainer.png
Normal file
BIN
src/include/explainer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
38
src/include/index.html
Normal file
38
src/include/index.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script src="main.js"></script>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Virtual 8-Bit Computer</title>
|
||||||
|
</head>
|
||||||
|
<body id="root">
|
||||||
|
<main>
|
||||||
|
<div id="grid">
|
||||||
|
<div id="title">VIRTUAL 8-BIT COMPUTER</div>
|
||||||
|
<div id="registers"></div>
|
||||||
|
<div id="labelcontainer">
|
||||||
|
<div id="registers_label">←REGISTERS</div>
|
||||||
|
<div id="memory_label">MEMORY↯</div>
|
||||||
|
</div>
|
||||||
|
<div id="memory"></div>
|
||||||
|
|
||||||
|
<div id="controls_bar">
|
||||||
|
<span id="controls_buttons"></span>
|
||||||
|
<label for="binary_upload" class="button">Load Binary</label>
|
||||||
|
<input id="binary_upload" name="binary_upload" id="binary_upload" style="display: none" type="file" />
|
||||||
|
<button type="button" id="save_button">Save</button>
|
||||||
|
<button type="button" id="edit_button"></button>
|
||||||
|
</div>
|
||||||
|
<span id="cycles"></span>
|
||||||
|
</div>
|
||||||
|
<div id="window_box">
|
||||||
|
<div id="instruction_explainer"></div>
|
||||||
|
<div id="printout"></div>
|
||||||
|
<div id="tv"></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<pre id="ISA"></pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
src/include/pencil.png
Normal file
BIN
src/include/pencil.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
src/include/texout.png
Normal file
BIN
src/include/texout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
src/include/tv.png
Normal file
BIN
src/include/tv.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -10,7 +10,7 @@ import { generate_isa } from "./isaGenerator";
|
||||||
import { UI } from "./ui";
|
import { UI } from "./ui";
|
||||||
import { u8 } from "./num";
|
import { u8 } from "./num";
|
||||||
|
|
||||||
import "./style.scss";
|
import "./style/style.scss";
|
||||||
import { CpuEvent } from "./events";
|
import { CpuEvent } from "./events";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
310
src/style.scss
310
src/style.scss
|
@ -1,310 +0,0 @@
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
font-size: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--Border: #ffff00;
|
|
||||||
--mem-instruction: #3af78f;
|
|
||||||
--mem-memory: #ff26a8;
|
|
||||||
--mem-register: #9e0ef7;
|
|
||||||
--mem-constant: #19f7f0;
|
|
||||||
--mem-invalid: #bf2e2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: #808080;
|
|
||||||
background-color: black;
|
|
||||||
font-size: 2.5em;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
#labelcontainer {
|
|
||||||
column-gap: 18px;
|
|
||||||
font-size: 0.85em;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
user-select: none;
|
|
||||||
grid-area: regmemlabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main {
|
|
||||||
justify-content: center;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: min-content max-content max-content min-content 500px;
|
|
||||||
grid-template-rows: min-content 1.5fr 10px 2fr 2fr min-content;
|
|
||||||
grid-template-areas:
|
|
||||||
"cycles registers regmemlabel . explainer "
|
|
||||||
"title . . ribbon explainer "
|
|
||||||
"title . . ribbon ."
|
|
||||||
"title . . ribbon printout "
|
|
||||||
"title . . . printout "
|
|
||||||
". buttons buttons . .";
|
|
||||||
#memory {
|
|
||||||
grid-column: 2/4;
|
|
||||||
grid-row: 2/6;
|
|
||||||
}
|
|
||||||
#cycles {
|
|
||||||
grid-area: cycles;
|
|
||||||
text-align: left;
|
|
||||||
align-self: center;
|
|
||||||
font-size: 0.48em;
|
|
||||||
}
|
|
||||||
#title {
|
|
||||||
grid-area: title;
|
|
||||||
writing-mode: vertical-lr;
|
|
||||||
text-align: left;
|
|
||||||
user-select: none;
|
|
||||||
transform: scale(-1, -1);
|
|
||||||
}
|
|
||||||
#ribbon_menu {
|
|
||||||
grid-area: ribbon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#printout {
|
|
||||||
border: 4px dashed var(--Border);
|
|
||||||
grid-area: printout;
|
|
||||||
padding: 10px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
word-break: break-all;
|
|
||||||
max-height: 200px;
|
|
||||||
overflow-x: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#instruction_explainer {
|
|
||||||
grid-area: explainer;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5px;
|
|
||||||
border: 5px dashed var(--Border);
|
|
||||||
#expl_box {
|
|
||||||
padding-inline: 20px;
|
|
||||||
padding-block-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#expl_text {
|
|
||||||
font-size: 0.6em;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#expl_icon {
|
|
||||||
margin-inline-end: 0.5em;
|
|
||||||
font-size: 30px;
|
|
||||||
padding: 5px;
|
|
||||||
color: var(--color);
|
|
||||||
outline: 3px dashed var(--color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.invalid {
|
|
||||||
--color: var(--mem-invalid);
|
|
||||||
}
|
|
||||||
.constant {
|
|
||||||
--color: var(--mem-constant);
|
|
||||||
}
|
|
||||||
.register {
|
|
||||||
--color: var(--mem-register);
|
|
||||||
}
|
|
||||||
.memory {
|
|
||||||
--color: var(--mem-memory);
|
|
||||||
}
|
|
||||||
.instruction {
|
|
||||||
--color: var(--mem-instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
div[contenteditable] {
|
|
||||||
&.caret_selected {
|
|
||||||
box-sizing: border-box;
|
|
||||||
outline: 2px solid red;
|
|
||||||
}
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pending_edit {
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
#memory {
|
|
||||||
grid-area: memory;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(16, min-content);
|
|
||||||
gap: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
border: 5px solid yellow;
|
|
||||||
|
|
||||||
div {
|
|
||||||
user-select: none;
|
|
||||||
caret-color: transparent;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.program_counter {
|
|
||||||
outline: 3px solid orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.instruction_argument,
|
|
||||||
.current_instruction {
|
|
||||||
outline: 3px dashed var(--color);
|
|
||||||
}
|
|
||||||
.recent_edit {
|
|
||||||
color: lime;
|
|
||||||
}
|
|
||||||
div.last_access {
|
|
||||||
color: orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invalid {
|
|
||||||
&::after {
|
|
||||||
user-select: none;
|
|
||||||
float: right;
|
|
||||||
position: relative;
|
|
||||||
right: 0.5em;
|
|
||||||
width: 0px;
|
|
||||||
font-size: 0.5em;
|
|
||||||
content: "!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div#main.editor {
|
|
||||||
#memory,
|
|
||||||
#registers {
|
|
||||||
border-style: dashed;
|
|
||||||
div {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ribbon_menu {
|
|
||||||
margin-inline: 8px;
|
|
||||||
.editor_toggle {
|
|
||||||
//TODO CHANGE COLORS WHen
|
|
||||||
&.off {
|
|
||||||
}
|
|
||||||
&.on {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#registers {
|
|
||||||
grid-area: registers;
|
|
||||||
border: 5px solid yellow;
|
|
||||||
border-bottom: none !important;
|
|
||||||
|
|
||||||
grid-template-columns: repeat(8, min-content);
|
|
||||||
max-width: fit-content;
|
|
||||||
display: grid;
|
|
||||||
column-gap: 5px;
|
|
||||||
color: lightgray;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
div {
|
|
||||||
max-height: min-content;
|
|
||||||
// margin-block: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
label.button {
|
|
||||||
border: 4px solid yellow;
|
|
||||||
color: gray;
|
|
||||||
margin: 10px;
|
|
||||||
margin-inline: 0px;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
font-family: monospace;
|
|
||||||
background-color: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled {
|
|
||||||
border: 4px solid rgb(255, 255, 128);
|
|
||||||
color: orange;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"]:disabled {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.no_style {
|
|
||||||
border: none;
|
|
||||||
color: inherit;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-size: inherit;
|
|
||||||
background-color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover,
|
|
||||||
label.button:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls_bar {
|
|
||||||
grid-area: buttons;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
#controls_buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"] {
|
|
||||||
background-color: transparent;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
margin: 18px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"]:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
// 2024 and we still have to do this
|
|
||||||
input[type="range"]::-webkit-slider-runnable-track {
|
|
||||||
height: 0.5em;
|
|
||||||
cursor: pointer;
|
|
||||||
background: yellow;
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
input[type="range"]::-webkit-slider-thumb {
|
|
||||||
border: 4px solid yellow;
|
|
||||||
background-color: black;
|
|
||||||
height: 42px;
|
|
||||||
width: 20px;
|
|
||||||
border-radius: 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: -18px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"]:focus::-webkit-slider-runnable-track {
|
|
||||||
background: yellow;
|
|
||||||
}
|
|
||||||
input[type="range"]::-moz-range-track {
|
|
||||||
height: 0.5em;
|
|
||||||
cursor: pointer;
|
|
||||||
background: yellow;
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
input[type="range"]::-moz-range-thumb {
|
|
||||||
border: 4px solid yellow;
|
|
||||||
background-color: black;
|
|
||||||
height: 36px;
|
|
||||||
width: 16px;
|
|
||||||
border-radius: 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
101
src/style/buttons.scss
Normal file
101
src/style/buttons.scss
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
@use "sass:math";
|
||||||
|
|
||||||
|
button,
|
||||||
|
label.button {
|
||||||
|
border: 4px solid yellow;
|
||||||
|
color: gray;
|
||||||
|
margin: 10px;
|
||||||
|
margin-inline: 0px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
border: 4px solid rgb(255, 255, 128);
|
||||||
|
color: orange;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.nostyle {
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
label.button:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#controls_bar {
|
||||||
|
grid-area: buttons;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
#controls_buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"] {
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
margin: 18px 0;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2024 and we still have to do this
|
||||||
|
|
||||||
|
@mixin sliderTrack {
|
||||||
|
height: 0.5em;
|
||||||
|
cursor: pointer;
|
||||||
|
background: yellow;
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin sliderThumb($height, $width) {
|
||||||
|
border: 4px solid yellow;
|
||||||
|
background-color: black;
|
||||||
|
height: $height;
|
||||||
|
width: $width;
|
||||||
|
border-radius: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
@include sliderTrack;
|
||||||
|
}
|
||||||
|
input[type="range"]::-moz-range-track {
|
||||||
|
@include sliderTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
@include sliderThumb(42px, 20px);
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin-top: -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-thumb {
|
||||||
|
@include sliderThumb(36px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]:focus::-webkit-slider-runnable-track {
|
||||||
|
background: yellow;
|
||||||
|
}
|
69
src/style/memory_registers.scss
Normal file
69
src/style/memory_registers.scss
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#memory {
|
||||||
|
grid-template-columns: repeat(16, min-content);
|
||||||
|
|
||||||
|
.program_counter {
|
||||||
|
outline: 3px solid orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instruction_argument,
|
||||||
|
.current_instruction {
|
||||||
|
outline: 3px dashed var(--color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid {
|
||||||
|
&::after {
|
||||||
|
user-select: none;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
right: 0.5em;
|
||||||
|
width: 0px;
|
||||||
|
font-size: 0.5em;
|
||||||
|
content: "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#registers {
|
||||||
|
border-bottom: none !important;
|
||||||
|
|
||||||
|
grid-template-columns: repeat(8, min-content);
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#labelcontainer {
|
||||||
|
column-gap: 18px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.celled_viewer {
|
||||||
|
display: grid;
|
||||||
|
max-width: fit-content;
|
||||||
|
gap: 5px;
|
||||||
|
border: 5px solid yellow;
|
||||||
|
padding: 10px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
div {
|
||||||
|
.pending_edit {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
&.recent_edit {
|
||||||
|
color: lime;
|
||||||
|
}
|
||||||
|
&.last_access {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
user-select: none;
|
||||||
|
caret-color: transparent;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--color);
|
||||||
|
&[contenteditable] {
|
||||||
|
&.caret_selected {
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: 2px solid red;
|
||||||
|
}
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
src/style/style.scss
Normal file
93
src/style/style.scss
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
@use "memory_registers";
|
||||||
|
@use "windows";
|
||||||
|
@use "buttons";
|
||||||
|
@use "vars";
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #808080;
|
||||||
|
background-color: black;
|
||||||
|
font-size: 2.5em;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid {
|
||||||
|
justify-content: center;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content min-content min-content;
|
||||||
|
grid-template-rows: min-content min-content min-content;
|
||||||
|
grid-template-areas:
|
||||||
|
"cycles registers regmemlabel"
|
||||||
|
"title memory memory"
|
||||||
|
". buttons buttons ";
|
||||||
|
#memory {
|
||||||
|
grid-area: memory;
|
||||||
|
// grid-column: 2/4;
|
||||||
|
// grid-row: 2/6;
|
||||||
|
}
|
||||||
|
#window_box {
|
||||||
|
grid-area: windowbox;
|
||||||
|
}
|
||||||
|
#registers {
|
||||||
|
grid-area: registers;
|
||||||
|
}
|
||||||
|
#labelcontainer {
|
||||||
|
grid-area: regmemlabel;
|
||||||
|
}
|
||||||
|
#cycles {
|
||||||
|
grid-area: cycles;
|
||||||
|
text-align: left;
|
||||||
|
align-self: center;
|
||||||
|
font-size: 0.48em;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
#title {
|
||||||
|
grid-area: title;
|
||||||
|
writing-mode: vertical-lr;
|
||||||
|
text-align: left;
|
||||||
|
user-select: none;
|
||||||
|
transform: scale(-1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid {
|
||||||
|
--color: var(--mem-invalid);
|
||||||
|
}
|
||||||
|
.constant {
|
||||||
|
--color: var(--mem-constant);
|
||||||
|
}
|
||||||
|
.register {
|
||||||
|
--color: var(--mem-register);
|
||||||
|
}
|
||||||
|
.memory {
|
||||||
|
--color: var(--mem-memory);
|
||||||
|
}
|
||||||
|
.instruction {
|
||||||
|
--color: var(--mem-instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#main.editor {
|
||||||
|
#memory,
|
||||||
|
#registers {
|
||||||
|
border-style: dashed;
|
||||||
|
div {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/style/vars.scss
Normal file
8
src/style/vars.scss
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
:root {
|
||||||
|
--border: #ffff00;
|
||||||
|
--mem-instruction: #3af78f;
|
||||||
|
--mem-memory: #ff26a8;
|
||||||
|
--mem-register: #9e0ef7;
|
||||||
|
--mem-constant: #19f7f0;
|
||||||
|
--mem-invalid: #bf2e2e;
|
||||||
|
}
|
108
src/style/windows.scss
Normal file
108
src/style/windows.scss
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#resize {
|
||||||
|
// background-color: red;
|
||||||
|
width: 100%;
|
||||||
|
height: 18px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
border-bottom: 5px solid yellow;
|
||||||
|
|
||||||
|
cursor: s-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#window_box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
max-width: 500px;
|
||||||
|
.window {
|
||||||
|
overflow-y: hidden;
|
||||||
|
position: relative;
|
||||||
|
border: 5px Solid var(--border);
|
||||||
|
border-bottom: unset;
|
||||||
|
&.collapsed {
|
||||||
|
.window_title {
|
||||||
|
// border-bottom: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.window_title {
|
||||||
|
position: sticky;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 0.6em;
|
||||||
|
color: lightgray;
|
||||||
|
border-bottom: 5px solid var(--border);
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
to top,
|
||||||
|
transparent,
|
||||||
|
transparent 2px,
|
||||||
|
transparent 2px,
|
||||||
|
yellow 2px,
|
||||||
|
yellow 4px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(to right, transparent, transparent 2px, transparent 2px, yellow 2px, yellow 4px);
|
||||||
|
|
||||||
|
#text {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
padding-inline: 10px;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
#collapse_button {
|
||||||
|
height: 23px !important;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border: 2px solid white;
|
||||||
|
background-color: black;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.window#tv {
|
||||||
|
height: unset;
|
||||||
|
#screen {
|
||||||
|
max-width: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#instruction_explainer {
|
||||||
|
grid-area: explainer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
height: 400px;
|
||||||
|
#expl_box {
|
||||||
|
padding-inline: 20px;
|
||||||
|
padding-block-start: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expl_text {
|
||||||
|
font-size: 0.6em;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expl_icon {
|
||||||
|
margin-inline-end: 0.5em;
|
||||||
|
font-size: 30px;
|
||||||
|
padding: 5px;
|
||||||
|
color: var(--color);
|
||||||
|
outline: 3px dashed var(--color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#printout {
|
||||||
|
grid-area: printout;
|
||||||
|
height: 500px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
overflow-x: hidden;
|
||||||
|
#printout_text {
|
||||||
|
padding-inline: 10px;
|
||||||
|
}
|
||||||
|
}
|
28
src/ui.ts
28
src/ui.ts
|
@ -1,19 +1,16 @@
|
||||||
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
import { CpuEvent, CpuEventHandler, UiEvent, UiEventHandler } from "./events";
|
||||||
import { $ } from "./etc";
|
import { $ } from "./etc";
|
||||||
import { InstructionExplainer } from "./ui/instructionExplainer";
|
import { InstructionExplainer } from "./ui/windows/instructionExplainer";
|
||||||
import { MemoryView } from "./ui/memoryView";
|
import { MemoryView } from "./ui/memoryView";
|
||||||
import { frequencyIndicator } from "./ui/frequencyIndicator";
|
import { frequencyIndicator } from "./ui/frequencyIndicator";
|
||||||
import { RegisterView } from "./ui/registerView";
|
import { RegisterView } from "./ui/registerView";
|
||||||
import { Screen } from "./ui/screen";
|
import { Screen } from "./ui/windows/screen";
|
||||||
import { Ribbon } from "./ui/ribbon";
|
import { EditButton } from "./ui/edit_button";
|
||||||
import { UiComponent, UiComponentConstructor } from "./ui/uiComponent";
|
import { UiComponent, UiComponentConstructor } from "./ui/uiComponent";
|
||||||
import { pausePlay } from "./ui/pausePlay";
|
import { pausePlay } from "./ui/pausePlay";
|
||||||
|
import { Printout } from "./ui/windows/printout";
|
||||||
|
|
||||||
export class UI {
|
export class UI {
|
||||||
printout: HTMLElement;
|
|
||||||
|
|
||||||
auto_running: boolean;
|
|
||||||
|
|
||||||
events: UiEventHandler = new UiEventHandler();
|
events: UiEventHandler = new UiEventHandler();
|
||||||
|
|
||||||
private components: Array<UiComponent>;
|
private components: Array<UiComponent>;
|
||||||
|
@ -30,27 +27,23 @@ export class UI {
|
||||||
this.register_component(frequencyIndicator, $("cycles"));
|
this.register_component(frequencyIndicator, $("cycles"));
|
||||||
this.register_component(InstructionExplainer, $("instruction_explainer"));
|
this.register_component(InstructionExplainer, $("instruction_explainer"));
|
||||||
this.register_component(RegisterView, $("registers"));
|
this.register_component(RegisterView, $("registers"));
|
||||||
this.register_component(Screen, $("screen") as HTMLCanvasElement);
|
this.register_component(Screen, $("tv"));
|
||||||
this.register_component(Ribbon, $("ribbon_menu"));
|
this.register_component(Printout, $("printout"));
|
||||||
|
this.register_component(EditButton, $("edit_button"));
|
||||||
this.register_component(pausePlay, $("controls_buttons"));
|
this.register_component(pausePlay, $("controls_buttons"));
|
||||||
this.printout = $("printout");
|
|
||||||
|
|
||||||
this.auto_running = false;
|
|
||||||
const pp_button = $("pause_play_button");
|
const pp_button = $("pause_play_button");
|
||||||
}
|
}
|
||||||
private register_component(c: UiComponentConstructor, e: HTMLElement): void {
|
private register_component(ctor: UiComponentConstructor, e: HTMLElement): void {
|
||||||
if (e === undefined) {
|
if (e === undefined) {
|
||||||
console.log(c);
|
console.log(ctor);
|
||||||
throw new Error("Could not find HTML element while registering UI component");
|
throw new Error("Could not find HTML element while registering UI component");
|
||||||
}
|
}
|
||||||
const component = new c(e, this.events);
|
const component = new ctor(e, this.events);
|
||||||
this.components.push(component);
|
this.components.push(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_events(cpu_events: CpuEventHandler): void {
|
init_events(cpu_events: CpuEventHandler): void {
|
||||||
cpu_events.listen(CpuEvent.Print, (char) => {
|
|
||||||
this.printout.textContent = (this.printout.textContent ?? "") + char;
|
|
||||||
});
|
|
||||||
cpu_events.listen(CpuEvent.Reset, () => {
|
cpu_events.listen(CpuEvent.Reset, () => {
|
||||||
this.reset();
|
this.reset();
|
||||||
});
|
});
|
||||||
|
@ -64,6 +57,5 @@ export class UI {
|
||||||
for (const c of this.components) {
|
for (const c of this.components) {
|
||||||
c.reset();
|
c.reset();
|
||||||
}
|
}
|
||||||
this.printout.textContent = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ export abstract class CelledViewer {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
this.element.classList.add("celled_viewer");
|
||||||
for (let i = 0; i < this.width * this.height; i++) {
|
for (let i = 0; i < this.width * this.height; i++) {
|
||||||
const mem_cell_el = el("div");
|
const mem_cell_el = el("div");
|
||||||
mem_cell_el.append("0", "0");
|
mem_cell_el.append("0", "0");
|
||||||
|
|
41
src/ui/edit_button.ts
Normal file
41
src/ui/edit_button.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { el, $ } from "../etc";
|
||||||
|
import { UiEventHandler, UiEvent } from "../events";
|
||||||
|
import { UiComponent } from "./uiComponent";
|
||||||
|
|
||||||
|
export class EditButton implements UiComponent {
|
||||||
|
element: HTMLElement;
|
||||||
|
events: UiEventHandler;
|
||||||
|
constructor(element: HTMLElement, event: UiEventHandler) {
|
||||||
|
this.element = element;
|
||||||
|
this.events = event;
|
||||||
|
|
||||||
|
const image = el("img");
|
||||||
|
image.src = "pencil.png";
|
||||||
|
image.style.width = "20px";
|
||||||
|
image.style.height = "20px";
|
||||||
|
this.element.classList.add("editor_toggle");
|
||||||
|
this.element.addEventListener("click", () => this.edit_toggle());
|
||||||
|
this.element.appendChild(image);
|
||||||
|
}
|
||||||
|
reset(): void {
|
||||||
|
const is_on = this.element.classList.contains("on");
|
||||||
|
if (is_on) {
|
||||||
|
this.edit_toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_toggle(): void {
|
||||||
|
const is_on = this.element.classList.contains("on");
|
||||||
|
if (is_on) {
|
||||||
|
this.element.classList.remove("on");
|
||||||
|
$("root").classList.remove("editor");
|
||||||
|
this.element.classList.add("off");
|
||||||
|
this.events.dispatch(UiEvent.EditOff);
|
||||||
|
} else {
|
||||||
|
this.events.dispatch(UiEvent.EditOn);
|
||||||
|
$("root").classList.add("editor");
|
||||||
|
this.element.classList.add("on");
|
||||||
|
this.element.classList.remove("off");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,14 @@ export class EditorContext {
|
||||||
cell.addEventListener("keydown", (e) => {
|
cell.addEventListener("keydown", (e) => {
|
||||||
this.keydown(e, i);
|
this.keydown(e, i);
|
||||||
});
|
});
|
||||||
|
cell.addEventListener("input", (e) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (target === null) return;
|
||||||
|
const text = target.textContent ?? "";
|
||||||
|
if (text.length !== 2) {
|
||||||
|
target.textContent = text.substring(0, 2);
|
||||||
|
}
|
||||||
|
});
|
||||||
cell.addEventListener("focus", () => {
|
cell.addEventListener("focus", () => {
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
this.current_cell_info.old = cell.textContent ?? "00";
|
this.current_cell_info.old = cell.textContent ?? "00";
|
||||||
|
|
|
@ -37,6 +37,9 @@ export class frequencyIndicator implements UiComponent {
|
||||||
this.element.textContent = `${value}hz`;
|
this.element.textContent = `${value}hz`;
|
||||||
this.last_value = value;
|
this.last_value = value;
|
||||||
}
|
}
|
||||||
|
if (value === 0) {
|
||||||
|
this.element.textContent = "";
|
||||||
|
}
|
||||||
this.last_time = new_time;
|
this.last_time = new_time;
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { el } from "../etc";
|
import { el } from "../etc";
|
||||||
import { UiEventHandler, CpuEventHandler, UiEvent } from "../events";
|
import { UiEventHandler, UiEvent } from "../events";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { UiComponent } from "./uiComponent";
|
||||||
|
|
||||||
const MAX_SLIDER = 1000;
|
const MAX_SLIDER = 1000;
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
import { el, $ } from "../etc";
|
|
||||||
import { UiEventHandler, UiEvent } from "../events";
|
|
||||||
import { UiComponent } from "./uiComponent";
|
|
||||||
|
|
||||||
function new_button(name: string, img_path: string, additional_class?: string): HTMLButtonElement {
|
|
||||||
const button = el("button", "", "no_style ribbon_button");
|
|
||||||
const image = el("img");
|
|
||||||
image.src = img_path;
|
|
||||||
image.width = 64;
|
|
||||||
image.height = 64;
|
|
||||||
if (additional_class !== undefined) {
|
|
||||||
button.classList.add(additional_class);
|
|
||||||
}
|
|
||||||
button.appendChild(image);
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Ribbon implements UiComponent {
|
|
||||||
element: HTMLElement;
|
|
||||||
events: UiEventHandler;
|
|
||||||
edit_button: HTMLButtonElement;
|
|
||||||
console_button: HTMLButtonElement;
|
|
||||||
display_button: HTMLButtonElement;
|
|
||||||
explainer_button: HTMLButtonElement;
|
|
||||||
constructor(element: HTMLElement, event: UiEventHandler) {
|
|
||||||
this.element = element;
|
|
||||||
this.events = event;
|
|
||||||
|
|
||||||
this.edit_button = new_button("Edit", "pencil.png", "editor_toggle");
|
|
||||||
this.console_button = new_button("Console", "texout.png");
|
|
||||||
this.display_button = new_button("Video", "tv.png");
|
|
||||||
this.explainer_button = new_button("Explainer", "explainer.png");
|
|
||||||
this.edit_button.addEventListener("click", () => this.edit_toggle());
|
|
||||||
this.element.appendChild(this.edit_button);
|
|
||||||
this.element.appendChild(this.console_button);
|
|
||||||
this.element.appendChild(this.display_button);
|
|
||||||
this.element.appendChild(this.explainer_button);
|
|
||||||
}
|
|
||||||
reset(): void {
|
|
||||||
const is_on = this.edit_button.classList.contains("on");
|
|
||||||
if (is_on) {
|
|
||||||
this.edit_toggle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
edit_toggle(): void {
|
|
||||||
const is_on = this.edit_button.classList.contains("on");
|
|
||||||
if (is_on) {
|
|
||||||
this.edit_button.classList.remove("on");
|
|
||||||
$("main").classList.remove("editor");
|
|
||||||
this.edit_button.classList.add("off");
|
|
||||||
this.events.dispatch(UiEvent.EditOff);
|
|
||||||
} else {
|
|
||||||
this.events.dispatch(UiEvent.EditOn);
|
|
||||||
$("main").classList.add("editor");
|
|
||||||
this.edit_button.classList.add("on");
|
|
||||||
this.edit_button.classList.remove("off");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,9 @@ export interface UiComponent {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
/** Allows listening and emitting UiEvents*/
|
/** Allows listening and emitting UiEvents*/
|
||||||
events: UiEventHandler;
|
events: UiEventHandler;
|
||||||
|
/** Completely reset the state of the component */
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
|
soft_reset?: () => void;
|
||||||
/** Allows listening CPUEvents*/
|
/** Allows listening CPUEvents*/
|
||||||
init_cpu_events?: (c: CpuEventHandler) => void;
|
init_cpu_events?: (c: CpuEventHandler) => void;
|
||||||
}
|
}
|
||||||
|
|
82
src/ui/windowBox.ts
Normal file
82
src/ui/windowBox.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import { el } from "../etc";
|
||||||
|
export abstract class WindowBox {
|
||||||
|
element: HTMLElement;
|
||||||
|
readonly title: string;
|
||||||
|
title_bar: HTMLElement;
|
||||||
|
private resize: HTMLElement;
|
||||||
|
private collapse_button: HTMLButtonElement;
|
||||||
|
private collapsed: boolean = false;
|
||||||
|
private resize_func: (e: MouseEvent) => void;
|
||||||
|
|
||||||
|
constructor(element: HTMLElement, title: string, options?: { collapsed?: boolean }) {
|
||||||
|
this.element = element;
|
||||||
|
this.title = title;
|
||||||
|
this.element.classList.add("window");
|
||||||
|
this.title_bar = el("div", undefined, "window_title");
|
||||||
|
this.element.appendChild(this.title_bar);
|
||||||
|
const title_bar_text_box = el("div", "text");
|
||||||
|
title_bar_text_box.textContent = title;
|
||||||
|
this.title_bar.appendChild(title_bar_text_box);
|
||||||
|
this.resize = el("div", "resize");
|
||||||
|
this.element.appendChild(this.resize);
|
||||||
|
this.resize_func = this.resize_move.bind(this);
|
||||||
|
this.collapse_button = el("button", "collapse_button", "nostyle");
|
||||||
|
this.collapse_button.addEventListener("click", () => {
|
||||||
|
this.toggle_collapse();
|
||||||
|
});
|
||||||
|
this.title_bar.appendChild(this.collapse_button);
|
||||||
|
this.resize.addEventListener("mousedown", (e) => {
|
||||||
|
window.addEventListener("mousemove", this.resize_func);
|
||||||
|
});
|
||||||
|
window.addEventListener("mouseup", () => {
|
||||||
|
this.remove_resize_listeners();
|
||||||
|
});
|
||||||
|
window.addEventListener("mouseleave", () => {
|
||||||
|
this.remove_resize_listeners();
|
||||||
|
});
|
||||||
|
if (options?.collapsed) {
|
||||||
|
this.collapse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse(): void {
|
||||||
|
this.element.classList.add("collapsed");
|
||||||
|
this.remove_resize_listeners();
|
||||||
|
this.resize.style.visibility = "hidden";
|
||||||
|
this.element.style.height = `${this.title_bar.offsetHeight + 4}px`;
|
||||||
|
this.collapsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle_collapse(): void {
|
||||||
|
if (this.collapsed) {
|
||||||
|
this.uncollapse();
|
||||||
|
} else {
|
||||||
|
this.collapse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uncollapse(): void {
|
||||||
|
this.element.classList.remove("collapsed");
|
||||||
|
this.resize.style.visibility = "unset";
|
||||||
|
this.element.style.height = `${this.title_bar.offsetHeight + 10 + 200}px`;
|
||||||
|
this.collapsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_resize_listeners(): void {
|
||||||
|
window.removeEventListener("mousemove", this.resize_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_move(e: MouseEvent): void {
|
||||||
|
if (this.collapsed) {
|
||||||
|
this.uncollapse();
|
||||||
|
this.remove_resize_listeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const distance_to_title = e.clientY - this.element.offsetTop - this.title_bar.offsetHeight + window.scrollY + 5;
|
||||||
|
if (distance_to_title <= 5) {
|
||||||
|
this.collapse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.element.style.height = `${e.clientY - this.element.offsetTop + window.scrollY + 8}px`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { UiEventHandler, CpuEventHandler, CpuEvent } from "../events";
|
import { UiEventHandler, CpuEventHandler, CpuEvent } from "../../events";
|
||||||
import { u1, u2 } from "../num";
|
import { u1, u2 } from "../../num";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { UiComponent } from "../uiComponent";
|
||||||
|
|
||||||
class BankIndicator implements UiComponent {
|
class BankIndicator implements UiComponent {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
|
@ -1,14 +1,14 @@
|
||||||
import { el, format_hex } from "../etc";
|
import { el, format_hex } from "../../etc";
|
||||||
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../events";
|
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../../events";
|
||||||
import { Instruction, ParamType, ParameterType } from "../instructionSet";
|
import { Instruction, ParamType, ParameterType } from "../../instructionSet";
|
||||||
import { u8 } from "../num";
|
import { u8 } from "../../num";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { WindowBox } from "../windowBox";
|
||||||
|
import { UiComponent } from "../uiComponent";
|
||||||
|
|
||||||
export class InstructionExplainer implements UiComponent {
|
export class InstructionExplainer extends WindowBox implements UiComponent {
|
||||||
element: HTMLElement;
|
|
||||||
events: UiEventHandler;
|
events: UiEventHandler;
|
||||||
constructor(element: HTMLElement, e: UiEventHandler) {
|
constructor(element: HTMLElement, e: UiEventHandler) {
|
||||||
this.element = element;
|
super(element, "Instruction Explainer");
|
||||||
this.events = e;
|
this.events = e;
|
||||||
}
|
}
|
||||||
add_instruction(instr: Instruction, pos: u8, byte: u8): void {
|
add_instruction(instr: Instruction, pos: u8, byte: u8): void {
|
||||||
|
@ -29,7 +29,7 @@ export class InstructionExplainer implements UiComponent {
|
||||||
this.element.appendChild(instr_box);
|
this.element.appendChild(instr_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_param(param: ParameterType, pos: u8, byte: u8): void {
|
add_parameter(param: ParameterType, pos: u8, byte: u8): void {
|
||||||
const t = param.type;
|
const t = param.type;
|
||||||
let name;
|
let name;
|
||||||
if (t === ParamType.Const) {
|
if (t === ParamType.Const) {
|
||||||
|
@ -51,7 +51,7 @@ export class InstructionExplainer implements UiComponent {
|
||||||
|
|
||||||
init_cpu_events(c: CpuEventHandler): void {
|
init_cpu_events(c: CpuEventHandler): void {
|
||||||
c.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
c.listen(CpuEvent.ParameterParsed, ({ param, code, pos }) => {
|
||||||
this.add_param(param, pos, code);
|
this.add_parameter(param, pos, code);
|
||||||
});
|
});
|
||||||
c.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
c.listen(CpuEvent.InstructionParsed, ({ instr, code, pos }) => {
|
||||||
this.add_instruction(instr, pos, code);
|
this.add_instruction(instr, pos, code);
|
||||||
|
@ -62,6 +62,6 @@ export class InstructionExplainer implements UiComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
this.element.innerHTML = "";
|
this.element.querySelectorAll("#expl_box").forEach((e) => e.remove());
|
||||||
}
|
}
|
||||||
}
|
}
|
25
src/ui/windows/printout.ts
Normal file
25
src/ui/windows/printout.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { el } from "../../etc";
|
||||||
|
import { CpuEvent, CpuEventHandler, UiEventHandler } from "../../events";
|
||||||
|
import { WindowBox } from "../windowBox";
|
||||||
|
import { UiComponent } from "../uiComponent";
|
||||||
|
|
||||||
|
export class Printout extends WindowBox implements UiComponent {
|
||||||
|
events: UiEventHandler;
|
||||||
|
text_box: HTMLElement;
|
||||||
|
constructor(element: HTMLElement, events: UiEventHandler) {
|
||||||
|
super(element, "Printout");
|
||||||
|
this.events = events;
|
||||||
|
this.text_box = el("div", "printout_text");
|
||||||
|
this.element.appendChild(this.text_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
init_cpu_events(c: CpuEventHandler): void {
|
||||||
|
c.listen(CpuEvent.Print, (c) => {
|
||||||
|
this.text_box.textContent += c;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.text_box.textContent = "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,39 @@
|
||||||
import { UiEventHandler, CpuEventHandler, CpuEvent } from "../events";
|
import { el } from "../../etc";
|
||||||
import { u4, u8 } from "../num";
|
import { UiEventHandler, CpuEventHandler, CpuEvent } from "../../events";
|
||||||
import { UiComponent } from "./uiComponent";
|
import { u4, u8 } from "../../num";
|
||||||
export class Screen implements UiComponent {
|
import { UiComponent } from "../uiComponent";
|
||||||
element: HTMLCanvasElement;
|
import { WindowBox } from "../windowBox";
|
||||||
|
export class Screen extends WindowBox implements UiComponent {
|
||||||
events: UiEventHandler;
|
events: UiEventHandler;
|
||||||
|
screen: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
scale: [number, number];
|
scale: [number, number];
|
||||||
constructor(element: HTMLElement, event: UiEventHandler) {
|
constructor(element: HTMLElement, event: UiEventHandler) {
|
||||||
this.element = element as HTMLCanvasElement;
|
super(element, "TV", { collapsed: true });
|
||||||
|
this.screen = el("canvas", "screen");
|
||||||
this.events = event;
|
this.events = event;
|
||||||
const canvas_size = [512, 512];
|
const canvas_size = [512, 512];
|
||||||
const data_size = [16, 16];
|
const data_size = [16, 16];
|
||||||
this.scale = [canvas_size[0] / data_size[0], canvas_size[1] / data_size[1]];
|
this.scale = [canvas_size[0] / data_size[0], canvas_size[1] / data_size[1]];
|
||||||
[this.element.width, this.element.height] = canvas_size;
|
[this.screen.width, this.screen.height] = canvas_size;
|
||||||
const ctx = this.element.getContext("2d");
|
const ctx = this.screen.getContext("2d");
|
||||||
if (ctx === null) {
|
if (ctx === null) {
|
||||||
throw new Error("todo");
|
throw new Error("could not load screen");
|
||||||
}
|
}
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
// for (let x = 0; x < 16; x++) {
|
this.element.appendChild(this.screen);
|
||||||
// for (let y = 0; y < 16; y++) {
|
}
|
||||||
// this.setPixel(x as u4, y as u4, (x + 16 * y) as u8);
|
|
||||||
// }
|
private test_pattern(): void {
|
||||||
// }
|
for (let x = 0; x < 16; x++) {
|
||||||
|
for (let y = 0; y < 16; y++) {
|
||||||
|
this.setPixel(x as u4, y as u4, (x + 16 * y) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
const ctx = this.element.getContext("2d");
|
const ctx = this.screen.getContext("2d");
|
||||||
if (ctx === null) {
|
if (ctx === null) {
|
||||||
throw new Error("todo");
|
throw new Error("todo");
|
||||||
}
|
}
|
74
svg.html
Normal file
74
svg.html
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Document</title>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
color: white;
|
||||||
|
background-color: black;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 100px;
|
||||||
|
align-content: center;
|
||||||
|
margin-inline: auto;
|
||||||
|
margin-block: auto;
|
||||||
|
}
|
||||||
|
#cont {
|
||||||
|
margin-top: 100px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
#cpu,
|
||||||
|
#target {
|
||||||
|
margin-block: auto;
|
||||||
|
border: solid 3px yellow;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
#targets {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 9px;
|
||||||
|
}
|
||||||
|
#connections {
|
||||||
|
}
|
||||||
|
div#target.gray {
|
||||||
|
border-color: gray;
|
||||||
|
}
|
||||||
|
svg polyline {
|
||||||
|
fill: transparent;
|
||||||
|
stroke-width: 3;
|
||||||
|
stroke-linecap: butt;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="cont">
|
||||||
|
<div id="cpu">CPU</div>
|
||||||
|
<svg
|
||||||
|
id="connections"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
width="100"
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
|
<polyline points="0,43 50,43 50,10, 100,10" stroke="yellow" />
|
||||||
|
<polyline points="0,48 64,48 64,37, 100,37" stroke="gray" />
|
||||||
|
<polyline points="0,53 64,53 64,63, 100,63" stroke="gray" />
|
||||||
|
<polyline points="0,58 50,58 50,90, 100,90" stroke="gray" />
|
||||||
|
</svg>
|
||||||
|
<div id="targets">
|
||||||
|
<div id="target">Main</div>
|
||||||
|
<div id="target" class="gray">Bank 1</div>
|
||||||
|
<div id="target" class="gray">Bank 2</div>
|
||||||
|
<div id="target" class="gray">VRAM</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
4
todo.md
4
todo.md
|
@ -3,7 +3,6 @@ Edit Mode
|
||||||
- Select where program counter is
|
- Select where program counter is
|
||||||
|
|
||||||
Implement HCF
|
Implement HCF
|
||||||
Move start/stop/auto logic into computer
|
|
||||||
|
|
||||||
Speed control slider behavior
|
Speed control slider behavior
|
||||||
Speed control slider styling
|
Speed control slider styling
|
||||||
|
@ -11,9 +10,6 @@ Overclock Box
|
||||||
|
|
||||||
error in instruction when number out of range (fix new Error("todo"))
|
error in instruction when number out of range (fix new Error("todo"))
|
||||||
|
|
||||||
UI for screen (toggling (click an icon?))
|
|
||||||
UI for togging other UI elements
|
|
||||||
|
|
||||||
UI for showing which Memory bank is selected
|
UI for showing which Memory bank is selected
|
||||||
VRAM select instruction
|
VRAM select instruction
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
/* eslint-disable no-undef */
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const CopyPlugin = require("copy-webpack-plugin");
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
entry: "./src/index.ts",
|
entry: "./src/index.ts",
|
||||||
|
@ -33,6 +36,11 @@ const config = {
|
||||||
filename: "main.js",
|
filename: "main.js",
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [{ from: "./src/include", to: "./" }],
|
||||||
|
}),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
module.exports = (env, argv) => {
|
module.exports = (env, argv) => {
|
||||||
if (argv.mode === "development") {
|
if (argv.mode === "development") {
|
||||||
|
|
Loading…
Reference in a new issue