Kurt Steiner hat geschrieben:Hallo Andrew,
ich denke bei einem 3 GHz Rechner wirst du definitiv Probleme mit in einigen Spielen bekommen, weil sie einfach zu schnell laufen Wing Comander 1 und 2 zum Beispiel. Die 3 läuft aber denke ich.
Beim lesen dieses Beitrages habe ich mir ein paar Gedanken gemacht die wahrscheinlich nicht besonders hilfreich sind, aber trotzdem ein bischen zum Neben-Thema "Rechner zu schnell" passen könnten:
Ganz spontan fallen mir zwei Methoden ein um
eigene Anwendungen die zu schnell laufen abzubremsen. Die erste Methode ist es die Ausgabegeschwindikeit durch den Rasterstrahl zu begrenzen. Eine weitere, zwar etwas altbackene Methode die aber sowohl auf neuen sowie auf älteren Rechnern funktioiniert ist es eine Geschwindigkeitsmessung vorzunehmen. Dafür benutze ich eine kleine Routine in der 64 Nops(No operation-Befehle) in einer Schleife mit einem zusätzlichen Register zum zählen der Runden enhalten sind. Die Schleife wird genau eine Sekunde lang ausgeführt. Diesen so ermittelten Wert des Rundenzählers kann man nun als Multiplikator für einen Verzögerungszähler verwenden.
Routine für eine Geschwindigkeitsmessung:
Code: Alles auswählen
; Datei abspeichern mit dem Namen: "SPEED.asm"
; Assemblieren und linken mit MASM 5:
; MASM /Z SPEED.asm,SPEED.obj,,
; LINK /CP:1 SPEED.obj,SPEED.exe,,,
.MODEL SMALL
.386
.CODE
org 100h
Cpu86 = 0
Cpu286 = 4
Cpu386 = 8
Cpu486 = 12
Cpu586 = 16
START: mov ax, @DATA
mov ds, ax ; DS auf Daten-Bereich
;-------------------------------------
call GETCPU ; Prozessor-Analyse: AX=CPU
;-------------------------------------
call GETSPEED ; Zählschleife
;-------------------------------------
call FILE ; create a new file
;-------------------------------------
mov ah, 4Ch ; Dos-Rücksprung, Programm-Ende
int 21h
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
GETCPU: mov ax, Cpu86
xor bx, bx
push bx ; Null auf Stack
popf ; Null in Flagregister
pushf
pop bx ; zurück nach bx
and bh, 0F0h
cmp bh, 0F0h ; wenn gleich, dann 8086
je short CPUOK
;-------------------------------------
mov ax, Cpu286
push 7000h ; dasselbe mit 7000h
popf
pushf
pop bx
and bh, 70h
jz short CPUOK
;-------------------------------------
mov ax, Cpu386
mov edx, esp
and esp, 0FFFCh ; durch vier teilbare Adr.
pushfd
pop ebx
mov ecx, ebx
btc ebx, 18 ; Bit 18 umdrehen
push ebx
popfd
pushfd
pop ebx
push ecx ; alte Flaggen zurück
popfd
mov esp, edx ; Stack zurück
cmp ecx, ebx ; wenn gleich dann 386
jz short CPUOK
;-------------------------------------
mov ax, Cpu486
btc ecx, 21
push ecx
popfd
pushfd
pop ebx
cmp ebx, ecx ; wenn ungleich, dann 486
jnz short CPUOK
;-------------------------------------
mov ax, Cpu586 ; sonst Pentium
;----------------------------------------------------------------------------
CPUOK: mov bp, ax
ret ; AX=Cpu
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
GETSPEED: cli ; Interrupt's verbieten
xor ax, ax
mov es, ax ; ES auf Seg.: 0
;-------------------------------------
mov di, es:[20h] ; Vector von INT 8 retten (Offset)
mov si, es:[22h] ; (Segment)
;-------------------------------------
mov es:[20h], OFFSET NEUVEC ; Interrupt-Vector von INT 8
mov es:[22h], cs ; auf neue Routine legen
;-------------------------------------
mov al, 36h ; RUNDE auf 18,2 Hertz (Standard)
out 43h, al
xor al, al
out 40h, al ; low
out 40h, al ; high
;-------------------------------------
cmp bp, 8 ; 32-Bit-CPU ?
jb short M16
jmp M32
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
M16: mov bp, 1 ; Aktiv-Flag = IRQ-Ende wenn 0
xor cx, cx ; Zähler low
xor dx, dx ; Zähler high
sti ; neuen Interrupt 8 starten
;-------------------------------------
S1: and bp, bp ; Auf IRQ-Ende warten
jnz S1
mov bp, 1 ; Für's Zählen IRQ Aktiv-Flag setzen
;-------------------------------------
S2: inc cx ; Hauptzählschleife
jnz short S3
inc dx
;-------------------------------------
S3: nop ; 64 Nop's
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;-------------------------------------
and bp, bp ; auf Timer-IRQ-Ende abfragen
jnz S2 ; weiter, wenn Timer-IRQ noch aktiv
;-------------------------------
mov RUNDE, cx ; Zähler low retten
mov RUNDE+2, dx ; Zähler high retten
;---------------------------------------------------------------------------
ANALYS: cli ; Interrupts verbieten
mov es:[20h], di ; alten Interrupt-Vector
mov es:[22h], si ; von INT 8 wiederherstellen
sti ; Interrupts erlauben
ret
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
M32: mov bp, 1 ; Aktiv-Flag = IRQ-Ende wenn 0
xor ecx, ecx ; Zähler
sti ; neuen Interrupt 8 starten
;-------------------------------------
S4: and bp, bp ; Auf IRQ-Ende warten
jnz S4
;-------------------------------------
mov bp, 1 ; Für's Zählen IRQ Aktiv-Flag setzen
;-------------------------------------
S5: inc ecx ; Hauptzählschleife
nop ; 64 Nop's
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;-------------------------------------
and bp, bp ; auf Timer-IRQ-Ende abfragen
jnz S5 ; weiter, wenn Timer-IRQ noch aktiv
;---------------------------------------------------------------------------
mov DWORD PTR[RUNDE], ecx ; Zähler retten
jmp ANALYS
;---------------------------------------------------------------------------
; neue I R Q - R o u t i n e für INT 8
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
NEUVEC: mov al, 20h ; neue IRQ-Routine für INT 8
dec bp ; Aktiv-Flag löschen
out 20h, al ; =EOI
iret
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
FILE: mov dx, OFFSET SPEEDNAM
xor cx, cx
mov ah, 3Ch ; Datei erstellen
int 21h
mov bx, ax
;---------------------------------------
mov dx, OFFSET RUNDE
mov cx, 4
mov ah, 40h ; Datei beschreiben
int 21h
;---------------------------------------
mov ah, 3Eh ; Datei schließen
int 21h
ret
;---------------------------------------------------------------------------
org START + ((($-START)/64)*64) + 64
;---------------------------------------------------------------------------
.DATA
org 0
;---------------------------------------------------------------------------
RUNDE DW 0, 0 ; Anzahl der Schleifen-Durchläufe
SPEEDNAM DB "SPEED.tic", 0
;---------------------------------------------------------------------------
.STACK 20h
end
Hinweis: Es wird eine Datei mit dem Namen "SPEED.TIC" mit 4 Bytes auf dem momentanen Datenträger/Verzeichniss angelegt die den ermittelten Wert der Schleifendurchläufe enthält.
Diese Routine dient
nicht dazu die MHZ der verwendeten CPU zu ermittlen, sondern um einen Vergleichswert zwischen den verschieden schnellen CPUs zu ermitteln um damit eine entsprechende Verzögerung zu realisieren.
Auf meinem Core2Quad 9550 mit 2,8 Ghz ausgeführt unter XP enthält die Datei SPEED.TIC folgende Bytes: A5, F4, 78, 00 = entspricht hex 78F4A5 Schleifendurchläufe.
....
Jetzt bin ich am hin und her überlegen wie man damit auch fremde Anwendungen wie z.B. Wing Comander 1 und 2 damit ebenfalls ausbremsen könnte. Für entsprechende Vorschläge wäre ich dankbar.
Dirk