home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
grafik
/
136color
/
136color.asm
next >
Wrap
Assembly Source File
|
1990-11-11
|
18KB
|
731 lines
; Programm: 136color.asm
; Autor: Ingo Kubbilun
; (c)1990 DMV Widuch GmbH & Co. KG
; Implementierung neuer Grafikroutinen
; zur Bereitstellung von 136 Farben
; gleichzeitig für die EGA-Modi 640x200,
; 640x350, 640x480 und 800x600 in das
; BIOS durch Halbierung der X-Auflösung
;
; Programm installiert sich resident im
; Speicher und kann durch nochmaligen
; Aufruf wieder entfernt werden.
CODE SEGMENT BYTE
ASSUME CS:CODE,DS:CODE
; EQU's
FBUFADR EQU INIT
TSENG EQU 29H
PARADISE EQU 58H
VIDEO7 EQU 62H
VMODE_800x600 EQU -1
REGAX EQU [BP+10H]
; Sprung zur Installierung
ORG 0100H
START: JMP INIT
;Sprung zur Installierungs-Sequenz
; Daten- und Variablenbereich
ENVSEG DW ?
MSG1 DB 0DH,0AH,"136COLOR V1.0 gel"
DB "aden und aktiviert...",0DH
DB 0AH,"$"
MSG2 DB 0DH,0AH,"136COLOR V1.0 aus"
DB " Speicher entfernt...",0DH
DB 0AH,"$"
MSG3 DB 0DH,0AH,"136COLOR V1.0 kon"
DB "nte nicht entfernt werden"
DB "...",0DH,0AH,"$"
OLDINT_10H DW ?,?
OLDSS DW ?
OLDSP DW ?
MAXX DW ?
MAXY DW ?
GETPOS_ADR DW ?
MODE_FLAG DB ?
CRT_MODE DB ?
ACTIVE_FLAG DB ?
COLOR DW ?
SCR_OFFSET DW ?
; Farbtabelle
COLTAB DB 00H,01H,02H,03H,04H,05H,06H
DB 07H,08H,09H,0AH,0BH,0CH,0DH
DB 0EH,0FH,11H,12H,13H,14H,15H
DB 16H,17H,18H,19H,1AH,1BH,1CH
DB 1DH,1EH,1FH,22H,23H,24H,25H
DB 26H,27H,28H,29H,2AH,2BH,2CH
DB 2DH,2EH,2FH,33H,34H,35H,36H
DB 37H,38H,39H,3AH,3BH,3CH,3DH
DB 3EH,3FH,44H,45H,46H,47H,48H
DB 49H,4AH,4BH,4CH,4DH,4EH,4FH
DB 55H,56H,57H,58H,59H,5AH,5BH
DB 5CH,5DH,5EH,5FH,66H,67H,68H
DB 69H,6AH,6BH,6CH,6DH,6EH,6FH
DB 77H,78H,79H,7AH,7BH,7CH,7DH
DB 7EH,7FH,88H,89H,8AH,8BH,8CH
DB 8DH,8EH,8FH,99H,9AH,9BH,9CH
DB 9DH,9EH,9FH,0AAH,0ABH,0ACH
DB 0ADH,0AEH,0AFH,0BBH,0BCH
DB 0BDH,0BEH,0BFH,0CCH,0CDH
DB 0CEH,0CFH,0DDH,0DEH,0DFH
DB 0EEH,0EFH,0FFH
; Neuer Interrupt-Handler 10H
KEYWORD DB "136COLOR"
NEWINT_10H PROC FAR
OR AH,AH
;Funktion "Bildschirmmodus setzen" ?
JNZ TEST1
;wenn nicht => nächste Fkt. testen
CALL SET_KOOR
;prüfen, ob einer der vier Modi und
;evtl. max. Bildschirmausdeh. setzen
JMP SHORT OLDINT_CALL
;Sprung ins BIOS, um Modus zu setzen
TEST1: CMP AH,0FFH
;Funktion "Prog. installiert" ?
JNZ TEST2
;wenn nicht => nächste Fkt. testen
MOV AL,0AAH
;anzeigen, daß Programm installiert
IRET
;zurück zum Aufrufer
TEST2: CMP AH,0FEH
;Funktion "Aktivieren/Deaktivieren"?
JNZ TEST3
;wenn nicht => nächste Fkt. testen
AND AL,01H
;nur 0 und 1 erlaubt
MOV CS:ACTIVE_FLAG,AL
;Aktivierungs-Flag setzen
IRET
;zurück zum Aufrufer
TEST3: CMP CS:MODE_FLAG,00H
;aktueller Modus unbekannt ?
JNZ FKT_OK
;wenn nicht => aufzurufene Funktion
;ausführen
OLDINT_CALL: JMP DWORD PTR CS:OLDINT_10H
;Sprung zur ursprüngl. BIOS-Funktion
FKT_OK: CMP CS:ACTIVE_FLAG,00H
;Erweiterung nicht aktiviert ?
JZ OLDINT_CALL
;dann Sprung ins BIOS
CMP AH,0CH
;Funktion "Punkt setzen" ?
JZ FKT_CALL
;dann Ok.
CMP AH,0DH
;Funktion "Punkt lesen" ?
JNZ OLDINT_CALL
;wenn nicht => Sprung ins BIOS
FKT_CALL: MOV CS:OLDSS,SS
;Stacksegment speichern
MOV CS:OLDSP,SP
;Stackpointer speichern
PUSH CS
POP SS
;Stacksegment=Codesegment
MOV SP,0100H
PUSH BP
PUSH AX
MOV BP,SP
;Basepointer zeigt auf AX
PUSH DX
PUSH DS
;Datensegment sichern
PUSH ES
;Extrasegment sichern
PUSH CS
POP DS
;Datensegment=Codesegment
PUSH AX
PUSH DX
;Register AX und DX auf Stapel
MOV DX,03CEH
MOV AX,0205H
OUT DX,AX
;Grafikmodi für EGA-Karte setzen:
;Lesemodus 0 / Schreibmodus 2
AND BH,03H
;Seitenangabe zwischen 0 und 3
MOV SCR_OFFSET,0000H
;Offset für Zugriff auf Seiten=0000H
OR BH,BH
;Seitennummer = 0 ?
JZ SCROFF_OK
;dann ist das Offset in Ordnung
CMP CRT_MODE,0EH
;Modus 640x200 ?
JNZ SCROFF_640x350
;nein ? => Seitenoffset für Modus
;640x350 setzen
MOV AL,BH
XOR AH,AH
;Seitennummer nach AX
MOV DX,4000H
;Länge einer Seite nach DX
MUL DX
;SCR_OFFSET berechnen
MOV SCR_OFFSET,AX
;und speichern
JMP SHORT SCROFF_OK
;Sprung zur Ausführungssequenz
SCROFF_640x350: MOV SCR_OFFSET,8000H
;Offset für Seite 1 setzen
SCROFF_OK: MOV AX,0A000H
MOV ES,AX
;Extrasegment als Videosegment inst.
POP DX
POP AX
;Register DX und AX restaurieren
CMP AH,0CH
;Funktion "Punkt setzen" ?
JNZ CHK_FKT1
;wenn nicht => nächste Fkt. prüfen
CALL PUT_PIXEL
;sonst Punkt setzen
JMP SHORT EXIT_NEWINT_10H
;und zurück zum Aufrufer
CHK_FKT1: CALL GET_PIXEL
;Funktion "Punkt lesen"
EXIT_NEWINT_10H: MOV DX,03CEH
MOV AX,0005H
OUT DX,AX
;alten Lese-/Schreibmodus setzen
MOV AX,0FF08H
OUT DX,AX
;Bit Mask Register installieren
POP ES
POP DS
POP DX
POP AX
POP BP
;alle Register vom Stapel
MOV SS,CS:OLDSS
;altes Stacksegment
MOV SP,CS:OLDSP
;und alten Stackpointer installieren
IRET
;zurück zum Aufrufer
NEWINT_10H ENDP
;Funktion: maximale Bildschirmausdehnung
; für spezifischen Bildschirm-
; modus für Grafikroutinen setzen
;Eingabe : AL = Bildschirmmodus
;Ausgabe : [MAXX], [MAXY] und [GETPOS_ADR]
; erhalten Werte, wenn AL =
; 0EH,10H,12H oder VMODE_800x600
; [MODE_FLAG]=1, wenn einer der
; o.g. Modi
; [CRT_MODE] = akt. Bildschirmm.
SET_KOOR PROC NEAR
PUSH DS
PUSH CS
POP DS
MOV CRT_MODE,AL
;akt. Bildschirmmodus speichern
CMP AL,0EH
;Modus 640x200 ?
JNZ MODE1
;wenn nicht => nächsten Modus testen
MOV MAXX,320
MOV MAXY,200
;max. Bildschirmausdehnung eintragen
MOV GETPOS_ADR,OFFSET GPOS_320
;Adr. der Routine zur Berechnung der
;Bildschirmposition eintragen
JMP SHORT MODE_OK
;Modus bestätigen
MODE1: CMP AL,10H
;Modus 640x350 ?
JNZ MODE2
MOV MAXX,320
MOV MAXY,350
MOV GETPOS_ADR,OFFSET GPOS_320
JMP SHORT MODE_OK
MODE2: CMP AL,12H
;Modus 640x480 ?
JNZ MODE3
MOV MAXX,320
MOV MAXY,480
MOV GETPOS_ADR,OFFSET GPOS_320
JMP SHORT MODE_OK
MODE3: CMP AL,VMODE_800x600
;Modus 800x600 ?
JNZ EXIT_SET_KOOR
;wenn nicht => unbekannter Modus
MOV MAXX,400
MOV MAXY,600
MOV GETPOS_ADR,OFFSET GPOS_400
MODE_OK: MOV MODE_FLAG,01H
;"Bekannter Modus" anzeigen
POP DS
RET
;zurück zum Aufrufer
EXIT_SET_KOOR: MOV MODE_FLAG,00H
;"Unbekannter Modus" anzeigen
MOV ACTIVE_FLAG,00H
;erweiterte Funktionen deaktivieren
POP DS
RET
;und zurück zum Aufrufer
SET_KOOR ENDP
;Funktion: Zu einer Farbnummer gehörenden
; Farbwert aus COLTAB auslesen
;Eingabe : AL = Farbe (0-135)
; DX = Y-Position
;Ausgabe : [COLOR] = linker und rechter
; Farbwert
GET_COLOR PROC NEAR
PUSH BX
MOV BL,AL
;Farbnummer nach BL
XOR BH,BH
MOV AL,[COLTAB+BX]
;Farbwert auslesen
POP BX
MOV AH,AL
;Farbwert nach AH kopieren
AND AX,0F00FH
;oberen Farbwert in AH, bzw. unteren
;Farbwert in AL ausmaskieren
MOV CL,04H
SHR AH,CL
;oberen Farbwert in unteren vier Bit
;schieben
RCR DX,1
;unteres Bit der Y-Position ins
;Carry-Flag
JNC GCOLOR_OK
;wenn Y-Position gerade => Farbe Ok.
XCHG AH,AL
;sonst linken und rechten Farbwert
;vertauschen
GCOLOR_OK: MOV COLOR,AX
;beide Farbwerte abspeichern
RET
;und zurück zum Aufrufer
GET_COLOR ENDP
;Funktion: Schnelles Berechnen der Bild-
; adresse zu einem Punkt für die
; Modi 320x200, 320x350, 320x480
;Eingabe : AL = Farbe (0-135)
; CX = X-Position
; DX = Y-Position
;Ausgabe : BX = Bildschirmadresse
GPOS_320 PROC NEAR
PUSH AX
PUSH DX
PUSH CX
;Farbe, X- und Y-Position auf Stapel
MOV BX,DX
;Y-Position nach BX
MOV CL,06H
SHL BX,CL
;mit 64 multiplizieren
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
ADD BX,DX
;Y-Position 16x aufaddieren
;=> Multiplikation mit 80 !
POP CX
PUSH CX
;X-Position nach CX holen
SHR CX,1
SHR CX,1
;durch 4 dividieren
ADD BX,CX
;und zur Bildschirmadr. aufaddieren
ADD BX,SCR_OFFSET
;Screenoffset (für Seiten) aufadd.
CALL GET_COLOR
;Farbwert aus Farbe in AL berechnen
POP CX
POP DX
POP AX
;alle Register restaurieren
RET
;und zurück zum Aufrufer
GPOS_320 ENDP
;Funktion: Schnelles Berechnen der Bild-
; adresse zu einem Punkt für den
; Modus 400x600
;Eingabe : AL = Farbe (0-135)
; CX = X-Position
; DX = Y-Position
;Ausgabe : BX = Bildschirmadresse
GPOS_400 PROC NEAR
PUSH AX
PUSH DX
PUSH CX
;Farbe, X- und Y-Position auf Stapel
MOV BX,DX
;Y-Position nach BX
MOV CX,07H
SHL BX,CL
;mit 128 multiplizieren
SUBLOOP: SUB BX,DX
SUB BX,DX
SUB BX,DX
SUB BX,DX
LOOP SUBLOOP
;Y-Position 28x subtrahieren
;=> Multiplikation mit 100 !
POP CX
PUSH CX
;X-Position nach CX holen
SHR CX,1
SHR CX,1
;durch 4 dividieren
ADD BX,CX
;und zur Bildschirmadr. aufaddieren
ADD BX,SCR_OFFSET
;Screenoffset (für Seiten) aufadd.
CALL GET_COLOR
;Farbwert aus Farbe in AL berechnen
POP CX
POP DX
POP AX
;alle Register restaurieren
RET
;und zurück zum Aufrufer
GPOS_400 ENDP
; Neue INT 10H-Funktionen
;Funktion: Routine zum Setzen eines Punk-
; tes durch Beschreiben der EGA-
; Karte
;Eingabe : CX = X-Position
; DX = Y-Position
; AL = Farbnummer (auf Stack)
;Ausgabe : keine
PUT_PIXEL PROC NEAR
MOV AL,[BP]
;Farbnummer holen
CMP CX,MAXX
;X-Position > Bildschirmausdehnung ?
JAE END_PUTPIX
;dann keinen Punkt setzen
CMP DX,MAXY
;Y-Position > Bildschirmausdehnung ?
JAE END_PUTPIX
;dann keinen Punkt setzen
CMP AL,87H
;Farbnummer zu groß ?
JA END_PUTPIX
;dann keinen Punkt setzen
PUSH AX
PUSH BX
PUSH CX
PUSH DX
;Register auf Stapel
PUSH CX
;X-Position auf Stapel
CALL GETPOS_ADR
;Bildschirmadresse berechnen
MOV AL,ES:[BX]
;Latch Register laden
MOV DX,03CEH
;Graphics Controller Adresse nach DX
POP CX
;X-Position nach CX
SHL CX,1
;mit 2 multiplizieren
AND CL,07H
;Bits 0-7 ausmaskieren
PUSH CX
;Maske auf Stapel
MOV AX,8008H
;Defaultmaske und Nr. des Bit Mask
;Registers (08H) nach AX
SHR AH,CL
;Maske für linken Punkt berechnen
OUT DX,AX
;und Bit Mask Register beschreiben
MOV AX,COLOR
;Farben nach AX holen
MOV ES:[BX],AH
;Farbe für linken Punkt setzen
POP CX
;Maske vom Stapel holen
INC CL
;erhöhen => Maske für rechten Punkt
PUSH AX
;Farben auf Stapel
MOV AL,ES:[BX]
;Latches laden
MOV AX,8008H
;Defaultmask./Bit Mask Reg. nach AX
SHR AH,CL
;Maske für rechten Punkt berechnen
OUT DX,AX
;und Bit Mask Register beschreiben
POP AX
;Farben holen
MOV ES:[BX],AL
;Farbe für rechten Punkt setzen
POP DX
POP CX
POP BX
POP AX
;alle Register restaurieren
END_PUTPIX: RET
;und zurück zum Aufrufer
PUT_PIXEL ENDP
;Funktion: Routine zum Lesen eines Punktes
; durch Beschreiben der EGA-Karte
;Eingabe : CX = X-Position
; DX = Y-Position
;Ausgabe : AL = Farbe (0-135)
; AL = 0FFH bedeutet Farbe nicht
; erkannt
;Bemerkung: Ausgabe geschieht über Stack
GET_PIXEL PROC NEAR
CMP CX,MAXX
;X-Position > Bildschirmausdehnung ?
JAE END_GETPIX
;dann keinen Punkt lesen
CMP DX,MAXY
;Y-Position > Bildschirmausdehnung ?
JAE END_GETPIX
;dann keinen Punkt lesen
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
;Register auf Stapel
PUSH DX
;Y-Position auf Stapel
PUSH CX
;X-Position auf Stapel
CALL GETPOS_ADR
;Bildschirmadresse berechnen
POP CX
;X-Position nach CX
SHL CX,1
;mit 2 multiplizieren
AND CL,07H
;Bits 0-7 ausmaskieren
INC CL
;erhöhen, damit Bitnummern 1-8
MOV DX,03CEH
;Graphics Controller Adresse nach DX
MOV AL,04H
OUT DX,AL
;Read Map Select Register wählen
INC DX
;erhöhen, damit DX auf Datenregister
;zeigt
MOV AL,03H
;Planenummer nach AL (0-3)
MOV SI,BX
;Bildschirmadresse nach SI
XOR BX,BX
;linker und rechter Farbwert = 0
TLOOP: OUT DX,AL
;Plane selektieren
MOV AH,ES:[SI]
;ein Byte aus Bildschirmspei. lesen
SHL AH,CL
;Wert d. linken Punktes ins Carry
RCL BH,1
;und nach BH überführen
SHL AH,1
;Wert d. rechten Punktes ins Carry
RCL BL,1
;und nach BL überführen
DEC AL
;Planenummer erniedrigen
JNS TLOOP
;Planes 3-0 bearbeiten
POP DX
;Y-Position nach DX
RCR DX,1
;Y-Position gerade ?
JNC TEST_OK
;dann Farbwerte Ok.
XCHG BH,BL
;sonst linken und rechten Farbwert
;vertauschen
TEST_OK: MOV CL,04H
SHL BH,CL
;linken Farbwert ins obere Nibble
MOV AL,BL
OR AL,BH
;beide Farbwerte nach AL schreiben
MOV DI,OFFSET COLTAB
;Adresse der Farbtabelle nach DI
PUSH ES
PUSH DS
POP ES
MOV CX,136
;136 Farben möglich
XOR AH,AH
;Zähler auf Null setzen
TLOOP1: SCASB
;Farbwerte in AL mit Tab. vergleich.
JZ END_TLOOP1
;wenn Farbwert gefunden => Ok.
INC AH
;sonst Zähler erhöhen
LOOP TLOOP1
;alle Farben vergleichen
MOV AH,0FFH
;Wert 0FFH bedeutet Farbe nicht gef.
END_TLOOP1: MOV AL,AH
;Farbnummer nach AL
MOV [BP],AL
;und auf Stapel
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
;alle Register restaurieren
RET
;zurück zum Aufrufer
END_GETPIX: MOV BYTE PTR [BP],00H
;wenn X- bzw. Y-Position außerhalb
;des Bildschirms => Farbe 0 zurückg.
RET
;zurück zum Aufrufer
GET_PIXEL ENDP
; Installierung
INIT: PUSH CS
POP DS
MOV AX,3510H
INT 21H
;Interrupt-Vektor 10H lesen
MOV DI,BX
;Offsetadresse nach DI
SUB DI,08H
;Zeiger auf evtl. Erkennungsstring
MOV SI,OFFSET KEYWORD
;Adr. des Erkennungsstrings nach SI
MOV CX,08H
;Erkennungsstring ist 8 Zeichen lang
REPZ CMPSB
;vergleichen
JZ DELETE_TSR
;wenn Programm vorhanden => aus
;Speicher entfernen
MOV OLDINT_10H,BX
MOV OLDINT_10H+2,ES
;sonst alte Interrupt-Adresse spei.
MOV AH,0FH
INT 10H
;akt. Bildschirmmodus auslesen
CALL SET_KOOR
;evtl. max. Bildschirmausdeh. setzen
MOV AX,2510H
MOV DX,OFFSET NEWINT_10H
INT 21H
;neue Interruptadresse setzen
MOV AX,CS:[002CH]
;Segmentadr. des Envir.-Ber. holen
MOV ENVSEG,AX
;und speichern (für evtl. Freigabe)
MOV AH,09H
MOV DX,OFFSET MSG1
INT 21H
;Meldung ausgeben
MOV AX,3100H
MOV DX,OFFSET INIT
MOV CL,04H
SHR DX,CL
INC DX
;Anzahl Paragraphen berechnen
INT 21H
;Programm resident machen und zurück
;zur DOS-Ebene
DELETE_TSR: PUSH ES
;Segmentadresse des residenten Pro-
;gramms auf Stapel legen
MOV ES,ES:ENVSEG
;Segmentadr. des Envir.-Ber. holen
MOV AH,49H
INT 21H
;Bereich freigeben
JC ERR_DELETE_TSR
;erfolglos => entfernen nicht mögl.
POP ES
;Segmentadresse des res. Pro. holen
MOV AH,49H
INT 21H
;Bereich freigeben
JC ERR_DELETE_TSR1
;erfolglos => nicht entfernen
PUSH DS
;akt. Datensegment sichern
MOV AX,2510H
LDS DX,DWORD PTR ES:OLDINT_10H
;Adr. d. ursprünglichen Int. holen
INT 21H
;und einsetzen
POP DS
;Datensegment restaurieren
MOV AH,09H
MOV DX,OFFSET MSG2
INT 21H
;Meldung ausgeben
MOV AX,4C01H
INT 21H
;und zurück zur DOS-Ebene
;(ERRORLEVEL=1)
ERR_DELETE_TSR: POP ES
;Segmentadr. d. res. Pro. holen
ERR_DELETE_TSR1: MOV AH,09H
MOV DX,OFFSET MSG3
INT 21H
;Meldung ausgeben
MOV AX,4C02H
INT 21H
;und zurück zur DOS-Ebene
;(ERRORLEVEL=2)
CODE ENDS
END START