Punkt zeichnen (int 10, al 0Ch)



  • Moin, Moin...

    Der Fehler des Programms liegt in der Zeile mov al, 12. Der
    betreffende Videomodus hat den Wert 012(hex). Das entspricht 18(dez)!

    Also entweder schreiben mov al,18 oder mov al,012h.

    Außerdem sollte wieder in den Textmodus geschaltet werden, bevor das Programm beendet wird.

    mov ah,0
    mov al,03h
    int 010h
    
    ; Programm beenden
    

    Ciao...

    [ Dieser Beitrag wurde am 30.05.2002 um 08:38 Uhr von KalEl editiert. ]

    [ Dieser Beitrag wurde am 30.05.2002 um 08:39 Uhr von KalEl editiert. ]



  • Wow, vielen Dank an alle! KaiEl hatte recht, mit 12h in al funktioniert es 🙂 🙂
    Aber dazu muss ich sagen, dass es dann in meinem Buch falsch stand, dort standen nämlich nur 12 :p

    Grafikprogrammierung ist ja dann ziemlich einfach, echt super 🙂
    Jetzt bastel ich mir mal ein paar Funktionen zum Beispiel zum Zeichnen eines Kreises. Ist es überhaupt möglich irgendwie Funktionen wie in C/C++ zu schreiben? Dachte man nimm Labels.

    ZeichneKreis:
    ; Code

    Aber dann kann ich ja nie Werte übergeben. Kann man sowas machen?



  • funktionen gibt es auch in Assembler!

    Beispiel

    ;...
    call kreis
    ;...
    
    kreis PROC NEAR
       ;...
       ret
    kreis ENDP
    


  • Moinsen...

    Ähm, mein Name lautet nicht KaiEl sonder KalEl. 😉

    Danke...



  • Danke, habe es jetzt versucht das Zeichnen der Linie in eine Funktion einzubetten, dazu habe ich auch in meinem Buch nachgelesen, aber jetzt stürtzt das Programm ab:

    ;----------------------------------------------------------
    ; Linie zeichnen
    ;----------------------------------------------------------

    Linie PROC NEAR
    push bx
    xor bx,bx
    linie01:
    mov ah, 0Ch
    mov cx, bx ; Splate
    mov dx, 10 ; Zeile
    mov al, 4 ; Farbattribut
    int 10h
    inc bx
    cmp bx, 20h ;zeichne eine Linie, die 0x20 Spalten lang ist
    jl linie01
    ret
    Linie ENDP

    call Linie ; Die Linie-Funktion aufrufen

    Windows meldet: "Die NTVDM-CPU hat einen ungültigen Befehl entdenkt."

    Was könnte der Fehler sein?

    @KalEl: Sorry, werde es mir merken 😃 :p 😃



  • ich sehe in der proc "push bx" aber kein "pop bx" 😉



  • Und nochmal Moinsen...

    Hier ein kleines Programm, das die Parameterübergabe an eine
    Assemblerfunktion zeigen soll:

    .model small
    
    .stack 0200h
    
    .data
    
    .code
    
    start:  push 10       ; 1. Parameter auf den Stack
            push 20       ; 2. Parameter auf den Stack
            call addiere  
            add  sp, 4    ; Stack bereinigen
    
            mov ah, 7
            int 21h
    
            mov ah, 04Ch
            int 21h
    
    ; Hier folgen die Funktionen
    
    addiere proc near
    
            push bp     ; Register bp sichern
            mov  bp, sp ; Stackframe aufbauen
    
            push bx     ; Registerinhalt retten
    
            mov  ax, word ptr [bp + 4] ; 1. Parameter nach ax
            mov  bx, word ptr [bp + 6] ; 2. Parameter nach bx
    
            add  ax, bx
    
            pop  bx
    
            mov  sp, bp ; alten Wert von sp wiederherstellen
            pop  bp     ; alten Wert von bp zurückholen
    
            ret
    
    addiere endp
    
    end Start
    

    Die Funktion addiert die beiden Parameter. Das Ergebnis steht in Register ax und kann so an das Hauptprogramm übergeben werden.

    Wichtig ist, dass der Stack bereinigt wird, d.h. die Parameter werden quasi wieder vom Stack entfernt.

    Diese Art der Parameterübergabe ist wie in C. Pascal macht das etwas anders.

    Ciao...



  • Danke dir 🙂 🙂

    Es lag an 2 Sachen, erstmal das pop bx und dann ging's immer noch nicht, da ich so dämlich war und die Funktion in den Code des start-Labels gepackt hatte *lol* :p

    Also hier nochmal der vollständige Code, falls es jemand ausprobieren möchte oder ähnliches 😉

    CODE SEGMENT WORD 'CODE'
    ASSUME CS:CODE
    
    ;----------------------------------------------------------
    ; DrawLine Prozedur
    ;----------------------------------------------------------
    
    DrawLine PROC NEAR
        push bx
        xor bx,bx
        LineLoop:
        mov ah, 0Ch
        mov cx, bx ; Splate
        mov dx, 80 ; Zeile
        mov al, 4 ; rot
        int 10h
        inc bx
        cmp bx, 80h ; zeichne eine Linie, die 0x80 Spalten lang ist
        jl LineLoop
        pop bx
        ret
    DrawLine ENDP
    
    start:
    
    ;----------------------------------------------------------
    ; In Videomodus 640 * 480 mit 16 Farben wechseln
    ;----------------------------------------------------------
    
    mov ah, 0
    mov al, 12h
    int 10h
    
    ;----------------------------------------------------------
    ; Grünes 'a' ausgeben
    ;----------------------------------------------------------
    
    mov ah, 9
    mov bh, 0 ; Bildschirmseite 0
    mov cx, 1 ; Ein Zeichen
    mov al, 97 ; 'a'
    mov bl, 2 ; grün
    int 10h
    
    ;----------------------------------------------------------
    ; Linie zeichnen
    ;----------------------------------------------------------
    
    call DrawLine
    
    ;----------------------------------------------------------
    ; Auf Eingabe eines Zeichens warten
    ;----------------------------------------------------------
    
    mov ah, 7
    int 21h
    
    ;----------------------------------------------------------
    ; Videomodus zurückschalten
    ;----------------------------------------------------------
    
    mov ah, 0
    mov al, 3h
    int 10h
    
    ;----------------------------------------------------------
    ; Programm beenden
    ;----------------------------------------------------------
    
    mov ah, 04Ch
    int 21h
    
    CODE ENDS
    
    END start
    


  • Habe auch mal ne Frage zu deinem Code KalEl:

    mov ax, word ptr [bp + 4] ; 1. Parameter nach ax
    mov bx, word ptr [bp + 6] ; 2. Parameter nach bx

    Was macht man denn, wenn man ganz viele Parameter hat? Soviele Register stehen ja garnicht zur Verfügung 😞



  • Dann verarbeitet man die Parameter halt hintereinander. Die bleiben schliesslich auf dem Stack erhalten. 😉
    Die Parameteruebergabe via Stack erscheint mir ehrlichgesagt sowieso nur sinnvoll, wenn entweder mehr Parameter verarbeitet werden muessen, als Register zur Verfuegung stehen (kommt fast nie vor)
    Der code so unglaublich kompliziert und lang ist, dass man zwischendurch die Parameter so und so pushen muesste (eigentlich auch selten - ich wuerde dann eher auf globale Variablen zurueckgreifen)
    Oder wenn man eine Assembler routine in eine Hochsprache wie zB. C einbinden will.



  • In der Tat sollte man die Parameter in den Registern übergeben, wenn es möglich ist. Jedoch stößt man hier schnell an die Grenzen der 80x86-Prozessoren, da die Anzahl der Register doch recht bescheiden ist.

    Sind nur wenig Parameter vorhanden(bis 6), so empfiehlt sich die Registerübergabe, ansonsten muss man zwangsläufig auf den Stack ausweichen.

    Ciao...



  • Wie könnte man bei Junger Mann's DrawLine Funktion z.B. die Länge variabel machen? Ich hab's mal versucht, aber nicht geschafft z.B. so:

    mov ax, 5
    call DrawLine

    und dann in der DrawLine Funktion anstatt der Konstanten ax eingesetzt:

    DrawLine PROC NEAR
    push bx
    xor bx,bx
    LineLoop:
    mov ah, 0Ch
    mov cx, bx ; Splate
    mov dx, 80 ; Zeile
    mov al, 4 ; rot
    int 10h
    inc bx
    cmp bx, ax ; Hier variable Länge
    jl LineLoop
    pop bx
    ret
    DrawLine ENDP

    Aber die Linie ist immer gleich lang, egal was bei ax reinschiebe *g*
    Wie geht das?



  • @Trilo:

    Das Problem ist, das Du die Länge der Linie in ax an die Funktion übergibst. ax wird aber in der Funktion verändert, sodass Dein Vergleich nicht mehr klappt. Da hilft ein push ax vor mov ah, 0Ch und ein pop ax vor dem Vergleich.

    Das ständige Sichern des Registers kostet aber ziemlich viel Zeit. Besser wäre es, ein Register zu nehmen, das nicht benutzt wird, wie z.B. si oder di.

    Ciao...

    [ Dieser Beitrag wurde am 30.05.2002 um 16:33 Uhr von KalEl editiert. ]

    [ Dieser Beitrag wurde am 30.05.2002 um 16:36 Uhr von KalEl editiert. ]



  • Danke KalEl, jetzt funktioniert das mit der Übergabe über das Register, ich habe mich für si entschieden :p
    Aber jetzt hab ich das Problem, das ich irgendwie nur Linien hinbekomme bis 255 Pixel Länge. Mach ich z.B.

    mov si, 300

    wird die Linie trotzdem nur 255 Pixel lang. Was kann ich dagegen tun?



  • @Trillo:

    Es gibt noch einen kleinen Fehler. Du benutzt Register bx, um die Spalte hochzuzählen. Jedoch wird bh benutzt, um die Bildschirmseite zu bestimmen, in dem der Punkt erscheint. Daher darf auch bx NICHT benutzt werden. Statt bx benutze di.

    BIOS-Aufruf 010h, Funktion 0Ch

    ah = Funktionsnummer(0Ch)
    al = Farbnummer
    bh = Bildschirmseite(0...x), x hängt vom Modus ab
    cx = Pixelspalte
    dx = Pixelzeile

    Ciao...

    [ Dieser Beitrag wurde am 31.05.2002 um 15:53 Uhr von KalEl editiert. ]



  • hmmm, danke, aber jetzt wird nur ein einziger Pixel gezeichnet 😕
    ich poste nochmal den vollständigen code:

    CODE SEGMENT WORD 'CODE'
    ASSUME CS:CODE
    
    ;----------------------------------------------------------
    ; DrawLine Prozedur
    ;----------------------------------------------------------
    
    DrawLine PROC NEAR
        push di
        xor di, di
        LineLoop:
        mov ah, 0Ch
        mov cx, bx ; Splate
        mov dx, 80 ; Zeile
        mov al, 4 ; rot
        int 10h
        inc di
        cmp di, si
        jl LineLoop
        pop di
        ret
    DrawLine ENDP
    
    start:
    
    ;----------------------------------------------------------
    ; In Videomodus 640 * 480 mit 16 Farben wechseln
    ;----------------------------------------------------------
    
    mov ah, 0
    mov al, 12h
    int 10h
    
    ;----------------------------------------------------------
    ; Linie zeichnen
    ;----------------------------------------------------------
    
    mov si, 240
    call DrawLine
    
    ;----------------------------------------------------------
    ; Auf Eingabe eines Zeichens warten
    ;----------------------------------------------------------
    
    mov ah, 7
    int 21h
    
    ;----------------------------------------------------------
    ; Videomodus zurückschalten
    ;----------------------------------------------------------
    
    mov ah, 0
    mov al, 3h
    int 10h
    
    ;----------------------------------------------------------
    ; Programm beenden
    ;----------------------------------------------------------
    
    mov ah, 04Ch
    int 21h
    
    CODE ENDS
    
    END start
    


  • Hier die bereinigte Version:

    DrawLine PROC NEAR
        push di
        xor di, di
        LineLoop:
        mov ah, 0Ch
        mov bh, 000h
        mov cx, di; Splate
        mov dx, 80 ; Zeile
        mov al, 4 ; rot
        int 10h
        inc di
        cmp di, si
        jl LineLoop
        pop di
        ret
    DrawLine ENDP
    

    Ciao...


Anmelden zum Antworten