27 Commits

Author SHA1 Message Date
964d34f73a Updated the year this was made 2021-05-09 19:06:17 +02:00
f2fe410cc1 Added delay to example loading 2021-05-09 19:05:32 +02:00
8b3d2d525b Cleaned up pc.js 2021-05-09 19:04:49 +02:00
a92da271d1 Updated Coloring for loader 2021-05-09 19:03:32 +02:00
c4a1884c6d Updated styles 2021-05-09 17:57:34 +02:00
1d7169ddb2 Updated examples for new model 2021-05-09 17:57:10 +02:00
8867374f85 Implemented Im- and Export by user 2021-05-09 17:56:40 +02:00
b3478d7eb3 Fixed overwriteAt, that did not overwrite if first pos in Array is to be changed 2021-05-09 15:45:19 +02:00
f4ad57b544 Updated styling 2021-05-09 15:36:48 +02:00
51d8ccf148 Updated elm.json to require file 2021-05-09 15:34:58 +02:00
87ec19157b Changed .gitignore so that builds aren't filling up repo 2021-05-07 08:52:12 +02:00
5664e0483b Added small build script to ease compiling 2021-05-06 14:51:51 +02:00
95985eb92a Small changes to fix styles that were broken by refactoring 2021-05-06 14:51:24 +02:00
c4a54ee2e4 A big ton of refactoring. Basically split up Mail.elm into a hand full smaller (more manageable) files. 2021-05-06 14:50:48 +02:00
8d0aded26f Told Elm where to start 2021-05-01 09:53:14 +02:00
ca60d8bae8 Updated gitignore to prevent editor files 2021-05-01 09:52:34 +02:00
a8195a3fba Updated Examples and tweaked some stuff form mobile layout 2020-12-28 18:01:06 +01:00
88f84a9c25 Updated .gitignore 2020-12-28 17:36:28 +01:00
6bbed4c655 Forgot to add them 2020-12-28 17:35:49 +01:00
49863a0079 Added an example and fixed comment display 2020-12-28 17:34:14 +01:00
9b789a1378 Added Mobile Layout and comments 2020-12-28 17:05:59 +01:00
1b7a502cd4 Fixed Cookie Auto-Nightmode and changed copyright 2020-12-27 23:16:01 +01:00
8e131d3ee4 Reorganized FileStructure and added Cookie-Banner 2020-12-27 23:07:14 +01:00
182662e2e0 Small fixes and auto-nightmode 2020-12-27 18:25:04 +01:00
dc9b5c725e Added whole Instruction step and a basic how to 2020-12-27 18:10:07 +01:00
20fb9914ef Forget to add backend example files 2020-12-27 13:21:32 +01:00
0aa08315d1 Added ability to load example from server 2020-12-26 20:00:56 +01:00
31 changed files with 3866 additions and 8626 deletions

5
.gitignore vendored
View File

@ -1,3 +1,8 @@
desktop.ini
elm-stuff/*
out/js/elm.js
*.zip
*.sublime*

25
build.sh Normal file
View File

@ -0,0 +1,25 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
echo "Building..."
# Create folders
mkdir -p out/css
mkdir -p out/js
# JS + TS
#cp src/js/*.js out/js/
# tsc --lib es2015 --lib dom --outDir out/js src/js/*.ts
# Compile Elm
elm make src/Main.elm --output out/js/elm.js --optimize
# CSS
#cp src/css/*.css out/css/
# cp out/main.js js/main.julius
echo "Build complete"

3
elm-tooling.json Normal file
View File

@ -0,0 +1,3 @@
{
"entrypoints": ["./src/Main.elm"]
}

View File

@ -8,10 +8,13 @@
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/file": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"

View File

@ -1,3 +1,4 @@
@media (prefers-color-scheme: dark){
:root {
--color-black: #05050F;
--color-white: #FFFFFF;
@ -39,7 +40,7 @@
--color-body: var(--color-black);
--color-body-text: var(--color-black);
--color-body-text: var(--color-white);
--color-addressbus: var(--color-addressbus-main);
--color-addressbus-text: var(--color-white);
@ -50,6 +51,7 @@
--color-controls-button-text: var(--color-white);
--color-controls-button-border: var(--color-white);
--color-controls-button-text-hover: var(--color-white-light1);
--color-controls-scroller-label-text: var(--color-black);
--color-header: var(--color-grey);
--color-header-text: var(--color-white);
@ -73,18 +75,40 @@
--color-table-ram-head-text: var(--color-white);
--color-table-ram-highlight: var(--color-ram-light2);
--color-table-ram-highlight-text: var(--color-black);
--color-table-ram-select: transparent;
--color-table-ram-select-text: inherit;
--color-table-ram-select-border: var(--color-grey-light2);
--color-table-ram-button-border: var(--color-controls-button-border);
--color-table-cu-head: var(--color-cu-dark1);
--color-table-cu-head-text: var(--color-white);
--color-table-cu-highlight: var(--color-cu-light2);
--color-table-cu-highlight-text: var(--color-black);
--color-table-cu-select: transparent;
--color-table-cu-select-text: inherit;
--color-table-cu-select-border: var(--color-grey-light2);
--color-table-cu-button-border: var(--color-controls-button-border);
--color-arrow: var(--color-arrow-main);
--color-arrow-text: var(--color-white);
--color-arrow-text-hover: var(--color-white-light2);
--color-arrow-border: var(--color-black-light1);
--color-modal: var(--color-black);
--color-modal-text: var(--color-white);
--color-modal-shadow: rgba( 0,0,0, 0.4 );
--color-code: var(--color-black-light1);
--color-code-text: var(--color-white);
--color-dragdrop: var(--color-code);
--color-dragdrop-text: var(--color-white);
--color-dragdrop-processing: var(--color-cu-main);
--color-dragdrop-processing-text: var(--color-white);
}
/* https://coolors.co/aa8f66-ed9b40-ffeedb-61c9a8-ba3b46-071013 */
/* https://coolors.co/faf3dd-000022-9c528b-62a87c-247ba0-429ea6-8fb8de-72705b */
}

View File

@ -50,6 +50,7 @@
--color-controls-button-text: var(--color-black);
--color-controls-button-border: var(--color-black);
--color-controls-button-text-hover: var(--color-black-light1);
--color-controls-scroller-label-text: var(--color-white);
--color-header: var(--color-grey);
--color-header-text: var(--color-white);
@ -76,6 +77,7 @@
--color-table-ram-select: transparent;
--color-table-ram-select-text: inherit;
--color-table-ram-select-border: var(--color-grey-light2);
--color-table-ram-button-border: var(--color-controls-button-border);
--color-table-cu-head: var(--color-cu-dark1);
--color-table-cu-head-text: var(--color-white);
@ -84,11 +86,24 @@
--color-table-cu-select: transparent;
--color-table-cu-select-text: inherit;
--color-table-cu-select-border: var(--color-grey-light2);
--color-table-cu-button-border: var(--color-controls-button-border);
--color-arrow: var(--color-arrow-main);
--color-arrow-text: var(--color-white);
--color-arrow-text-hover: var(--color-white-light2);
--color-arrow-border: var(--color-black-light1);
--color-modal: var(--color-white-light1);
--color-modal-text: var(--color-black);
--color-modal-shadow: rgba( 0,0,0, 0.4 );
--color-code: var(--color-white-light2);
--color-code-text: var(--color-black);
--color-dragdrop: var(--color-code);
--color-dragdrop-text: var(--color-black);
--color-dragdrop-processing: var(--color-cu-light1);
--color-dragdrop-processing-text: var(--color-black);
}

53
out/css/cookie.css Normal file
View File

@ -0,0 +1,53 @@
.cookie-banner{
position: fixed;
bottom: 0;
left: 0;
box-sizing: border-box;
width: 100vw;
height: min-content;
color: black;
background-color: white;
border-top: 1px solid black;
padding: .75rem 2rem;
z-index: 2500;
}
.cookie-banner button {
display: inline;
height: 2.5rem;
padding: .5rem 1rem;
margin: 0;
line-height: 1em;
color: black;
border-color: black;
}
.cookie-banner * {
margin-right: 1rem !important;
vertical-align: baseline;
}
.cookie-banner > :first-child {
display: inline;
}
.cookie-banner > :last-child {
margin-right: 0 !important;
}
@media (prefers-color-scheme: dark){
.cookie-banner {
background-color: black;
border-color: white;
color: white;
}
.cookie-banner button{
color: white;
border-color: white;
}
}

310
out/css/loader.css Normal file
View File

@ -0,0 +1,310 @@
/* Variables */
* {
--loaderDivCol: var(--color-dragdrop-processing-text);
--circR: 1rem;
--circD: 2rem;
--circ6D: 12rem;
--timing: ease-in-out;
--fullCycle: 5s;
}
.loader.hidden {
display: none;
}
.loader {
position: relative;
box-sizing: border-box;
height: var(--circD);
width: var(--circ6D);
margin: calc(var(--circD) * 3) var(--circD);
padding: var(--circR) 0;
}
.loader > * {
position: absolute;
box-sizing: border-box;
height: 0;
width: calc(2 * var(--circD));
opacity: 0;
display: flex;
justify-content: space-between;
--keyframe-sequence: "loading0";
--delay: 0;
--animation: var(--keyframe-sequence) var(--fullCycle) var(--timing) calc(0s - var(--fullCycle) * (1 - (var(--delay)) / 8) ) infinite;
-webkit-animation: var(--animation);
-moz-animation: var(--animation);
-ms-animation: var(--animation);
-o-animation: var(--animation);
animation: var(--animation);
}
.loader div::before,
.loader div::after {
content: "";
display: block;
box-sizing: border-box;
width: var(--circD);
height: var(--circD);
border: 1px solid var(--loaderDivCol);
background: var(--loaderDivCol);
border-radius: 100%;
position: absolute;
top: calc(0px - var(--circR));
}
.loader div::before {
left: calc(0px - var(--circR));
}
.loader div::after {
right: calc(0px - var(--circR));
}
@keyframes loading0 {
0% {
transform: rotate(0deg);
opacity: 1;
}
12.52% {
opacity: 1;
}
12.56% {
opacity: 0;
}
99.7% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes loading2 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.56% {
opacity: 0;
}
24.6% {
opacity: 0;
}
24.97% {
opacity: 1;
}
37.52% {
opacity: 1;
}
37.57% {
opacity: 0;
transform: rotate(180deg);
}
99.95% {
opacity: 0;
transform: rotate(0deg);
}
100% {
opacity: 1;
}
}
@keyframes loading3 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 1;
}
12.56% {
opacity: 0;
}
37.4% {
opacity: 0;
}
37.47% {
opacity: 1;
}
50.02% {
opacity: 1;
}
50.1% {
opacity: 0;
transform: rotate(180deg);
}
99.8% {
opacity: 0;
transform: rotate(0deg);
}
100% {
opacity: 1;
}
}
@keyframes loading5 {
0% {
opacity: 1;
transform: rotate(0deg);
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 1;
}
12.58% {
opacity: 0;
}
62.4% {
opacity: 0;
}
62.47% {
opacity: 1;
}
75.02% {
opacity: 1;
}
75.1% {
opacity: 0;
transform: rotate(180deg);
}
99.7% {
transform: rotate(0deg);
opacity: 0;
}
100% {
opacity: 1;
transform: rotate(0deg);
}
}
@keyframes loading6 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 1;
}
12.57% {
opacity: 0;
}
74.85% {
opacity: 0;
}
74.97% {
opacity: 1;
}
87.52% {
opacity: 1;
}
87.6% {
opacity: 0;
transform: rotate(180deg);
}
99.8% {
opacity: 0;
transform: rotate(0deg);
}
100% {
opacity: 1;
}
}
.loader :nth-child(1) {
width: 66.66%;
--keyframe-sequence: "loading5";
--delay: 0;
}
.loader :nth-child(2) {
width: 66.66%;
margin-left: 0;
--keyframe-sequence: "loading2";
--delay: 0;
}
.loader :nth-child(3) {
width: 33.33%;
margin-left: 33.33%;
--keyframe-sequence: "loading2";
--delay: 1;
}
.loader :nth-child(4) {
width: 66.66%;
margin-left: 33.33%;
--keyframe-sequence: "loading6";
--delay: 2;
}
.loader :nth-child(5) {
width: 100%;
--keyframe-sequence: "loading6";
--delay: 3;
}
.loader :nth-child(6) {
width: 100%;
--keyframe-sequence: "loading3";
--delay: 3;
}
.loader :nth-child(7) {
width: 33.33%;
--keyframe-sequence: "loading3";
--delay: 4;
}
.loader :nth-child(8) {
width: 66.66%;
margin-left: 33.33%;
--keyframe-sequence: "loading3";
--delay: 5;
}
.loader :nth-child(9) {
width: 33.33%;
margin-left: 33.33%;
--keyframe-sequence: "loading5";
--delay: 6;
}
.loader :nth-child(10) {
width: 33.33%;
margin-left: 66.66%;
--keyframe-sequence: "loading5";
--delay: 7;
}

827
out/css/pc.css Normal file
View File

@ -0,0 +1,827 @@
/* COLORS */
.pc .ram {
background-color: var(--color-ram);
color: var(--color-ram-text);
}
.pc .cu {
background-color: var(--color-cu);
color: var(--color-cu-text);
}
.pc .alu {
background-color: var(--color-alu);
color: var(--color-alu-text);
}
.pc .section h1.header {
background-color: var(--color-header);
color: var(--color-header-text);
}
/* TABLE COLORS */
.pc .ram .scroller table thead.head th {
background-color: var(--color-table-ram-head);
color: var(--color-table-ram-head-text);
}
.pc .cu .scroller table thead.head th {
background-color: var(--color-table-cu-head);
color: var(--color-table-cu-head-text);
}
.pc .scroller table tr td {
background-color: var(--color-table-row);
color: var(--color-table-text);
border-bottom: 1px solid var(--color-table-border);
}
.pc .scroller table tr:nth-child(even) td{
background-color: var(--color-table-row-alt);
}
.pc .scroller table tr.empty td {
color: var(--color-table-text-empty);
}
.pc .ram .scroller table tr.current td {
background-color: var(--color-table-ram-highlight);
color: var(--color-table-ram-highlight-text);
}
.pc .cu .scroller table tr.current td {
background-color: var(--color-table-cu-highlight);
color: var(--color-table-cu-highlight-text);
}
.pc button,
.pc .button{
text-transform: none !important;
font-weight: 600;
height: 2.5em;
line-height: 1em;
margin: 0;
vertical-align: top;
padding: 0.25em 2em;
}
/* CONTROLS COLORS */
.pc .controls .checker::before {
border: 1px solid var(--color-controls-button-border);
}
.pc .controls .checker.checked::before {
color: var(--color-controls-button-text);
}
/* FORMATTING STUFF */
.pc {
/*height: 400px;
height: 99vh;*/
box-sizing: border-box;
padding: 1em;
display: grid;
grid-template-columns: auto auto auto;
/* grid-template-columns: max-content auto max-content; */
gap: 9px;
}
.pc .grid-fullwidth{
grid-column: 1 / span 3;
}
.pc .pc-main {
width: 100%;
grid-column: 1 / span 3;
}
.pc .pc-main > div {
/*height: 400px;
height: 99vh;*/
width: 100%;
box-sizing: border-box;
padding: 1em 0;
display: grid;
grid-template-columns: auto auto auto;
/* grid-template-columns: max-content auto max-content; */
gap: 9px;
}
.pc .section {
min-height: 25em;
max-height: calc(80vh - 8em);
min-width: 20%;
box-sizing: border-box;
padding: 2.5em 1em 1em 1em;
display: flex;
flex-direction: column;
position: relative;
/*top: 0;
left: 0;*/
}
.pc .section h1.header {
font-size: 1.2em;
position: absolute;
top: 3px;
left: 4px;
padding: 3px;
}
.pc .row {
display: flex;
justify-content: space-evenly;
}
.pc .scroller {
overflow-x: auto;
overflow-y: scroll;
/*position: relative;*/
/* max-height: 60%; */
padding: 0;
box-sizing: border-box;
width: 100%;
margin: 1em 0 0 0;
}
/*.pc .scroller:last-child {
margin-bottom: -1em;
}*/
.pc .scroller table {
margin: 0;
}
.pc .scroller table thead.head {
position: sticky;
top: -2px;
left: 0;
/*height: 1em;*/
/*padding: 1em;*/
font-size: .8em;
transition: 0.2s;
}
.pc .scroller table thead th {
position: -webkit-sticky;
position: sticky;
top: 0;
width: min-content;
}
.pc .scroller table thead th:last-child {
width: max-content;
}
.pc .scroller table thead.head.shrunk {
/*height: .5rem;*/
/*font-size: .8em;*/
}
.pc .scroller table thead.head th {
padding: .2em 3px;
transition: 0.2s;
text-align: center;
/*border: 1px solid black !important;*/
}
.pc .scroller table thead.head.shrunk th {
/*padding-top: .2em;
padding-bottom: .2em;*/
}
.pc .scroller table .num {
text-align: right;
white-space: nowrap;
}
.pc .scroller table td {
padding: 6px 3px;
vertical-align: baseline;
/*border: 1px solid black !important;*/
}
.pc .scroller table tr td:first-child {
padding: 12px 8px;
}
.pc .scroller table tr.empty td:first-child {
padding: 3px 8px;
}
.pc .cu .scroller table tr.empty select {
padding: 3px 8px;
height: min-content;
}
.pc .scroller table tr td :last-child {
margin: 0;
}
.pc .scroller tr:first-child td {
padding-top: 1.5rem !important;
}
/*.pc .ram .comment {
padding: 12px 5px;
}*/
.pc .scroller table tbody button:last-child {
text-decoration: none;
text-transform: none;
height: max-content;
line-height: 2em;
font-weight: normal;
font-size: inherit;
padding: 0px 10px;
}
th.address {
width: 5rem;
padding-left: 8px;
text-align: right;
}
.pc input[type=number] {
margin: 0 .5em 0 0;
padding: 0 .25em;
height: 2.5rem;
line-height: 1em;
}
.pc input[type=number].instruction {
width: 4em !important;
}
.pc input[type=number].address {
width: 5em !important;
}
/* CONTROLS */
.pc .controls > :not(:last-child) {
margin-right: 0.75em;
}
.pc .controls .checker {
display: inline-flex;
align-items: center;
padding-left: 3em;
}
.pc .controls .checker label {
display: inline;
/*font-size: 0.8em;*/
white-space: initial;
white-space: break-spaces;
text-transform: none;
width: 6em;
width: min-content;
vertical-align: middle;
line-height: .9em;
margin: 0;
cursor: pointer;
}
.pc .controls input[type=checkbox]{
display: none;
margin-left: -1em;
margin-right: 1em;
opacity: 0;
z-index: 0;
}
.pc .controls .checker::before{
content: "✔";
display: inline-block;
width: 2rem;
height: 2rem;
color: rgba(0,0,0,0);
border-radius: 4px;
vertical-align: middle;
margin: 0 .5em 0 -1em;
line-height: 1.8rem;
font-size: 1.4em;
box-sizing: border-box;
}
/* END CONTROLS */
/* RAM */
.pc .ram .scroller {
/* height: 100%; */
/* padding: 0.2em; */
box-sizing: border-box;
}
.pc .ram .scroller table {
width: 100%;
}
.pc .ram input {
background-color: var(--color-table-ram-select);
color: var(--color-table-ram-select-text);
border-color: var(--color-table-ram-select-border);
}
.pc .ram table tr td:nth-child(2){
text-align: center;
}
.pc .ram .scroller table tbody tr:last-child button{
background-color: var(--color-table-ram-select);
color: var(--color-table-ram-select-text);
border-color: var(--color-table-ram-button-border);
width: 9.5em;
height: 2.5rem;
padding: 2px 1px;
line-height: 1em;
}
.pc .ram .ram-entry:last-child {
margin-right: 0 !important;
}
.pc .ram .comment input{
border: none;
margin: 0;
font-size: .8em;
width: 100%;
padding: 0;
}
/* CONTROL UNIT */
.pc .cu p {
margin: 0 0 .2em 0;
}
.pc .cu .scroller table {
width: 100%;
}
.pc .cu .input-row {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0 0 .5em 0;
}
.pc .cu .input-row:last-child {
margin: 0;
}
.pc .cu input {
color: var(--color-cu-text);
border-color: var(--color-cu-text);
background-color: transparent;
}
.pc .cu input[type=number] {
width: 9.5em;
}
.pc .cu label {
display: inline;
margin-bottom: 0;
}
.pc .cu select{
margin: 0;
width: 100%;
background-color: var(--color-table-cu-select);
color: var(--color-table-cu-select-text);
border: 1px solid var(--color-table-cu-select-border);
}
.pc .cu .scroller table tbody tr:last-child button {
background-color: var(--color-table-cu-select);
color: var(--color-table-cu-select-text);
border: 1px solid var(--color-table-cu-button-border);
width: 100%;
height: min-content;
padding: 3px 15px;
text-align: left;
}
.pc .cu .scroller table tr td:first-child {
padding: 12px 12px 12px 8px;
}
.pc .cu button,
.pc .cu .button {
height: 2.5rem;
box-sizing: border-box;
color: var(--color-cu-text);
border-color: var(--color-cu-text);
background-color: transparent;
}
.pc .modal .download-button {
display: block;
margin-bottom: 2em;
padding: 2px 15px;
font-weight: normal;
font-size: inherit;
height: min-content;
line-height: 1.6;
}
.pc .action-button {
width: 8em;
padding: 4px;
}
.pc .cu .input-group button {
width: 10em;
}
/* ALU */
.pc .alu input, .pc .alu .button, .pc .alu button{
color: var(--color-alu-text);
border-color: var(--color-alu-text);
background-color: transparent;
}
.pc .alu button {
margin-right: 1em;
}
.pc .alu button:last-child {
margin-right: 0;
}
/* BUSSES */
.pc .databus,
.pc .addressbus{
/*position: relative;*/
text-align: left;
margin: 0;
padding: .75em .5em;
}
.pc .databus .label,
.pc .addressbus .label {
/* position: absolute; */
/* left: .5em; */
margin-right: 1em;
}
.pc .addressbus input {
color: var(--color-addressbus-text);
border-color: var(--color-addressbus-text);
background-color: var(--color-addressbus);
}
.pc .databus input {
color: var(--color-databus-text);
border-color: var(--color-databus-text);
background-color: var(--color-databus);
}
.pc .addressbus {
margin-bottom: 1em;
background-color: var(--color-addressbus);
color: var(--color-addressbus-text);
}
.pc .databus {
margin-top: 2em;
background-color: var(--color-databus);
color: var(--color-databus-text);
}
/* ARROWS */
.pc .arrow {
position: absolute;
bottom: 0;
left: 50%;
display: flex;
justify-content: center;
align-items: center;
width: 3rem;
height: 5rem;
/* transform: rotate(90deg) translate(1.5rem, 2.5rem) ; */
--transformation: translate(0, 3rem);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
z-index: 100;
font-size: 0.5em;
color: var(--color-arrow-text);
background-color: var(--color-arrow);
}
.pc .arrow.down {
left: 25%;
}
.pc .arrow.up {
left: 75%;
--transformation: rotate(180deg) translate(0, -4.5rem);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
}
.pc .arrow.up > :nth-child(1){
/* transform: rotate(90deg) translate(0rem, 2rem); */
--transformation: rotate(180deg);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
}
.pc .arrow.up ~ .arrow.up {
left: 50%;
}
.pc .arrow.up ~ .arrow.up ~ .arrow.up {
left: 25%;
}
.pc .arrow.top {
bottom: auto;
top: -6rem;
}
.pc .arrow > :nth-child(1) {
font-size: 1.2em;
line-height: 1.1em;
font-weight: 600;
color: var(--color-arrow-text) !important;
background-color: var(--color-arrow) !important;
border-color: var(--color-arrow-text) !important;
text-transform: none;
padding: 2px 10px;
margin: 0;
/* transform: rotate(-90deg) translate(0rem, -2rem); */
white-space: normal;
height: min-content;
z-index: 10;
}
.pc .arrow > :nth-child(1) *{
color: var(--color-arrow-text);
display: block;
white-space: break-spaces;
}
.pc .arrow > :nth-child(1):hover, .pc .arrow > :nth-child(1) *:hover {
color: var(--color-arrow-text-hover);
}
.pc .arrow > :nth-child(2) {
width: 0;
height: 0;
border-left: 2.5rem solid transparent;
border-right: 2.5rem solid transparent;
border-top: 2rem solid var(--color-arrow);
border-bottom: 0rem solid transparent;
position: absolute;
left: -1rem;
bottom: -2rem;
}
/* MODALS */
.modal {
position: fixed;
top: 0;
left: 0;
z-index: 1000;
box-sizing: border-box;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.modal.hidden {
display: none;
}
.modal-card {
z-index: 1500;
display: block;
width: 40em;
min-width: 45vw;
min-height: 5em;
position: relative;
box-sizing: border-box;
padding: 2.5em 2em 1em 2em;
background-color: var(--color-modal);
color: var(--color-modal-text);
}
.modal > :first-child {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--color-modal-shadow);
}
.modal .modal-close {
position: absolute;
top: .5em;
right: .5em;
}
.modal .modal-close::before {
content: "❌";
cursor: pointer;
}
.modal .scroller table {
width: 100%;
}
.input-group > *{
margin-right: 0.5em !important;
}
.input-group :last-child {
margin-right: 0;
}
@media(max-width: 1000px){
.pc{
grid-template-rows: auto max-content auto;
justify-items: center;
overflow-x: hidden;
}
.pc .section {
grid-column: 2;
width: 100%;
min-height: 25rem;
max-height: 50rem;
}
.pc .grid-fullwidth.grid-addressbus,
.pc .grid-fullwidth.grid-databus {
--width: 5rem;
--text-height: 35rem;
--margin-side: 2rem;
width: var(--width);
box-sizing: border-box;
grid-row: 2 / span 3;
position: relative;
padding-bottom: var(--text-height);
}
.pc .grid-fullwidth.grid-addressbus {
grid-column: 1;
background-color: var(--color-addressbus);
color: var(--color-addressbus-text);
justify-self: flex-end;
margin-right: var(--margin-side);
}
.pc .grid-fullwidth.grid-databus {
grid-column: 3;
background-color: var(--color-databus);
color: var(--color-databus-text);
justify-self: flex-start;
margin-left: var(--margin-side);
}
.pc .grid-fullwidth.grid-addressbus > *,
.pc .grid-fullwidth.grid-databus > * {
position: sticky;
top: 0;
left: 0;
margin: 0;
box-sizing: border-box;
height: var(--width);
width: var(--text-height);
--transformation: rotate(-90deg) translate( calc(var(--width) / 2 - 50%), calc( 50% - var(--text-height) / 2));
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
background-color: transparent;
}
.pc .controls.grid-fullwidth {
grid-column: 1 / span 3;
}
.pc .arrow.down{
left: inherit;
right: 0;
bottom: 25%;
--transformation: rotate(-90deg) translate(0, 1rem);
}
.pc .arrow.down > :nth-child(1) {
--transformation: rotate(90deg);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
}
.pc .arrow.up{
left: inherit;
right: 0;
top: 25%;
--transformation: rotate(90deg) translate(0, -2.5rem);
}
.pc .arrow.up > :nth-child(1) {
--transformation: rotate(-90deg);
}
.pc .arrow.top {
right: inherit;
left: -4.5rem !important;
top: 25%;
}
.pc .arrow.arrow2{
top: 75%;
}
.pc .alu {
text-align: center;
}
}
@media(max-width: 800px){
.pc .cu .input-row {
display: block;
padding-left: 2rem;
}
.pc .cu .input-row label {
display: block;
}
}

296
out/css/roller.css Normal file
View File

@ -0,0 +1,296 @@
/*
Roller
*/
* {
--loaderDivCol: #eee;
--circD: 1rem;
--circ6D: 6rem;
--circR: 0.5rem;
--scrollbarBG: #f5f5f5;
--thumbBG: #C1DCEA;
}
#elm {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.roller {
margin: 2.5rem 0;
}
@keyframes loading0 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(0deg);
opacity: 1;
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 0;
}
100% {
opacity: 0;
transform: rotate(0deg);
}
}
@keyframes loading2 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 0;
}
24.97% {
opacity: 0;
}
25.02% {
opacity: 1;
}
37.47% {
opacity: 1;
}
37.52% {
opacity: 0;
}
99.95% {
transform: rotate(180deg);
}
100% {
opacity: 0;
transform: rotate(0deg);
}
}
@keyframes loading3 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 0;
}
37.47% {
opacity: 0;
}
37.52% {
opacity: 1;
}
49.97% {
opacity: 1;
}
50.02% {
opacity: 0;
}
100% {
opacity: 0;
transform: rotate(180deg);
}
}
@keyframes loading5 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 0;
}
62.47% {
opacity: 0;
}
62.52% {
opacity: 1;
}
74.97% {
opacity: 1;
}
75.02% {
opacity: 0;
}
100% {
opacity: 0;
transform: rotate(180deg);
}
}
@keyframes loading6 {
0% {
transform: rotate(0deg);
opacity: 1;
}
7% {
transform: rotate(180deg);
}
12.47% {
opacity: 1;
}
12.52% {
opacity: 0;
}
74.97% {
opacity: 0;
}
75.02% {
opacity: 1;
}
87.47% {
opacity: 1;
}
87.52% {
opacity: 0;
}
100% {
opacity: 0;
transform: rotate(180deg);
}
}
.loader {
position: relative;
height: var(--circD);
width: var(--circ6D);
padding: var(--circR) 0;
box-sizing: border-box;
z-index: -1;
}
.loader :nth-child(n) {
position: absolute;
opacity: 0;
box-sizing: border-box;
width: 0;
display: flex;
justify-content: space-between;
}
.loader div::before,
.loader div::after {
content: "";
display: block;
width: var(--circD);
height: var(--circD);
border: 1px solid var(--loaderDivCol);
background: var(--loaderDivCol);
border-radius: 100%;
position: absolute;
top: var(--circR);
}
.loader div::before {
left: calc(-var(--circR));
}
.loader div::after {
right: calc(-var(--circR));
}
.loader :nth-child(1) {
width: 66.66%;
/*^{animation "loading5" (timeDiv 0)}*/
--timing: "cubic-bezier(.39,.58,.57,1)";
--fullCycle: "4s";
--animation: "loading5" var(--fullCycle) var(--timing) calc(-(var(--fullCycle) * 1 / 8 )) infinite;
-webkit-animation: var(--animation);
-moz-animation: var(--animation);
-ms-animation: var(--animation);
-o-animation: var(--animation);
animation: var(--animation);
/*- fromInteger fullDiv * (1 - (fromInteger a) / 8 )*/
}
.loader :nth-child(2) {
width: 66.66%;
margin-left: 0;
/*^{animation "loading2" (timeDiv 0)}*/
}
.loader :nth-child(3) {
width: 33.33%
margin-left: 33.33%
/*^{animation "loading2" (timeDiv 1)}*/
}
.loader :nth-child(4) {
width: 66.66%
margin-left: 33.33%
/*^{animation "loading6" (timeDiv 2)}*/
}
.loader :nth-child(5) {
width: 100%
/*^{animation "loading6" (timeDiv 3)} */
}
.loader :nth-child(6) {
width: 100%
/*^{animation "loading3" (timeDiv 3)}*/
}
.loader :nth-child(7) {
width: 33.33%
/*^{animation "loading3" (timeDiv 4)}*/
}
.loader :nth-child(8) {
width: 66.66%
margin-left: 33.33%
/*^{animation "loading3" (timeDiv 5)}*/
}
.loader :nth-child(9) {
width: 33.33%
margin-left: 33.33%
/*^{animation "loading5" (timeDiv 6)}*/
}
.loader :nth-child(10) {
width: 33.33%
margin-left: 66.66%
/*^{animation "loading5" (timeDiv 7)} */
}

View File

@ -1,514 +1,132 @@
/* COLORS */
body {
background-color: var(--color-body);
color: var(--color-body-text);
background-color: var(--color-body);
color: var(--color-body-text);
}
.pc .addressbus {
background-color: var(--color-addressbus);
color: var(--color-addressbus-text);
code {
background-color: var(--color-code);
border-color: var(--color-code-text);
color: var(--color-code-text);
}
.pc .databus {
background-color: var(--color-databus);
color: var(--color-databus-text);
.noscript {
box-sizing: border-box;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.pc .ram {
background-color: var(--color-ram);
color: var(--color-ram-text);
.spacer {
height: 3rem;
width: 100%;
}
.pc .cu {
background-color: var(--color-cu);
color: var(--color-cu-text);
.hidden {
display: none !important;
}
.pc .alu {
background-color: var(--color-alu);
color: var(--color-alu-text);
section.fullheight {
min-height: 100vh;
}
.pc .section h1.header {
background-color: var(--color-header);
color: var(--color-header-text);
footer{
margin-top: 20rem;
}
/* TABLE COLORS */
.pc .ram .scroller table thead.head th {
background-color: var(--color-table-ram-head);
color: var(--color-table-ram-head-text);
}
.pc .cu .scroller table thead.head th {
background-color: var(--color-table-cu-head);
color: var(--color-table-cu-head-text);
}
.pc .scroller table tr td {
background-color: var(--color-table-row);
color: var(--color-table-text);
border-bottom: 1px solid var(--color-table-border);
}
.pc .scroller table tr:nth-child(even) td{
background-color: var(--color-table-row-alt);
}
.pc .scroller table tr.empty td {
color: var(--color-table-text-empty);
}
.pc .ram .scroller table tr.current td {
background-color: var(--color-table-ram-highlight);
color: var(--color-table-ram-highlight-text);
}
.pc .cu .scroller table tr.current td {
background-color: var(--color-table-cu-highlight);
color: var(--color-table-cu-highlight-text);
}
/* CONTROLS COLORS */
.controls button, .controls .button {
/* background-color: whitesmoke; */
color: var(--color-controls-button-text);
border-color: var(--color-controls-button-border);
}
.controls button:hover, .controls .button:hover{
color: var(--color-controls-button-text-hover);
}
.pc .controls .checker::before {
border: 1px solid var(--color-controls-button-border);
}
.pc .controls .checker.checked::before {
color: var(--color-controls-button-text);
}
/* FORMATTING STUFF */
button {
margin: 0;
}
.pc {
height: 400px;
height: 99vh;
box-sizing: border-box;
padding: 1em;
display: grid;
grid-template-columns: auto auto auto;
/* grid-template-columns: max-content auto max-content; */
gap: 9px;
}
.pc .grid-fullwidth{
grid-column: 1 / span 3;
}
.pc .section {
min-height: 25em;
max-height: calc(80vh - 8em);
min-width: 20%;
box-sizing: border-box;
padding: 2.5em 1em 1em 1em;
display: flex;
flex-direction: column;
position: relative;
/*top: 0;
left: 0;*/
}
.pc .section h1.header {
font-size: 1.2em;
position: absolute;
top: 3px;
left: 4px;
padding: 3px;
}
.pc .row {
display: flex;
justify-content: space-evenly;
}
.pc .scroller {
overflow-x: auto;
overflow-y: scroll;
/*position: relative;*/
/* max-height: 60%; */
padding: 0;
box-sizing: border-box;
width: 100%;
margin: 1em 0 0 0;
}
.pc .scroller:last-child {
margin-bottom: -1em;
}
.pc .scroller table thead.head {
position: sticky;
top: -2px;
left: 0;
height: 1em;
padding: 1em;
transition: 0.2s;
}
.pc .scroller table thead th {
position: -webkit-sticky;
position: sticky;
top: 0;
}
.pc .scroller table thead.head.shrunk {
height: .5em;
font-size: .8em;
}
.pc .scroller table thead.head th {
padding: 12px 4px 12px 15px;
transition: 0.2s;
}
.pc .scroller table thead.head.shrunk th {
padding-top: .2em;
padding-bottom: .2em;
}
.pc .scroller table .num {
text-align: right;
}
.pc .scroller table td:first-child,
.pc .scroller table td:last-child {
padding: 12px 15px;
}
.pc .scroller table tr.empty td {
padding: 3px 15px;
}
.pc .scroller table tbody button:last-child {
text-decoration: none;
text-transform: none;
height: max-content;
line-height: 2em;
font-weight: normal;
font-size: inherit;
padding: 0px 10px;
}
th.address {
width: 5rem;
padding-left: 8px;
text-align: right;
}
.pc input[type=number] {
margin: 0 .5em 0 0;
padding: 0 .25em;
height: 1.5em;
line-height: 1em;
}
.dragDrop {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
/* CONTROLS */
.pc .controls button,
.pc .controls .button{
text-transform: none !important;
font-weight: 600;
height: 2.5em;
line-height: 1em;
margin: 0;
vertical-align: top;
padding: 0.25em 2em;
}
.pc .controls > :not(:last-child) {
margin-right: 0.75em;
}
.pc .controls .checker {
display: inline-flex;
align-items: center;
padding-left: 3em;
}
.pc .controls .checker label {
display: inline;
/*font-size: 0.8em;*/
white-space: initial;
white-space: break-spaces;
text-transform: none;
width: 6em;
width: min-content;
vertical-align: middle;
line-height: .9em;
margin: 0;
cursor: pointer;
}
.pc .controls input[type=checkbox]{
display: none;
margin-left: -1em;
margin-right: 1em;
opacity: 0;
z-index: 0;
}
.pc .controls .checker::before{
content: "✔";
display: inline-block;
width: 2rem;
height: 2rem;
color: rgba(0,0,0,0);
border-radius: 4px;
vertical-align: middle;
margin: 0 .5em 0 -1em;
line-height: 1.8rem;
font-size: 1.4em;
box-sizing: border-box;
}
/* END CONTROLS */
/* RAM */
.pc .ram .scroller {
/* height: 100%; */
/* padding: 0.2em; */
box-sizing: border-box;
}
.pc .ram .scroller table {
width: 100%;
}
.pc .ram input[type=number] {
background-color: var(--color-table-ram-select);
color: var(--color-table-ram-select-text);
border-color: var(--color-table-ram-select-border);
}
.pc .ram input[type=number].instruction {
width: 5em;
}
.pc .ram input[type=number].address {
width: 7em;
}
.pc .ram table tr td:nth-child(2){
text-align: left;
}
.pc .ram .scroller table tbody button:last-child{
background-color: var(--color-table-ram-select);
color: var(--color-table-ram-select-text);
border-color: var(--color-table-ram-select-border);
}
/* CONTROL UNIT */
.pc .cu p {
margin: 0 0 .2em 0;
}
.pc .cu .scroller table {
width: 100%;
}
.pc .cu .input-row {
display: flex;
justify-content: space-between;
align-items: baseline;
margin: 0 0 .5em 0;
}
.pc .cu .input-row:last-child {
margin: 0;
}
.pc .cu input {
color: var(--color-cu-text);
border-color: var(--color-cu-text);
background-color: transparent;
}
.pc .cu label {
display: inline;
}
background-color: var(--color-dragdrop);
color: var(--color-dragdrop-text);
.pc .cu select{
margin: 0;
width: 100%;
visibility: hidden;
opacity: 0;
z-index: 1000;
background-color: var(--color-table-cu-select);
color: var(--color-table-cu-select-text);
border: 1px solid var(--color-table-cu-select-border);
}
.pc .cu .scroller table tbody button:last-child {
background-color: var(--color-table-cu-select);
color: var(--color-table-cu-select-text);
border: 1px solid var(--color-table-cu-select-border);
}
/* ALU */
.pc .alu input {
color: var(--color-alu-text);
border-color: var(--color-alu-text);
background-color: transparent;
}
/* BUSSES */
.pc .databus,
.pc .addressbus{
/*position: relative;*/
text-align: left;
margin: 0;
padding: .75em .5em;
}
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.pc .databus .label,
.pc .addressbus .label {
/* position: absolute; */
/* left: .5em; */
margin-right: 1em;
--transition: all 0.25s ease-in-out 0s;
transition: var(--transition);
}
.pc .addressbus input {
color: var(--color-addressbus-text);
border-color: var(--color-addressbus-text);
background-color: var(--color-addressbus);
.dragDrop.hover, .dragDrop.loading {
visibility: visible;
opacity: 1;
}
.pc .databus input {
color: var(--color-databus-text);
border-color: var(--color-databus-text);
background-color: var(--color-databus);
.dragDrop.loading {
background-color: var(--color-dragdrop-processing);
color: var(--color-dragdrop-processing-text);
}
.pc .addressbus {
margin-bottom: 1em;
.dragDrop .loader {
display: none;
}
.pc .databus {
margin-top: 2em;
.dragDrop.loading .loader {
display: block;
}
/*.dragDrop.loading p:first-child::before {
content: "⋮";
/* ARROWS */
.arrow {
position: absolute;
bottom: 0;
left: 50%;
display: flex;
justify-content: center;
align-items: center;
display: inline-flex;
width: 1em;
height: 1em;
width: 3rem;
height: 5rem;
justify-content: center;
align-items: center;
align-content: center;
transform: rotate(0);
}*/
/* transform: rotate(90deg) translate(1.5rem, 2.5rem) ; */
transform: translate(0, 3rem);
z-index: 100;
font-size: 0.5em;
color: var(--color-arrow-text);
background-color: var(--color-arrow);
.pc .examples-list {
border: 1px solid var(--color-controls-button-border);
margin: 0;
border-radius: 0 4px 4px 4px;
}
.arrow.down {
left: 25%;
.pc .examples-list table td:first-child {
padding: 12px 8px 12px 15px;
}
.arrow.up {
left: 75%;
transform: rotate(180deg) translate(0, -4.5rem);
}
.arrow.up > :nth-child(1){
/* transform: rotate(90deg) translate(0rem, 2rem); */
transform: rotate(180deg);
.pc .example-scroller-label {
display: inline-block;
margin: 0;
border: 1px solid var(--color-controls-button-border);
border-bottom-style: none;
color: var(--color-controls-button-text);
border-radius: 4px 4px 0 0;
padding: 2px 15px;
}
.arrow.up.arrow2 {
left: 50%;
button, .button {
/* background-color: whitesmoke; */
color: var(--color-controls-button-text);
border-color: var(--color-controls-button-border);
}
.arrow.top {
bottom: auto;
top: -6rem;
button:hover, .button:hover{
color: var(--color-controls-button-text-hover);
}
.arrow > :nth-child(1) {
font-size: 1.2em;
line-height: 1.1em;
font-weight: 600;
color: var(--color-arrow-text);
background-color: var(--color-arrow);
border-color: var(--color-arrow-text);
text-transform: none;
padding: 2px 10px;
margin: 0;
/* transform: rotate(-90deg) translate(0rem, -2rem); */
white-space: normal;
height: min-content;
.button-group {
margin-bottom: 2em;
}
.arrow > :nth-child(1) *{
color: var(--color-arrow-text);
display: block;
white-space: break-spaces;
.button-group > * {
border-radius: 0;
}
.arrow > :nth-child(1):hover, .arrow > :nth-child(1) *:hover {
color: var(--color-arrow-text-hover);
.button-group :first-child {
border-radius: 4px 0 0 4px;
}
.arrow > :nth-child(2) {
width: 0;
height: 0;
border-left: 2.5rem solid transparent;
border-right: 2.5rem solid transparent;
border-top: 2rem solid var(--color-arrow);
border-bottom: 0rem solid transparent;
position: absolute;
left: -1rem;
bottom: -2rem;
.button-group :last-child {
border-radius: 0 4px 4px 0;
}
/* HELPERS */
.text-center {
text-align: center;

7180
out/elm.js

File diff suppressed because it is too large Load Diff

23
out/examples-list.json Normal file
View File

@ -0,0 +1,23 @@
{
"available":
[
{
"title": "A simple Counter",
"version": "0.3",
"url": "examples/simple-counter.json",
"enabled": 1
},
{
"title": "Adding 2 numbers together",
"version": "0.2",
"url": "examples/adding.json",
"enabled": 1
},
{
"title": "Empty Canvas",
"version": "0.1",
"url": "examples/empty.json",
"enabled": 1
}
]
}

1
out/examples/adding.json Normal file
View File

@ -0,0 +1 @@
{"model-version":"3","pc_model":{"pc":{"addressBus":0,"dataBus":0,"instructionReg":0,"programmCounter":0,"uCounter":0,"accumulator":0,"ram":[[100013,"Load ValB to Acc"],[300000,"Acc ++"],[200013,"Store Acc to ValB"],[100012,"Load ValA"],[400000,"Acc --"],[200012,"Store Acc to ValA"],[600008,"Jmp If eq 0"],[500000,"Jmp #000"],[0,"END OF PROGRAM"],[0,""],[0,""],[0,""],[7,"ValA"],[14,"ValB + Result"],[0,""],[0,""],[0,""]]},"uCodes":["pc2ab","ram2db","db2ir","pcInc","ir2uc","n","n","n","n","n","ir2ab","ram2db","db2acc","ucReset","n","n","n","n","n","n","acc2db","ir2ab","db2ram","ucReset","n","n","n","n","n","n","accInc","ucReset","n","n","n","n","n","n","n","n","accDec","ucReset","n","n","n","n","n","n","n","n","ir2pc","ucReset","n","n","n","n","n","n","n","n","ir2pciacceq0","ucReset","n","n","n","n","n","n","n","n"]},"autoscroll":true}

1
out/examples/empty.json Normal file
View File

@ -0,0 +1 @@
{"model-version":"3","pc_model":{"pc":{"addressBus":0,"dataBus":0,"instructionReg":0,"programmCounter":0,"uCounter":0,"accumulator":0,"ram":[[0,""],[0,""],[0,""],[0,""],[0,""],[0,""],[0,""],[0,""],[0,""],[0,""],[0,""]]},"uCodes":["pc2ab","ram2db","db2ir","pcInc","ir2uc","n","n","n","n","n","ir2ab","ram2db","db2acc","ucReset","n","n","n","n","n","n","acc2db","ir2ab","db2ram","ucReset","n","n","n","n","n","n","accInc","ucReset","n","n","n","n","n","n","n","n"]},"autoscroll":true}

View File

@ -0,0 +1 @@
{"model-version":"3","pc_model":{"pc":{"addressBus":0,"dataBus":0,"instructionReg":0,"programmCounter":0,"uCounter":0,"accumulator":0,"ram":[[100005,"LoadA #005"],[300000,"IncA"],[200005,"StoreA #005"],[400000,"JMP #000"],[0,""],[5,"val"],[0,""],[0,""],[0,""],[0,""],[0,""]]},"uCodes":["pc2ab","ram2db","db2ir","pcInc","ir2uc","n","n","n","n","n","ir2ab","ram2db","db2acc","ucReset","n","n","n","n","n","n","acc2db","ir2ab","db2ram","ucReset","n","n","n","n","n","n","accInc","ucReset","n","n","n","n","n","n","n","n","ir2pc","ucReset","n","n","n","n","n","n","n","n"]},"autoscroll":true}

10
out/icon/cross.svg Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Cross" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M14.348,14.849c-0.469,0.469-1.229,0.469-1.697,0L10,11.819l-2.651,3.029c-0.469,0.469-1.229,0.469-1.697,0
c-0.469-0.469-0.469-1.229,0-1.697l2.758-3.15L5.651,6.849c-0.469-0.469-0.469-1.228,0-1.697c0.469-0.469,1.228-0.469,1.697,0
L10,8.183l2.651-3.031c0.469-0.469,1.228-0.469,1.697,0c0.469,0.469,0.469,1.229,0,1.697l-2.758,3.152l2.758,3.15
C14.817,13.62,14.817,14.38,14.348,14.849z"/>
</svg>

After

Width:  |  Height:  |  Size: 835 B

View File

@ -4,19 +4,23 @@
<!-- Basic Page Needs
-->
<meta charset="utf-8" />
<title>Zähler</title>
<meta name="description" content="" />
<meta name="author" content="" />
<title>Johnny Simulator</title>
<meta name="description" content="Web based Johhny-Simulator" />
<meta name="author" content="Christian" />
<!-- Mobile Specific Metas
-->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<!-- CSS
-->
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/skeleton.css" />
<link rel="stylesheet" href="css/cookie.css" />
<link rel="stylesheet" href="css/colors-light.css">
<link rel="stylesheet" href="css/colors-dark.css">
<link rel="stylesheet" href="css/loader.css" />
<link rel="stylesheet" href="css/pc.css" />
<link rel="stylesheet" href="css/style.css" />
<!-- Favicon
@ -27,11 +31,360 @@
<body>
<!-- Primary Page Layout
-->
<div id="elm"></div>
<div id="elm">
<div class="noscript">Sorry, but this app needs Javascript to run :/</div>
</div>
<div class="spacer"></div>
<section class="container fullheight">
<div id="langPicker">
<button id="langPickerDE">German</button>
<button id="langPickerEN">English</button>
</div>
<div id="langDE" class="hidden">
<h1>Wie diese App funktioniert</h1>
<p>
Hallo, schön dass du dir diese Seite anschaust.<br>
Damit du besser verstehst, wie diese Anwendung funktioniert, hier einmal die Basics:
</p>
<h2>Kontrollknöpfe</h2>
<p>
Ganz oben findest du eine Reihe mit Kontrollknöpfen. Jeder Knopf hat seine eigene Funktion.
</p>
<ul>
<li>
<b>µCycle</b>
Mit diesem Knopf kannst du einen einzelnen Schritt im µCode ausführen.
</li>
<li>
<b>Instruction</b>
Hiermit kannst du eine ganze Instruction ausführen lassen und musst nicht durch jeden µCode Schritt einzeln durchdrücken.
</li>
<li>
<b>Reset PC</b>
Damit kannst du den PC zurücksetzten. Dabei bleibt der RAM und der µCode erhalten.
</li>
<li>
<b>Autoscroll</b>
Nachdem im RAM oder im µCode ein anderer Eintrag ausgewählt wurde, kann automatisch zum Eintrag gescrollt werden
</li>
<li>
<b>Load Example</b>
Mit diesem Knopf kannst du ein Beispielprogramm in den PC laden. Dabei wird dein momentanes Programm überschrieben.
</li>
</ul>
<h2>Bausteine</h2>
<p>
Der Computer ist in mehrere Bausteine aufgeteilt. Jeder Baustein hat eine eigene spezielle Funktion. Ein echter Computer ist natürlich deutlich komplizierter, aber so ist der PC deutlich verständlicher.
</p>
<h3>RAM</h3>
<p>
Im Arbeitsspeicher wird das Programm gespeichert. Jeder Eintrag ist dabei in ein Low-Byte und ein High-Byte unterteilt. Dadurch kann man in einem Eintrag die Instruktion und Addresse einfacher unterscheiden.<br>
<a href="#befehl">Siehe Befehle</a>
</p>
<h3>Control Unit</h3>
<p>
Wie der Name es schon sagt, steuert und verwaltet die Control Unit alle Vorgänge im Computer. Das passiert dadurch, dass eine Instruktion in viele kleine µCodes aufgeteilt wird.
</p><p>
Diese µCodes sind in der Tabelle aufgeführt. Jede Instruktion besteht hier aus bis zu 10 µCodes. <br>
Bei einem Befehl z.B. <code>001 00000</code> ist die Instruktion in den ersten drei Stellen zu finden. Dieser Wert wird dann mit 10 multipliziert und in den µCode Counter geladen. <br>
In diesem Fall stände dann <code>0010</code> im Counter.<br>
In der Tabelle sind dann alle Befehle für die Instruktion <code>001</code> zu finden.
</p>
<h3>ALU</h3>
<p>
Die Arithmetik Logic Unit ist hier sehr einfach aufgebaut.
</p>
<p>
Sie kann den Akkumulator nur erhöhen oder erniedrigen. Dafür können Werte aber direkt vom Datenbus geladen werden.
</p>
<h3>Datenbus</h3>
<p>
Über den Datenbus können Daten und Befehle zwischen RAM, Control Unit und ALU übertragen werden.
</p>
<h3>Addressbus</h3>
<p>
Über diesen Bus kann die Control Unit steuern, welcher Wert im RAM ausgewählt wird.<br>
Bei normalen Rechnern sind hier natürlich noch deutlich mehr Werte angeschlossen.
</p>
<a id="befehl"></a>
<h2>Befehle</h2>
<p>
Ein Befehl besteht aus einer Instruktion und einem Argument. Deshalb sind im RAM und im Instruction Register alle Werte separiert.
</p>
<pre>
<code>
0 0 0 0 0 0 0 0
Instr Argument
</code>
</pre>
<h2>µCodes</h2>
<p>
Eine Instruktion kann nicht direkt ausgeführt werden. Deshalb wird sie durch mehrere kleine Befehle, sog. µCodes zusammengesetzt.
</p>
<table>
<thead>
<tr>
<th>µCode</th>
<th>Beschreibung</th>
</tr>
</thead>
<tbody>
<tr>
<td>ProgCounter -> AddrBus</td>
<td>Lade den Wert des Programm Counters in den Adressbus</td>
</tr>
<tr>
<td>InstrReg -> ProgCounter</td>
<td>Lade das Argument des Instruktionsregisters in den Programm Counter</td>
</tr>
<tr>
<td>ProgCounter ++</td>
<td>Erhöhe den Wert des Programm Counter um 1</td>
</tr>
<tr>
<td>Acc == 0 => InstReg -> ProgCounter</td>
<td>Wenn der Wert des Akkumulators 0 ist, dann lade das Arggument des Instruktionsregisters in den Programm Counter</td>
</tr>
<tr>
<td>Ram -> DataBus</td>
<td>Schreibe den aktuellen Wert aus den RAM auf den Datembus</td>
</tr>
<tr>
<td>DataBus -> Ram</td>
<td>Schreibe den Wert des Datenbus in die momentane Stelle des RAM</td>
</tr>
<tr>
<td>DataBus -> InstReg</td>
<td>Lade den Befehl vom Datenbus in das Instruktionsregister</td>
</tr>
<tr>
<td>DataBus -> Acc</td>
<td>Lade den Wert vom Datenbus in den Akkumulator der ALU</td>
</tr>
<tr>
<td>Acc -> DataBus</td>
<td>Schreibe den Wert vom Akkumulator auf den Datenbus</td>
</tr>
<tr>
<td>Acc ++</td>
<td>Erhöhe den Wert des Akkumulators um 1</td>
</tr>
<tr>
<td>Acc --</td>
<td>Verringere den Wert des Akkumulators um 1</td>
</tr>
<tr>
<td>InstReg -> µCounter</td>
<td>Nehme das Argument des Befehls im Instruktionsregister, füge am Ende eine 0 an und Lade ihn in den µCounter</td>
</tr>
<tr>
<td>InstReg -> AddrBus</td>
<td>Lade das Argument im Instruktionsregister in den Addressbus</td>
</tr>
<tr>
<td>µCounter = 0</td>
<td>Setzte den µCounter zurück</td>
</tr>
</tbody>
</table>
<h1>Source</h1>
<p>
Im Moment ist dieser Code noch nicht ordentlich genug, dass es Sinn hat ihn zu veröffentlichen.
</p>
<p>
Dieses Projekt ist angelehnt an den <a href="https://sourceforge.net/projects/johnnysimulator/" target="_blank">Johnny-Simulator</a>.
</p>
</div>
<div id="langEN">
<h1>How this App works</h1>
<p>
Hello. In order for you to understand what this App does, I want to show you some basics of this app.
</p>
<h2>Control Buttons</h2>
<p>
At the top of the application you can see a row of control buttons:
</p>
<ul>
<li>
<b>µCycle</b>
With this button you can execute a single µCode Step.
</li>
<li>
<b>Instruction</b>
This button executes a whole instruction at a time. This way you don't have to press µCycle all the time.
</li>
<li>
<b>Reset PC</b>
With this, you can reset the pc. Please note that ram und µCodes are not reset.
</li>
<li>
<b>Autoscroll</b>
After a value in RAM or in the µCodes is selected you can automatically scroll to them
</li>
<li>
<b>Load Example</b>
Click this button and select an example you want to load. This will overwrite the whole pc including ram and µCode
</li>
</ul>
<h2>Blocks</h2>
<p>
This computer is made up by multiple blocks like any other neumann-maschiene. Every block has it's own unique set of functions. A normal computer is much more complex than this, but the principle is the same.
</p>
<h3>RAM</h3>
<p>
The current programm is stored in the RAM. Every entry is seperated as mentioned in <a href="#entry">entry</a>.
</p>
<h3>Control Unit</h3>
<p>
As the name suggests, the control unit manages everything that is done. To know what needs to be done it has a list of µCodes that gets executed when a instruction is requested.
</p><p>
These µCodes can be found in the table. Every instruction consists of up to 10 µCodes. <br>
When a entry is executed, the first three digits (the instruction) gets multiplied by 10. This now is written into the µCounter and the µCodes for it get's executed.
</p><p>
Example:<br>
When the entry <code>001 00000</code> gets executed, the µCounter would be set to <code>0010</code>. Now every µCode starting at location <code>0010</code> in the µCodes gets executed.
</p>
<h3>ALU</h3>
<p>
The Arithmetic Logic Unit is pretty simple in this case.
</p>
<p>
The ALU can only increment or decrement the accumulator. But it can read numbers from databus.
</p>
<h3>Databus</h3>
<p>
Via the Databus values and entrys can be transported between RAM, Control Unit and ALU.
</p>
<h3>Addressbus</h3>
<p>
With the addressbus the Control Unit can control which value is selected in RAM. On a normal computer there are a lot mor things attached to this bus.
</p>
<a id="entry"></a>
<h2>Entry</h2>
<p>
Each entry consits of a instruction and an argument. That's why the entrys in RAM and in µCodes are displayed seperatly.
</p>
<pre>
<code>
0 0 0 0 0 0 0 0
Instr Argument
</code>
</pre>
<h2>µCodes</h2>
<p>
Every instruction consists of a list of µCodes. Here is an explanaition for all of them:
</p>
<table>
<thead>
<tr>
<th>µCode</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>ProgCounter -> AddrBus</td>
<td>Load the value from programm counter to addressbus</td>
</tr>
<tr>
<td>InstrReg -> ProgCounter</td>
<td>Load the argument from instruction register to programm counter</td>
</tr>
<tr>
<td>ProgCounter ++</td>
<td>Increment programm counter by 1</td>
</tr>
<tr>
<td>Acc == 0 => InstReg -> ProgCounter</td>
<td>If the accumulator is 0 then write the argument from instruction register to programm counter</td>
</tr>
<tr>
<td>Ram -> DataBus</td>
<td>Load selected value from RAM to databus</td>
</tr>
<tr>
<td>DataBus -> Ram</td>
<td>Write value from databus to selected value in RAM</td>
</tr>
<tr>
<td>DataBus -> InstReg</td>
<td>Write entry from databus to instruction register</td>
</tr>
<tr>
<td>DataBus -> Acc</td>
<td>Write value from databus to accumulator</td>
</tr>
<tr>
<td>Acc -> DataBus</td>
<td>Load value from accumulator to databus</td>
</tr>
<tr>
<td>Acc ++</td>
<td>Increment accumulator by 1</td>
</tr>
<tr>
<td>Acc --</td>
<td>Decrement accumulator by 1</td>
</tr>
<tr>
<td>InstReg -> µCounter</td>
<td>Take the instruction from instruction register, add a 0 at the tail and write it to µCounter</td>
</tr>
<tr>
<td>InstReg -> AddrBus</td>
<td>Write the argument from instruction register to addressbus</td>
</tr>
<tr>
<td>µCounter = 0</td>
<td>Set µCounter to 0</td>
</tr>
</tbody>
</table>
<h1>Source</h1>
<p>
At the moment the code for this project isn't good enough to share it online.
</p>
<p>
This project is my take on <a href="https://sourceforge.net/projects/johnnysimulator/" target="_blank">Johnny-Simulator</a>.
</p>
</div>
</section>
<footer>
<div class="container">
<p>
Made with ☕ <br>
© <a href="https://github.com/ChrisgammaDE" target="_blank">Christian</a>, 2021
</p>
<p>
<a href="https://yokta.de/i/impressum.html" target="_blank">Impressum</a>
</p>
</div>
</footer>
<!-- End Document
-->
<script src="elm.js"></script>
<script src="script.js"></script>
<script src="js/elm.js"></script>
<script src="js/cookie.js"></script>
<script src="js/pc.js"></script>
<script src="js/script.js"></script>
</body>
</html>

65
out/js/cookie.js Normal file
View File

@ -0,0 +1,65 @@
// Check if cookie banner has been accepted by running cookieAccepted()
// Please import cookie.css!!!!
function __cookie_internal_addBanner__(){
let banner = document.createElement("div");
let text = document.createElement("div");
let link_datenschutz = document.createElement("a");
let button_accept = document.createElement("button");
let button_deny = document.createElement("button");
banner.classList.add("cookie-banner");
text.innerText =
"In order for this computer to keep it's data after reloading,\
this page uses cookies and localStorage. ";
link_datenschutz.href = "https://yokta.de/i/datenschutz.html";
link_datenschutz.innerText = "Privacy Policy";
link_datenschutz.target = "_blank";
text.appendChild( link_datenschutz );
button_accept.innerText = "I'm ok with that"
button_deny.innerText = "Not on my watch!"
button_accept.addEventListener("click", (message) => {
localStorage.setItem("cookie", "accepted");
let parent = message.target.parentElement;
document.body.removeChild(parent);
});
button_deny.addEventListener("click", (message) => {
let parent = message.target.parentElement;
document.body.removeChild(parent);
});
banner.appendChild( text );
banner.appendChild( button_accept );
banner.appendChild( button_deny );
document.body.appendChild(banner);
}
// Returns true if cookies are accepted
function cookieAccepted() {
let maybe_cookie_status = localStorage.getItem("cookie");
let cookie_status = 0; // 0 = not answered, 1 = accepted, 2 = denied
if( maybe_cookie_status == null ) cookie_status = 0;
else if(maybe_cookie_status == "accepted") cookie_status = 1;
else cookie_status = 2;
if (cookie_status == 1) return true;
if (cookie_status == 0) {
let maybe_banner = document.getElementsByClassName("cookie-banner")[0];
if(maybe_banner == undefined){
__cookie_internal_addBanner__();
}
return false;
}
return false;
}
cookieAccepted();

75
out/js/pc.js Normal file
View File

@ -0,0 +1,75 @@
// Init Elm
var localStuff = localStorage.getItem("pc_data");
if (typeof localStuff !== "string") localStuff = "";
var app = Elm.Main.init({
node: document.getElementById("elm"),
flags: localStuff
});
// ###################################################################
// ###################################################################
// Dom Objects
let pc = document.getElementsByClassName("pc")[0];
let pc_ram = pc.getElementsByClassName("ram")[0];
let pc_cu = pc.getElementsByClassName("cu")[0];
let pc_alu = pc.getElementsByClassName("alu")[0];
let pc_ram_scroller = pc_ram.getElementsByClassName("scroller")[0];
let pc_cu_scroller = pc_cu.getElementsByClassName("scroller")[0];
let control_autoscroll = document.getElementById("enableScrolling");
// Methods
function scrollToCurrent(){
if( control_autoscroll.checked == false ) return;
let current_ram = pc_ram.getElementsByClassName("current")[0];
let current_uCode = pc_cu.getElementsByClassName("current")[0];
if( pc.scrollIntoViewIfNeeded == undefined ){
if( typeof current_ram != "undefined"){
current_ram.scrollIntoView({behavior: "smooth", block: "nearest"});
}
if( typeof current_uCode != "undefined"){
current_uCode.scrollIntoView({behavior: "smooth", block: "nearest"});
}
}else{
if( typeof current_ram != "undefined"){
current_ram.scrollIntoViewIfNeeded({behavior: "smooth", block: "nearest"});
}
if( typeof current_uCode != "undefined"){
current_uCode.scrollIntoViewIfNeeded({behavior: "smooth", block: "nearest"});
}
}
// pc.scrollIntoView();
}
// ###################################################################
// ###################################################################
// EVENT LISTENERS
// Recieve Elm updates via ports
app.ports.sendUUpdate.subscribe( (message) => {
// console.log("Update: ", message);
scrollToCurrent();
// Make sure that even when the calculation takes longer it will scroll correctly
setTimeout( scrollToCurrent, 100 );
} );
// Recieve LocalSession Updates via Ports
app.ports.localStorageSend.subscribe( (message) => {
// console.log("localSessionSend: ", message);
if( cookieAccepted() )
localStorage.setItem("pc_data", message);
} );
// ###################################################################
// ###################################################################
// Done.

26
out/js/script.js Normal file
View File

@ -0,0 +1,26 @@
let text_de = document.getElementById("langDE");
let text_en = document.getElementById("langEN");
let btn_changeToDe = document.getElementById("langPickerDE");
let btn_changeToEn = document.getElementById("langPickerEN");
let lang = (typeof document.documentElement.lang == "string") ? document.documentElement.lang: "en"
function changeLang(lang){
if(lang == "de"){
text_de.classList.remove("hidden");
text_en.classList.add("hidden");
}else{
text_en.classList.remove("hidden");
text_de.classList.add("hidden");
}
}
btn_changeToEn.addEventListener("click", () => { changeLang("en") } );
btn_changeToDe.addEventListener("click", () => { changeLang("de") } );
// Do stuff on loading
changeLang( lang );

View File

@ -1,76 +0,0 @@
// Init Elm
var app = Elm.Main.init({
node: document.getElementById("elm"),
// flags: Date.now()
});
// Dom Objects
let pc = document.getElementsByClassName("pc")[0];
let pc_ram = pc.getElementsByClassName("ram")[0];
let pc_cu = pc.getElementsByClassName("cu")[0];
let pc_alu = pc.getElementsByClassName("alu")[0];
let pc_ram_scroller = pc_ram.getElementsByClassName("scroller")[0];
let pc_cu_scroller = pc_cu.getElementsByClassName("scroller")[0];
let control_autoscroll = document.getElementById("enableScrolling");
// Methods
function scrollToCurrent(){
if( control_autoscroll.checked == false ) return;
let current_ram = pc_ram.getElementsByClassName("current")[0];
if( typeof current_ram != "undefined"){
current_ram.scrollIntoView({behavior: "smooth", block: "center"});
}
let current_uCode = pc_cu.getElementsByClassName("current")[0];
if( typeof current_uCode != "undefined"){
current_uCode.scrollIntoView({behavior: "smooth", block: "center"});
}
}
function shrinkTableHead(scroll){
let scroller = scroll.target;
let pos = scroller.scrollTop;
let thead = scroller.getElementsByClassName("head")[0];
if( pos > 70 ){
thead.classList.add("shrunk");
}else if (pos < 40){
thead.classList.remove("shrunk");
}
}
function loadStorage() {
let content = localStorage.getItem("pc_data");
if( typeof content == "string" ){
app.ports.localStorageRecieve.send( content );
}
}
// Load last state of pc
loadStorage();
// EVENT LISTENERS
pc_ram_scroller.addEventListener("scroll", shrinkTableHead);
pc_cu_scroller.addEventListener("scroll", shrinkTableHead);
// Recieve Elm updates via ports
app.ports.sendUUpdate.subscribe( (message) => {
// console.log("Update: ", message);
scrollToCurrent();
// Make sure that even when the calculation takes longer it will scroll correctly
setTimeout( scrollToCurrent, 100 );
} );
// Recieve LocalSession Updates via Ports
app.ports.localStorageSend.subscribe( (message) => {
console.log("localSessionSend: ", message);
localStorage.setItem("pc_data", message);
} );

File diff suppressed because it is too large Load Diff

107
src/PC/Defaults.elm Normal file
View File

@ -0,0 +1,107 @@
module PC.Defaults exposing (..)
import Array exposing (Array)
import PC.Types exposing (..)
import PC.UActions exposing (..)
initalModel : PC_Model
initalModel =
{ pc = initialPC
, uCodes = initialUCodes
}
initialPC : PC
initialPC =
{ ram = initialRam
, dataBus = 0
, addressBus = 0
, instructionReg = 0
, programmCounter = 0
, uCounter = 0
, accumulator = 0
}
initialRam : Array (Int, String)
initialRam = Array.fromList
[ (100005, "LoadA #005") -- 000 -- LoadA #005
, (300000, "IncA") -- 001 -- IncA
, (200005, "StoreA #005") -- 002 -- StoreA #005
, (400000, "JMP #000") -- 003 -- JMP #000
, (0,"") -- 004
, (5,"val") -- 005
, (0, "") -- 006
, (0, "") -- 007
, (0, "") -- 008
, (0, "") -- 009
, (0, "") -- 010
]
initialUCodes : Array UAction
initialUCodes = Array.fromList
[ UA_ProgrammCounter2AddressBus -- 000
, UA_Ram2DataBus -- 001
, UA_DataBus2InstructionReg -- 002
, UA_ProgrammCounterIncrement -- 003
, UA_InstructionReg2UCounter -- 004
, UA_Nothing -- 005
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 009
-- 010 LOADA
, UA_InstructionReg2AddressBus -- 010
, UA_Ram2DataBus -- 011
, UA_DataBus2Accumulator -- 012
, UA_ResetUCounter -- 013
, UA_Nothing -- 014
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 019
-- 020 STOA
, UA_Accumulator2DataBus -- 020
, UA_InstructionReg2AddressBus -- 021
, UA_DataBus2Ram -- 022
, UA_ResetUCounter -- 023
, UA_Nothing --024
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 029
-- 030 INCA
, UA_AccumulatorIncrement -- 030
, UA_ResetUCounter -- 031
, UA_Nothing -- 032
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 039
-- 040 JMP
, UA_InstructionReg2ProgrammCounter -- 040
, UA_ResetUCounter -- 041
, UA_Nothing -- 042
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 049
]

92
src/PC/Helpers.elm Normal file
View File

@ -0,0 +1,92 @@
module PC.Helpers exposing (..)
import Array exposing (Array)
import Http exposing (..)
-- Convert a number from 42 to 0042
-- number : (Prefered positive) whole number
-- length : positive whole number
-- Please note that only 0 are added. The number will not be shortend!
addLeadingZero : Int -> Int -> String
addLeadingZero number length =
let
num_str = String.fromInt number
in
(String.fromList <| List.repeat (length - String.length num_str) '0'
)
++ num_str
-- Get the value at a given position in a List.
-- For performance reasons it might be better
-- to use an Array instead.
valueAt : Int -> List a -> Maybe a
valueAt pos list = List.head <| List.drop pos list
-- Change the value at a given position in a List.
-- If your pos is greater than the length of
-- the list, then the rest is filled with the
-- default element.
overwriteAt : a -> Int -> a ->List a -> List a
overwriteAt default pos newVal list =
let
len = List.length list
in
if pos > len then
list ++
(List.repeat (pos-len) default) ++
[newVal]
else
let
before = List.take pos list
after = List.drop (pos+1) list
in
before ++ [newVal] ++ after
overwriteAt_Arr : a -> Int -> a -> Array a -> Array a
overwriteAt_Arr default pos newVal list =
let
len = Array.length list
in
if pos > len then
Array.append list
<| Array.append (Array.repeat (pos-len) default)
<| Array.fromList [newVal]
else
Array.set pos newVal list
-- Prints Http Errors into something readable
printHttpError : Http.Error -> String
printHttpError err =
case err of
Http.BadUrl str -> "Bad Url: " ++ str
Http.Timeout -> "Timeout"
Http.NetworkError -> "Network Error"
Http.BadStatus num -> "Bad Status: " ++ String.fromInt num
Http.BadBody str -> "Bad Body: " ++ str
seperateInstructionsEntry : Int -> (Int, Int)
seperateInstructionsEntry i =
let
instruction = i // 100000
address = i - instruction*100000
in
(instruction, address)
valueAtRam : Int -> Array (Int, String) -> (Int, String)
valueAtRam pos arr =
case Array.get pos arr of
Just a -> a
Nothing -> (0, "")
changeAtRam : Int -> Int -> Array (Int, String) -> Array (Int,String)
changeAtRam pos newVal list =
let
(_,comment) = valueAtRam pos list
in
overwriteAt_Arr (0, "") pos (newVal, comment) list

112
src/PC/JSON.elm Normal file
View File

@ -0,0 +1,112 @@
module PC.Json exposing ( pcModelDecoder
, pcModelEncoder
, tuple2Decoder
, tuple2Encoder
)
import PC.Types exposing (..)
import Maybe
import Array exposing (Array)
import Json.Encode as JE exposing (Value)
import Json.Decode as JD exposing (Decoder)
import PC.Types exposing (..)
import PC.UActions exposing (..)
-- ##########################################################
-- Decoders
-- ##########################################################
pcModelDecoder : Decoder PC_Model
pcModelDecoder =
JD.map2
PC_Model
(JD.field "pc" pcDecoder)
(JD.field "uCodes" uCodeDecoder)
pcDecoder : Decoder PC
pcDecoder =
JD.map7
PC
(JD.field "ram" <| JD.array <| tuple2Decoder JD.int JD.string)
(JD.field "dataBus" JD.int)
(JD.field "addressBus" JD.int)
(JD.field "instructionReg" JD.int)
(JD.field "programmCounter" JD.int)
(JD.field "uCounter" JD.int)
(JD.field "accumulator" JD.int)
uCodeDecoder : Decoder (Array UAction)
uCodeDecoder =
JD.array <| JD.map uActionDecoder JD.string
uActionDecoder : String -> UAction
uActionDecoder str =
Maybe.withDefault UA_Nothing <| string2uAction str
tuple2Decoder : Decoder a -> Decoder b -> Decoder (a,b)
tuple2Decoder enc1 enc2 =
JD.map2 Tuple.pair
(JD.index 0 enc1)
(JD.index 1 enc2)
-- ##########################################################
-- ##########################################################
-- ##########################################################
-- Encoders
-- ##########################################################
pcModelEncoder : PC_Model -> Value
pcModelEncoder model =
JE.object
[ ( "pc" , pcEncoder model.pc )
, ( "uCodes" , uCodesEncoder model.uCodes )
]
pcEncoder : PC -> Value
pcEncoder pc =
JE.object
[ ( "addressBus" , JE.int pc.addressBus )
, ( "dataBus" , JE.int pc.dataBus )
, ( "instructionReg" , JE.int pc.instructionReg )
, ( "programmCounter" , JE.int pc.programmCounter )
, ( "uCounter" , JE.int pc.uCounter )
, ( "accumulator" , JE.int pc.accumulator )
, ( "ram" , ramEncoder pc.ram )
]
ramEncoder : Array (Int, String) -> Value
ramEncoder arr =
JE.array
(tuple2Encoder JE.int JE.string)
arr
uCodesEncoder : Array UAction -> Value
uCodesEncoder uActions =
JE.array encodeSingleuCode uActions
encodeSingleuCode : UAction -> Value
encodeSingleuCode action =
let
uCode = uAction2UCode action
in
JE.string uCode.id
tuple2Encoder : (a -> Value) -> (b -> Value) -> (a,b) -> Value
tuple2Encoder encA encB (valA, valB) =
JE.list identity [ encA valA, encB valB ]
-- ##########################################################
-- ##########################################################
-- Done.

28
src/PC/PC.elm Normal file
View File

@ -0,0 +1,28 @@
module PC.PC exposing (..)
import Html exposing (Html)
--import Json.Encode as JE
import Json.Decode as JD
import PC.Types exposing (..)
import PC.Defaults exposing (..)
import PC.Helpers exposing (..)
import PC.Update exposing (..)
import PC.View exposing (..)
update : PC_Msg -> PC_Model -> (PC_Model, PC_AfterUpdateAction)
update = pc_update
view : PC_Model -> Html PC_Msg
view = pc_view
init : PC_Model
init = initalModel

78
src/PC/Types.elm Normal file
View File

@ -0,0 +1,78 @@
module PC.Types exposing (..)
import Array exposing (Array)
pcModelVersion = "3"
type alias PC_Model =
{ pc : PC
, uCodes : Array UAction
}
type alias PC =
{ ram : Array (Int, String)
, dataBus : Int
, addressBus : Int
, instructionReg : Int
, programmCounter : Int
, uCounter : Int
, accumulator : Int
}
type alias UCode =
{ variant : UAction
, id : String
, action : PC -> PC
, label : String
}
type UAction
= UA_Accumulator2DataBus
| UA_AccumulatorDecrement
| UA_AccumulatorIncrement
| UA_DataBus2Accumulator
| UA_DataBus2InstructionReg
| UA_DataBus2Ram
| UA_InstructionReg2AddressBus
| UA_InstructionReg2ProgrammCounter
| UA_InstructionReg2UCounter
| UA_ProgrammCounterIncrement
| UA_InstructionReg2ProgrammCounterIfAccEq0
| UA_Ram2DataBus
| UA_ResetUCounter
| UA_ProgrammCounter2AddressBus
| UA_Nothing
-- To make it easier to understand everything has name convention
-- PM_ -> PC_Msg in general
-- PM_B_ -> for a Button
-- PM_C_ -> for a Checkbox
-- PM_F_ -> for a TextField
type PC_Msg
= PM_B_UCycleStep
| PM_B_InstructionStep
| PM_B_Reset
| PM_B_RamAddBelow
| PM_B_CuAddBelow
| PM_F_RamEditInstr Int String
| PM_F_RamEditAddress Int String
| PM_F_RamEditComment Int String
| PM_F_CuEditAction Int String
| PM_F_CuInstrRegEditAddr String
| PM_F_CuInstrRegEditInstr String
| PM_F_CuProgCounterEdit String
| PM_F_CuUCounterEdit String
| PM_F_EditAddressBus String
| PM_F_EditDataBus String
| PM_F_AluEdit String
| PM_ManualStep UAction
-- Tells main what is supposed
-- to happen after a update
type PC_AfterUpdateAction
= PUA_Nothing -- Do nothing
| PUA_Storage -- Update localStorage
| PUA_Scroller -- Scroll to value
| PUA_Storage_And_Scroller -- Update localStorage and scroll to values

163
src/PC/UActions.elm Normal file
View File

@ -0,0 +1,163 @@
module PC.UActions exposing ( uCodes
, uAction2Label
, string2uAction
, uAction2UCode )
import Array exposing (Array)
import Tuple
import PC.Types exposing (..)
import PC.Helpers exposing (..)
uCodes : List UCode
uCodes =
[ UCode UA_Accumulator2DataBus "acc2db" actAccumulator2DataBus "Acc -> DataBus"
, UCode UA_AccumulatorDecrement "accDec" actAccumulatorDecrement "Acc --"
, UCode UA_AccumulatorIncrement "accInc" actAccumulatorIncrement "Acc ++"
, UCode UA_DataBus2Accumulator "db2acc" actDataBus2Accumulator "DataBus -> Acc"
, UCode UA_DataBus2InstructionReg "db2ir" actDataBus2InstructionReg "DataBus -> InstReg"
, UCode UA_DataBus2Ram "db2ram" actDataBus2Ram "DataBus -> Ram"
, UCode UA_InstructionReg2AddressBus "ir2ab" actInstructionReg2AddressBus "InstReg -> AddrBus"
, UCode UA_InstructionReg2ProgrammCounter "ir2pc" actInstructionReg2ProgrammCounter "InstReg -> ProgCount"
, UCode UA_InstructionReg2UCounter "ir2uc" actInstructionReg2UCounter "InstReg -> µCounter"
, UCode UA_ProgrammCounterIncrement "pcInc" actProgrammCounterIncrement "ProgCounter ++"
, UCode UA_Ram2DataBus "ram2db" actRam2DataBus "Ram -> DataBus"
, UCode UA_ResetUCounter "ucReset" actResetUCounter "µCounter = 0"
, UCode UA_ProgrammCounter2AddressBus "pc2ab" actProgrammCounter2AddressBus "ProgCounter -> AddrBus"
, UCode UA_Nothing "n" (\s -> s) "Empty"
, UCode UA_InstructionReg2ProgrammCounterIfAccEq0
"ir2pciacceq0" actInstructionReg2ProgrammCounterIfAccEq0 "Acc == 0 => InstReg -> ProgCounter"
]
-- #######################################################################################
-- ACTIONS
-- #######################################################################################
actRam2DataBus : PC -> PC
actRam2DataBus pc =
let
ab =
pc.addressBus
db =
Tuple.first <| valueAtRam ab pc.ram
in
{ pc | dataBus = db }
actDataBus2InstructionReg : PC -> PC
actDataBus2InstructionReg pc =
{ pc | instructionReg = pc.dataBus }
actResetUCounter : PC -> PC
actResetUCounter pc =
{ pc | uCounter = 0 }
actInstructionReg2UCounter : PC -> PC
actInstructionReg2UCounter pc =
-- Multiply by ten, because every instruction is 10 uCodes long
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | uCounter = instruction * 10}
actInstructionReg2AddressBus : PC -> PC
actInstructionReg2AddressBus pc =
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | addressBus = address }
actInstructionReg2ProgrammCounter : PC -> PC
actInstructionReg2ProgrammCounter pc =
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | programmCounter = address }
actProgrammCounterIncrement : PC -> PC
actProgrammCounterIncrement pc =
{ pc | programmCounter = pc.programmCounter + 1 }
actProgrammCounter2AddressBus : PC -> PC
actProgrammCounter2AddressBus pc =
{ pc | addressBus = pc.programmCounter }
actInstructionReg2ProgrammCounterIfAccEq0 : PC -> PC
actInstructionReg2ProgrammCounterIfAccEq0 pc =
if pc.accumulator == 0 then
let
(_,addr) = seperateInstructionsEntry pc.instructionReg
in
{ pc | programmCounter = addr }
else
pc
actDataBus2Accumulator : PC -> PC
actDataBus2Accumulator pc =
{ pc | accumulator = pc.dataBus }
actAccumulator2DataBus : PC -> PC
actAccumulator2DataBus pc =
{ pc | dataBus = pc.accumulator }
actAccumulatorIncrement : PC -> PC
actAccumulatorIncrement pc =
{ pc | accumulator = pc.accumulator + 1 }
actAccumulatorDecrement : PC -> PC
actAccumulatorDecrement pc =
{ pc | accumulator = pc.accumulator - 1 }
actDataBus2Ram : PC -> PC
actDataBus2Ram pc =
let
newRam =
changeAtRam pc.addressBus pc.dataBus pc.ram
in
{ pc | ram = newRam }
-- #################################################################
-- Helpers
-- #################################################################
uAction2Label : UAction -> String
uAction2Label variant =
let
filtered_list = List.filter (\u -> u.variant == variant ) uCodes
in
case List.head filtered_list of
Just uCode -> uCode.label
Nothing -> "IDK"
uAction2UCode : UAction -> UCode
uAction2UCode variant =
let
filtered_list = List.filter (\u -> u.variant == variant ) uCodes
in
case List.head filtered_list of
Just uCode -> uCode
Nothing -> UCode UA_Nothing "n" (\s -> s) "Empty"
string2uAction : String -> Maybe UAction
string2uAction str =
let
filtered_list = List.filter (\u -> u.id == str) uCodes
in
case List.head filtered_list of
Just uCode -> Just uCode.variant
_ -> Nothing

246
src/PC/Update.elm Normal file
View File

@ -0,0 +1,246 @@
module PC.Update exposing (pc_update)
import Array exposing (Array)
import PC.Types exposing (..)
import PC.UActions exposing (..)
import PC.Defaults exposing (..)
import PC.Helpers exposing (..)
pc_update : PC_Msg -> PC_Model -> (PC_Model, PC_AfterUpdateAction)
pc_update msg model =
case msg of
PM_B_UCycleStep ->
( uStepPC model
, if model.pc.uCounter == 0 then PUA_Storage_And_Scroller
else PUA_Scroller
)
PM_B_InstructionStep ->
( executeInstruction model
, PUA_Storage_And_Scroller )
PM_B_Reset ->
( { model | pc = { initialPC | ram = model.pc.ram } }
, PUA_Storage_And_Scroller )
PM_B_RamAddBelow ->
let
old_pc = model.pc
new_pc = {old_pc | ram = Array.append old_pc.ram <| Array.fromList [(0, "")]}
in
({model | pc = new_pc}
, PUA_Storage)
PM_B_CuAddBelow ->
({model | uCodes = Array.append model.uCodes <| Array.repeat 10 UA_Nothing}
, PUA_Storage)
PM_F_RamEditAddress addr may_int ->
case String.toInt may_int of
Just int ->
let
(inst,_) = seperateInstructionsEntry ( Tuple.first <| valueAtRam addr model.pc.ram )
new_val = inst * 100000 + int
old_pc = model.pc
new_pc = { old_pc | ram = (changeAtRam addr new_val old_pc.ram) }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> (model, PUA_Nothing)
PM_F_RamEditInstr addr may_int ->
case String.toInt may_int of
Just int ->
let
(_,address) = seperateInstructionsEntry ( Tuple.first <| valueAtRam addr model.pc.ram )
new_val = int * 100000 + address
old_pc = model.pc
new_pc = { old_pc | ram = (changeAtRam addr new_val old_pc.ram) }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_RamEditComment addr str ->
let
(val, _) = valueAtRam addr model.pc.ram
old_pc = model.pc
new_pc = { old_pc | ram = overwriteAt_Arr (0,"") addr (val, str) old_pc.ram }
in
({ model | pc = new_pc }, PUA_Storage)
PM_F_CuEditAction addr may_action ->
case string2uAction may_action of
Just action ->
let
newCode = Array.set addr action model.uCodes
in
({ model | uCodes = newCode }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuInstrRegEditAddr text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
(instr,_) = seperateInstructionsEntry old_pc.instructionReg
new_pc = { old_pc | instructionReg = instr * 100000 + int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuInstrRegEditInstr text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
(_,addr) = seperateInstructionsEntry old_pc.instructionReg
new_pc = { old_pc | instructionReg = int * 100000 + addr }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuProgCounterEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | programmCounter = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuUCounterEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | uCounter = int }
in
( { model | pc = new_pc }, PUA_Storage_And_Scroller )
_ -> ( model, PUA_Nothing )
PM_F_EditAddressBus text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | addressBus = int }
in
( { model | pc = new_pc }, PUA_Storage_And_Scroller )
_ -> ( model, PUA_Nothing )
PM_F_EditDataBus text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | dataBus = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_AluEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | accumulator = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_ManualStep action ->
let
instruction = getAction action
new_model = { model | pc = instruction model.pc }
in
( new_model, PUA_Storage_And_Scroller )
-- ###############################################################################
-- ###############################################################################
-- ###############################################################################
-- Update Helpers
-- ###############################################################################
-- Practically a part of uStepPC but sepeated for manual mode
getAction : UAction -> (PC -> PC)
getAction uAction =
let
possible_instructions =
List.filter (\u -> u.variant == uAction) uCodes
in
case List.head possible_instructions of
Just uCode ->
uCode.action
_ ->
(\s -> s)
uStepPC : PC_Model -> PC_Model
uStepPC model =
let
uCounter =
model.pc.uCounter
may_code : Maybe UAction
may_code = Array.get uCounter model.uCodes
--valueAt uCounter model.uCodes
in
case may_code of
Just code ->
let
-- code :: UAction
old_pc = model.pc
temp_pc = { old_pc | uCounter = uCounter + 1 }
uCode = uAction2UCode code
f = uCode.action
new_pc = f temp_pc
in
{ model | pc = new_pc }
--let
-- possible_instructions =
-- List.filter (\s -> Tuple.first s == action) uCodeMaps
--in
--case List.head possible_instructions of
-- Just ( name, instruction ) ->
-- let
-- old_pc =
-- model.pc
-- new_pc =
-- { old_pc | uCounter = old_pc.uCounter + 1 }
-- in
-- { model | pc = instruction new_pc }
-- _ ->
-- let
-- old_pc =
-- model.pc
-- new_pc =
-- { old_pc | uCounter = 0 }
-- in
-- { model | pc = new_pc }
_ ->
model
executeInstruction : PC_Model -> PC_Model
executeInstruction model =
let
new_model = uStepPC model
in
if new_model.pc.uCounter == 0 then
uStepPC new_model
else
executeInstruction new_model
-- ###############################################################################
-- ###############################################################################
-- Done.

383
src/PC/View.elm Normal file
View File

@ -0,0 +1,383 @@
module PC.View exposing (pc_view)
import Html exposing (Html, button, div, h1, p, text)
import Html.Attributes as HAttr exposing (class, classList, value)
import Html.Events as HEvent exposing (onClick, onInput)
import Html.Lazy exposing (lazy)
import Array exposing (Array)
import Json.Decode as JD
import PC.Types exposing (..)
import PC.UActions exposing (..)
import PC.Helpers exposing (..)
pc_view : PC_Model -> Html PC_Msg
pc_view model = div []
[ div
[ class "grid-fullwidth", class "grid-addressbus" ]
[ lazy viewAddressBus model ]
, lazy viewRam model
, lazy viewCu model
, lazy viewAlu model
, div
[ class "grid-fullwidth", class "grid-databus" ]
[ lazy viewDataBus model ]
]
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- RAM
-- #####################################################################
viewRam : PC_Model -> Html PC_Msg
viewRam model =
div [ class "section", class "ram" ]
[ h1 [ class "header" ] [ text "RAM" ]
, div [ class "arrow", class "down", class "top"] [ div [] [] , div [] [] ]
, div [ class "scroller" ]
[ Html.table [ class "" ]
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "Addr" ]
, Html.th [] [ text "Value" ]
, Html.th [] [ text "Comment" ]
]
]
, lazy viewRamContent model
]
]
, drawArrow Bottom Down UA_Ram2DataBus "Ram -> DataBus"
, drawArrow Bottom Up UA_DataBus2Ram "DataBus -> Ram"
]
viewRamContent : PC_Model -> Html PC_Msg
viewRamContent model =
let
--indexedRam =
-- List.indexedMap Tuple.pair <| Array.toList model.pc.ram
ram2table : Int -> (Int, String) -> Html PC_Msg
ram2table id entry =
let
(val,comment) = entry
(instruction, address) = seperateInstructionsEntry val
in
Html.tr
[ classList [ ( "current", id == model.pc.addressBus ) ] ]
[ Html.td [ class "num" ] [ text (addLeadingZero id 3) ]
, Html.td [ class "num " ]
[ Html.input
[ HAttr.type_ "number"
, HAttr.value <| addLeadingZero instruction 3
, onInput <| PM_F_RamEditInstr id
, class "ram-entry"
, class "instruction"
]
[]
, Html.input
[ HAttr.type_ "number"
, HAttr.value <| addLeadingZero address 5
, onInput <| PM_F_RamEditAddress id
, class "ram-entry"
, class "address"
]
[]
]
, Html.td[ class "comment" ]
[ Html.input
[ HAttr.type_ "text"
, HAttr.value comment
, onInput <| PM_F_RamEditComment id ]
[]
]
]
in
Html.tbody []
((Array.toList <| Array.indexedMap ram2table model.pc.ram)
++
[ Html.tr []
[ Html.td [] []
, Html.td []
[ button
[ onClick PM_B_RamAddBelow ]
[ text "Add Entry"]
]
, Html.td [][]
]
]
)
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- Control Unit
-- #####################################################################
viewCu : PC_Model -> Html PC_Msg
viewCu model =
let
( instrRegInst, instrRegAddr ) = seperateInstructionsEntry model.pc.instructionReg
in
div [ class "section", class "cu" ]
[ drawArrow Top Up UA_InstructionReg2AddressBus "InstR -> AddrB"
, drawArrow Top Up UA_ProgrammCounter2AddressBus "ProgCounter -> AddrB"
--, div [ class "arrow", class "up", class "top"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (PM_ManualStep ActInstructionReg2AddressBus)] [ text "InstR -> AddrB" ]]
-- , div [] []
-- ]
--, div [ class "arrow", class "up", class "top", class "arrow2"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (PM_ManualStep ActProgrammCounter2AddressBus)] [ text "ProgCounter -> AddrB" ]]
-- , div [] []
-- ]
, h1 [ class "header" ] [ text "Control Unit" ]
, p []
[ div [class "input-row"]
[ Html.label [ HAttr.for "cu-progcounter" ] [ text "Programm Counter:" ]
, div [ class "input-group" ]
[ button
[ onClick <| PM_ManualStep UA_InstructionReg2ProgrammCounter ]
[ text "InstRA -> " ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-progcounter"
, value (addLeadingZero model.pc.programmCounter 3)
, onInput PM_F_CuProgCounterEdit
] []
]
]
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-instrReg" ] [ text "Instruction Register:" ]
, div []
[ Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "instruction"
, value (addLeadingZero instrRegInst 3)
, onInput PM_F_CuInstrRegEditInstr
] []
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "address"
, value (addLeadingZero instrRegAddr 5)
, onInput PM_F_CuInstrRegEditAddr
] []
]
]
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-uCounter" ] [ text "µCode Counter:" ]
, div [ class "input-group" ]
[ button
[ onClick <| PM_ManualStep UA_InstructionReg2UCounter ]
[ text "IntrRI ->" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-uCounter"
, value (addLeadingZero model.pc.uCounter 4)
, onInput PM_F_CuUCounterEdit
] []
]
]
]
, div [ class "scroller" ]
[ viewCuUCode model
]
--, div [ class "arrow", class "up"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (MsgManualStep ActDataBus2InstructionReg) ] [ text "DB -> InstR" ]]
-- , div [] []
-- ]
, drawArrow Bottom Up UA_DataBus2InstructionReg "DB -> InstR"
]
viewCuUCode : PC_Model -> Html PC_Msg
viewCuUCode model =
Html.table []
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "µCounter" ]
, Html.th [] [ text "µCode" ]
]
]
, lazy viewCuUCodeContent model
]
viewCuUCodeContent : PC_Model -> Html PC_Msg
viewCuUCodeContent model =
let
list2table : Int -> UAction -> Html PC_Msg
list2table id code =
Html.tr
[ classList [ ( "current", id == model.pc.uCounter ), ("empty", code == UA_Nothing) ] ]
[ Html.td [ class "num" ] [ text (addLeadingZero id 4) ]
, Html.td [] [ viewCuInstrSelect id code ]
]
in
Html.tbody []
((Array.toList <| Array.indexedMap list2table model.uCodes)
++
[ Html.tr []
[ Html.td [] []
, Html.td []
[ button
[ onClick PM_B_CuAddBelow ]
[ text "Add Entry"]
]
]
]
)
viewCuInstrSelect : Int -> UAction -> Html PC_Msg
viewCuInstrSelect id current =
let
info2option uCode =
Html.option
[ HAttr.selected (uCode.variant == current)
, HAttr.value uCode.id ]
[ text uCode.label ]
listOptions = List.map info2option uCodes
in
Html.select
[ HEvent.on "change" ( JD.map (PM_F_CuEditAction id) selectCuValueDecoder) ]
listOptions
viewInstrEntry : Int -> Html PC_Msg
viewInstrEntry i =
let
(instruction, address) = seperateInstructionsEntry i
in
text ( (addLeadingZero instruction 3) ++ " " ++ (addLeadingZero address 5) )
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- ALU
-- #####################################################################
viewAlu : PC_Model -> Html PC_Msg
viewAlu model =
div [ class "section", class "alu" ]
[ h1 [ class "header" ] [ text "ALU" ]
, p []
[ Html.label [ HAttr.for "alu-accumulator" ] [ text "Accumulator:" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "alu-accumulator"
, value (addLeadingZero model.pc.accumulator 8)
, onInput PM_F_AluEdit
] []
]
, p []
[ button [ onClick <| PM_ManualStep UA_AccumulatorIncrement ] [ text "Acc ++" ]
, button [ onClick <| PM_ManualStep UA_AccumulatorDecrement ] [ text "Acc --" ]
]
, drawArrow Bottom Up UA_DataBus2Accumulator "DB -> ALU"
, drawArrow Bottom Down UA_Accumulator2DataBus "ALU -> DB"
--, div [ class "arrow", class "up"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (MsgManualStep ActDataBus2Accumulator)] [ text "DB -> ALU" ]]
-- , div [] []
-- ]
--, div [ class "arrow", class "down"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (MsgManualStep ActAccumulator2DataBus)] [ text "ALU -> DB" ]]
-- , div [] []
-- ]
]
-- #####################################################################
-- Busses
-- #####################################################################
viewDataBus : PC_Model -> Html PC_Msg
viewDataBus model =
div [ class "databus" ]
[ Html.span [ class "label" ] [ text "Databus" ]
, Html.span []
[ Html.input
[ HAttr.type_ "number"
, value (addLeadingZero model.pc.dataBus 8)
, onInput PM_F_EditDataBus
] []
]
]
viewAddressBus : PC_Model -> Html PC_Msg
viewAddressBus model =
div [ class "addressbus" ]
[ Html.span [ class "label" ] [ text "Addressbus" ]
, Html.span []
[ Html.input
[ HAttr.type_ "number"
, value (addLeadingZero model.pc.addressBus 3)
, onInput PM_F_EditAddressBus
] []
]
]
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- Helpers
-- #####################################################################
type Arrow_Pos = Top | Bottom
type Arrow_Dir = Up | Down
drawArrow : Arrow_Pos -> Arrow_Dir -> UAction -> String -> Html PC_Msg
drawArrow pos dir act str =
div
[ HAttr.classList
[ ("arrow", True)
, ("top", pos == Top)
, ("up", dir == Up)
, ("down", dir == Down)]
]
[ div [ class "button" ]
[ Html.a
[ onClick (PM_ManualStep act) ]
[ text str ]
]
, div [] []
]
selectCuValueDecoder : JD.Decoder String
selectCuValueDecoder =
JD.field "target" ( JD.field "value" JD.string)
-- #####################################################################
-- #####################################################################
-- Done.