;************************************** ;* Sinus- und Cosinusfunktion mittels * ;* Coprozessor berechnen und grafisch * ;* darstellen. 2010 H.V.Viehof * ;* Aenderungen: * ;* Amplitude steuerbar, es wird auf * ;* erreichen von Min / Max getested * ;************************************** ;************************************** ;* Grundlegende Grafik Macros * ;* Menory Mapped Input/Output * ;* 2010 H.V.Viehof * ;************************************** ;-------------------------------------- ; SetGraph Macro - Graphikmodus setzen ;-------------------------------------- SetGraph MACRO ; al = Modus mov ah, 0 ; die Funktion 0 des Videointerupts int 010 #EM ;-------------------------------------- ; ClearScreen Macro ;-------------------------------------- ClearScrn MACRO ; loescht den Inhalt des Videorams mov bx, 0 mov ax, 0a000 ; Segmentaddresse des Videoram mov ds, ax ; setzen ClearLoop: mov ds: b[bx], 0 ; 0 an die Addresse speichern inc bx ; bx hochzaehlen fuer naechsten Punkt cmp bx, 38400 ; das sind 80x480 Bytes mit je 8 Bildpunkten jnz ClearLoop ; tekrarla! #EM ;-------------------------------------- ; DrawPixelD Macro - einzelnen Punkt ; zeichnen durch unmittelbaren Zugriff ; auf den Grafikspeicher bei a000:0000 ;-------------------------------------- DrawPixelD MACRO ; einzelner Punkt unmittelbar ins Videoram push es ; Register sichern push dx push cx xor ah, ah ; soll 0 sein wegen der Schiebeoperation mov al, 10000000xb ; ein Bit links setzen für einen Punkt and cx, 7 ; die unteren drei Bits von CX addressieren das Bit shr ax, cl ; das Bit fuer den Punkt auf Position schieben pop cx ; alten Wert von CX zurueckholen push cx ; und auch wieder auf den Stack push ax ; AL von AX zeigt auf das einzelne Bit shr cx, 3 ; CX / 8 denn drei Bits ergaben ja die Punktposition mov bx, 80 ; 80 Bytes ist die Zeile lang mov ax, dx ; DX (Spaltenposition) in AX mov dx, 0 ; DX loeschen denn es wird multipliziert mul bx ; Speicheraddresse = Zeile + Spalte x 80 add ax, cx ; deshalb: addieren mov bx, ax ; In BX, das wird als Pointer benutzt mov dx, 0a000 ; Segmentaddresse des Videoram mov es, dx ; setzen pop ax ; im 'alten' AL befindet sich die Bitposition or al, es: b[bx] ; diesen neuen Punkt per Oder in das Speicherbyte einfuegen mov es: b[bx], al ; an dieselbe Addresse zurueckspeichern pop cx ; 'alte' Register wiederherstellen pop dx pop es #EM ;-------------------------------------- ; DrawLine Macro - horizontale Linie ; dx = position y / hoehe ; ; kurze Erklaerung: ein Byte in einer ; Ebene des Videorams sind 8 ; aufeinanderfolgende Pixel, also ist es ; effizienter zum Zeichnen horizontaler ; Linien die Bytes komplett zu fuellen. ; Dabei sollte die Zaehlschleife die ; die Bytes addressiert moeglichst kurz ; gehalten werden. ;-------------------------------------- DrawLineD MACRO push es push dx ; Register sichern mov cx, 0 ; CX zaehlt die Pos innerhalb der Zeile und faengt mit 0 an mov ax, 0a000 ; Segmentaddresse des Videoram mov es, ax ; setzen mov bx, 80 ; 80 Bytes ist die Zeile lang, das ist der Multiplikator mov ax, dx ; DX (Zeilenposition) in AX mov dx, 0 ; DX loeschen denn es wird multipliziert mul bx ; Speicheraddresse = Spalte + Zeile x 80 L1: mov bx, ax ; In BX, das wird als Pointer benutzt add bx, cx ; deshalb: Spaltenposition addieren mov es: b[bx], 0ff ; 0ff an die Addresse speichern inc cx ; cx runterzaehlen fuer naechsten Punkt cmp cx, 79 ; 0 bis 79 = 80 Positionen (der Konflikt Kardinal- zu Ordinalzaehlung) jnz L1 ; den naechsten Punkt zeichnen pop dx ; alle gesicherten Registerinhalte zurueckholen pop es #EM ;-------------------------------------- ; DrawVLine Macro - zeichnet vertikale Linie ; cx = position x ;-------------------------------------- DrawVLineD MACRO ; dieses Macro ist etwas anders mov dx, 0 ; DX zaehlt PunktPositionen in einer Reihe von oben nach unten L2: DrawPixelD inc dx cmp dx, 01e0 ; zeichne eine vertikale Linie bis dx = 480 unterer Bildschirmrand jl L2 #EM ;______________________________________ ; ; stapelsegment : ;______________________________________ stack segment stack word 'stack' dw 90 dup (?) stack ends CODE SEGMENT WORD PUBLIC 'CODE' ASSUME CS:CODE, DS:data, SS:stack, ES:variablen start: mov ax, seg variablen ; Vorbereiten von mov es, ax ; Datensegment und mov es: b color, 25 ; Farbe des Textes mov es: b Merker, 0 ; Text anzeigen / verbergen mov es: w Amplitude, 240 ; Amplitude des Sinus ;-------------------------------------- ; In Videomodus 640 * 480 mit 16 Farben wechseln ;-------------------------------------- mov al, 012 ; 012h ist genau der richtige Modus SetGraph ; 06a wäre 800 x 600 evtl. 18 = 1024 x 768 moegl. drawall: ClearScrn ; Bildschirm 'schwarz malen' ;-------------------------------------- ; Rahmen zeichnen ;-------------------------------------- mov dx, 0 ; Startwert fuer die erste hor. Linie DrawLineD ; Das Macro oben mov dx, 479 ; DX + Step = Position der naechsten hor. Linie DrawLineD ; noch nicht? dann: weitere Linie mov cx, 0 ; Startwert fuer die erste ver. Linie DrawVLineD ; im Prinzip dasselbe wie fuer die horz. Linien... mov cx, 639 ; wieder: alte Linie + Step = neue Linie DrawVLineD ;-------------------------------------- ; Funktionsgraph zeichnen ;-------------------------------------- mov ax, seg korr ; dort sind Konstanten mov ds, ax mov ax, seg ein ; und da Variablen mov es, ax fninit ; Coprozessor initialisieren mov es: w ein, 5120 ; entro: mov cx, es: w ein ; cx = x Wert shr cx, 3 fild es: w ein ; Wert aus Speicherstelle laden fdiv ds: d korr ; durch Korrekturwert teilen fldpi ; und mit PI fmul ; multiplizieren = Grad zu Rad umwandeln fsincos ; jetzt kann man den Sinus (ST1) / Cosinus (ST0) bilden fimul es: w Amplitude ; mit Faktor 240 multiplizieren frndint ; auf ganze Zahl runden fistp es: w aus ; ST0 in den Speicher schreiben fimul es: w Amplitude ; mit Faktor 240 multiplizieren frndint ; auf ganze Zahl runden fistp es: w aus2 ; ST1 in den Speicher schreiben cmp es: w aus, 241 ; Minimum jl >O1 cmp es: w aus, -241 ; Maximum jl >O1 jmp Exception O1: mov dx, 240 ; 240 ist die Bildschirmitte von oben sub dx, es: w aus2 ; davon subtrahiere ich die Ausgabe der Sin. Funkt. DrawPixelD ; das Macro zeichnet den Punkt an cx/dx mov dx, 240 ; 240 ist die Bildschirmitte von oben sub dx, es: w aus ; davon subtrahiere ich die Ausgabe der Sin. Funkt. DrawPixelD ; das Macro zeichnet den Punkt an cx/dx dec es: w ein jz TextOut jmp entro ; solange Wert > 0 das oben alles wiederholen Exception: mov ax, seg minmax mov ds, ax mov bl, 12 mov dh, 0 ; Positionen laden: Anfang Textfensteroberkante mov si, offset minmax ; Anfang des Textes jmp Display ;-------------------------------------- ; Textdarstellung ;-------------------------------------- TextOut: cmp es: b Merker, 0 ; Merker == 0: Fenster anzeigen jnz Key ; Merker != 0: Fenster verbergen mov ax, seg message mov ds, ax mov bl, es: b color mov dh, 0 ; Positionen laden: Anfang Textfensteroberkante mov si, offset message ; Anfang des Textes jmp Display ;-------------------------------------- ; Auf Eingabe eines Zeichens warten ;-------------------------------------- Key: mov ah, 7 ; auf Tastendruck warten int 021 ; ein 'Minimenu' cmp al, '+' jnz >W1 inc es: w Amplitude jmp drawall W1: cmp al, '-' jnz W2 dec es: w Amplitude jmp drawall W2: cmp al, 'C' jnz W3 dec es: b color jmp drawall W3: cmp al, 'c' jnz W6 inc es: b color jmp drawall W6: cmp al, 'h' jnz W9 xor es: w Merker, 1 ; das XOR realisiert einen 'Toggleswitch', cok güzel! jmp drawall W9: cmp al, 'q' jnz Key ;-------------------------------------- ; Videomodus zurückschalten und ; Programm beenden ;-------------------------------------- mov al, 3 SetGraph mov ax, 04C00 int 021 ;-------------------------------------- ; Textdarstellung ;-------------------------------------- Display: xor bh, bh ; geloescht, weil das die Textbildschirmseite ist mov cx, 1 ; nur einmal das Zeichen ausgeben L5: inc dh mov dl, 2 ; Anfang der dargestellten Zeile L3: ds: lodsb ; zeichen holen cmp al, 0 ; 0 beendet die Textausgabe jz >L2 ; Ende Textdarstellung cmp al, 0a ; oa ist Ende der dargestellten Zeile jz L5 L1: mov ah, 2 ; cursor setzen int 010 mov ah, 9 ; Funktion 9 von Int 010: Zeichendarstellung mit Attributen int 010 inc dl jmp L3 L2: jmp Key CODE ENDS ;______________________________________ ; ; Datensegment I: Text, feste Faktoren ;______________________________________ data segment public word 'daten' message db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿",0a db "³ uit toggle Message Window ³",0a db "³ change Messagecolor ³",0a db "³ <+> <-> increase/decrease Amplitude ³",0a db "³ 2010 ³",0a db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ",0 minmax db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿",0a db "³ Maximum / Minimum erreicht ³",0a db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ",0 korr dd 1440.0 data ends ;______________________________________ ; ; Datensegment II: 'echte' Variablen ;______________________________________ variablen segment public word 'daten' ein dw ? aus dw ? aus2 dw ? Amplitude dw ? color db ? Merker db ? variablen ends END start