| |
|
|
- Seite 1 - |
|
 HofK | Auf einen heißen Tipp von IF hin, habe ich mir mal three.js [...] angeschaut. Da [...] (ganz unten) die ersten Resultate. |
|
|
| |
|
|
|
| |
|
- Seite 39 - |
|
 HofK | Die Zuordnung der 8 Bit Maschinenbefehle zu den Assembler-Mnemonics und den Operanden ist eine recht umfangreiche XProfan Prozedur.
proc assembler_to_binary_code ' Assembler --> Binärcode
Ich habe sie zwar einfach in mein Javascript kopieren können, aber dann geht die Arbeit erst richtig los.
Bei der Entwicklung der "höheren" Programmiersprachen in den letzten mehr als 60 Jahren, sind die Autoren nicht sehr einheitlich vorgegangen. Zwar ist das Vokabular ( bzw. die Abkürzungen ) in der Regel der englischen Sprache entnommen, aber für eine Sache werden trotzdem verschiedene Bezeichner benutzt. Und dann die unterschiedlichen Trennzeichen und Klammerungen. Da kann man leicht den Überblick verlieren.
Aus select mn$ ... endselect wird switch( mn$ ) { ... }
und die Fälle ändern sich von z.B. caseof "NOP" zu case "NOP":
Macht man aus caseof per Ersetzung case, fehlt noch der Doppelpunkt und man bemerkt hinterher, dass da schon ein case in XProfan war!
case mn$="JIN" : oc$ = "000"+"0"+"10"+"01"
Hätte man vorher zu einem if( mn$ === "JIN" ) oc$ = "000"+"0"+"10"+"01"; machen sollen.
Mit etwas Geduld ist es aber geschafft!
Ein weiteres Problem ist das unterschiedliche Ereignismodell.
In XProfan habe ich mit einer verschachtelten Ereignisabfrage gearbeitet.
repeat' >>>>>> Ereignisschleife Halt/Weiter/Einzelschritt und MGA-Display >>>>>>>
'------- (äussere Ereignisschleife)
waitinput
'-------
...
repeat' innere Ereignisschleife
'........
waitinput' EREIGNISABFRAGE für mögliche Aktionen: X STOP Programm / weiter ausführen / einen Befehl weiter
'........
...
Im Browser benutzt man Ereignis-Lauscher in der Form
mn.addEventListener( 'input', onMnInput );
für jedes Element und jedes Ereignis und ordnet dem eine Funktion zu.
Das wirft den ganzen Algorithmus in seiner Struktur über den Haufen. Man muss es gänzlich neu strukturieren.
Auf /dev [...] funktioniert jetzt erst einmal der Eintrag des 8 Bit Binärcodes in das Feld Op Code links neben Mnemonic.
Beim Test darauf achten, dass nur gültige Befehle zu einem sinnvollen Ergebnis führen, unsinnige Kombinationen ergeben immer den NOP Befehl 00000000. |
|
|
| |
|
|
|
 HofK | Der Anfang für die Verbindung von 2D HTML/CSS GUI und 3D three.js RAM ist gemacht. Die binären Operationscodes werden in den RAM übertragen.
Allerdings ist die Sache noch nicht vollständig. Die Funktion restore_instruction( ); muss noch realisiert werden und die Adresse wird noch dezimal angezeigt. Auch gibt es Abweichungen wegen des Ereignismodells.
function animate() {
// t += 0.005;
requestAnimationFrame( animate );
for ( let i = 0; i < 8 ; i ++ ) {
if ( oc$[i] ==='0' ) {
visibilityRAM( iMeshRamDig0, coderow, i, visible );
visibilityRAM( iMeshRamDig1, coderow, i, hidden );
} else {// === '1'
visibilityRAM( iMeshRamDig0, coderow, i, hidden );
visibilityRAM( iMeshRamDig1, coderow, i, visible );
}

Aktuell bei /dev
----- |
|
|
| |
|
|
|
 p.specht | Tolles Lehrmittel! Bedeutet restore_instruction(), dass dein Programm sogar disassemblieren kann? Frohe Festtage, Klaus! |
|
|
| |
|
|
|
 HofK | Wenn man mit Hilfe der Buttons

im RAM vor und zurück geht, muss der Befehl (ebenso die Konstante) aus dem RAM wieder in der Programmieroberfläche rekonstruiert werden. Ansonsten wird der RAM Inhalt an der neuen Stelle mit den in der Oberfläche stehenden Werten überschrieben. Das ist gegenwärtig noch der Stand. Bald nicht mehr!
Der Code von XProfan muss angepasst übernommen werden.
'{--- Hilfsprozeduren Assembler ------
proc restore_instruction' Befehl (Eingabe) mit Kommentar wiederherstellen
settext mn% , left$( gettext$(RAM%, coderow%,3) , 3)' Mnemonic setzen
settext op1%, mid$( gettext$(RAM%, coderow%,3) , 5, 4)' Op 1 setzen
settext op2%, mid$( gettext$(RAM%, coderow%,3) ,10, 4)' Op 2 setzen
settext opcomm%, trim$(mid$(comment$[coderow%],2,255))' Kommentar zum Befehlsetzen
endproc
proc restore_const' Konstante (Eingabe) mit Kommentar wiederherstellen
settext coninp%, trim$( left$( gettext$(RAM%, conrow%,3) ,4) )
settext concomm%, trim$(mid$(comment$[conrow%],2,255))
endproc
proc restore_from_RAM' Befehl oder Konstante aus RAM mit Kommentar wiederherstellen
if (ramrow% > -1) AND (ramrow% < 128)' ramrow% ist -1 wenn auf "Teilzeile" am Ende der Gridbox geklickt wird!
coderow% = ramrow%
restore_instruction' Mnemonic Op1,2 und Kommentar in Eingabe-Edits setzen
endif
if (ramrow% > 127) AND (ramrow% < 256)
conrow% = ramrow%
restore_const' Konstante (Eingabe) mit Kommentar setzen
endif
endproc
Wird etwas aufwändiger, da der RAM in 3D gestaltet ist.
----------- |
|
|
| |
|
|
|
 p.specht | Die Industrie ätzt Chips ja mittlerweile auch in 3D bzw. viel-lagig. Anders wären die Smarthandys ja nie so flach zu kriegen. Faszinierend! |
|
|
| |
|
|
|
 HofK | Bisher bestand der RAM nur aus den 8 Bit Zellen in 3D. Da der Mensch die vielen Nullen und Einsen geistig aber in der Regel nicht verkraftet, habe ich die Assemblerbefehle danebengestellt.
Nach einigen Tests habe ich mich entschieden, diese als THREE.PlaneBufferGeometry zu realisieren. Dabei wird der dynamische Inhalt mittels Canvas Textur dargestellt.
Das ist nicht echt 3D, aber three.js 3D Text ist zu aufwändig und diese "Hilfsdarstellung" würde zu sehr vom eigentlichen RAM mit Nullen und Einsen in den transparenten 3D Zellen ablenken.
Da instanced Meshes zwar unterschiedliche Farben und Positionen der einzelnen Meshes unterstützen [...] , nicht aber unterschiedliche Texturen, muss man ein Array von Rechtecken erzeugen und positionieren. Das Seitenverhältnis der PlaneBufferGeometry entspricht dem von canvas.
In der animate Funktion aktualisiert man den Text.
Dazu benutzt man die Funktion changeCanvas.

aktuell bei /dev |
|
|
| |
|
|
|
 HofK | Beim RAM gab es noch einige Änderungen und er ist nun auch schon wesentlich funktioneller.
function changeCanvas( canvasTexture, ctx, txt ) ist nun function canvasSet( texture, ctx, bgr, w, h, txt )
Dazu kommt
um die aktuelle Assemblerzeile hervorzuheben. Bei XProfan erledigte das die Suche mit
in der Gridbox.
Hier sieht man, dass man Abläufe nicht so einfach übertragen kann.
Im Unterschied zur Windows Gridbox wird im Browser nur der Assemblerteil farblich hervorgehoben.
Man kann nun bereits im RAM (im Assemblerteil) herumklicken und dann links unter ASSEMBLER-COMMAND Befehle eingeben. Das sowohl mit der Auswahlliste, als auch durch Eintrag. Die Buttons für vorheriger/nächster Befehl funktionieren ebenfalls.
aktuell bei /dev |
|
|
| |
|
|
|
 HofK | 3D macht an einige Stellen erheblich mehr Code notwendig. Bei der XProfan Gridbox
var RAM% = create("Gridbox", %hwnd, ramkopf$, 0, 4, 18, 379, 664)
bekommt man von Windows die Bedienung der Scrolleiste gratis dazu.
Für die Browservariante habe ich zwei 3D Pfeile gebastelt und sie mit Funktionalität versehen. Das wird mit raycast realisiert. Dabei funktioniert .name wie bei Radiobuttons als Gruppenname. Es wird also nur geprüft, ob das Element diesen Namen hat.

const RAMup = new THREE.Group( );
const geoRAMupCyl = new THREE.CylinderBufferGeometry( 0.2, 0.2, 6, 6, 1 );
const meshRAMupCyl = new THREE.Mesh( geoRAMupCyl, matRAMupDown );
meshRAMupCyl.name ='up';
RAMup.add( meshRAMupCyl );
objectsToRaycast.push( meshRAMupCyl );
const geoRAMupCone = new THREE.CylinderBufferGeometry( 0, 0.4, 1.6, 6, 1 );
const meshRAMupCone = new THREE.Mesh( geoRAMupCone, matRAMupDown );
meshRAMupCone.name ='up';
meshRAMupCone.position.y = 3.8;
RAMup.add( meshRAMupCone );
objectsToRaycast.push( meshRAMupCone );
RAMup.position.x = 24.5;
RAMup.position.y = 4;
sceneRight.add( RAMup )
Mittlerweile kann man Assemblerbefehle und Konstanten eingeben und den grünen Startknopf drücken. Da werden bisher nur die Programmierelemente verborgen. Mit dem x Button neben STOP kommen sie wieder.
aktuell bei /dev |
|
|
| |
|
|
|
 HofK | Seit Ende 2020 gibt es einen deutschen Kanal für three.js auf discord.

Da ist bisher noch nicht viel los. Gestern kam eine Frage zum Import von Modellen. Daraufhin habe ich mein altes Beispiel aktualisiert und gleichzeitig ES6 Module benutzt. Dabei 3 Varianten zur Einbindung der Module zum Test aufgelistet.
<script type="module">
// ----- import from the web -----
// current revision from the repository
/*
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { OBJLoader } from 'https://threejs.org/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'https://threejs.org/examples/jsm/loaders/MTLLoader.js';
*/
// or a specific revision from a CDN ( Content Delivery Network, e.g. https://www.jsdelivr.com/package/npm/three )
/*
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.124.0/build/three.module.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.124.0/examples/jsm/controls/OrbitControls.js';
import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.124.0/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.124.0/examples/jsm/loaders/MTLLoader.js';
*/
// ----- import local -----
// NOTE! changed identifiers (.rev) and changed import statements at the beginning of the files
// https://hofk.de/main/discourse.threejs/Local%20use%20of%20the%20examples.pdf
// see https://hofk.de/main/discourse.threejs/Module%20usage.pdf
import * as THREE from'../jsm/three.module.124.js'; //
import { OrbitControls } from'../jsm/OrbitControls.124.js';
import { OBJLoader } from'../jsm/OBJLoader.124.js';
import { MTLLoader } from'../jsm/MTLLoader.124.js';
Siehe discord [...] 
und bei discourse [...]  |
|
|
| |
|
|
|
 HofK | Bei der CPU Simulation geht es stückweise weiter. Neben dem RAM ist nun auch in der CPU etwas darstellbar. Allerdings fehlt dort noch die Beschriftung der Bytes. Da sich die Übernahme des Codes der eigentlichen Verarbeitung recht schwierig gestaltet und fehleranfällig ist, habe ich einige JavaScript Erweiterungen eingebunden. Damit ist ein leichterer Vergleich des XProfan- und JS Codes möglich.
Die originalen JS Statements sind teilweise etwas umständlich/länger und nicht sehr übersichtlich. So ist .value kein Wert, sondern auch ein String. Mit const gettext = ( elm ) => ( elm.innerHTML || elm.value ); und neuem .val wird es übersichtlicher und passt besser zu XProfan. Momentan ist noch nicht der gesamte Code derart umgestellt,
Das .innerHTML stammt aus der Zeit, als HTML wirklich nur eine Seitenbeschreibung war und passt mit JS eigentlich nicht mehr. Aber solche "Alten Zöpfe" gibt es massenhaft bei der teils chaotischen Entwicklung in der IT.
Mit der JS-Anpassung an XProfan ist die Übernahme dann übersichtlicher.
Ein Beispiel aus define_constant:
Aus
settext conbin%, conbin$' binär anzeigen
settext conhex%, bin8_to_hex2(conbin$)' hexadezimal anzeigen
settext RAM%, conrow%, 2, conbin$' binär im RAM ablegen
sp_h$ = space$(5-len(coninp$)) +"h"' variable Leerzeichen vor h für hexadezimalen Wert
settext RAM%,conrow%,3,coninp$+sp_h$+gettext$(conhex%)' Wert im RAM darstellen
comment$[conrow%] = ";"+concomm$' Konstanten-Kommentar in Kommentarfeld speichern
wird
settext( conbin, conbin$ );// binär anzeigen
settext( conhex, bin8_to_hex2( conbin$ ) );// hexadezimal anzeigen
RAM[ conrow ][ 2 ] = conbin$;// binär im RAM ablegen
sp_h$ = mkstr$(' ', 5 - coninp$.length ) + 'h'; // variable Leerzeichen vor h für hexadezimalen Wert
RAM[ conrow ][ 3 ] = coninp$ +sp_h$ + gettext( conhex );// Wert im RAM darstellen
comment$[ conrow ] = ";" + concomm$;// Konstanten-Kommentar in Kommentarfeld speichern
Da CPU und RAM in 3D dargestellt werden, musste ich intern für die Inhalte Variablen oder Datenfelder anlegen, aus denen dann die 3D Darstellungen dynamisch generiert werden. Das ist etwas mehr Aufwand als mit den Windows Controls in XProfan, aber andererseits erspart es Code.
Aus
wird
for ( let i = 0; i < 4; i ++ ) {
R[i] = "00000000";// D, A-Register mit 0 initialisieren
S[i] = "00000000";// SD,SA-Register mit 0 initialisieren
}
IR = "00000000";// No Operation im IR
aktuell bei /dev |
|
|
| |
|
|
| |
|
- Seite 40 - |
|
|
 HofK | Lange angekündigt ist es nun soweit.
Die anfängerfreundliche aber im professionellen Einsatz nicht so günstige Geometry verschwindet stückweise aus three.js. Dazu gibt es eine Diskussionsthema [...] 
Das hat mich veranlasst, die alte Problematik der Performance noch einmal genauer unter die Lupe zu nehmen. Siehe [...] 
Dort auch der Link zur Lösung [...] 
Bei BufferGeometrie muss man persönlich die zwei Dreiecke des Rechtecks in eine Materialgruppe packen. Bei der Umwandlung von Geometry zu BufferGeometry packt es das System irgendwie selbst. Und mehr Gruppen bedeutet mehr Last, also weniger Performance. |
|
|
| |
|
|
|
 HofK | Das Maschinenprogramm, der Binärcode läuft.
Wenn auch bisher nur mit einer minimalen Befehlsanzahl:
NOP SWD LDC
Nachdem ich zu NOP noch einige Befehle, teils ohne vollständigen Code, hinzugenommen hatte, gab es ein merkwürdiges Verhalten. Der Befehlszähler machte unerklärliche Sprünge.
Es hat eine Weile gedauert, bis ich die Ursache gefunden habe.
Die Zuordnung der Funktionen zur Befehlsausführung geschieht über eine stark verschachtelte Struktur mit switch, in XProfan select.
Im Unterschied zu XProfan muss in JavaScript jeder Fall mit break; abgeschlossen werden, da sonst der nächste Fall auch bearbeitet wird. Das ist für einige Anwendungsfälle eventuell sinnvoll, aber insgesamt eher nervig. Da die verschachtelte Struktur mit ca. 200 Zeilen und wenig Leerzeilen recht umfangreich ist, führen wenige fehlende break; zu merkwürdigem Verhalten.
Wenn ich seinerzeit die Simulation mit JavaScript programmiert hätte, dann hätte ich sicher eine andere Möglichkeit der Zuordnung genutzt. Denkbar ist ein mehrdimensionales Array. Da ich aber möglichst eng am Original-Quellcode bleiben möchte, habe ich keine andere Wahl, als alle breaks; korrekt zu setzen.
Ohne eine solche Faltung, sieht man überhaupt nicht mehr durch!

aktuell bei /dev |
|
|
| |
|
|