Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Themen - Survari

Seiten: [1]
1
Lowlevel-Coding / Ein Spiel im Boot-Sektor
« am: 11. May 2021, 16:18 »
Spiele in den 512 Bytes des Boot-Sektors unterzubringen ist keine Neuheit, daher wollte ich auch mal etwas kleines probieren. Wie mit meinem letzten Projekt, bei dem ich hier um Rat gebeten habe, versuche ich etwas mehr über die Funktionsweise von Rechnern und x86-Assembly zu erfahren. Aktuell ist es erstmal mein Ziel, ein Rechteck mit Pfeiltasten über den Bildschirm zu bewegen.

Gesagt, getan. Das Programm läuft in QEMU super, Eingabe und Anzeige funktionieren wie gewollt. Jetzt das Problem: Es läuft nur auf QEMU (und Bochs). Sobald ich das Programm von einem USB-Stick auf meinem Rechner starte, macht es gar nichts mehr (Bildschirm bleibt leer, Cursor blinkt). Dabei ist mir ein möglicher Zusammenhang aufgefallen (bitte schlagt mich nicht, es folgen gefährliches Halbwissen und wahrscheinlich haufenweise falsche Annahmen): Es gibt Ausnahmen. Ich hatte viel Zeit das Programm an vielen Computern meiner Schule zu testen. Dabei ist mir aufgefallen, dass besonders Computer, die neuer waren, das Programm nicht richtig ausgeführt haben. Ich hatte die Überlegung, dass es möglicherweise am vom UEFI simulierten BIOS liegen könnte. Auf Rechnern ohne UEFI funktioniert es tatsächlich (zumindest gehe ich davon aus, dass die jeweiligen Rechner kein UEFI hatten, ich bin mir unsicher, wie genau ich das herausfinde). Soweit ich das beurteilen kann, würde ich außerdem eine Inkompatibilität aufgrund der Prozessorarchitektur ausschließen, da die meisten Computer auf x86/x64 laufen und sonst wahrscheinlich gar nichts passiert wäre (es gab Phasen, in denen Teile des Programmes auch auf den UEFI-Rechnern funktioniert haben, daher schließe ich das Problem mit den Architekturen aus).

Aktuell hat das Programm nette 118 Zeilen (NASM):
K_LEFT          equ 75
K_RIGHT         equ 77
K_UP            equ 72
K_DOWN          equ 80
MEM_VIDEO       equ 0xb800
SCREEN_WIDTH    equ 80
SCREEN_HEIGHT   equ 25
TICK_LENGTH     equ 4

org 0x7C00
bits 16

init:
    mov     ax, 0x0002      ; 16 farben, 80x25 Zeichen
    int     0x10

    ; -- Stack initialisieren
    xor     ax, ax
    mov     ds, ax
    mov     ss, ax
    mov     sp, 0x9c00

    mov     ax, MEM_VIDEO   ; zeiger auf bildschirmspeicher
    mov     es, ax          ; ES=MEM_VIDEO
    mov     al, 0x03
    int     0x10

    mov     ah, 1
    mov     ch, 0x26
    int     0x10

main:
    ; -- Bildschirm löschen und neu zeichnen
    call    clear_screen
    call    draw

    ; -- Eingabe und zurück zum Anfang springen
    call    input
    jmp     main

input:     ; steuerung
    xor     ah, ah
    int     0x16            ; tasteneingabe

    cmp     ah, K_RIGHT     ; Pfeiltaste nach Rechts
    je     .right_arrow

    cmp     ah, K_LEFT      ; Pfeiltaste nach Links
    je     .left_arrow

    cmp     ah, K_DOWN      ; Pfeiltaste nach Unten
    je     .down_arrow

    cmp     ah, K_UP        ; Pfeiltaste nach Oben
    je      .up_arrow

    jmp     .end

    .right_arrow:
        cmp     word [x_pos], word SCREEN_WIDTH-2
        jg      .end                    ; x_pos > SCREEN_WIDTH-2, keine veränderänderung
        add word [x_pos], 1
        jmp     .end

    .left_arrow:
        cmp     word [x_pos], word 1
        jl      .end                    ; x_pos < 1, keine veränderung
        sub     word [x_pos], 1
        jmp .end

    .down_arrow:
        cmp     word [y_pos], word SCREEN_HEIGHT-2
        jg      .end                    ; y_pos > SCREEN_HEIGHT-2, keine veränderung
        add     word [y_pos], 1
        jmp .end

    .up_arrow:
        cmp     word [y_pos], word 1
        jl      .end                    ; y_pos < 1, keine veränderung
        sub     word [y_pos], 1
        jmp .end

    .end:
        ret

clear_screen:
    ; -- Ganzen Bildschirm mit Schwarz füllen
    xor     di, di
    mov     cx, 0x07d0
    mov     ax, 0x0000
    rep     stosw
    ret

draw: ; Block an der Stelle aus [x_pos] und [y_pos] zeichnen
    ; -- Umwandeln der Koordinaten in Index für den Bildschirmspeicher, Ergebnis in dx
    mov     ax, word [y_pos]
    mov     bx, 160
    mul     bx
    mov     dx, ax

    mov     ax, word [x_pos]
    add     dx, ax
    add     dx, ax

    ; -- Datenindex setzen und zeichnen
    mov     di, dx
    mov     ax, 0xa020
    stosw
    ret

done:
    jmp     $           ; Endlosschleife am Ende (was eigentlich nie erreicht wird)

x_pos: times 10 dw 0
y_pos: times 10 dw 0

times 510-($-$$) db 0
dw 0xaa55            ; Signatur für's BIOS

Meine Frage dazu wäre dann wahrscheinlich klar: Warum läuft das Programm nicht? Gibt es Unterschiede am vom UEFI simulierten BIOS? Liegt es vielleicht an etwas völlig Anderem? Ich bin für jede Hilfe und Erklärung dankbar!
2
Lowlevel-Coding / Lochstreifen und Opcodes
« am: 02. June 2020, 19:22 »
Hallo :). Lange ist es her, seit ich auf dieser Seite mal vorbeigeschaut habe. Derzeit grabe ich in den Tiefen der Computergeschichte und bin auf die Lochstreifen gestoßen. Irgendwie haben mich die so fasziniert, dass ich auf die Idee gekommen bin, einfach mal selber welche zu machen und ein Lesegerät dafür zu bauen: Und dann ging es weiter... Natürlich hab ich mir die Frage gestellt, was ich denn eigentlich mit den Lochstreifen machen will und dachte da dann, man könnte sich ja mal an 'ner Prozessor-Emulation wagen und dann dafür Programme schreiben :roll: .

Ich will später einen Assembler bauen, der dann kleine Programme kompiliert und mir zeigt, wo ich welche Löcher stanzen muss :-D . Jetzt aber zum eigentlichen Problem: Ich habe Probleme beim Verstehen von Opcodes. Und mehr Lowlevel als per Hand Opcodes schreiben geht wohl nicht! Da muss ich mich doch an dieses Forum hier wenden :wink: .

Mal ein Beispiel an einem Pseudoassembler:

mov 2, 4 # speicher an stelle 2 auf 4 setzen
Die obige Zeile kann ich auch in Pseudo-Opcodes für meinen Emulator übersetzen (hier einfach mal Beispielsweise wären die in Dezimal dann "1 2 4" oder so). Das Problem ist aber so ein Beispiel:

mov 1, [1+1] # wert von speicherstelle 2 (= 1+1) nach speicherstelle 1
So ähnlich kann man das ja in NASM machen. Mein Problem dabei: Wie stelle ich das als Opcode dar? Einen Ansatz habe ich bereits: Ich habe bereits einige Pseudoassembler und Programmiersprachen geschrieben (nur recht kleine). In einer handhabe ich das so, dass alles, was in [] steht, als mathematischer Ausdruck gilt ([] haben da eine andere Bedeutung als die [] in NASM) und vom Compiler per einfachem Shunting-Yard-Algorithmus in neue Befehle übersetzt wird, die dann den Stack als Zwischenspeicher der Ergebnisse nutzen. Ach, am Besten ich zeig einfach ein Beispiel:

println [ 2*4+1 ]

Würde übersetzt werden (auch wieder nur Pseudo-Code):

push 2 # 2 auf den stack
push 4 # 4 auf den stack
mul # 2 obersten werte vom stack nehmen, multiplizieren, ergebnis auf den stack
push 1 # 1 auf den stack
add # 2 obersten werte vom stack nehmen, addieren, ergebnis auf den stack
println $!  # $! ist hier einfach ein operator, der den obersten wert vom stack löscht und ihm den befehl übergibt. alle []-ausdrücke werden durch $! ersetzt, da die Ergenisse immer auf dem Stack liegen

Wenn ich das oben mit meinem Pseudo-Assembler für den Emulator kombiniere, würde aus mov 1, [1+1] Folgendes:

push 1
push 1
adds # befehl zum addieren von den obersten 2 stackelementen, ergebnis auf den stack
mov 1, [sp] # adresse des obersten stackelements auslesen und dessen wert nach speicherstelle 1

Das könnte ich dann ja übersetzen (IDs: mov=1, push=2, adds=3): 2 1 2 1 3 1 2 [sp] (Für die Darstellung von [sp] denke ich mir noch was aus, auch da gilt: Wenn ihr Ideen habt, sagt gerne was!)

Meine Frage wäre daher: Wie machen Assembler, wie zum Beispiel NASM, das? Und wie findet ihr meinen Ansatz? Habt ihr eigene Ideen? Allgemeine Kommentare und Hinweise zum Projekt?
3
Softwareentwicklung / Eigene Programmiersprache
« am: 18. December 2016, 13:10 »
Hey !

Bevor ich mi meinem Beitrag Anfange, denke ich das es angebracht wäre wenn ich mich mal hier vorstelle:
Mich nennt man Survari, ich bin 13 und bin ein totaler Low-Level Fanatiker, auch wenn ich nicht wirklich Assembler kann (Schande über mich  :-D ). Ich programmiere seit eineinhalb Jahren C++ und bin ein leidenschaftlicher Linux-Nutzer. Außer C++ hab ich schon viele Sprachen ausprobiert. "Können", tue ich noch Java und ne andere kleine Programmiersprache auf die ich gleich zurückkommen werde  :wink: Im IRC war ich bis jetzt auch schon ein paar mal, besonders wegen tyndur
Ich hab mich hier vor ein paar Monaten angemeldet, da ich mit dem OS-Development anfangen wollte, hab da aber zu hoch gegriffen (wie ich denke alle in meinem Alter). Für eine Übung wär's zwar gut, aber da muss ich mich erst nochmal richtig mit beschäftigen.

Seit diesem Sommer arbeite ich an einer kleinen Programmiersprache, die ich erst in Java programmiert hatte, jetzt vor einem Monat aber zu C++ umgestiegen bin. Ich denke das die Sprache schon ein bisschen kann. Ihr Syntax ist dem von Assembler (keiner Spezifisch) ähnlich und ist schon so weit das man Variablen, Funktionen, Sprungmarken, Headerdateien und weiteres anlegen kann. Sie soll ein ein Projekt zum üben, aber auch ein kleiner "High-Level-Assembler" werden. Es ist auch möglich die Sprache in C++ umzuwandeln, also in die Ausgangssprache. Vielleicht ist das jetzt noch nichts allzu großes, aber ich würde mich vielleicht über etwas Feedback freuen, besonders da sich hier die Experten herumtreiben was Programmierung betrifft :-D !

Das letzte Update habe ich gerade eben hochgeladen und eine Dokumentation sowie Beispielcode ist auch verfügbar.
, sonnst hier mal ein kleines Additionsprogramm:

{main}
  defi z1,[0];
  say "Zahl eingeben: ";
  inp z1;

  add [2], z1;
  say  "Deine Zahl ergibt mit 2 addiert: ";
  prv  z1;@

  end;
  endf;

(Hab ichs doch gleich das erste mal mit dem Code-Tag verhauen  :-D )

Schönen Sontag euch noch  :-)
Seiten: [1]

Einloggen