Added whole Instruction step and a basic how to

This commit is contained in:
Christian 2020-12-27 18:10:07 +01:00
parent 20fb9914ef
commit dc9b5c725e
5 changed files with 1249 additions and 1326 deletions

View File

@ -1,571 +1,30 @@
/* COLORS */
body {
background-color: var(--color-body);
color: var(--color-body-text);
.noscript {
box-sizing: border-box;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.pc .addressbus {
background-color: var(--color-addressbus);
color: var(--color-addressbus-text);
.spacer {
height: 3rem;
width: 100%;
}
.pc .databus {
background-color: var(--color-databus);
color: var(--color-databus-text);
.hidden {
display: none !important;
}
.pc .ram {
background-color: var(--color-ram);
color: var(--color-ram-text);
section.fullheight {
min-height: 100vh;
}
.pc .cu {
background-color: var(--color-cu);
color: var(--color-cu-text);
footer{
margin-top: 20rem;
}
.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);
}
/* 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 {
margin: 0;
}
.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;
}
/* 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;
}
.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 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;
}
.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;
}
.pc .databus {
margin-top: 2em;
}
/* ARROWS */
.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) ; */
transform: translate(0, 3rem);
z-index: 100;
font-size: 0.5em;
color: var(--color-arrow-text);
background-color: var(--color-arrow);
}
.arrow.down {
left: 25%;
}
.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);
}
.arrow.up.arrow2 {
left: 50%;
}
.arrow.top {
bottom: auto;
top: -6rem;
}
.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;
}
.arrow > :nth-child(1) *{
color: var(--color-arrow-text);
display: block;
white-space: break-spaces;
}
.arrow > :nth-child(1):hover, .arrow > :nth-child(1) *:hover {
color: var(--color-arrow-text-hover);
}
.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: "❌";
}

1455
out/elm.js

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,9 @@
<!-- 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
-->
@ -17,6 +17,7 @@
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/skeleton.css" />
<link rel="stylesheet" href="css/colors-light.css">
<link rel="stylesheet" href="css/pc.css" />
<link rel="stylesheet" href="css/style.css" />
<!-- Favicon
@ -27,11 +28,359 @@
<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 ☕
by <a href="https://github.com/ChrisgammaDE" target="_blank">Christian</a>
</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="pc.js"></script>
<script src="script.js"></script>
</body>
</html>

View File

@ -1,76 +1,26 @@
// Init Elm
var app = Elm.Main.init({
node: document.getElementById("elm"),
// flags: Date.now()
});
let text_de = document.getElementById("langDE");
let text_en = document.getElementById("langEN");
// 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 btn_changeToDe = document.getElementById("langPickerDE");
let btn_changeToEn = document.getElementById("langPickerEN");
let pc_ram_scroller = pc_ram.getElementsByClassName("scroller")[0];
let pc_cu_scroller = pc_cu.getElementsByClassName("scroller")[0];
let lang = (typeof document.documentElement.lang == "string") ? document.documentElement.lang: "en"
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 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");
}
}
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 );
}
}
btn_changeToEn.addEventListener("click", () => { changeLang("en") } );
btn_changeToDe.addEventListener("click", () => { changeLang("de") } );
// 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);
} );
// Do stuff on loading
changeLang( lang );

View File

@ -74,6 +74,7 @@ type UAction
| ActInstructionReg2ProgrammCounter
| ActInstructionReg2UCounter
| ActProgrammCounterIncrement
| ActInstructionReg2ProgrammCounterIfAccEq0
| ActRam2DataBus
| ActResetUCounter
| ActProgrammCounter2AddressBus
@ -91,6 +92,7 @@ uCodeDescriptions =
, ( ActInstructionReg2ProgrammCounter, "InstReg -> ProgCount" )
, ( ActInstructionReg2UCounter, "InstReg -> µCounter" )
, ( ActProgrammCounterIncrement, "ProgCounter ++" )
, ( ActInstructionReg2ProgrammCounterIfAccEq0, "Acc == 0 => InstReg -> ProgCounter")
, ( ActRam2DataBus, "Ram -> DataBus" )
, ( ActResetUCounter, "µCounter = 0" )
, ( ActProgrammCounter2AddressBus, "ProgCounter -> AddrBus" )
@ -109,6 +111,7 @@ uCodeIds =
, ( ActInstructionReg2ProgrammCounter, "ir2pc" )
, ( ActInstructionReg2UCounter, "ir2uc" )
, ( ActProgrammCounterIncrement, "pcInc" )
, ( ActInstructionReg2ProgrammCounterIfAccEq0, "ir2pciacceq0")
, ( ActRam2DataBus, "ram2db" )
, ( ActResetUCounter, "ucReset" )
, ( ActProgrammCounter2AddressBus, "pc2ab" )
@ -127,6 +130,7 @@ uCodeMaps =
, ( ActInstructionReg2ProgrammCounter, actInstructionReg2ProgrammCounter )
, ( ActInstructionReg2UCounter, actInstructionReg2UCounter )
, ( ActProgrammCounterIncrement, actProgrammCounterIncrement )
, ( ActInstructionReg2ProgrammCounterIfAccEq0, actInstructionReg2ProgrammCounterIfAccEq0 )
, ( ActRam2DataBus, actRam2DataBus )
, ( ActResetUCounter, actResetUCounter )
, ( ActProgrammCounter2AddressBus, actProgrammCounter2AddressBus )
@ -236,7 +240,8 @@ type Msg
| MsgRamAddBelow
| MsgCuEditAction Int String
| MsgCuAddBelow
| MsgCuInstrRegEdit String
| MsgCuInstrRegEditAddr String
| MsgCuInstrRegEditInstr String
| MsgCuUCounterEdit String
| MsgCuProgCounterEdit String
| MsgEditAddressBus String
@ -265,16 +270,22 @@ update msg model =
)
MsgInstructionStep ->
( model, Cmd.none )
( executeInstruction model
, cmdSenduUpdate model )
MsgReset ->
updateModel { model | pc = { initialPC | ram = model.pc.ram } }
let
new_model = { model | pc = { initialPC | ram = model.pc.ram } }
in
( new_model, cmdSenduUpdate new_model )
MsgManualStep action ->
let
instruction = getAction action
new_model = { model | pc = instruction model.pc }
in
updateModel { model | pc = instruction model.pc}
( new_model, cmdSenduUpdate new_model )
MsgRamEditAddress addr may_int ->
case String.toInt may_int of
@ -319,11 +330,22 @@ update msg model =
MsgCuAddBelow ->
updateModel {model | uCode = model.uCode ++ [ ActNothing ]}
MsgCuInstrRegEdit text ->
MsgCuInstrRegEditAddr text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | instructionReg = int }
(instr,_) = seperateInstructionsEntry old_pc.instructionReg
new_pc = { old_pc | instructionReg = instr * 100000 + int }
in
updateModel { model | pc = new_pc }
_ -> ( model, Cmd.none )
MsgCuInstrRegEditInstr 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
updateModel { model | pc = new_pc }
_ -> ( model, Cmd.none )
@ -374,7 +396,14 @@ update msg model =
_ -> ( model, Cmd.none )
MsgAutoscrollUpdate ->
updateModel { model | autoscroll = not model.autoscroll }
if model.autoscroll then
updateModel { model | autoscroll = False }
else
let
new_model = { model | autoscroll = True }
in
( new_model
, cmdSenduUpdate new_model )
MsgLocalSessionExport ->
( model, cmdUpdateLocalStorage model )
@ -481,6 +510,16 @@ uStepPC model =
model
executeInstruction : Model -> Model
executeInstruction model =
let
new_model = uStepPC model
in
if new_model.pc.uCounter == 0 then
uStepPC new_model
else
executeInstruction new_model
encodeModel : Model -> String
encodeModel model =
JE.object
@ -595,7 +634,7 @@ viewPC model =
div
[ class "pc" ]
[ div [ class "controls", class "grid-fullwidth" ]
[ button [ onClick MsgUCycleStep ] [ text "µZyklus" ]
[ button [ onClick MsgUCycleStep ] [ text "µCycle" ]
, button [ onClick MsgInstructionStep ] [ text "Instruction" ]
, button [ onClick MsgReset ] [ text "Reset PC" ]
, div
@ -616,7 +655,6 @@ viewPC model =
[ HAttr.for "enableScrolling" ]
[ text "Autoscroll" ]
]
, button [ onClick MsgLocalSessionExport ] [ text "Export" ]
, button [ onClick MsgToggleLoadExample ] [ text "Load Example" ]
]
, div [ class "grid-fullwidth" ] [ lazy viewAddressBus model ]
@ -715,6 +753,9 @@ viewRamContent model =
viewCu : Model -> Html Msg
viewCu model =
let
( instrRegInst, instrRegAddr ) = seperateInstructionsEntry model.pc.instructionReg
in
div [ class "section", class "cu" ]
[ div [ class "arrow", class "up", class "top"]
[ div [ class "button" ]
@ -730,6 +771,9 @@ viewCu model =
, p []
[ div [class "input-row"]
[ Html.label [ HAttr.for "cu-progcounter" ] [ text "Programm Counter:" ]
, button
[ onClick <| MsgManualStep ActInstructionReg2ProgrammCounter ]
[ text "InstRA -> " ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-progcounter"
@ -740,16 +784,30 @@ viewCu model =
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-instrReg" ] [ text "Instruction Register:" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, value (addLeadingZero model.pc.instructionReg 8)
, onInput MsgCuInstrRegEdit
] []
, div []
[ Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "instruction"
, value (addLeadingZero instrRegInst 3)
, onInput MsgCuInstrRegEditInstr
] []
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "address"
, value (addLeadingZero instrRegAddr 5)
, onInput MsgCuInstrRegEditAddr
] []
]
]
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-uCounter" ] [ text "µCode Counter:" ]
, button
[ onClick <| MsgManualStep ActInstructionReg2UCounter
]
[ text "IntrRI ->" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-uCounter"
@ -775,8 +833,8 @@ viewCuUCode model =
Html.table []
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "Addr" ]
, Html.th [] [ text "Code" ]
[ Html.th [ class "address" ] [ text "µCounter" ]
, Html.th [] [ text "µCode" ]
]
]
, lazy viewCuUCodeContent model
@ -846,7 +904,10 @@ viewAlu model =
, value (addLeadingZero model.pc.accumulator 8)
, onInput MsgAluEdit
] []
]
, p []
[ button [ onClick <| MsgManualStep ActAccumulatorIncrement ] [ text "Acc ++" ]
, button [ onClick <| MsgManualStep ActAccumulatorDecrement ] [ text "Acc --" ]
]
, div [ class "arrow", class "up"]
[ div [ class "button" ]
@ -1003,6 +1064,15 @@ 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 =