ASM86FAQ - Lösungen
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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).
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 ----------------------------------------------------------------
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 ------------------------------------------------------------------
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 ------------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ------------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------
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 ----------------------------------------------------------------