Merge pull request 'ALU improvments and CSS cleanup' (#1) from dev into master

Reviewed-on: #1
This commit is contained in:
Christian 2022-05-04 14:45:15 +02:00
commit 7ffad6e002
12 changed files with 464 additions and 341 deletions

View File

@ -269,11 +269,20 @@ th.address {
}
.pc input[type=number].instruction {
width: 4em !important;
width: 4.5em !important;
margin-left: auto;
margin-right: 0;
}
.pc input[type=number].address {
width: 5em !important;
width: 6em !important;
}
.pc .cu input[type=number].address {
width: 100% !important;
align-self: end;
margin-left: auto;
margin-right: 0;
}
@ -385,6 +394,13 @@ th.address {
width: 100%;
}
.pc .cu .action-area {
display: grid;
grid-template-columns: 1fr min-content 0.5fr;
grid-row-gap: 0.5em;
grid-column-gap: 0.5em;
}
.pc .cu .input-row {
display: flex;
justify-content: space-between;
@ -403,7 +419,7 @@ th.address {
}
.pc .cu input[type=number] {
width: 9.5em;
width: 100%;
}
.pc .cu label {
@ -443,6 +459,7 @@ th.address {
color: var(--color-cu-text);
border-color: var(--color-cu-text);
background-color: transparent;
margin-bottom: 0;
}
.pc .modal .download-button {
@ -471,6 +488,10 @@ th.address {
background-color: transparent;
}
.pc .alu input {
width: 100%;
}
.pc .alu button {
margin-right: 1em;
}
@ -479,6 +500,16 @@ th.address {
margin-right: 0;
}
.pc .alu .button-group-alu__2-elements {
display: grid;
grid-template-columns: 1fr 1fr;
}
.pc .alu .button-group-alu__4-elements {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
/* BUSSES */
.pc .databus,
@ -509,7 +540,7 @@ th.address {
}
.pc .addressbus {
margin-bottom: 1em;
margin-bottom: 2em;
background-color: var(--color-addressbus);
color: var(--color-addressbus-text);
@ -523,46 +554,101 @@ th.address {
}
/* ARROWS */
.pc .arrow {
position: absolute;
bottom: 0;
left: 50%;
.pc .arrow-line {
display: flex;
justify-content: space-around;
height: 0;
width: 100%;
}
.pc .arrow {
width: 3rem;
height: 5rem;
--transformation: translate(0, -2rem);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
color: var(--color-arrow-text);
background-color: var(--color-arrow);
/* Arrow Label */
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 > :nth-child(1) {
/* Arrow Label Field */
color: var(--color-arrow-text) !important;
background-color: var(--color-arrow) !important;
border-color: var(--color-arrow-text) !important;
padding: 2px 10px;
margin: 0;
}
.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 * {
z-index: 1000;
/* Arrow Label Text */
color: var(--color-arrow-text) !important;
font-size: 1rem !important;
line-height: 1.1em !important;
font-weight: 600 !important;
text-transform: none !important;
white-space: normal !important;
height: min-content !important;
}
.pc .arrow.up > :nth-child(1){
/* transform: rotate(90deg) translate(0rem, 2rem); */
.pc .arrow :nth-child(2) {
/* Arrow Head */
height: 0;
width: 0;
border-left: 2.5rem solid transparent;
border-right: 2.5rem solid transparent;
border-top: 2rem solid transparent;
border-bottom: 2rem solid var(--color-arrow);
position: absolute;
left: -1rem;
bottom: 5rem;
}
.pc .arrow-line.top {
position: absolute;
top: 0;
}
.pc .arrow-line.bottom {
position: absolute;
bottom: 0;
}
.pc .arrow-line.top .arrow.up {
--transformation: translate(0, -2.5rem);
}
.pc .arrow-line.bottom .arrow.up {
--transformation: translate(0, -0.5rem);
}
.pc .arrow-line.top .arrow.down {
--transformation: translate(0, -4.5rem) rotate(180deg);
}
.pc .arrow-line.bottom .arrow.down {
--transformation: translate(0, -2.5rem) rotate(180deg);
}
.pc .arrow-line.top .arrow.down :nth-child(1) {
--transformation: rotate(180deg);
transform: var(--transformation);
@ -571,61 +657,13 @@ th.address {
-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;
.pc .arrow-line.bottom .arrow.down :nth-child(1) {
--transformation: rotate(180deg);
transform: var(--transformation);
-moz-transform: var(--transformation);
-webkit-transform: var(--transformation);
-o-transform: var(--transformation);
}
@ -720,7 +758,7 @@ th.address {
.pc .grid-fullwidth.grid-databus {
--width: 5rem;
--text-height: 32rem;
--margin-side: 2rem;
--margin-side: 3rem;
width: var(--width);
box-sizing: border-box;
@ -754,7 +792,7 @@ th.address {
.pc .grid-fullwidth.grid-addressbus > *,
.pc .grid-fullwidth.grid-databus > * {
position: sticky;
top: 0;
top: 6em;
left: 0;
margin: 0;
box-sizing: border-box;
@ -794,55 +832,38 @@ th.address {
margin: -1rem;
padding: 1rem;
border-bottom: 1px solid var(--color-controls-button-border);
width: 100%;
}
.pc .arrow-line {
width: 0;
height: 100%;
.pc .arrow.down{
left: inherit;
flex-direction: column;
}
.pc .arrow-line.top {
left: 0;
}
.pc .arrow-line.bottom {
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: auto !important;
right: 0;
top: 25%;
--transformation: rotate(90deg) translate(0, -2.5rem);
.pc .arrow-line.top .arrow.up {
--transformation: rotate(-90deg) translate(0, -2.85rem);
}
.pc .arrow.up > :nth-child(1) {
--transformation: rotate(-90deg);
}
.pc .arrow.top {
right: auto !important;
left: -4.5rem !important;
top: 25%;
}
/*.pc .arrow.up ~ .arrow.up {
}
.pc .arrow.up ~ .arrow.up ~ .arrow.up {
}*/
.pc .arrow.arrow2{
top: 75%;
.pc .arrow-line.bottom .arrow.up {
--transformation: rotate(-90deg) translate(0, 0.75rem);
}
.pc .arrow-line.top .arrow.down {
--transformation: rotate(90deg) translate(0, 4.5rem);
}
.pc .arrow-line.bottom .arrow.down {
--transformation: rotate(90deg) translate(0, 0.1rem);
}
.pc .alu {
text-align: center;

View File

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

View File

@ -1 +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"],[700008,"Jmp If eq 0"],[600000,"Jmp #000"],[500000,"END OF PROGRAM"],[0,""],[0,""],[0,""],[4,"ValA"],[17,"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","alert","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}
{"model-version":"4","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"],[700008,"Jmp If eq 0"],[600000,"Jmp #000"],[500000,"END OF PROGRAM"],[0,""],[0,""],[0,""],[4,"ValA"],[17,"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","alert","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}

View File

@ -1 +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}
{"model-version":"4","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"]},"autoscroll":true}

View File

@ -1 +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}
{"model-version":"4","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

@ -60,7 +60,7 @@
</li>
<li>
<b>Instruction</b>
Hiermit kannst du eine ganze Instruction ausführen lassen und musst nicht durch jeden µCode Schritt einzeln durchdrücken.
Hiermit kannst du eine ganze Instruktion ausführen lassen und musst nicht durch jeden µCode Schritt einzeln durchdrücken.
</li>
<li>
<b>Reset PC</b>
@ -72,7 +72,7 @@
</li>
<li>
<b>Configs</b>
Hier können sie die momentane Konfigration herunterladen, selber eine Hochladen oder aus einer Liste von Beispielen laden.
Hier können sie die momentane Konfiguration herunterladen, selber eine Hochladen oder aus einer Liste von Beispielen laden.
</li>
</ul>
@ -83,7 +83,7 @@
<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>
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 Adresse einfacher unterscheiden.<br>
<a href="#befehl">Siehe Befehle</a>
</p>
@ -107,7 +107,7 @@
<p>
Über den Datenbus können Daten und Befehle zwischen RAM, Control Unit und ALU übertragen werden.
</p>
<h3>Addressbus</h3>
<h3>Adressbus</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.
@ -116,14 +116,20 @@
<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.
Ein Befehl besteht aus einer Instruktion und einem Argument. Deshalb sind im RAM und im Instruction&nbsp;Register alle Werte separiert.
</p>
<pre><code>0 0 2 0 0 5 0 4
Instr Argument
</code></pre>
<p>
In den ersten 3&nbsp;Stellen wird hier der OpCode der Instruction codiert. Wenn dieser Teil in der Control&nbsp;Unit in den µCode&nbsp;Counter geladen wird, dann wird der OpCode mit 10 multipliziert.
</p>
<p>
In den letzten 5&nbsp;Stellen wird ein beliebiger Zahlenwert gespeichert. Dieser kann als Argument für einen Befehl genutzt werden.
</p>
<p>
In diesem Beispiel hier würden die µCodes ab Adresse 20 im µCode Speicher ausgeführt werden.
</p>
<pre>
<code>
0 0 0 0 0 0 0 0
Instr Argument
</code>
</pre>
<h2>µCodes</h2>
<p>
@ -138,64 +144,92 @@
</thead>
<tbody>
<tr>
<td>ProgCounter -> AddrBus</td>
<td><code>ProgCounter -> AddrBus</td>
<td>Lade den Wert des Programm Counters in den Adressbus</td>
</tr>
<tr>
<td>InstrReg -> ProgCounter</td>
<td><code>InstrReg -> ProgCounter</code></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>
<td><code>ProgCounter ++</td>
<td>Erhöhe den Wert des Programm Counter um 1</td></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>
<td><code>Acc == 0 => InstReg -> ProgCounter</code></td>
<td>Wenn der Wert des Akkumulators 0 ist, dann lade das Argument 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>
<td><code>Ram -> DataBus</code></td>
<td>Schreibe den aktuellen Wert aus den RAM auf den Datenbus</td>
</tr>
<tr>
<td>DataBus -> Ram</td>
<td><code>DataBus -> Ram</code></td>
<td>Schreibe den Wert des Datenbus in die momentane Stelle des RAM</td>
</tr>
<tr>
<td>DataBus -> InstReg</td>
<td><code>DataBus -> InstReg</code></td>
<td>Lade den Befehl vom Datenbus in das Instruktionsregister</td>
</tr>
<tr>
<td>DataBus -> Acc</td>
<td><code>DataBus -> Acc</code></td>
<td>Lade den Wert vom Datenbus in den Akkumulator der ALU</td>
</tr>
<tr>
<td>Acc -> DataBus</td>
<td><code>Acc -> DataBus</code></td>
<td>Schreibe den Wert vom Akkumulator auf den Datenbus</td>
</tr>
<tr>
<td>Acc ++</td>
<td><code>Acc ++</code></td>
<td>Erhöhe den Wert des Akkumulators um 1</td>
</tr>
<tr>
<td>Acc --</td>
<td><code>Acc --</code></td>
<td>Verringere den Wert des Akkumulators um 1</td>
</tr>
<tr>
<td>InstReg -> µCounter</td>
<td><code>Acc << DataBus</code></td>
<td>Verschiebt den Wert im Akkumulator nach links um den Wert im DatenBus.</td>
</tr>
<tr>
<td><code>Acc >> DataBus</code></td>
<td>Verschiebt den Wert im Akkumulator nach rechts um den Wert im DatenBus.</td>
</tr>
<tr>
<td><code>Acc + DataBus</code></td>
<td>Addiere den Wert im Datenbus auf den Akkumulator</td>
</tr>
<tr>
<td><code>Acc - DataBus</code></td>
<td>Subtrahiere den Wert im Datenbus auf den Akkumulator</td>
</tr>
<tr>
<td><code>Acc * DataBus</code></td>
<td>Multipliziere den Wert im Datenbus mit dem Akkumulator</td>
</tr>
<tr>
<td><code>Acc / DataBus</code></td>
<td>Dividiere den Akkumulator durch den Datenbus</td>
</tr>
<tr>
<td><code>InstReg -> µCounter</code></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>
<td><code>InstReg -> AddrBus</code></td>
<td>Lade das Argument im Instruktionsregister in den Adressbus</td>
</tr>
<tr>
<td>µCounter = 0</td>
<td><code>InstReg -> DataBus</code></td>
<td>Lade das Argument im Instruktionsregister in den Adressbus</td>
</tr>
<tr>
<td><code>µCounter = 0</code></td>
<td>Setzte den µCounter zurück</td>
</tr>
<tr>
<td>Signal End of Program</td>
<td>Zeige ein Popup, dass das Ende des Programms signalisiert.</td>
<td><code>Signal End of Program</code></td>
<td>Zeigt ein Popup, dass das Ende des Programms signalisiert.</td>
</tr>
</tbody>
</table>
@ -249,7 +283,7 @@
<h3>RAM</h3>
<p>
The current programm is stored in the RAM. Every entry is seperated as mentioned in <a href="#entry">entry</a>.
The current program is stored in the RAM. Every entry is separated as mentioned in <a href="#entry">entry</a>.
</p>
<h3>Control Unit</h3>
@ -271,28 +305,33 @@
</p>
<h3>Databus</h3>
<p>
Via the Databus values and entrys can be transported between RAM, Control Unit and ALU.
Via the databus values and entries 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.
With the addressbus the Control Unit can control which value is selected in RAM. On a normal computer there are a lot more 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.
Each entry consists of a instruction and an argument. That's why the entrys in RAM and in µCodes are displayed separately.
<pre><code>0 0 2 0 0 5 0 4
Instr Argument
</code></pre>
<p>
Here, the first 3 digits are the opCode of the instruction. When you try to load this part into the µCode&nbsp;Counter of the Control&nbsp;Unit, it will be automatically multiplied by 10.
<br>
In this example µCodes starting at the Address 20 will be executed.
</p>
<p>
The last 5 digits are a numerical value that can be used as an argument for the command.
</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:
Every instruction consists of a list of µCodes. Here is an explanation for all of them:
</p>
<table>
<thead>
@ -303,63 +342,91 @@
</thead>
<tbody>
<tr>
<td>ProgCounter -> AddrBus</td>
<td>Load the value from programm counter to addressbus</td>
<td><code>ProgCounter -> AddrBus</code></td>
<td>Load the value from program counter to addressbus</td>
</tr>
<tr>
<td>InstrReg -> ProgCounter</td>
<td>Load the argument from instruction register to programm counter</td>
<td><code>InstrReg -> ProgCounter</code></td>
<td>Load the argument from instruction register to program counter</td>
</tr>
<tr>
<td>ProgCounter ++</td>
<td>Increment programm counter by 1</td>
<td><code>ProgCounter ++</code></td>
<td>Increment program 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>
<td><code>Acc == 0 => InstReg -> ProgCounter</code></td>
<td>If the accumulator is 0 then write the argument from instruction register to program counter</td>
</tr>
<tr>
<td>Ram -> DataBus</td>
<td><code>Ram -> DataBus</code></td>
<td>Load selected value from RAM to databus</td>
</tr>
<tr>
<td>DataBus -> Ram</td>
<td><code>DataBus -> Ram</code></td>
<td>Write value from databus to selected value in RAM</td>
</tr>
<tr>
<td>DataBus -> InstReg</td>
<td><code>DataBus -> InstReg</code></td>
<td>Write entry from databus to instruction register</td>
</tr>
<tr>
<td>DataBus -> Acc</td>
<td><code>DataBus -> Acc</code></td>
<td>Write value from databus to accumulator</td>
</tr>
<tr>
<td>Acc -> DataBus</td>
<td><code>Acc -> DataBus</code></td>
<td>Load value from accumulator to databus</td>
</tr>
<tr>
<td>Acc ++</td>
<td><code>Acc ++</code></td>
<td>Increment accumulator by 1</td>
</tr>
<tr>
<td>Acc --</td>
<td><code>Acc --</code></td>
<td>Decrement accumulator by 1</td>
</tr>
<tr>
<td>InstReg -> µCounter</td>
<td><code>Acc << DataBus</code></td>
<td>Shift the Accumulator left by the value in databus</td>
</tr>
<tr>
<td><code>Acc >> DataBus</code></td>
<td>Shift the Accumulator right by the value in databus</td>
</tr>
<tr>
<td><code>Acc + DataBus</code></td>
<td>Add the value of the databus to the accumulator</td>
</tr>
<tr>
<td><code>Acc - DataBus</code></td>
<td>Subtract the value of the databus from the accumulator</td>
</tr>
<tr>
<td><code>Acc * DataBus</code></td>
<td>Multiply the value of the databus with the accumulator</td>
</tr>
<tr>
<td><code>Acc / DataBus</code></td>
<td>Divide the accumulator by the value of the databus</td>
</tr>
<tr>
<td><code>InstReg -> µCounter</code></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><code>InstReg -> AddrBus</code></td>
<td>Write the argument from instruction register to addressbus</td>
</tr>
<tr>
<td>µCounter = 0</td>
<td><code>InstReg -> DataBus</code></td>
<td>Write the argument from instruction register to databus</td>
</tr>
<tr>
<td><code>µCounter = 0</code></td>
<td>Set µCounter to 0</td>
</tr>
<tr>
<td>Signal End of Program</td>
<td><code>Signal End of Program</code></td>
<td>Show an alert that the end of program is reached.</td>
</tr>
</tbody>
@ -367,7 +434,7 @@
<h1>Source</h1>
<p>
This is a hobby projekt so please don't take my code as a "best-practice" implementation.<br>
This is a hobby project so please don't take my code as a "best-practice" implementation.<br>
</p>
<a href="https://git.yokta.de/Christian/Johnny" class="button">See Source Code</a>
<p>
@ -382,7 +449,7 @@
<div class="container">
<p>
Made with ☕ <br>
© <a href="https://github.com/ChrisgammaDE" target="_blank">Christian</a>, 2021
© <a href="https://github.com/ChrisgammaDE" target="_blank">Christian</a>, 2022
</p>
<p>
<a href="https://yokta.de/i/impressum.html" target="_blank">Impressum</a>

View File

@ -25,8 +25,8 @@ import File.Download as Download
-- PC Stuff
import PC.Types exposing (..)
import PC.PC as PC
import PC.Json
import PC.PC as PC
import PC.Json
import PC.Helpers exposing (..)
-- Note that general Stuff is at the end of the document
@ -287,7 +287,7 @@ cmd_up_lStorage_n_Scroller model =
Cmd.batch
[ cmd_up_lStorage model
, cmd_scoller model
]
]
-- ###############################################################################
-- ###############################################################################
@ -329,15 +329,15 @@ doDecodeModel jText =
_ -> Nothing
in
jText
|> JD.decodeString modelDecoder
|> JD.decodeString modelDecoder
|> error2maybe
modelDecoder : JD.Decoder Model
modelDecoder =
modelDecoder =
let
mainDecoder : String -> JD.Decoder Model
mainDecoder version =
if (version == pcModelVersion) then
if (version == "4" || version == "3") then
JD.map2
(\a b -> Model a b [] False Waiting Waiting initDragDrop False )
( JD.field "pc_model" PC.Json.pcModelDecoder )

View File

@ -43,11 +43,11 @@ initialRam = Array.fromList
initialUCodes : Array UAction
initialUCodes = Array.fromList
[ UA_ProgrammCounter2AddressBus -- 000
[ UA_CU_ProgrammCounter2AddressBus -- 000
, UA_Ram2DataBus -- 001
, UA_DataBus2InstructionReg -- 002
, UA_ProgrammCounterIncrement -- 003
, UA_InstructionReg2UCounter -- 004
, UA_CU_ProgrammCounterIncrement -- 003
, UA_CU_InstructionReg2UCounter -- 004
, UA_Nothing -- 005
, UA_Nothing
, UA_Nothing
@ -55,10 +55,10 @@ initialUCodes = Array.fromList
, UA_Nothing -- 009
-- 010 LOADA
, UA_InstructionReg2AddressBus -- 010
, UA_CU_InstructionReg2AddressBus -- 010
, UA_Ram2DataBus -- 011
, UA_DataBus2Accumulator -- 012
, UA_ResetUCounter -- 013
, UA_CU_ResetUCounter -- 013
, UA_Nothing -- 014
, UA_Nothing
, UA_Nothing
@ -67,10 +67,10 @@ initialUCodes = Array.fromList
, UA_Nothing -- 019
-- 020 STOA
, UA_Accumulator2DataBus -- 020
, UA_InstructionReg2AddressBus -- 021
, UA_ALU_Accumulator2DataBus -- 020
, UA_CU_InstructionReg2AddressBus -- 021
, UA_DataBus2Ram -- 022
, UA_ResetUCounter -- 023
, UA_CU_ResetUCounter -- 023
, UA_Nothing --024
, UA_Nothing
, UA_Nothing
@ -79,8 +79,8 @@ initialUCodes = Array.fromList
, UA_Nothing -- 029
-- 030 INCA
, UA_AccumulatorIncrement -- 030
, UA_ResetUCounter -- 031
, UA_ALU_AccumulatorIncrement -- 030
, UA_CU_ResetUCounter -- 031
, UA_Nothing -- 032
, UA_Nothing
, UA_Nothing
@ -91,8 +91,8 @@ initialUCodes = Array.fromList
, UA_Nothing -- 039
-- 040 JMP
, UA_InstructionReg2ProgrammCounter -- 040
, UA_ResetUCounter -- 041
, UA_CU_InstructionReg2ProgrammCounter -- 040
, UA_CU_ResetUCounter -- 041
, UA_Nothing -- 042
, UA_Nothing
, UA_Nothing

View File

@ -2,7 +2,7 @@ module PC.Types exposing (..)
import Array exposing (Array)
pcModelVersion = "3"
pcModelVersion = "4"
type alias PC_Model =
{ pc : PC
@ -26,21 +26,29 @@ type alias UCode =
, label : String
}
-- UActions that can be used in µCode
type UAction
= UA_Accumulator2DataBus
| UA_AccumulatorDecrement
| UA_AccumulatorIncrement
= UA_ALU_Accumulator2DataBus
| UA_ALU_AccumulatorDecrement
| UA_ALU_AccumulatorIncrement
| UA_ALU_AccumulatorShiftLeftByDataBus
| UA_ALU_AccumulatorShiftRightByDataBus
| UA_ALU_AccumulatorAddByDataBus
| UA_ALU_AccumulatorSubtractByDataBus
| UA_ALU_AccumulatorMultiplyByDataBus
| UA_ALU_AccumulatorDivideByDataBus
| UA_CU_InstructionReg2AddressBus
| UA_CU_InstructionReg2DataBus
| UA_CU_InstructionReg2ProgrammCounter
| UA_CU_InstructionReg2UCounter
| UA_CU_ProgrammCounterIncrement
| UA_CU_InstructionReg2ProgrammCounterIfAccEq0
| UA_CU_ProgrammCounter2AddressBus
| UA_CU_ResetUCounter
| UA_DataBus2Accumulator
| UA_DataBus2InstructionReg
| UA_DataBus2Ram
| UA_InstructionReg2AddressBus
| UA_InstructionReg2ProgrammCounter
| UA_InstructionReg2UCounter
| UA_ProgrammCounterIncrement
| UA_InstructionReg2ProgrammCounterIfAccEq0
| UA_Ram2DataBus
| UA_ResetUCounter
| UA_ProgrammCounter2AddressBus
| UA_AlertUser
| UA_Nothing

View File

@ -11,23 +11,30 @@ import PC.Helpers exposing (..)
uCodes : List UCode
uCodes =
[ UCode UA_Nothing "n" (\s -> s) "Empty"
, 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_InstructionReg2ProgrammCounterIfAccEq0
"ir2pciacceq0" actInstructionReg2ProgrammCounterIfAccEq0 "Acc == 0 => InstReg -> ProgCounter"
, UCode UA_AlertUser "alert" actDoAlert "Signal End of Programm"
[ UCode UA_Nothing "n" (\s -> s) "Empty"
, UCode UA_ALU_Accumulator2DataBus "acc2db" actAccumulator2DataBus "Acc -> DataBus"
, UCode UA_ALU_AccumulatorDecrement "accDec" actAccumulatorDecrement "Acc --"
, UCode UA_ALU_AccumulatorIncrement "accInc" actAccumulatorIncrement "Acc ++"
, UCode UA_ALU_AccumulatorShiftLeftByDataBus "accLsN" actAccumulatorShiftLeft "Acc << DataBus"
, UCode UA_ALU_AccumulatorShiftRightByDataBus "accRsN" actAccumulatorShiftRight "Acc >> DataBus"
, UCode UA_ALU_AccumulatorAddByDataBus "accAdd" actAccumulatorAdd "Acc + DataBus"
, UCode UA_ALU_AccumulatorSubtractByDataBus "accSub" actAccumulatorSub "Acc - DataBus"
, UCode UA_ALU_AccumulatorMultiplyByDataBus "accMul" actAccumulatorMultiply "Acc * DataBus"
, UCode UA_ALU_AccumulatorDivideByDataBus "accDiv" actAccumulatorDivide "Acc / DataBus"
, UCode UA_CU_InstructionReg2AddressBus "ir2ab" actInstructionReg2AddressBus "InstReg -> AddrBus"
, UCode UA_CU_InstructionReg2DataBus "ir2db" actInstructionReg2DataBus "InstReg -> DataBus"
, UCode UA_CU_InstructionReg2ProgrammCounter "ir2pc" actInstructionReg2ProgrammCounter "InstReg -> ProgCount"
, UCode UA_CU_InstructionReg2UCounter "ir2uc" actInstructionReg2UCounter "InstReg -> µCounter"
, UCode UA_CU_ProgrammCounterIncrement "pcInc" actProgrammCounterIncrement "ProgCounter ++"
, UCode UA_CU_ProgrammCounter2AddressBus "pc2ab" actProgrammCounter2AddressBus "ProgCounter -> AddrBus"
, UCode UA_CU_ResetUCounter "ucReset" actResetUCounter "µCounter = 0"
, UCode UA_CU_InstructionReg2ProgrammCounterIfAccEq0
"ir2pciacceq0" actInstructionReg2ProgrammCounterIfAccEq0 "Acc == 0 => InstReg -> ProgCounter"
, UCode UA_DataBus2Accumulator "db2acc" actDataBus2Accumulator "DataBus -> Acc"
, UCode UA_DataBus2InstructionReg "db2ir" actDataBus2InstructionReg "DataBus -> InstReg"
, UCode UA_DataBus2Ram "db2ram" actDataBus2Ram "DataBus -> Ram"
, UCode UA_Ram2DataBus "ram2db" actRam2DataBus "Ram -> DataBus"
, UCode UA_AlertUser "alert" actDoAlert "Signal End of Programm"
]
@ -73,6 +80,12 @@ actInstructionReg2AddressBus pc =
in
{ pc | addressBus = address }
actInstructionReg2DataBus : PC -> PC
actInstructionReg2DataBus pc =
let
(_, data) = seperateInstructionsEntry pc.instructionReg
in
{ pc | dataBus = data }
actInstructionReg2ProgrammCounter : PC -> PC
actInstructionReg2ProgrammCounter pc =
@ -121,6 +134,31 @@ actAccumulatorDecrement : PC -> PC
actAccumulatorDecrement pc =
{ pc | accumulator = pc.accumulator - 1 }
actAccumulatorShiftLeft : PC -> PC
actAccumulatorShiftLeft pc =
{ pc | accumulator = pc.accumulator * (2 ^ pc.dataBus) }
actAccumulatorShiftRight : PC -> PC
actAccumulatorShiftRight pc =
{ pc | accumulator = pc.accumulator // (2 ^ pc.dataBus) }
actAccumulatorAdd : PC -> PC
actAccumulatorAdd pc =
{ pc | accumulator = pc.accumulator + pc.dataBus }
actAccumulatorSub : PC -> PC
actAccumulatorSub pc =
{ pc | accumulator = pc.accumulator - pc.dataBus }
actAccumulatorMultiply : PC -> PC
actAccumulatorMultiply pc =
{ pc | accumulator = pc.accumulator * pc.dataBus }
actAccumulatorDivide : PC -> PC
actAccumulatorDivide pc =
{ pc | accumulator = pc.accumulator // pc.dataBus }
actDataBus2Ram : PC -> PC
actDataBus2Ram pc =

View File

@ -11,9 +11,9 @@ import PC.Helpers exposing (..)
pc_update : PC_Msg -> PC_Model -> (PC_Model, PC_AfterUpdateAction)
pc_update msg model =
case msg of
PM_B_UCycleStep ->
PM_B_UCycleStep ->
let (new_model, reqAlert) = uStepPC model
in
in
( new_model
, if reqAlert == True then PUA_Alert
else if model.pc.uCounter == 0 then PUA_Storage_And_Scroller

View File

@ -37,7 +37,9 @@ 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 "arrow-line", class "top" ]
[ div [ class "arrow", class "down"] [ div [] [] , div [] [] ]
]
, div [ class "scroller" ]
[ Html.table [ class "" ]
[ Html.thead [ class "head" ]
@ -50,8 +52,10 @@ viewRam model =
, lazy viewRamContent model
]
]
, drawArrow Bottom Down UA_Ram2DataBus "Ram -> DataBus"
, drawArrow Bottom Up UA_DataBus2Ram "DataBus -> Ram"
, div [ class "arrow-line", class "bottom" ]
[ drawArrow Down UA_Ram2DataBus "Ram -> DataBus"
, drawArrow Up UA_DataBus2Ram "DataBus -> Ram"
]
]
@ -129,81 +133,58 @@ viewCu model =
( 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 [] []
-- ]
[ div [ class "arrow-line", class "top" ]
[ drawArrow Up UA_CU_InstructionReg2AddressBus "InstR -> AddrB"
, drawArrow Up UA_CU_ProgrammCounter2AddressBus "ProgCounter -> AddrB"
]
, 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 "action-area" ]
[ -- Programm Counter
Html.label [ HAttr.for "cu-progcounter" ] [ text "Programm Counter:" ]
, button
[ onClick <| PM_ManualStep UA_CU_InstructionReg2ProgrammCounter ]
[ text "InstRA -> " ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-progcounter"
, value (addLeadingZero model.pc.programmCounter 3)
, onInput PM_F_CuProgCounterEdit
] []
-- IR
, Html.label [HAttr.for "cu-instrReg" ] [ text "Instruction Register:" ]
, 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
] []
-- µCounter
, Html.label [ HAttr.for "cu-uCounter" ] [ text "µCode Counter:" ]
, button
[ onClick <| PM_ManualStep UA_CU_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"
, div [ class "arrow-line", class "bottom" ]
[ drawArrow Up UA_DataBus2InstructionReg "DB -> InstR"
, drawArrow Down UA_CU_InstructionReg2DataBus "InstR -> DB"
]
]
@ -282,7 +263,7 @@ viewAlu : PC_Model -> Html PC_Msg
viewAlu model =
div [ class "section", class "alu" ]
[ h1 [ class "header" ] [ text "ALU" ]
, p []
, p []
[ Html.label [ HAttr.for "alu-accumulator" ] [ text "Accumulator:" ]
, Html.input
[ HAttr.type_ "number"
@ -291,22 +272,31 @@ viewAlu model =
, onInput PM_F_AluEdit
] []
]
, p []
[ button [ onClick <| PM_ManualStep UA_AccumulatorIncrement ] [ text "Acc ++" ]
, button [ onClick <| PM_ManualStep UA_AccumulatorDecrement ] [ text "Acc --" ]
, div []
[ Html.span [] [ text "General µActions" ]
, Html.br [] []
, div [ class "button-group-alu__2-elements" ]
[ button [ onClick <| PM_ManualStep UA_ALU_AccumulatorIncrement ] [ text "Acc ++" ]
, button [ onClick <| PM_ManualStep UA_ALU_AccumulatorDecrement ] [ text "Acc --" ]
]
]
, div []
[ Html.span [] [ text "µActions from DataBus" ]
, div [ class "button-group-alu__2-elements" ]
[ button [ onClick <| PM_ManualStep UA_ALU_AccumulatorShiftLeftByDataBus ] [ text "LeftShift"]
, button [ onClick <| PM_ManualStep UA_ALU_AccumulatorShiftRightByDataBus ] [ text "RightShift" ]
]
, div [ class "button-group-alu__4-elements" ]
[ button [ onClick <| PM_ManualStep UA_ALU_AccumulatorAddByDataBus ] [ text "+" ]
, button [ onClick <| PM_ManualStep UA_ALU_AccumulatorSubtractByDataBus ] [ text "-" ]
, button [ onClick <| PM_ManualStep UA_ALU_AccumulatorMultiplyByDataBus ] [ text "*" ]
, button [ onClick <| PM_ManualStep UA_ALU_AccumulatorDivideByDataBus ] [ text "/" ]
]
]
, div [ class "arrow-line", class "bottom" ]
[ drawArrow Up UA_DataBus2Accumulator "DB -> ALU"
, drawArrow Down UA_ALU_Accumulator2DataBus "ALU -> DB"
]
, 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 [] []
-- ]
]
-- #####################################################################
@ -350,17 +340,16 @@ viewAddressBus model =
-- 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 =
drawArrow : Arrow_Dir -> UAction -> String -> Html PC_Msg
drawArrow dir act str =
div
[ HAttr.classList
[ ("arrow", True)
, ("top", pos == Top)
, ("up", dir == Up)
, ("down", dir == Down)]
, ("up", dir == Up)
, ("down", dir == Down)
]
]
[ div [ class "button" ]
[ Html.a