;************************************** ;* Sinus- und Cosinusfunktion mittels * ;* Coprozessor berechnen und grafisch * ;* darstellen. 2010 H.V.Viehof * ;* Aenderungen: * ;************************************** ;************************************** ;* 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 C1: 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 C1 ; 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 mov ax, 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, 80 ; 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 120 dup (?) ; 120 Words, ich denke das reicht 'so gerade'... stack ends ;______________________________________ ; ; Start des Hauptteils ;______________________________________ 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, 7 ; Farbe des Textes: verweist auf die Palette mov es: b Merker, 0 ; Text anzeigen / verbergen mov es: w phase, 0 ; Phasenverschiebung 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. ;-------------------------------------- ; VGA Palette abspeichern, wird innerhalb ; des Programms evtl. aber beim Verlassen ; auf jeden Fall gebraucht ;-------------------------------------- GetPal: mov dx, 03c8 ; Paletten gehoeren ins RAMDAC mov al, 0 ; Funktionswahl Palette schreiben cli ; maskable Interrupts sperren out dx, al ; Indexregister cld mov dx, 03c9 ; Datenregister Portadresse mov cx, 768 ; Die Palette besteht aus 256 Farbtrippels mit je drei Byte mov di, offset VgaPal ; allerdings gelten nur Bits 0 bis 5, rot, gruen, blau S3: in al, dx es: stosb ; wir speichern die 'alte' VGA Palette mit 786 Werten ab loop S3 ;-------------------------------------- ; Palette generieren, nicht sehr elegant ; aber zum testen ausreichend ; (wenn man keine eigene Palette definiert ; werden Standart VGA Farben benutzt) ; die ersten 16 Palettenfarben werden ; gesetzt, der Rest wiederholt sich ;-------------------------------------- NewPal: mov ax, seg data mov ds, ax mov bx, 16 ; ergibt insgesammt 768 Farbwerte mov dx, 03c8 ; Paletten gehoeren ins RAMDAC mov al, 0 ; Funktionswahl Palette schreiben ;cli ; maskable Interrupts sperren (ist weiter oben schon geschehen) out dx, al ; Indexregister cld mov dx, 03c9 ; Datenregister Portadresse S1: mov cx, 48 ; Die Palette besteht aus 256 Farbtrippels mit je drei Byte mov si, offset Colors ; allerdings gelten nur Bits 0 bis 5, rot, gruen, blau S2: lodsb ; wir fuellen die ersten 16 Trippels mit individuellen Werten, out dx, al ; der Rest wiederholt sich... loop S2 dec bx jnz S1 ;sti ; Ext. Int. zulassen (noch nicht, erst spaeter wieder) ;-------------------------------------- ; Bildaufbau ;-------------------------------------- drawall: ;ClearScrn ; Bildschirm 'schwarz malen' ; dieses loeschen des Bildschirms muss fuer alle Planes (Farbebene) mov dx, 03c4 ; erfolgen, deshalb: Planes umschalten! mov al, 2 ; weiter unten ist erklaert wie diese Sequenz arbeitet out dx, al mov dx, 03c5 mov al, 0f out dx, al ClearScrn ;mov dx, 03c4 ; auskommentiert: z.Zt. nicht erforderlich ;mov al, 2 ; Wuerde man hier jetzt einen bestimmten Plane ansprechen ;out dx, al ; wuerde das den Rahmen gesondert einfaerben ;mov dx, 03c5 ;mov al, 1 ;out dx, al ;-------------------------------------- ; Rahmen zeichnen ;-------------------------------------- mov dx, 0 ; Startwert fuer die erste hor. Linie DrawLineD ; Das Macro oben mov dx, 479 ; neue Position der naechsten hor. Linie DrawLineD ; zeichnen... mov cx, 0 ; Startwert fuer die erste ver. Linie DrawVLineD ; im Prinzip dasselbe wie fuer die horz. Linien... mov cx, 639 ; wieder: neue Linie DrawVLineD ;-------------------------------------- ; Funktionsgraph zeichnen ;-------------------------------------- mov ax, seg data ; dort sind Konstanten mov ds, ax mov ax, seg variablen ; und da Variablen mov es, ax mov dx, 03C4 ; Das ist aehnlich wie oben mov al, 2 ; out dx, al ; mov dx, 03C5 mov al, 04 out dx, al mov cx, 0 entro: mov bx, cx add bx, es: w phase cmp bx, 360 jle >X1 X2: sub bx, 360 cmp bx, 360 ja X2 X1: shl bx, 1 mov dx, 240 ; 240 ist die Bildschirmitte von oben sub dx, ds: w [bx + offset WerteTabelle] DrawPixelD ; das Macro zeichnet den Punkt an cx/dx inc cx cmp cx, 640 jnz entro ; solange Wert > 0 das oben alles wiederholen ;-------------------------------------- ; Textdarstellung ;-------------------------------------- TextOut: cmp es: b Merker, 0 ; Merker == 0: Fenster anzeigen jnz Key ; Merker != 0: Fenster verbergen mov ax, seg data 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: ;sti mov ah, 7 ; auf Tastendruck warten int 021 ; ein 'Minimenu' cmp al, '+' jnz >W1 inc es: w phase jmp drawall W1: 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 W7 xor es: w Merker, 1 ; das XOR realisiert einen 'Toggleswitch', cok güzel! jmp drawall W7: cmp al, 'v' jnz W8 call SetPal jmp drawall W8: cmp al, 'n' jnz W9 jmp NewPal W9: cmp al, 'q' jnz Key ;-------------------------------------- ; Videomodus zurückschalten und ; Programm beenden ;-------------------------------------- sti call SetPal ; faktisch zwar nicht erforderlich, aber sauber programmieren mov al, 3 ; bedeutet auch das alle Zustaende wieder so hergestellt werden SetGraph ; wie vor dem Programmaufruf 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 ;-------------------------------------- ; VGA Palette wiederherstellen, nicht ; sehr elegant aber zum testen ausreichend ;-------------------------------------- SetPal: mov ax, seg variablen mov ds, ax mov dx, 03c8 ; Paletten gehoeren ins RAMDAC mov al, 0 ; Funktionswahl Palette schreiben ;cli ; maskable Interrupts sperren out dx, al ; Indexregister cld mov dx, 03c9 ; Datenregister Portadresse mov cx, 768 ; Die Palette besteht aus 256 Farbtrippels mit je drei Byte mov si, offset VgaPal ; allerdings gelten nur Bits 0 bis 5, rot, gruen, blau S4: ds: lodsb ; wir fuellen die ersten 16 Trippels mit individuellen Werten, out dx, al ; der Rest wiederholt sich... loop S4 ret CODE ENDS ;______________________________________ ; ; Datensegment I: Text, feste Faktoren ;______________________________________ data segment public word 'daten' include tabelle.inc message db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿",0a db "³ uit toggle Message Window ³",0a db "³ change Messagecolor ³",0a db "³ <+> shift Phase of Graph ³",0a db "³ ga Palette eue Palette ³",0a db "³ 2010 ³",0a db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ",0 Colors db 0,0,0, 32,0,32, 46,16,0, 16,0,16, 48,0,0, 48,0,32, 52,16,0, 0,0,32 db 0,0,16, 32,0,40, 46,16,8, 16,0,24, 48,0,8, 48,0,40, 52,16,8, 0,0,40 data ends ;______________________________________ ; ; Datensegment II: 'echte' Variablen ;______________________________________ variablen segment public word 'daten' phase dw ? color db ? Merker db ? VgaPal db 786 dup (?) variablen ends END start