Letzte Änderung: 26.01.98

ASM86FAQ - Lösungen



(Übersicht)

Wie erfahre ich, welche CPU vorhanden ist?

Juergen Thelen 2:2450/55.5:

Es existieren verschiedene Wege, um eine CPU zu identifizieren. Der imo wohl exakteste Weg ist die sogenannte "CPU-Shutdown Methode". Bei dieser Methode wird meist ein "Triple Fault" ausgelöst, wodurch die CPU in den ShutdownMode geht und im Real Address Mode erneut gestartet wird. Beim Neustart enthalten dann verschiedene Register Codes, anhand derer sich Hersteller, Prozessoren- modell und -typ, Masken, Revisionen u.ä. identifizieren lassen.

Allerdings ist diese Methode zum einen sehr aufwendig, und zum anderen sind derart präzise Identifizierungen nur sehr selten erforderlich.

Eine weiterer Weg ist die sogenannte "Illegal Opcode Methode". Dabei wird eine Interrupt 6 ISR eingeklinkt, die auf die Ausführung von dem Prozessor unbekannten Opcodes reagiert. Die Identifikationsroutine führt dann einfach nacheinander Instructions aus, die erst ab einer bestimmten CPU-Reihe exi- stieren. Wird Interrupt 6 aufgrund eines unbekannten Opcodes ausgelöst, kann dann ermittelt werden, welche Instruction die letzte noch bekannte war, und folglich ist die CPU identifiziert.

Da auch diese Methode nicht ganz problemlos ist, setze ich meist die nach- folgende Routine ein, die größtenteils auf offiziellen Intel-Informationen beruht. Voraussetzung für den Einsatz der Routine ist allerdings, daß sich die CPU im Real Address Mode befindet (Gründe: offizieller Intel 286-Check, sowie Beschreiben des Code Segmentes).

Btw: Das ist eine etwas ältere Version des Moduls und noch nicht vollständig redundanzfrei. Komme im Moment nicht an meine aktuelle Version, da ich mir beim Testen eines meiner Proggies mal wieder eine der Lib-Platten geschossen hab' und erstmal die FAT restaurieren muss... ;)

;--- Snip ---------------------------------------------------------------- ; ; Modul Get_CPU_ID_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Identifikation der Central Processing Unit ; ; In - ; ; Out AL = CPUTyp: ; ; 1 NEC V20 ; 2 NEC V30 ; 3 8086 ; 4 8088 ; 5 80186 ; 6 80188 ; 7 80286 ; 8 80386 ; 9 80486 ; 10 P5 ; 11 PPro ; 12 Sexium? ;) ; ; Chg EAX, BX, ECX, EDX, SI, DI, ES

PROC Get_CPU_ID_

;------ ; Prüfung auf 8086, 8088, NEC V20, NEC V30, 80186, 80188 ; ; Auf CPUs dieser Serien sind die Bits 12..15 in FLAGS immer gesetzt.

pushf pop ax ; AX = FLAGS and ax, 0fffH ; Bits 12..15 löschen push ax popf ; FLAGS forcieren pushf pop ax ; FLAGS erneut holen and ax, 0f000H ; Bits 12..15 isolieren cmp ax, 0f000H ; Bits wieder gesetzt? jne @@5 ; nein, 286+ ->

;------ ; Prüfung auf 80186, 80188 ; ; CPUs dieser Serien ignorieren Shift-Anweisungen > 32bit, d.h. sie ; shiften überhaupt nicht. 8086/8088/V20/V30 dagegen shiften 32bit.

mov ax, 0ffffH mov cl, 33 shl ax, cl ; 80186/80188? je @@1 ; nein, 8086/8088/V20/V30 ->

;------ ; Unterscheidung zwischen 80186 und 80188 ; ; Erfolgt durch Prüfung der Befehlsqueue-Länge.

mov dl, 6 ; angenommen 80188 jmp @@3

@@1:

;------ ; Prüfung auf NEC V20, NEC V30 ; ; CPUs dieser Serien arbeiten im Gegensatz zu 8086/8088 auch einen ; Segment Override bei REP Stringbefehlen korrekt ab. Ein 8086/8088 ; wuerde aufgrund seines "Multiple Prefix Bugs" mit CX = fffeH enden.

xor si, si mov cx, 0ffffH sti rep es:lodsb or cx, cx ; komplett abgearbeitet worden? jne @@2 ; nein, dann 8086/8088 ->

;------ ; Unterscheidung zwischen NEC V20 und NEC V30 ; ; Erfolgt durch Prüfung der Befehlsqueue-Länge.

mov dl, 2 ; angenommen V30 jmp @@3

;------ ; Unterscheidung zwischen 8086 und 8088 ; ; Erfolgt durch Prüfung der Befehlsqueue-Länge.

@@2: mov dl, 4 ; angenommen 8088 jmp @@3

@@3:

;------ ; Unterscheidung 8bit, 16bit Datenbus ; ; CPUs mit 16bit Datenbus (8086/80186/NEC V20) besitzen einen 6 Bytes, ; 8088/80188/NEC V30 (8bit) einen nur 4 Bytes langen Befehlsqueue. ; ; Bei Ausführung von REP STOSB wären auf 16bit-Systemen bereits die ; Befehle CLD,NOP,NOP,NOP,NOP,DEC DL im Queue, d.h. das DEC DL würde ; ausgeführt, obwohl es vom REP STOSB genopped wird. Auf 8bit-Systemen ; wären nur CLD,NOP,NOP,NOP im Queue, das vierte NOP und DEC DL würden ; also mit effektiver Auswirkung genopped.

push cs pop es mov di, Offset @@4 mov al, 90H ; Opcode für NOP mov cx, 2 std cli rep stosb cld nop nop nop nop

@@4: dec dl ; 8086/80186/V20 OHNE Wirkung sti jmp @@X

;------ ; Prüfung auf 80286 ; ; Auf CPUs dieser Serie sind im RealMode die Bits 12..15 in FLAGS ; immer gelöscht. ; ; Diese Prüfung NUR im RealMode ausführen, sonst Hang-a-la-bang... ;)

@@5: pushf pop ax ; AX = FLAGS or ax, 0f000H ; Bits 12..15 setzen push ax popf ; FLAGS forcieren pushf pop ax ; FLAGS erneut holen and ax, 0f000H ; Bits wieder gelöscht? jne @@6 ; nein, 386+ ->

mov dl, 7 ; CPU ist 80286 jmp @@X

;------ ; Prüfung auf 80386 ; ; Auf CPUs dieser Serie ist Bit 18 (AC-Bit) in EFLAGS immer gelöscht.

@@6: mov bx, sp and sp, 0fffcH ; alignen um AC-Fault zu vermeiden pushfd pop eax mov ecx, eax xor eax, 00040000H ; = Bit 18 flip push eax popfd pushfd pop eax xor eax, ecx ; Bit 18 geändert? mov sp, bx jne @@7 ; ja, 486+ ->

mov dl, 8 ; CPU ist 80386 jmp @@X

@@7: and sp, 0fffcH ; alignen um AC-Fault zu vermeiden push ecx popfd mov sp, bx

;------ ; Prüfung auf 80486 ; ; Auf CPUs dieser Serie ist Bit 21 (CPUID-Bit) in EFLAGS normalerweise ; gelöscht (bis auf einige neuere 486er)

mov dl, 9 ; 80486 angenommen

pushfd pop eax mov ecx, eax xor eax, 00200000H ; = Bit 21 flip push eax popfd pushfd pop eax xor eax, ecx ; Bit 21 geändert? je @@X ; nein, dann ist es ein 80486 ->

push ecx popfd

mov eax, 1 db 0fH, 0a2H ; Opcodes für CPUID shr al, 4 ; Model auf Basis and al, 0fH ; und isolieren mov dl, 5 ; Minimum 486 add dl, al ; = 9 (486), = 10 (P5) ...

@@X: mov al, dl ret

ENDP Get_CPU_ID_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie erfahre ich, welche FPU vorhanden ist?

Juergen Thelen 2:2450/55.5:

Nachstehend meine Routine zur Identifizierung einer FPU. Das Modul benötigt zur FPU-Identifizierung den von Get_CPU_ID_ ermittelten CPU-Typ (LSG0001).

Diese Routine entspricht weitgehend der "offiziellen" Intel-Methode und ist für den Real Mode konzipiert (Beschreiben des Code Segments).

;--- Snip ---------------------------------------------------------------- ; ; Modul Get_FPU_ID_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Identifikation der Floating Point Unit ; ; In AL = CPUTyp: ; ; 1 NEC V20 ; 2 NEC V30 ; 3 8086 ; 4 8088 ; 5 80186 ; 6 80188 ; 7 80286 ; 8 80386 ; 9 80486 ; 10 P5 ; ; Out AL = FPUTyp: ; ; 0 keine ; 1 8087 ; 2 80187 ; 3 80287 ; 4 80387 ; 5 integriert ; ; Chg AX, BL, SI

PROC Get_FPU_ID_

mov bl, al ; CPUTyp push ds

call @@1

DW 0 ; FPU Status/Control Word

@@1:

;------ ; Zur FPU-Identifizierung wird festgestellt, ob sich Status und Control ; Words des Coprozessors beschreiben lassen. ; ; Funktioniert dies nicht, ist logischerweise keine FPU vorhanden. ; ; Ist eine FPU vorhanden, wird anhand des zuvor ermittelten CPU-Typs der ; der entsprechende FPU-Typ ermittelt. ; ; Lediglich bei einem 80386 (CPUTyp 8) erfolgt eine weitere Prüfung, da ; auf 80386ern eine 80287 oder eine 80387 FPU betrieben werden kann. ; Zur Unterscheidung wird die Endlichkeit der FPU überprüft, denn nur ; auf 80287 FPUs ist die positive Endlichkeit gleich der negativen.

pop si ; Offset für Status/Control Word push cs pop ds

fninit ; FPU Status Reset mov [w si], 5a5aH ; auf Wert ungleich Null setzen fnstsw [si] ; Status Word sichern mov ax, [si] or al, al ; ist Status jetzt Null? je @@3 ; ja, könnte FPU sein ->

@@2: xor al, al ; definitiv keine FPU jmp @@X

@@3: fnstcw [si] ; Control Word auf Null setzen mov ax, [si] and ax, 103fH cmp ax, 3fH ; Nullen und Einsen gelesen? jne @@2 ; nein, keine FPU ->

mov al, 1 ; FPU existiert cmp bl, 8 ; CPUTyp = 80386? je @@4 ; ja, Infinity prüfen ->

:------ ; FPU ist 8087, 80187, 80287 oder integriert

mov al, 2 ; 8087 angenommen cmp bl, 5 ; entsprechende CPU? jb @@X ; ja ->

mov al, 3 ; 80187 angenommen cmp bl, 7 ; entsprechende CPU? jb @@X ; ja ->

mov al, 4 ; 80287 angenommen cmp bl, 7 ; entsprechende CPU? je @@X ; ja ->

mov al, 5 ; integrierte FPU (486+) jmp @@X

@@4: fld1 ; Standard Control von FNINIT fldz ; Endlichkeit generieren fdiv fld st ; negative Endlichkeit fchs ; bei 80387 pos <> neg fcompp ; vergleichen und entfernen fstsw [si] ; Status von FCOMPP sichern mov ax, [si] mov al, 3 ; 80287 angenommen sahf ; Endlichkeiten gleich? je @@X ; ja ->

mov al, 4 ; nein, ist 80387

@@X: pop ds ret

ENDP Get_FPU_ID_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wo liegen die Kommandozeilenparameter meines Programmes?

Juergen Thelen 2:2450/55.5:

Die Kommandozeilenparameter findet man im PSP (Program Segment Prefix) des Programmes. Die Adresse des PSP erfährt man über Int 21.62H (BX = PSP).

Die Parameter des Programmes plus CR (0dH) liegen ab PSP:0081H. Die Länge der Kommandozeile (ohne CR) liegt bei PSP:0080H (Byte).


(Übersicht)

Wie komme ich an das Startverzeichnis meines Programmes?

Juergen Thelen 2:2450/55.5:

Den vollständigen Pfad zu seinem Programm findet man seit DOS 3.0+ hinter den DOS-Variablen im Environment Segment seines Prozesses.

Nachfolgend eine meiner allgemeineren Routinen, die unter anderem auch zur Ermittlung der RunPath-Adresse dient:

;--- Snip ---------------------------------------------------------------- ; ; Modul Get_Env_Parms_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Ermitteln von Adresse und Länge des Environments, sowie des ; RunPath-Offsets. ; ; In - ; ; Out AX = Environment-Segment des aktuellen Prozesses ; ; BX = Offset des ersten RunPath-Zeichens (ASCIZ) ; BX-2 = Länge des Environments EXKL. RunPath (nur EnvVars) ; ; CX = Gesamtlänge des Environments INKL. RunPath ; ; Chg AX, BX, CX

PROC Get_Env_Parms_

STRUC frm pDS DW ? pDI DW ? pSI DW ? pBP DW ? pSP DW ? pBX DW ? pDX DW ? pCX DW ? pAX DW ? ENDS frm

pusha push ds mov bp, sp ; Stackframe initialisieren

mov ah, 62H ; GET_CURRENT_PID int 21H ; PSP des aktiven Prozesses holen

mov ds, bx mov ax, [ds:002cH] ; EnvSeg des aktiven Prozesses mov [bp+frm.pAX], ax ; sichern mov ds, ax xor si, si ; DS:SI = EnvSeg:0 xor cx, cx cld

@@1: lodsb inc cl or al, al ; Ende einer Variable ? jne @@1 ; nein ->

cmp [b si], 0 ; Ende aller Variablen ? jne @@1 ; nein ->

add cx, 3 add si, 3 ; Zeiger auf Start des RunPaths mov [bp+frm.pBX], si ; sichern

@@2: lodsb inc cl or al, al ; Ende des RunPaths ? jne @@2 ; nein ->

mov [bp+frm.pCX], cx ; = Gesamtlänge Environmentblock

pop ds popa ret

ENDP Get_Env_Parms_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Grundgerüst für RM/Flat4G und XMS

Juergen Thelen 2:2450/55.5:

Hier eine meiner Beispielsources für den Pseudomodus RM/Flat4G (s. BAW0015).

Sie zeigt, wie man unter RM/Flat4G mit XMS zusammen arbeiten kann. Die XMS- Unterstützung kann in mehreren Fällen durchaus sinnvoll sein, z.B. für den Fall, daß der Anwender das DOS-Kernel oder sonstige Dinge in die HMA ausge- lagert hat, um konventionelles RAM zu sparen, oder für den Fall, daß man auf die XMS-Fähigkeit, Speicherbereiche gegen Verlagerung durch andere Programme sperren zu können (Konfliktverhinderung), nicht verzichten möchte, o.ä.

Normalerweise sind Datenbewegungen (Copy o.ä.) in XMS-Blocks bekanntlich nur über den Treiber, genauer über das Handle des entsprechenden Blocks möglich. Nach dem LOCKen eines oder mehrerer XMS-Blocks gilt das unter RM/Flat4G na- türlich nicht mehr... &)

Wer es lieber RAW mag ;), oder nach Möglichkeiten zur direkten A20-Steuerung oder einer WrapAround-Prüfung sucht, findet in LSG0006 eine entsprechend ab- geänderte Source-Variante...

;--- Snip ------------------------------------------------------------------ ; ; Programm RMF4GXMS ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; OS DOS 2.0+ ; CPU 386+ ; ; Aufgabe Grundgerüst RM/Flat4G für XMS-Umgebungen ; ; .OBJ TASM /m /ml /dMDL=Modell RMF4GXMS.ASM ; .EXE TLINK /c RMF4GXMS.OBJ ;

IFNDEF MDL

DISPLAY "Fehler: '/dMDL=Modell' zur Assemblierung erforderlich!" ERR

ELSE

% MODEL USE16 MDL

IDEAL JUMPS LOCALS DOSSEG

STACK

;---------------------------------------------------------------------------

o EQU Offset s EQU Seg b EQU byte ptr w EQU word ptr d EQU dword ptr p EQU pword ptr

;---------------------------------------------------------------------------

; Nachfolgende Equates einfach den jeweiligen Anforderungen anpassen... ;)

MIN_XMS = 4096 ; Min. KByte XMS-RAM (frei) MIN_CNV = 256 ; Min. KByte konventionelles RAM (frei)

;---------------------------------------------------------------------------

P8086

CODESEG STARTUPCODE

;------ ; überflüssigen Heap an DOS zurückgeben

mov bx, sp add bx, 15 mov cl, 4 shr bx, cl mov ax, ss add bx, ax mov ax, es sub bx, ax mov ah, 4aH ; ResizeMemBlock int 21H ; Heap an DOS zurückgeben

mov dx, o DTitle mov ah, 9 int 21H

call Init_ ; Fehler während Initialisierung? jc Cancel ; ja ->

;------ ; Prozessor für RM/Flat4G einrichten

P386

mov eax, s RM4G_GDT shl eax, 4 ; GDT-Segment Paragraph -> Linear xor ebx, ebx mov bx, o RM4G_GDT add eax, ebx ; + Offset(GDT) mov [d RM4G_GDTR+2], eax ; = GDTR.Base mov [w RM4G_GDTR], 2*8 ; GDTR.Limit = 2 Descriptors lgdt [p RM4G_GDTR] ; GDTR für neuen GDT laden

push ds ; Bezug zum DATASEG sichern cli

mov eax, cr0 or eax,1 ; CR0.PE setzen mov cr0, eax ; rein in den Protected Mode jmp @@PQFlush1 ; Prefetch-Queue löschen!

@@PQFlush1: mov bx, 8 ; Selector für 2. Descriptor

mov ds, bx ; DS.Limit = 4 GByte mov es, bx ; ES.Limit = 4 GByte mov fs, bx ; FS.Limit = 4 GByte mov gs, bx ; GS.Limit = 4 GByte

and eax, 0feH ; CR0.PE löschen mov cr0, eax ; zurück in den Real Address Mode jmp @@PQFlush2 ; Prefetch-Queue löschen!

@@PQFlush2: sti pop ds ; Bezug zum DATASEG restaurieren

call Main_ ; Hauptprogramm call CleanUp_ ; aufräumen

xor al, al ; ExitCode: ok jmp EndProgram

Cancel: mov bx, dx shl bx, 1 add bx, o ErrTxtTbl mov dx, [bx] mov ah, 9 int 21H

mov al, 1 ; ExitCode: Fehler

EndProgram: mov ah, 4cH int 21H ; Programm beenden

;--- Init ------------------------------------------------------------------

PROC Init_

P8086

cld

;------ ; Mit Sicherheit scheiterndes AllocMemBlock ausführen, um den ; größten freien Block (= freies konventionelles RAM) nach BX ; zu holen.

mov bx, 0ffffH ; 65.535 Paras mov ah, 48H ; AllocMemBlock int 21H ; = MaxAvail nach BX holen

;------ ; Prüfen, ob Anforderung MIN_CNV erfüllt ist

mov dx, 1 ; Annahme: Fehlercode 1 mov cl, 6 shr bx, cl ; Paras in KByte cmp bx, MIN_CNV ; genug konventionelles RAM frei? jb InitErr ; nein, Fehler ->

;------ ; 8086/8088 CPUs ausfiltern

mov dx, 2 ; Annahme: Fehlercode 2 push sp pop ax cmp ax, sp ; ungleich: 8086/88? jne InitErr ; ja, Fehler: kein 386er ->

P286

;------ ; CPUs im PM bzw. VM ausfiltern (dadurch auch EMS/XMS auf PM-Basis)

mov dx, 3 ; Annahme: Fehlercode 3 smsw ax ; MSW holen shr ax, 1 ; MSW.PE ins CF schieben jc InitErr ; Fehler: nicht im RM ->

;------ ; 80286 CPUs ausfiltern

mov dx, 2 ; Annahme: Fehlercode 2 pushf ; FLAGS sichern pushf pop ax ; AX = FLAGS or ax, 0f000H ; Bits 12..15 setzen push ax popf ; FLAGS forcieren pushf pop ax ; FLAGS erneut holen popf ; FLAGS restaurieren and ax, 0f000H ; Bits 12..15 wieder gelöscht? je InitErr ; ja, Fehler: kein 386er ->

P386

;------ ; Systeme ohne aktiven XMS-Treiber ausfiltern

mov dx, 4 ; Annahme: Fehlercode 4 mov ax, 4300H int 2fH cmp al, 80H ; XMS-Treiber aktiv? jne InitErr ; nein, Fehler ->

;------ ; XMS-Vektor für zukünftige FAR CALLs ermitteln und sichern

mov ax, 4310H int 2fH mov [w XMSVector], bx mov [w XMSVector+2], es

;------ ; XMS-Versionen vor 2.0 ausfiltern

xor ah, ah ; GetXMSVersion call [d XMSVector] mov dx, 5 ; Annahme: Fehlercode 5 cmp ah, 2 ; mindestens 2.x? jb InitErr ; nein, Fehler: älter als 2.0 ->

;------ ; Prüfen, ob Anforderung MIN_XMS erfüllt ist

mov ah, 8 ; QueryFreeXMS xor bl, bl ; für richtigen ErrCode in DirtyBIOSs call [d XMSVector] cmp dx, MIN_XMS ; genug XMS-RAM frei? mov dx, 6 ; Annahme: Fehlercode 6 jb InitErr ; nein, Fehler ->

;------ ; XMS-Block in Größe MIN_XMS allokieren

mov dx, MIN_XMS mov ah, 9 ; AllocXMSBlock call [d XMSVector] mov [XMSHandle], dx mov dx, 7 ; Annahme: Fehlercode 7 or al, al ; erfolgreich (1)? je InitErr ; nein, Fehler ->

;------ ; XMS-Block LOCKen (um Verlagerungen auszuschließen)

mov dx, [XMSHandle] mov ah, 12 ; LockXMSBlock call [d XMSVector] mov [w LFlatBottom], bx ; Startadresse des mov [w LFlatBottom+2], dx ; Flat-RAMs (32bit linear) mov dx, 8 ; Annahme: Fehlercode 8 or al, al ; erfolgreich (1)? je InitErr ; nein, Fehler ->

;------ ; LocalA20Enable (Zugriff auf XMM ermöglichen (WrapAround deaktivieren))

mov ah, 5 ; LocalA20Enable call [d XMSVector] mov dx, 9 ; Annahme: Fehlercode 9 or al, al ; erfolgreich (1)? je InitErr ; nein, Fehler ->

clc jmp InitX

InitErr: stc

InitX: ret

ENDP Init_

;--- Main ------------------------------------------------------------------

PROC Main_

; ; Hier ist der Platz um eure RM/Flat4G (XMS) Schlachten zu schlagen... ;) ; ; Beispielzugriffe RM/Flat4G: ; ; mov edi, 000b8000H ; mov al, 7 ; mov [es:edi], al ; ; mov esi, [LFlatBottom] ; mov al, [es:esi] ; mov ax, [fs:esi] ; mov eax, [gs:esi] ; ; Achso, und nicht vergessen: Bei einem USE16-Segment (wie hier) werden ; String-Instructions vom Assembler natürlich 16bit übersetzt (SI/DI).. ;) ;

ret ENDP Main_

;--- CleanUp ---------------------------------------------------------------

PROC CleanUp_

;------ ; LocalA20Disable (um nachfolgende Programme nicht zu verwirren ;)

mov ah, 6 ; LocalA20Disable call [d XMSVector]

;------ ; Unseren geLOCKten XMS-Block wieder für Verlagerungen freigeben

mov ah, 13 ; UnlockXMSBlock mov dx, [XMSHandle] call [d XMSVector]

;------ ; Unseren XMS-Block wieder der Allgemeinheit anvertrauen ;)

mov ah, 10 ; FreeXMSBlock mov dx, [XMSHandle] call [d XMSVector]

; ; weitere eventuell erforderliche Aufräumarbeiten ;

ret ENDP CleanUp_

;---------------------------------------------------------------------------

DATASEG

RM4G_GDT db 8 DUP(0) ; Null-Descriptor

; 2. Descriptor mit 4 GByte-Limit

dw 0ffffH ; Limit (Bits 0..15)

dw 0 ; Base (Bits 0..15)

db 0 ; Base (Bits 16..23)

db 10010010b ; |++||||+- not accessed ; | ||||+-- writable ; | |||+--- no ExpandDown ; | ||+---- immer 0 ; | |+----- immer 1 ; | +------ DPL = 0 ; +-------- present

db 11001111b ; ||||+--+ ; |||| +- Limit (Bits 16..19) ; |||+----- available ; ||+------ immer 0 ; |+------- big Segment ; +-------- Granularity = 4 KByte (Limit in 4 KByte-Units)

db 0 ; Base (Bits 24..31)

RM4G_GDTR db 6 DUP(0)

XMSVector dd 0 XMSHandle dw 0

LFlatBottom dd 0

DTitle db 13, 10 db 'RM/Flat4G (XMS), (p) 1996 J. Thelen, Public Domain' db 13, 10, 36

ErrTxt1 db 13, 10, 7 db 'Fehler: 256 KByte RAM erforderlich (nach HeapRelease).' db 13, 10, 36

ErrTxt2 db 13, 10, 7 db 'Fehler: 80386 CPU (oder höher) erforderlich.' db 13, 10, 36

ErrTxt3 db 13, 10, 7 db 'Fehler: CPU befindet sich nicht im Real Address Mode.' db 13, 10, 36

ErrTxt4 db 13, 10, 7 db 'Fehler: XMS-Treiber erforderlich. Bitte aktivieren.' db 13, 10, 36

ErrTxt5 db 13, 10, 7 db 'Fehler: XMS-Treiber zu alt (min. XMS 2.0+ erforderlich).' db 13, 10, 36

ErrTxt6 db 13, 10, 7 db 'Fehler: Zuwenig XMS-RAM frei (min. 4 MByte erforderlich).' db 13, 10, 36

ErrTxt7 db 13, 10, 7 db 'Fehler: XMS-Blockreservierung mißlungen (FATAL!).' db 13, 10, 36

ErrTxt8 db 13, 10, 7 db 'Fehler: XMS-Blocksperrung mißlungen (FATAL!).' db 13, 10, 36

ErrTxt9 db 13, 10, 7 db 'Fehler: A20-Gate nicht ansteuerbar (FATAL!).' db 13, 10, 36

ErrTxtTbl dw 0 dw o ErrTxt1, o ErrTxt2, o ErrTxt3, o ErrTxt4 dw o ErrTxt5, o ErrTxt6, o ErrTxt7, o ErrTxt8 dw o ErrTxt9

;---------------------------------------------------------------------------

ENDIF

END

;--- Snap ------------------------------------------------------------------


(Übersicht)

Grundgerüst für RM/Flat4G und RAW

Juergen Thelen 2:2450/55.5:

Hier eine weitere Beispielsource für RM/Flat4G, die aber im Gegensatz zu der vorstehenden LSG0005 nicht mit XMS arbeitet, sondern davon ausgeht, daß noch kein XMS Memory Manager aktiv ist. Die Source geht sogar noch etwas weiter, und schließt auch die Aktivität jeglichen EMS-Treibers aus. Das Fehlen jeg- lichen Memory Managers ist übrigens auch der Grund, warum man eine derartige Betriebsart häufig auch als RAW (englisch, roh) bezeichnet...

Diese Source ist im Prinzip also für eigene RM/Flat4G-Programme gedacht, die ausschließen wollen, daß ihnen ein Memory Manager dazwischenfunkt (aus wel- chen Gründen auch immer)... ;)

Genauso gut ließen sich aber auch Teile dieser Source mit LSG0005 verbinden. Das wäre z.B. sinnvoll, wenn man erreichen möchte, daß bei nicht vorhandenem XMS-Treiber das Programm halt auf XMS verzichtet und stattdessen einfach RAW weiterarbeitet. Dadurch entfiele für den Anwender automatisch der "Zwang", erst selbst einen XMS-Treiber aktivieren, das System resetten und das Pro- gramm erneut starten zu müssen.

Die Source zeigt außerdem, wie man die A20-Leitung direkt über den Keyboard Controller steuert und eine WrapAround-Prüfung auf die Beine stellt. Solche Routinen sind in LSG0005 nicht enthalten.

;--- Snip ------------------------------------------------------------------ ; ; Programm RMF4GRAW ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; OS DOS 2.0+ ; CPU 386+ ; ; Aufgabe Grundgerüst RM/Flat4G für RAW-Umgebungen ; ; .OBJ TASM /m /ml /dMDL=Modell RMF4GRAW.ASM ; .EXE TLINK /c RMF4GRAW.OBJ ;

IFNDEF MDL

DISPLAY "Fehler: '/dMDL=Modell' zur Assemblierung erforderlich!" ERR

ELSE

% MODEL USE16 MDL

IDEAL NOJUMPS LOCALS DOSSEG

STACK

;---------------------------------------------------------------------------

o EQU Offset s EQU Seg b EQU byte ptr w EQU word ptr d EQU dword ptr p EQU pword ptr

;---------------------------------------------------------------------------

; Nachfolgende Equates könnt ihr natürlich euren Anforderungen entsprechend ; anpassen. In der hier vorliegenden Form erwartet das Proggie 550 KByte ; freies konventionelles RAM (nach HeapRelease!)... ; ; Was das fürs Debugging bedeuten würde, dürfte wohl klar sein... &)

MIN_XMM = 16384 ; Min. KByte erweiterter Speicher (installiert) MIN_CNV = 550 ; Min. KByte konventionelles RAM (frei)

;---------------------------------------------------------------------------

P8086

CODESEG STARTUPCODE

;------ ; überflüssigen Heap an DOS zurückgeben

mov bx, sp add bx, 15 mov cl, 4 shr bx, cl mov ax, ss add bx, ax mov ax, es sub bx, ax mov ah, 4aH ; ResizeMemBlock int 21H ; Heap an DOS zurückgeben

mov dx, o DTitle mov ah, 9 int 21H

call Init_ ; Fehler während Initialisierung? jc Cancel ; ja ->

;------ ; Prozessor für RM/Flat4G einrichten

P386

mov eax, s RM4G_GDT shl eax, 4 ; GDT-Segment Paragraph -> Linear xor ebx, ebx mov bx, o RM4G_GDT add eax, ebx ; + Offset(GDT) mov [d RM4G_GDTR+2], eax ; = GDTR.Base mov [w RM4G_GDTR], 2*8 ; GDTR.Limit = 2 Descriptors lgdt [p RM4G_GDTR] ; GDTR für neuen GDT laden

push ds ; Bezug zum DATASEG sichern cli

mov eax, cr0 or eax,1 ; CR0.PE setzen mov cr0, eax ; rein in den Protected Mode jmp @@PQFlush1 ; Prefetch-Queue löschen!

@@PQFlush1: mov bx, 8 ; Selector für 2. Descriptor

mov ds, bx ; DS.Limit = 4 GByte mov es, bx ; ES.Limit = 4 GByte mov fs, bx ; FS.Limit = 4 GByte mov gs, bx ; GS.Limit = 4 GByte

and eax, 0feH ; CR0.PE löschen mov cr0, eax ; zurück in den Real Address Mode jmp @@PQFlush2 ; Prefetch-Queue löschen!

@@PQFlush2: sti pop ds ; Bezug zum DATASEG restaurieren

call Main_ ; Hauptprogramm call CleanUp_ ; Fehler während des Aufräumens? jc Cancel ; ja ->

xor al, al ; ExitCode: ok jmp EndProgram

Cancel: mov bx, dx shl bx, 1 add bx, o ErrTxtTbl mov dx, [bx] mov ah, 9 int 21H

mov al, 1 ; ExitCode: Fehler

EndProgram: mov ah, 4cH int 21H ; Programm beenden

;--- GetWrapState ----------------------------------------------------------

PROC GetWrapState_ pusha push ds push es les di, [WrapAddrINT] ; 0000:0000 lds si, [WrapAddrHMA] ; ffff:0010 mov cx, 64/4 repe cmpsd ; Bereiche vergleichen stc ; Annahme: WrapAround ist aktiv jcxz @@X ; stimmt ->

clc ; Annahme falsch, A20 ist frei...

@@X: pop es pop ds popa ret ENDP GetWrapState_

;--- SwitchA20 -------------------------------------------------------------

PROC SwitchA20_ pusha xor cx, cx mov dl, 0ddH ; Basis A20Disable add dl, al ; AL: 0 (Disable), 1 (Enable) cli

@@1: in al, 64H ; KBC_STATE and al, 02H ; InputBuffer leer? loopne @@1 ; nein ->

jne @@4 ; immer noch voll, TimeOut ->

mov al, 0d1H ; KBC_DATA Write out 64H, al ; ankündigen

@@2: in al, 64H ; KBC_STATE and al, 02H ; Befehl verarbeitet? loopne @@2 ; nein ->

jne @@4 ; immer noch nicht, TimeOut ->

mov al, dl ; A20Disable (ddH) | A20Enable (dfH) out 60H, al ; an KBC_DATA

@@3: in al, 64H ; KBC_STATE and al, 02H ; Befehl verarbeitet? loopne @@3 ; nein ->

@@4: sti clc ; ok je @@X

stc ; TimeOut

@@X: popa ret ENDP SwitchA20_

;--- Init ------------------------------------------------------------------

PROC Init_

P8086

cld

;------ ; Mit Sicherheit scheiterndes AllocMemBlock ausführen, um den ; größten freien Block (= freies konventionelles RAM) nach BX ; zu holen.

mov bx, 0ffffH ; 65.535 Paras mov ah, 48H ; AllocMemBlock int 21H ; = MaxAvail nach BX holen

;------ ; Prüfen, ob Anforderung MIN_CNV erfüllt ist

mov dx, 1 ; Annahme: Fehlercode 1 mov cl, 6 shr bx, cl ; Paras in KByte cmp bx, MIN_CNV ; genug konventionelles RAM frei? jb InitErr ; nein, Fehler ->

;------ ; 8086/8088 CPUs ausfiltern

mov dx, 2 ; Annahme: Fehlercode 2 push sp pop ax cmp ax, sp ; ungleich: 8086/88? jne InitErr ; ja, Fehler: kein 386er ->

P286

;------ ; CPUs im PM bzw. VM ausfiltern (dadurch auch EMS/XMS auf PM-Basis)

mov dx, 3 ; Annahme: Fehlercode 3 smsw ax ; MSW holen shr ax, 1 ; MSW.PE ins CF schieben jc InitErr ; Fehler: nicht im RM ->

;------ ; 80286 CPUs ausfiltern

mov dx, 2 ; Annahme: Fehlercode 2 pushf ; FLAGS sichern pushf pop ax ; AX = FLAGS or ax, 0f000H ; Bits 12..15 setzen push ax popf ; FLAGS forcieren pushf pop ax ; FLAGS erneut holen popf ; FLAGS restaurieren and ax, 0f000H ; Bits 12..15 wieder gelöscht? je InitErr ; ja, Fehler: kein 386er ->

P386

;------ ; Prüfen, ob Anforderung MIN_XMM erfüllt ist

mov dx, 4 ; Annahme: Fehlercode 4 mov al, 23 out 70H, al in al, 71H ; Extended Mem Lo holen mov bl, al mov al, 24 out 70H, al in al, 71H ; Extended Mem Hi holen mov bh, al cmp bx, MIN_XMM ; genug Extendend Memory da? jb InitErr ; nein, Fehler ->

;------ ; Systeme mit aktivem EMS-Treiber (RM-Basis) ausfiltern

mov dx, 5 ; Annahme: Fehlercode 5 mov ax, 3567H int 21H ; ES:BX = Vektor INT 67H mov di, 10 mov si, Offset EMS_ID_Str mov cx, 8 repe cmpsb ; EMS-ID gefunden ('EMMXXXX0')? jcxz InitErr ; ja, Fehler: RAW gewünscht ->

;------ ; Systeme mit aktivem XMS-Treiber (RM-Basis) ausfiltern

mov dx, 6 ; Annahme: Fehlercode 6 mov ax, 4300H int 2fH cmp al, 80H ; XMS-Treiber aktiv? je InitErr ; ja, Fehler: RAW gewünscht ->

;------ ; Prüfen, ob WrapAround aktiv ist, ggf. A20 freischalten

mov dx, 7 ; Annahme: Fehlercode 7 call GetWrapState_ ; WrapAround aktiv? jnc InitX ; nein, A20 frei, CF=0 (ok) ->

mov al, 1 ; A20Enable call SwitchA20_ ; TimeOut? jc InitX ; ja, Fehler ->

call GetWrapState_ ; WrapAround immer noch aktiv? jnc InitX ; nein, A20 frei, CF=0 (ok) ->

InitErr: stc

InitX: ret

ENDP Init_

;--- Main ------------------------------------------------------------------

PROC Main_

; ; Hier könnt ihr jetzt RM/Flat4G (RAW) wüten, wie ihr wollt... ;) ;

ret ENDP Main_

;--- CleanUp ---------------------------------------------------------------

PROC CleanUp_

mov dx, 7 ; Annahme: Fehlercode 7 xor al, al ; A20Disable call SwitchA20_ ; TimeOut? jc @@X ; ja, Fehler ->

; ; weitere eventuell erforderliche Aufräumarbeiten ;

@@X: ret ENDP CleanUp_

;---------------------------------------------------------------------------

DATASEG

RM4G_GDT db 8 DUP(0) ; Null-Descriptor

; 2. Descriptor mit 4 GByte-Limit

dw 0ffffH ; Limit (Bits 0..15)

dw 0 ; Base (Bits 0..15)

db 0 ; Base (Bits 16..23)

db 10010010b ; |++||||+- not accessed ; | ||||+-- writable ; | |||+--- no ExpandDown ; | ||+---- immer 0 ; | |+----- immer 1 ; | +------ DPL = 0 ; +-------- present

db 11001111b ; ||||+--+ ; |||| +- Limit (Bits 16..19) ; |||+----- available ; ||+------ immer 0 ; |+------- big Segment ; +-------- Granularity = 4 KByte (Limit in 4 KByte-Units)

db 0 ; Base (Bits 24..31)

RM4G_GDTR db 6 DUP(0)

WrapAddrINT dd 0 WrapAddrHMA dd 0ffff0010H

EMS_ID_Str db 'EMMXXXX0'

DTitle db 13, 10 db 'RM/Flat4G (RAW), (p) 1996 J. Thelen, Public Domain' db 13, 10, 36

ErrTxt1 db 13, 10, 7 db 'Fehler: 550 KByte RAM erforderlich (nach HeapRelease).' db 13, 10, 36

ErrTxt2 db 13, 10, 7 db 'Fehler: 80386 CPU (oder höher) erforderlich.' db 13, 10, 36

ErrTxt3 db 13, 10, 7 db 'Fehler: CPU befindet sich nicht im Real Address Mode.' db 13, 10, 36

ErrTxt4 db 13, 10, 7 db 'Fehler: 16 MByte Extended Memory erforderlich.' db 13, 10, 36

ErrTxt5 db 13, 10, 7 db 'Fehler: EMS-Treiber lokalisiert. Bitte deaktivieren.' db 13, 10, 36

ErrTxt6 db 13, 10, 7 db 'Fehler: XMS-Treiber lokalisiert. Bitte deaktivieren.' db 13, 10, 36

ErrTxt7 db 13, 10, 7 db 'Fehler: A20-Gate nicht ansteuerbar (KBC-TimeOut).' db 13, 10, 36

ErrTxtTbl dw 0 dw o ErrTxt1, o ErrTxt2, o ErrTxt3, o ErrTxt4 dw o ErrTxt5, o ErrTxt6, o ErrTxt7

;---------------------------------------------------------------------------

ENDIF

END

;--- Snap ------------------------------------------------------------------


(Übersicht)

Wie kann ich in allen Modes (RM, VM, PM) auf 386+ CPUs prüfen?

Juergen Thelen 2:2450/55.5:

Es gibt einige Situationen, in denen der Programmierer, egal in welchem Pro- zessormodus (Real Address, Virtual 86 oder Protected Mode) feststellen kön- nen muß, ob eine 32bit CPU (also ein 80386 oder höher) vorhanden ist.

Für dieses Problem gibt es mehrere Lösungsmöglichkeiten. Folgend eine meiner Routinen, die ich aufgrund ihrer Kürze selbst gerne einsetze:

;--- Snip ---------------------------------------------------------------- ; ; Modul CPU32bit_Chk4_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Prüfung auf 32bit CPU (Variante 4, alle Modes) ; ; In - ; ; Out CF = 0 ok ; 1 Fehler, keine 32bit CPU ; ; Chg CF

PROC CPU32bit_Chk4_

push ax

;------ ; CPUs vor 80286 ausfiltern. ; ; Zur Unterscheidung wird das auf 8086/88 und ab 80286 unterschiedliche ; Verhalten der Instruction PUSH SP benutzt. Zum besseren Verständnis ; sei SP hier = 8002H. ; ; Vor dem 286 wird durch PUSH SP der SP zuerst um 2 vermindert und erst ; dann auf den Stack geschoben (8000H läge auf dem Stack). Durch ein ; nachfolgendes POP SP würde SP aufgrund des entsprechenden Umkehrmecha- ; nismus wieder zu 8002H. ; ; Anders ab 80286: SP wird unverändert auf den Stack geschoben und erst ; danach dekrementiert (8002H läge auf dem Stack). Nach POP SP wäre na- ; türlich auch hier SP wieder 8002H. ; ; Benutzt man nun anstatt POP SP z.B. POP AX, kommt der Umkehrmechanis- ; mus nicht mehr zum Zuge, es wird exakt der auf dem Stack liegende Wert ; geholt. ; ; Sind AX und SP gleich, muß es sich folglich mindestens um einen 80286 ; handeln, da ja nur 286+ SP unverändert auf den Stack schieben... &)

push sp pop ax cmp ax, sp ; ungleich: CPU vor 80286? jne @@X ; ja, Fehler: keine 32bit CPU ->

;------ ; 80286 CPUs ausfiltern ; ; Zur Feststellung, ob es sich evtl. um einen 80286 handelt, wird hier ; die SGDT-Methode angewandt. Mit SGDT kann man sich bekanntlich die ; aktuellen Werte aus dem GDTR (Global Descriptor Table Register) holen. ; ; Im GDTR befinden sich 16bit-Limit und 32bit-Base des GDT. Da ein 80286 ; lediglich über 24 Adressleitungen verfügt, sind die obersten 8bit der ; GDT-Base natürlich nicht zu gebrauchen, sie sind immer gesetzt (ffh). ; ; Anders ab 80386, hier wird Base immer in voller Breite genutzt. Befin- ; det sich der GDT innerhalb des 24bit-Bereiches sind die obersten 8bit ; gleich 00H, im 25bit-Bereich gleich 01H, und so weiter. ; ; Damit haben wir ein eindeutiges Unterscheidungskriterium, denn die ; Eindeutigkeit verfiele erst, wenn der GDT oberhalb des 2 GByte-Raumes ; läge, und wer im LowEnd-Bereich hat schon soviel RAM... ;) ; ; Das Schöne an der SGDT-Methode ist, daß es sich bei SGDT um eine un- ; privilegierte Instruction handelt. So kann der Test immer durchgeführt ; werden, egal in welchem Modus (RM, VM, PM) und mit welchem CPL... 8)

push bp mov bp, sp ; SP sichern and sp, 0fffcH ; AlignMode könnte aktiv sein (P5+) sub sp, 8 ; Platz für GDTR schaffen sgdt [pword ptr bp-6] ; GDTR auf den Stack add sp, 6 ; hier unwichtig pop ax ; oberste 16bit der Base mov sp, bp ; SP restaurieren pop bp or ah, ah ; Hi-Byte = ffH? jns @@X ; nein, ok: ist 32bit CPU ->

stc

@@X: pop ax ret

ENDP CPU32bit_Chk4_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie implementiere ich eine Random-Funktion in Assembler?

Horst Kraemer 2:2410/249.5:

;--- Snip ----------------------------------------------------------------

COMMENT #

RandSeed (DWord):

Sollte vor Anwendung initialisiert werden. Z.B. durch Laden des Timer- Tickers 40h:6ch

Random bzw. Random32:

INPUT BX OUTPUT AX

Gibt einen im Intervall [0..BX-1] gleichverteilten Wert in AX zurück.

NewRandom bzw. NewRandom32:

INPUT - OUTPUT -

Die Generatorfunktion. Wird von Random bzw. Random32 aufgerufen. Liefert eine Permutation der Werte 0..0ffffffffh. Für Zufallsfolgen i.A. unge- eignet.

FRandom/FRandom32:

INPUT - OUTPUT Extended-Zufallswert 0 <= Random < 1 auf dem FPU-Stack

Anwendung:

Wiederholte Aufrufe von Random bzw. Random32 mit einem Wert N in BX er- geben eine annähernd gleichverteilte Zufallsfolge mit Werten zwischen 0 und N-1.

Der Output von frandom/random enspricht

function random:extended;

bzw.

function random(limit:word):word;

in Borland Pascal 7.0

#

.MODEL SMALL .DATA RandSeed dd 0 Shift32 dd -32 Bias dd 4f000000h

.CODE Magic_HI equ 0808h Magic_LO equ 8405h

NewRandom proc near mov ax, Magic_LO mul word ptr RandSeed mov si, ax mov di, dx mov ax, Magic_LO mul word ptr RandSeed[2] add di, ax mov ax, Magic_HI mul word ptr RandSeed add di, ax add si, 1 adc di, 0 mov word ptr RandSeed, si mov word ptr RandSeed[2], di ret endp

Random proc call NewRandom mov ax, bx mul word ptr RandSeed mov si, dx xchg ax, bx mul word ptr RandSeed[2] add ax, si adc dx, 0 xchg ax, dx ret endp

FRandom proc near call NewRandom fild Shift32 fild RandSeed fadd Bias fscale fstp st(1) ret endp

Magic equ 08088405h

.386

NewRandom32 proc near mov eax, Magic mul RandSeed inc eax mov RandSeed, eax ret endp

Random32 proc near call NewRandom32 movzx ebx, bx mul ebx mov ax, dx ret endp

FRandom32 proc near call NewRandom32 fild Shift32 fild RandSeed fadd Bias fscale fstp st(1) ret endp end

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie ermittle ich den Typ der aktiven Grafikkarte?

Juergen Thelen 2:2450/55.5:

Hier einer meiner Quellcodes zur Unterscheidung diverser Grafikkarten. Bei mir hat er bis jetzt problemlos gearbeitet. Trotzdem sei darauf hingewiesen, daß diese Variante z.B. nicht auf SVGAs/XGAs ohne VESA BIOS Extension prüft (sind mir zu selten) und zudem auch einige EGAs nicht abfängt, die bereits die Funktion 10.1a00H unterstützen (obwohl das eigentlich erst ab VGAs der Fall sein sollte).

;--- Snip ---------------------------------------------------------------- ; ; Modul Get_DA_ID6_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Identifikation des aktiven Grafikkartentyps (Variante 6) ; ; In - ; ; Out AL = Grafikadaptertyp: ; ; 0 unbekannt ; 1 MDA (Monochrome Display Adapter) ; 2 HGC (Hercules Graphics Card) ; 3 CGA (Color Graphics Adapter) ; 4 EGA (Enhanced Graphics Adapter) ; 5 VGA (Video Graphics Array) ; 6 XBE (XGA mit VESA BIOS Extension) ; 7 VBE (SVGA mit VESA BIOS Extension) ; ; Chg AL

PROC Get_DA_ID6_

push es push di push dx push bp

mov bp, sp ; SP sichern and sp, 0fffcH ; AlignMode könnte aktiv sein (P5+) sub sp, 200H ; allgemeinen Puffer einrichten

mov ax, ss mov es, ax mov di, sp ; ES:DI = SS:SP

;------ ; Auf SVGA mit VESA BIOS Extension prüfen

mov dl, 7 ; Annahme: SVGA mit VBE mov ax, 4f00H ; GetVBEInfo int 10H

cmp al, 4fH ; stimmt Annahme? je @@X ; ja ->

;------ ; Auf XGA mit VESA BIOS Extension prüfen

mov dl, 6 ; Annahme: XGA mit VBE mov ax, 4e00H ; GetXBEInfo int 10H

cmp al, 4eH ; stimmt Annahme? je @@X ; ja ->

;------ ; Karten vor EGA ausfiltern

mov ah, 12H ; AFS mov bx, 0ff10H ; GetEGAInfo int 10H

cmp bh, 0ffH ; mindestens EGA? je @@1 ; nein ->

;------ ; VGA oder EGA?

mov dl, 5 ; Annahme: VGA mov ax, 1a00H ; GetDispCombiCode int 10H

cmp al, 1aH ; stimmt Annahme? je @@X ; ja ->

mov dl, 4 ; nein, dann müsste es eine EGA sein jmp @@X

@@1:

;------ ; CGA, oder HCG/MDA?

mov dl, 3 ; Annahme: CGA mov ax, 40H ; BIOS Datasegment mov es, ax mov ax, [word ptr es:0063H] ; CRTC Baseport holen cmp ax, 03d4H ; stimmt Annahme? je @@X ; ja ->

;------ ; HCG/MDA

xor dl, dl ; Annahme: unbekannt cmp ax, 03b4H ; richtiger Port für HGC/MDA? jne @@X ; nein, unbekannte Karte ->

mov dx, 03baH in al, dx and al, 80H ; VSync-Bit isolieren mov ah, al ; und merken mov di, 8000H

@@2: in al, dx and al, 80H cmp al, ah ; Hat sich der VSync-Status geändert? jne @@3 ; ja, dann müsste es eine HGC sein ->

dec di jmp @@2

;------ ; keine Änderung des VSync-Bits. Sollte ein MDA sein.

mov dl, 1 jmp @@X

@@3: mov dl, 2 ; HGC

@@X: mov al, dl

mov sp, bp ; SP restaurieren pop bp pop dx pop di pop es

ret

ENDP Get_DA_ID6_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich einen Mode X (320x???, 360x???) [Lang]?

Juergen Thelen 2:2450/55.5:

Nachstehend ein Sourcebeispiel zum Initialisieren verschiedener Mode X Vari- anten (320x200, 320x240, 320x400, 320x480, 360x200, 360x240, 360x400 sowie 360x480). Das Programm kündigt einfach nur jede Initialisierung an, schaltet dann für jeweils 3 Sekunden in den angekündigten Modus und zeigt ein Mode X Testbild (horizontale Linien mit wechselnder Farbe, Bild weiß umrahmt).

Um die Verständlichkeit zu erleichtern und die Zusammenhänge besser zu ver- deutlichen, wurden bewußt keine CRTC-Werttabellen benutzt und der Code auch in keinster Weise optimiert. Sollten dennoch Fragen zur Funktionsweise einer bestimmten Mode X Variante auftauchen, sollte das Topic BAW0020 diese beant- worten können. Falls nicht, fragt mich halt... ;)

;--- Snip ------------------------------------------------------------------ ; ; Programm MODXTEST ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; OS DOS 2.0+ ; CPU 86+ ; GFX VGA+ ; ; Aufgabe Anzeigetest verschiedener Mode X Varianten ; ; .OBJ TASM /m /ml /dMDL=Modell MODXTEST.ASM ; .EXE TLINK /c MODXTEST.OBJ ;

IFNDEF MDL

DISPLAY "Fehler: '/dMDL=Modell' zur Assemblierung erforderlich!" ERR

ELSE

% MODEL USE16 MDL

IDEAL NOJUMPS LOCALS DOSSEG

STACK

;---------------------------------------------------------------------------

o EQU Offset s EQU Seg b EQU byte ptr w EQU word ptr d EQU dword ptr p EQU pword ptr

;---------------------------------------------------------------------------

P8086

CODESEG STARTUPCODE

;------ ; überflüssigen Heap an DOS zurückgeben

mov bx, sp add bx, 15 mov cl, 4 shr bx, cl mov ax, ss add bx, ax mov ax, es sub bx, ax mov ah, 4aH ; ResizeMemBlock int 21H ; Heap an DOS zurückgeben

mov dx, o DTitle mov ah, 9 int 21H

call Init_ ; Fehler während Initialisierung? jc Cancel ; ja ->

call Main_

xor al, al ; ExitCode: ok jmp EndProgram

Cancel: mov bx, dx shl bx, 1 add bx, o ErrTxtTbl mov dx, [bx] mov ah, 9 int 21H

mov al, 1 ; ExitCode: Fehler

EndProgram: mov ah, 4cH int 21H ; Programm beenden

;--- Init ------------------------------------------------------------------

PROC Init_

;------ ; Karten vor EGA ausfiltern

mov dx, 1 ; Annahme: Fehlercode 1 mov ah, 12H ; AFS mov bx, 0ff10H ; GetEGAInfo int 10H

cmp bh, 0ffH ; mindestens EGA? je InitErr ; nein, Fehler ->

;------ ; EGAs ausfiltern

mov ax, 1a00H ; GetDispCombiCode int 10H

cmp al, 1aH ; VGA? jne InitErr ; nein, Fehler ->

clc ; Mindestvoraussetzung erfüllt jmp InitX

InitErr: stc

InitX: ret

ENDP Init_

;--- AnnounceModeX ---------------------------------------------------------

PROC AnnounceModeX

push ax push bx push cx push dx push di

mov bx, dx inc bx shl bx, 1 add bx, o ModeXTxtTbl mov di, [bx] ; Textoffset der Variante vormerken

mov ax, 0003H ; Textmodus 80x25 int 10H

mov ah, 2 ; SetCursorPos xor bh, bh ; Page 0 mov dx, 0c14H ; Zeile 12, Spalte 28 int 10H

mov dx, o ModeXTxt ; 'Nächster Modus: ' mov ah, 9 int 21H ; ausgeben

mov dx, di ; entsprechenden Variantentext int 21H ; ausgeben

pop di pop dx pop cx pop bx pop ax

ret

ENDP AnnounceModeX

;--- Wait3Seconds ----------------------------------------------------------

PROC Wait3Seconds

push ax push bx push cx push dx push di

xor ah, ah ; GetSystemTime int 1aH

mov di, dx add di, 55 ; 55 Ticks (÷ 3 Sekunden) aufaddieren

Wait3SecondsLoop:

xor ah, ah int 1aH cmp dx, di ; Zeit abgelaufen? jb Wait3SecondsLoop ; nein ->

pop di pop dx pop cx pop bx pop ax ret

ENDP Wait3Seconds

;--- Unchain ---------------------------------------------------------------

PROC Unchain

push ax push dx

mov ax, 0013H ; Videomode 13H (320x200x256, chained) int 10H ; aktivieren

;------ ; Chain4 aus

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax

;------ ; DWord-Addressing aus

mov dx, 03d4H ; CRTC mov ax, 0014H ; Register 14H, Bit 6 löschen out dx, ax

;------ ; Byte-Addressing ein

mov dx, 03d4H ; CRTC mov ax, 0e317H ; Register 17H, Bit 6 setzen out dx, ax

pop dx pop ax

ret

ENDP Unchain

;--- DoubleScanOff ---------------------------------------------------------

PROC DoubleScanOff

push ax push dx

mov dx, 03d4H ; CRTC Index mov al, 09H ; Register 9 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx ; Register 9 einlesen and al, 60H ; Bits 0..4 und 7 löschen

out dx, al ; DoubleScan aus

pop dx pop ax

ret

ENDP DoubleScanOff

;--- DisableWP -------------------------------------------------------------

PROC DisableWP

push ax push dx

mov dx, 03d4H ; CRTC Index mov al, 11H ; Register 11H out dx, al ; auswählen

inc dx ; CRTC Data in al, dx ; Register 11H einlesen and al, 7fH ; Bit 7 löschen

out dx, al ; Schreibschutz für Register 0..7 AUS

pop dx pop ax ret

ENDP DisableWP

;--- EnableWP --------------------------------------------------------------

PROC EnableWP

push ax push dx

mov dx, 03d4H ; CRTC Index mov al, 11H ; Register 11H out dx, al ; auswählen

inc dx ; CRTC Data in al, dx ; Register 11H einlesen or al, 80H ; Bit 7 setzen

out dx, al ; Schreibschutz für Register 0..7 EIN

pop dx pop ax ret

ENDP EnableWP

;--- Set480Lines -----------------------------------------------------------

PROC Set480Lines

push ax push bx push dx

mov dx, 03ccH ; Miscellaneous Output Read in al, dx and al, 3fH ; Bits 6 und 7 ausblenden or al, 0c0H ; 480 Zeilen setzen mov bl, al ; neuen Registerwert merken

mov dx, 03c4H ; Timing Sequencer mov ax, 0100H ; Reset einleiten out dx, ax

mov dx, 03c2H ; Miscellaneous Output Write mov al, bl ; gemerkten Wert out dx, al ; setzen

mov dx, 03c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

call DisableWP

;------ ; Vertical Total auf 525 (020dH = 1 0 00001101) setzen

mov dx, 03d4H ; CRTC Index mov ax, 0d06H ; Register 6, VT-Bits 0..7 out dx, ax

mov dx, 03d4H ; CRTC Index mov al, 07H ; Register 7 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0deH ; Bits 0 und 5 ausblenden or al, 20H ; VT9 (Bit 5 = 1), VT8 (Bit 0 = 0) out dx, al

;------ ; Vertical Display End auf 479 (01dfH = 0 1 11011111) setzen

mov dx, 03d4H ; CRTC Index mov ax, 0df12H ; Register 12, VDE-Bits 0..7 out dx, ax

mov dx, 03d4H ; CRTC Index mov al, 07H ; Register 7 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0bdH ; Bits 1 und 6 ausblenden or al, 02H ; VDE9 (Bit 6 = 0), VDE8 (Bit 1 = 1) out dx, al

;------ ; Vertical Blanking Start auf 487 (01e7H = 0 1 11100111) setzen

mov dx, 03d4H ; CRTC Index mov ax, 0e715H ; Register 15, VBS-Bits 0..7 out dx, ax

mov dx, 03d4H ; CRTC Index mov al, 07H ; Register 7 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0f7H ; Bit 3 ausblenden or al, 08H ; VBS8 (Bit 3 = 1) out dx, al

mov dx, 03d4H ; CRTC Index mov al, 09H ; Register 9 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0dfH ; VBS9 (Bit 5 = 0) out dx, al

;------ ; Vertical Retrace Start auf 490 (01eaH = 0 1 11101010) setzen

mov dx, 03d4H ; CRTC Index mov ax, 0ea10H ; Register 10H, VRS-Bits 0..7 out dx, ax

mov dx, 03d4H ; CRTC Index mov al, 07H ; Register 7 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 7bH ; Bits 2 und 7 ausblenden or al, 04H ; VRS9 (Bit 7 = 0), VRS8 (Bit 2 = 1) out dx, al

;------ ; Vertical Retrace End auf 12 (0cH = 1100) setzen (entspricht Line# 492)

mov dx, 03d4H ; CRTC Index mov al, 11H ; Register 11H out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0f0H ; Bits 0..3 ausblenden or al, 0cH ; VRE-Bits 0..3 setzen out dx, al

;------ ; Vertical Blanking End auf 6 (06H) setzen (entspricht Line# 518)

mov dx, 03d4H ; CRTC Index mov ax, 0616H ; Register 16H, VBE-Bits out dx, ax

call EnableWP

pop dx pop bx pop ax

ret

ENDP Set480Lines

;--- Set360Pixel -----------------------------------------------------------

PROC Set360Pixel

push ax push bx push dx

mov dx, 03ccH ; Miscellaneous Output Read in al, dx and al, 0f3H ; Bits 2 und 3 ausblenden or al, 4 ; 28 MHz (360 Pixel) setzen mov bl, al ; neuen Registerwert merken

mov dx, 03c4H ; Timing Sequencer mov ax, 0100H ; Reset einleiten out dx, ax

mov dx, 03c2H ; Miscellaneous Output Write mov al, bl ; gemerkten Wert out dx, al ; setzen

mov dx, 03c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

call DisableWP

;------ ; Horizontal Total auf 107 (6bH) setzen

mov dx, 03d4H ; CRTC Index mov ax, 6b00H ; Register 0, HT-Bits out dx, ax

;------ ; Horizontal Display End auf 89 (59H) setzen

mov dx, 03d4H ; CRTC Index mov ax, 5901H ; Register 1, HDE-Bits out dx, ax

;------ ; Horizontal Blanking Start auf 90 (5aH) setzen

mov dx, 03d4H ; CRTC Index mov ax, 5a02H ; Register 2, HBS-Bits out dx, ax

;------ ; Horizontal Retrace Start auf 94 (5eH) setzen

mov dx, 03d4H ; CRTC Index mov ax, 5e04H ; Register 4, HRS-Bits out dx, ax

;------ ; Horizontal Retrace End auf 10 (0aH) setzen (entspricht CCU# 106)

mov dx, 03d4H ; CRTC Index mov al, 5 ; Register 5 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0e0H ; Bits 0..4 ausblenden or al, 0aH ; HRE-Bits 0..4 setzen out dx, al

;------ ; Horizontal Blanking End auf 46 (2eH = 1 01110) setzen (entspr. CCU# 110)

mov dx, 03d4H ; CRTC Index mov al, 03H ; Register 3 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx and al, 0e0H ; Bits 0..4 ausblenden or al, 0eH ; HBE-Bits 0..4 setzen out dx, al

mov dx, 03d4H ; CRTC Index mov al, 05H ; Register 5 out dx, al ; auswählen

inc dx ; CRTC Data in al, dx or al, 80H ; HBE5 (Bit 7 = 1) out dx, al

call EnableWP

;------ ; Zeilenlänge im Video-RAM auf 360 / 4 / 2 = 45 (2dH) Bytes anpassen

mov dx, 03d4H ; CRTC Index mov ax, 2d13H ; Register 13H, AUPVL setzen out dx, ax

pop dx pop bx pop ax

ret

ENDP Set360Pixel

;--- Init320x200 -----------------------------------------------------------

PROC Init320x200

call Unchain ret

ENDP Init320x200

;--- Init320x240 -----------------------------------------------------------

PROC Init320x240

call Unchain call Set480Lines ret

ENDP Init320x240

;--- Init320x400 -----------------------------------------------------------

PROC Init320x400

call Unchain call DoubleScanOff ret

ENDP Init320x400

;--- Init320x480 -----------------------------------------------------------

PROC Init320x480

call Unchain call DoubleScanOff call Set480Lines ret

ENDP Init320x480

;--- Init360x200 -----------------------------------------------------------

PROC Init360x200

call Unchain call Set360Pixel ret

ENDP Init360x200

;--- Init360x240 -----------------------------------------------------------

PROC Init360x240

call Unchain call Set480Lines call Set360Pixel ret

ENDP Init360x240

;--- Init360x400 -----------------------------------------------------------

PROC Init360x400

call Unchain call DoubleScanOff call Set360Pixel ret

ENDP Init360x400

;--- Init360x480 -----------------------------------------------------------

PROC Init360x480

call Unchain call DoubleScanOff call Set480Lines call Set360Pixel ret

ENDP Init360x480

;--- HLine -----------------------------------------------------------------

PROC HLine

push ax push cx push dx push es push di

mov ax, 0a000H mov es, ax mov ax, cx mul [w LineLength] mov di, ax

mov dx, 03c4H ; Timing Sequencer mov ax, 0f02H ; Register 2, alle Planes ein out dx, ax

mov cx, [LineLength] mov al, bl cld rep stosb

pop di pop es pop dx pop cx pop ax

ret

ENDP HLine

;--- VLine -----------------------------------------------------------------

PROC VLine

push ax push cx push dx push es push di

mov ax, 0a000H mov es, ax

mov di, cx shr di, 1 shr di, 1 ; Video-RAM Offset

mov ax, 1 and cx, 3 shl ax, cl ; PlaneMask bilden mov ah, al mov al, 2 ; Register 2

mov dx, 03c4H ; Timing Sequencer out dx, ax

mov cx, [LastY]

VLineLoop: mov [b es:di], bl add di, [LineLength] dec cx jne VLineLoop

pop di pop es pop dx pop cx pop ax

ret

ENDP VLine

;--- ShowModeXTestPic ------------------------------------------------------

PROC ShowModeXTestPic

push ax push bx push cx push dx push di

mov bx, dx inc bx shl bx, 1 mov di, bx add bx, o MaxYTbl mov dx, [bx] ; MaxY holen mov [LastY], dx mov bx, di add bx, o MaxXTbl mov di, [bx] ; MaxX holen

xor cx, cx ; Zeilenzähler xor bl, bl ; Farbbyte

ShowLoop1: call HLine inc bl inc cx cmp cx, dx jb ShowLoop1

xor cx, cx mov bl, 15 call HLine mov cx, dx dec cx call HLine

xor cx, cx call VLine mov cx, di dec cx call VLine

pop di pop dx pop cx pop bx pop ax

ret

ENDP ShowModeXTestPic

;--- Main ------------------------------------------------------------------

PROC Main_

mov [w LineLength], 80 ; Zeilenlänge für 320x??? Modes

xor dx, dx call AnnounceModeX call Wait3Seconds call Init320x200 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init320x240 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init320x400 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init320x480 call ShowModeXTestPic call Wait3Seconds

mov [w LineLength], 90 ; Zeilenlänge für 360x??? Modes

inc dx call AnnounceModeX call Wait3Seconds call Init360x200 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init360x240 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init360x400 call ShowModeXTestPic call Wait3Seconds

inc dx call AnnounceModeX call Wait3Seconds call Init360x480 call ShowModeXTestPic call Wait3Seconds

mov ax, 0003H ; Textmodus 80x25 int 10H

ret

ENDP Main_

;---------------------------------------------------------------------------

DATASEG

DTitle db 13, 10 db 'Mode X Test, (p) 1997 J. Thelen, Public Domain' db 13, 10, 36

ErrTxt1 db 13, 10, 7 db 'Fehler: Mindestens VGA-Karte erforderlich.' db 13, 10, 36

ErrTxtTbl dw 0 dw o ErrTxt1

ModeXTxt db 'Nächste Mode X Variante: ', 36

ModeXTxt1 db '320x200', 0, 36 ModeXTxt2 db '320x240', 0, 36 ModeXTxt3 db '320x400', 0, 36 ModeXTxt4 db '320x480', 0, 36 ModeXTxt5 db '360x200', 0, 36 ModeXTxt6 db '360x240', 0, 36 ModeXTxt7 db '360x400', 0, 36 ModeXTxt8 db '360x480', 0, 36

ModeXTxtTbl dw 0 dw o ModeXTxt1, o ModeXTxt2, o ModeXTxt3, o ModeXTxt4 dw o ModeXTxt5, o ModeXTxt6, o ModeXTxt7, o ModeXTxt8

LineLength dw ? LastY dw ?

MaxYTbl dw 0 dw 200, 240, 400, 480, 200, 240, 400, 480

MaxXTbl dw 0 dw 320, 320, 320, 320, 360, 360, 360, 360

;---------------------------------------------------------------------------

ENDIF

END

;--- Snap ------------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 320x200 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 320x200. Der Code ist rein raumoptimiert, im RM 25 Bytes lang, und dürfte imo kaum noch zu kürzen sein. Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX320200_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 320x200x256 ; ; - AspectRatio X:Y 1.200:1.000 ; - LineLength 80 Bytes ; - PageLength 16000 Bytes ; - MaxPages 4 ; ; In - ; ; Out - ; ; Chg -

PROC IMX320200_

pushaw

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus

mov dl, 0d4H ; CRTC mov ax, 0014H ; Register 14H, Bit 6 löschen out dx, ax ; DWord-Addressing aus mov ax, 0e317H ; Register 17H, Bit 6 setzen out dx, ax ; Byte-Addressing ein

popaw

ret

ENDP IMX320200_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 320x240 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 320x240. Der Code ist zwar bereits raumoptimiert (ist im RM 68 Bytes lang), kann aber noch auf 60 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX320240_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 320x240 ; ; - AspectRatio X:Y 1.000:1.000 ; - LineLength 80 Bytes ; - PageLength 19200 Bytes ; - MaxPages 3 ; ; In - ; ; Out - ; ; Chg -

DATASEG t320240 dw 00014H, 0e317H, 00c11H, 00d06H, 03e07H dw 08c11H, 0ea10H, 0df12H, 0e715H, 00616H

CODESEG

PROC IMX320240_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 0e3H out dx, al ; 480 Lines setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t320240 mov cx, 10 cld ; # rep outsw ; Register für 320x240 programmieren

pop ds ; # popaw

ret

ENDP IMX320240_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 320x400 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 320x400. Der Code ist rein raumoptimiert, im RM 29 Bytes lang, und dürfte imo kaum noch zu kürzen sein. Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX320400_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 320x400x256 ; ; - AspectRatio X:Y 2.400:1.000 ; - LineLength 80 Bytes ; - PageLength 32000 Bytes ; - MaxPages 2 ; ; In - ; ; Out - ; ; Chg -

PROC IMX320400_

pushaw

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus

mov dl, 0d4H ; CRTC mov ax, 0014H ; Register 14H, Bit 6 löschen out dx, ax ; DWord-Addressing aus mov ax, 0e317H ; Register 17H, Bit 6 setzen out dx, ax ; Byte-Addressing ein mov ax, 4009H ; Register 9, Bits 0..4 und 7 löschen out dx, ax ; DoubleScan aus

popaw

ret

ENDP IMX320400_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 320x480 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 320x480. Der Code ist zwar bereits raumoptimiert (ist im RM 70 Bytes lang), kann aber noch auf 62 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX320480_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 320x480 ; ; - AspectRatio X:Y 2.000:1.000 ; - LineLength 80 Bytes ; - PageLength 38400 Bytes ; - MaxPages 1 ; ; In - ; ; Out - ; ; Chg -

DATASEG t320480 dw 00014H, 0e317H, 04009H, 00c11H, 00d06H, 03e07H dw 08c11H, 0ea10H, 0df12H, 0e715H, 00616H

CODESEG

PROC IMX320480_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 0e3H out dx, al ; 480 Lines setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t320480 mov cx, 11 cld ; # rep outsw ; Register für 320x480 programmieren

pop ds ; # popaw

ret

ENDP IMX320480_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 360x200 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 360x200. Der Code ist zwar bereits raumoptimiert (ist im RM 70 Bytes lang), kann aber noch auf 62 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX360200_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 360x200 ; ; - AspectRatio X:Y 1.350:1.000 ; - LineLength 90 Bytes ; - PageLength 18000 Bytes ; - MaxPages 3 ; ; In - ; ; Out - ; ; Chg -

DATASEG t360200 dw 00014H, 0e317H, 00e11H, 06b00H, 05901H dw 05a02H, 08e03H, 05e04H, 08a05H, 08e11H, 02d13H

CODESEG

PROC IMX360200_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 067H out dx, al ; 360 Pixel setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t360200 mov cx, 11 cld ; # rep outsw ; Register für 360x200 programmieren

pop ds ; # popaw

ret

ENDP IMX360200_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 360x240 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 360x240. Der Code ist zwar bereits raumoptimiert (ist im RM 82 Bytes lang), kann aber noch auf 74 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX360240_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 360x240 ; ; - AspectRatio X:Y 1.125:1.000 ; - LineLength 90 Bytes ; - PageLength 21600 Bytes ; - MaxPages 3 ; ; In - ; ; Out - ; ; Chg -

DATASEG t360240 dw 00014H, 0e317H, 00c11H, 06b00H, 05901H, 05a02H dw 08e03H, 05e04H, 08a05H, 00d06H, 03e07H, 08c11H dw 0ea10H, 0df12H, 02d13H, 0e715H, 00616H

CODESEG

PROC IMX360240_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 0e7H out dx, al ; 360 Pixel und 480 Lines setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t360240 mov cx, 17 cld ; # rep outsw ; Register für 360x240 programmieren

pop ds ; # popaw

ret

ENDP IMX360240_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 360x400 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 360x400. Der Code ist zwar bereits raumoptimiert (ist im RM 72 Bytes lang), kann aber noch auf 64 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX360400_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 360x400 ; ; - AspectRatio X:Y 2.700:1.000 ; - LineLength 90 Bytes ; - PageLength 36000 Bytes ; - MaxPages 1 ; ; In - ; ; Out - ; ; Chg -

DATASEG t360400 dw 00014H, 0e317H, 04009H, 00e11H, 06b00H, 05901H dw 05a02H, 08e03H, 05e04H, 08a05H, 08e11H, 02d13H

CODESEG

PROC IMX360400_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 067H out dx, al ; 360 Pixel setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t360400 mov cx, 12 cld ; # rep outsw ; Register für 360x400 programmieren

pop ds ; # popaw

ret

ENDP IMX360400_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie initialisiere ich Mode X 360x480 (Kurzversion)?

Juergen Thelen 2:2450/55.5:

Nachstehend eine meiner Initsources für Mode X 360x480. Der Code ist zwar bereits raumoptimiert (ist im RM 84 Bytes lang), kann aber noch auf 76 Bytes verkürzt werden, falls beim Einsprung DS = DATASEG und DF = 0 (CLD) bereits gegeben sind (was meist eh der Fall ist). Falls ja, einfach alle mit '#' ge- kennzeichneten Zeilen entfernen oder blocken.

Bei grundsätzlichen Fragen zur Mode X Funktionsweise siehe Topic BAW0020.

;--- Snip ---------------------------------------------------------------- ; ; Modul IMX360480_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Initialisierung der Mode X Variante 360x480 ; ; - AspectRatio X:Y 2.250:1.000 ; - LineLength 90 Bytes ; - PageLength 43200 Bytes ; - MaxPages 1 ; ; In - ; ; Out - ; ; Chg -

DATASEG t360480 dw 00014H, 0e317H, 04009H, 00c11H, 06b00H, 05901H dw 05a02H, 08e03H, 05e04H, 08a05H, 00d06H, 03e07H dw 08c11H, 0ea10H, 0df12H, 02d13H, 0e715H, 00616H

CODESEG

PROC IMX360480_

pushaw push ds ; #

mov ax, 13H int 10H ; Videomode 13H ein

mov dx, 03c4H ; Timing Sequencer mov ax, 0604H ; Register 04H, Bit 3 löschen out dx, ax ; Chain4 aus mov ax, 0100H ; Reset einleiten out dx, ax

mov dl, 0c2H ; Miscellaneous Output Write mov al, 0e7H out dx, al ; 360 Pixel und 480 Lines setzen

mov dl, 0c4H ; Timing Sequencer mov ax, 0300H ; Reset beenden out dx, ax

mov dl, 0d4H ; CRTC mov ax, @data ; # mov ds, ax ; # mov si, offset t360480 mov cx, 18 cld ; # rep outsw ; Register für 360x480 programmieren

pop ds ; # popaw

ret

ENDP IMX360480_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie stelle ich fest, ob PCI Bus #0 CASAM1 unterstützt?

Juergen Thelen 2:2450/55.5:

Dieses Modul überprüft, ob auf den CAS (Configuration Address Space) von PCI Devices an PCI-Bus 0 mittels CASAM1 zugegriffen werden kann. CASAM1 ist seit Revision 2.10 der PCI-Spezifikation der empfohlene und vorrangig zu verwen- dende Mechanismus. CASAM2 (siehe dazu LSG0020) sollte nicht mehr eingesetzt werden, funktioniert aber mitunter trotzdem noch. Bei grundsätzlichen Fragen zum CAS siehe bitte Topic BAW0023.

;--- Snip ---------------------------------------------------------------- ; ; Modul Chk_CASAM1_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Prüfung von PCI-Bus #0 auf CASAM1-Support ; ; CPU 386+ ; ; In - ; ; Out CF = 0 ja, CASAM1 wird unterstützt ; 1 nein, kein CASAM1-Support ; ; Chg CF

PROC Chk_CASAM1_

push eax push ecx push edx

mov dx, 0cf8H ; CONFADD in eax, dx mov ecx, eax ; originalen Portinhalt sichern aad ; Delay

mov eax, 80000000H out dx, eax aad ; Delay

in eax, dx cmp eax, 80000000H stc ; Annahme: CASAM1 supported je @@X ; stimmt ->

clc ; nein, kein CASAM1 Support

@@X: pushf ; CF sichern aad ; Delay mov eax, ecx out dx, eax ; originalen Inhalt restaurieren popf ; CF restaurieren

pop edx pop ecx pop eax ret

ENDP Chk_CASAM1_

;--- Snap ----------------------------------------------------------------


(Übersicht)

Wie stelle ich fest, ob PCI-Bus #0 CASAM2 unterstützt?

Juergen Thelen 2:2450/55.5:

Dieses Modul überprüft, ob auf den CAS (Configuration Address Space) von PCI Devices an PCI-Bus 0 mittels CASAM2 zugegriffen werden kann. Zu grundsätz- lichen Fragen den CAS betreffend sei auf Topic BAW0023 verwiesen.

HINWEIS: Mit Revision 2.10 der PCI-Spezifikation ist der Zugriffsmechanismus CASAM2 als hinfällig zu betrachten und es wird empfohlen, nur noch mit dem neuen Mechanismus CASAM1 (siehe dazu LSG0019) zu arbeiten.

Trotzdem unterstützen diverse 2.10+ BIOSs auch weiterhin CASAM2. ;)

;--- Snip ---------------------------------------------------------------- ; ; Modul Chk_CASAM2_ ; Sprache TASM 3.2 ; Autor Juergen Thelen 2:2450/55.5 ; ; Aufgabe Prüfung von PCI-Bus #0 auf CASAM2-Support ; ; In - ; ; Out CF = 0 ja, CASAM2 wird unterstützt ; 1 nein, kein CASAM2-Support ; ; Chg CF

PROC Chk_CASAM2_

push ax push dx

xor al, al mov dx, 0cf8H ; CONFADD out dx, al mov dl, 0faH ; CONFDATA (alt) out dx, al aad ; Delay

in al, dx mov ah, al mov dl, 0f8H ; CONFADD in al, dx add ah, al ; beide Ports = 00H? stc ; Annahme: ja je @@X ; stimmt, CASAM2 supported ->

clc ; nein, kein CASAM2 Support

@@X: pop dx pop ax ret

ENDP Chk_CASAM2_

;--- Snap ----------------------------------------------------------------








converted with af2html V 0.01d Win95/NT
a Green meadoW production MXMVIII
copyright © by Guido Wischrop