22 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
28 changed files with 2955 additions and 9974 deletions

7
.gitignore vendored
View File

@ -1,3 +1,8 @@
desktop.ini
elm-stuff/*
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,13 +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/file": "1.0.5",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"

View File

@ -51,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);
@ -77,6 +78,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);
@ -85,6 +87,7 @@
--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);
@ -97,6 +100,11 @@
--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);
}

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,6 +86,7 @@
--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);
@ -96,6 +99,11 @@
--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);
}

View File

@ -7,6 +7,7 @@
width: 100vw;
height: min-content;
color: black;
background-color: white;
border-top: 1px solid black;
@ -20,6 +21,9 @@
padding: .5rem 1rem;
margin: 0;
line-height: 1em;
color: black;
border-color: black;
}
.cookie-banner * {
@ -33,4 +37,17 @@
.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;
}

File diff suppressed because it is too large Load Diff

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

@ -36,8 +36,96 @@ footer{
}
.dragDrop {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
background-color: var(--color-dragdrop);
color: var(--color-dragdrop-text);
visibility: hidden;
opacity: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
--transition: all 0.25s ease-in-out 0s;
transition: var(--transition);
}
.dragDrop.hover, .dragDrop.loading {
visibility: visible;
opacity: 1;
}
.dragDrop.loading {
background-color: var(--color-dragdrop-processing);
color: var(--color-dragdrop-processing-text);
}
.dragDrop .loader {
display: none;
}
.dragDrop.loading .loader {
display: block;
}
/*.dragDrop.loading p:first-child::before {
content: "⋮";
display: inline-flex;
width: 1em;
height: 1em;
justify-content: center;
align-items: center;
align-content: center;
transform: rotate(0);
}*/
.pc .examples-list {
border: 1px solid var(--color-controls-button-border);
margin: 0;
border-radius: 0 4px 4px 4px;
}
.pc .examples-list table td:first-child {
padding: 12px 8px 12px 15px;
}
.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;
}
button, .button {
/* background-color: whitesmoke; */
color: var(--color-controls-button-text);
border-color: var(--color-controls-button-border);
}
button:hover, .button:hover{
color: var(--color-controls-button-text-hover);
}
.button-group {
margin-bottom: 2em;
}
.button-group > * {
border-radius: 0;
}
.button-group :first-child {
border-radius: 4px 0 0 4px;
}
.button-group :last-child {
border-radius: 0 4px 4px 0;
}
/* HELPERS */
.text-center {

View File

@ -1,17 +1,23 @@
{
"available":
[
{
"title": "Simple Counter",
"version": "0.1",
"available":
[
{
"title": "A simple Counter",
"version": "0.3",
"url": "examples/simple-counter.json",
"enabled": 1
},
{
"title": "Add 2 numbers(placeholder)",
"version": "0.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

@ -1 +1 @@
{"model-version":1,"pc":{"addressBus":0,"dataBus":0,"instructionReg":0,"programmCounter":0,"uCounter":0,"accumulator":0,"ram":[100005,300000,200005,400000,0,5,0,0,0,0,0]},"uCode":["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}
{"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}

View File

@ -10,7 +10,7 @@
<!-- 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
-->
@ -19,6 +19,7 @@
<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" />
@ -370,8 +371,8 @@
<footer>
<div class="container">
<p>
Made with ☕
by <a href="https://github.com/ChrisgammaDE" target="_blank">Christian</a>
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>

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,15 @@
// Init Elm
var localStuff = localStorage.getItem("pc_data");
if (typeof localStuff !== "string") localStuff = "";
var app = Elm.Main.init({
node: document.getElementById("elm"),
// flags: Date.now()
flags: localStuff
});
// ###################################################################
// ###################################################################
// Dom Objects
let pc = document.getElementsByClassName("pc")[0];
let pc_ram = pc.getElementsByClassName("ram")[0];
@ -41,36 +47,11 @@ function scrollToCurrent(){
// pc.scrollIntoView();
}
// ###################################################################
// ###################################################################
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");
}
thead.classList.add("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) => {
@ -87,3 +68,8 @@ app.ports.localStorageSend.subscribe( (message) => {
if( cookieAccepted() )
localStorage.setItem("pc_data", message);
} );
// ###################################################################
// ###################################################################
// Done.

View File

@ -1,26 +0,0 @@
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 );

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.