VGA-Karte und Interrupt?

Auswahl, Einrichtung und Betrieb von Rechnern und Komponenten
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: VGA-Karte und Interrupt?

Beitrag von freecrac »

DOSferatu hat geschrieben:Das Problem ist, wenn ein Spiel mit 50 Hz scrollt, weil sich die Figur mit 50 "Steps" pro Sekunde bewegt (Screenausschnitt scrollt ja "um die Spielfigur herum"), nützt es nichts, ob man das Bild 60x pro Sekunde darstellt oder nicht - es wird trotzdem ruckeln, weil jedes 5. und 6. Frame gleich sein werden und alle anderen nicht.
Klingt einleuchtend.

Dirk
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Mittlerweile hab ich mal wieder mit Copperbars experimentiert. Jetzt hab ich eine Lösung gefunden, die kein Schneegestöber produziert :-) Man wartet auf den Beginn eines neuen Bildes (beginn der Hauptschleife), dann auf den Beginn einer neuen Rasterzeile, setzt Rot und Grün-Anteil der Farbe, wartet auf das Ende der Zeile und setzt den Blau-Anteil der Farbe - somit wird ausgeschlossen, dass die Palette geändert wird, während die Zeile am Bildschirm erscheint. Die Variante sollte selbst auf einem 80286 klappen. Ich werde mal den Source "zurecht machen" und hier posten - wird aber noch ein paar Tage dauern :-)
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: VGA-Karte und Interrupt?

Beitrag von freecrac »

Brueggi hat geschrieben:Mittlerweile hab ich mal wieder mit Copperbars experimentiert. Jetzt hab ich eine Lösung gefunden, die kein Schneegestöber produziert :-) Man wartet auf den Beginn eines neuen Bildes (beginn der Hauptschleife), dann auf den Beginn einer neuen Rasterzeile, setzt Rot und Grün-Anteil der Farbe, wartet auf das Ende der Zeile und setzt den Blau-Anteil der Farbe - somit wird ausgeschlossen, dass die Palette geändert wird, während die Zeile am Bildschirm erscheint. Die Variante sollte selbst auf einem 80286 klappen. Ich werde mal den Source "zurecht machen" und hier posten - wird aber noch ein paar Tage dauern :-)
Wenn beim Schreiben der blaue Farbanteil nicht verändert werden soll, genügt es dann nur den rot und grün Anteil zu schreiben, um dann über Port 3C8h eine neue Farbe einzustellen und damit den Zyklus zu beenden und einen neuen anzufangen?

RBIL->inter61d.zip->Ports.b
03C8 RW (VGA,MCGA) PEL address register (write mode)
Sets DAC in write mode and assign start of color register
index (0..255) for following write accesses to 3C9h.
Don't read from 3C9h while in write mode. Next access to
03C8h will stop pending mode immediatly.
http://www.osdever.net/FreeVGA/vga/colorreg.htm#note
Note: I have noticed some great variance in the actual behavior of these registers on VGA chipsets. The best way to ensure compatibility with the widest range of cards is to start an operation by writing to the appropriate address register and performing reads and writes in groups of 3 color values. While the automatic increment works fine on all cards tested, reading back the value from the DAC Address Write Mode Register may not always produce the expected result. Also interleaving reads and writes to the DAC Data Register without first writing to the respected address register may produce unexpected results. In addition, writing values in anything other than groups of 3 to the DAC Data Register and then performing reads may produce unexpected results. I have found that some cards fail to perform the desired update until the third value is written.
Hier steht leider nicht viel darüber:
http://wiki.osdev.org/VGA_Hardware

Dirk
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Also bei meinen (vorläufigen) Versuchen hab ich herausgefunden, dass beim fehlenden Blau-Anteil und erneutem Schreiben nach $3C8 die Farbe komplett schwarz bleibt. Zumindest bei meiner Onboard-CL GD 5426.
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Hier der Teil aus meiner selbstgebastelten TPU:

Vorbereitung:
Wx=WordVar;

w3:=Segment der Palette;
w4:=Offset der Palette;
farbe=Farbnummer
w1=Anzahl Rasterzeilen/2 (im Textmode w1=max. 200)
r,g,b: RGB-Werte für die farbe unterhalb des "Copper-Bar"

Der Speicherbereich der Palette muss <w1>*Einträge zu je 3 Bytes (R,G und B) enthalten. RGB-Werte müssen zwischen 0 und 63 liegen. Viel Spaß beim Experimentieren.

Code: Alles auswählen

  asm
   mov es,w3
    mov ah,farbe
@rest:
   cli
    mov si,w4
    mov dx,$3DA
@vsync:
    in al,dx
    and al,$08
    jz @vsync
@vsync2:
    in al,dx
    and al,$08
    jnz @vsync2

    mov cx,w1
@raster:
    mov dx,$3DA
@raster0:
    in al,dx
    and al,$01
    jz @raster0

    mov bh,[es:si]
    inc si
    mov bl,[es:si]
    inc si
    mov ah,[es:si]
    inc si

    mov al,farbe
    mov dx,$3C8
    out dx,al

    inc dx

    mov al,bh
    out dx,al
    mov al,bl
    out dx,al
    mov bx,$3C9
    mov dx,$3DA
@raster1:
    in al,dx
    and al,$01
    jnz @raster1
@raster2:
    in al,dx
    and al,$01
    jz @raster2

    xchg bx,dx
    mov al,ah
    out dx,al
    xchg bx,dx
@raster3:
    in al,dx
    and al,$01
    jnz @raster3
    loop @raster

    mov dx,$3C8
    mov al,farbe
    out dx,al
    inc dx
    mov al,r
    out dx,al
    mov al,g
    out dx,al
    mov al,b
    out dx,al
   sti
   push es
   mov cx,$0040
   mov es,cx
   mov ax,[es:$001A]
   mov bx,[es:$001C]
   pop es
   cmp ax,bx
   jnz @endbow
   jmp @rest
@endbow:
  end;
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: VGA-Karte und Interrupt?

Beitrag von freecrac »

Brueggi hat geschrieben:Also bei meinen (vorläufigen) Versuchen hab ich herausgefunden, dass beim fehlenden Blau-Anteil und erneutem Schreiben nach $3C8 die Farbe komplett schwarz bleibt. Zumindest bei meiner Onboard-CL GD 5426.
Dann gehe ich jetzt erstmal davon aus, das es sich bei anderen GraKas auch so verhällt und man so etwas berücksichtigen sollte.
Ich bin immer noch zu faul gewesen es unter DOS selber auszuprobieren. Ich schäme mich.

Aber ich habe dein Listing mal etwas verändert und Befehle ersetzt und herausgenommen und neue eingefügt und hoffe das es so noch funktioniert und ich kein Fehler eingebaut habe.
Hinweis: Vor allen Befehlen die ersetzt werden sollen habe ich davor ein Semikolon plaziert. Alle neuen Befehl die ich eingefügt habe stehen vorne in der ersten Spalte plaziert.
Dadurch sieht es zunächst etwas unübersichtlicher aus. (Für den besseren Überblick kopiert man es sich am besten in ein *.txt-file.)

Was hälst du davon(noch ungetestet)?:

Code: Alles auswählen

Vorbereitung:
Wx=WordVar;

w3:=Segment der Palette;
w4:=Offset der Palette;
farbe=Farbnummer
w1=Anzahl Rasterzeilen/2 (im Textmode w1=max. 200)
r,g,b: RGB-Werte für die farbe unterhalb des "Copper-Bar"

 asm

;    mov es,w3
mov ds,w3 ; Die Palette(Farbanteile) legen wir auch in den Datenbereich

mov ax,$0040
mov es,ax

mov di,$3C9
mov bp,$3DA

    mov ah,farbe

@rest:
    cli
    mov si,w4

;    mov dx,$3DA
mov dx,bp

@vsync:
    in al,dx
    and al,$08
    jz @vsync
@vsync2:
    in al,dx
    and al,$08
    jnz @vsync2

    mov cx,w1
@raster:

;    mov dx,$3DA
mov dx,bp

@raster0:
    in al,dx
    and al,$01
    jz @raster0

;    mov bh,[es:si]
;    inc si
;    mov bl,[es:si]
;    inc si
mov bx,[si]
lea si,[si+2]

;    mov ah,[es:si]
mov ah,[si]

;    inc si
lea si,[si+1]

    mov al,farbe
    mov dx,$3C8
    out dx,al
    inc dx

;    mov al,bh
mov al,bl

    out dx,al

;    mov al,bl
mov al,bh

    out dx,al

;    mov bx,$3C9
;    mov dx,$3DA
mov dx,bp

@raster1:
    in al,dx
    and al,$01
    jnz @raster1
@raster2:
    in al,dx
    and al,$01
    jz @raster2

;    xchg bx,dx
mov dx,di

    mov al,ah
    out dx,al

;    xchg bx,dx
mov dx,bp

@raster3:
    in al,dx
    and al,$01
    jnz @raster3
    loop @raster

    mov dx,$3C8
    mov al,farbe
    out dx,al
    inc dx
    mov al,r
    out dx,al
    mov al,g
    out dx,al
    mov al,b
    out dx,al
   sti

:   push es
;   mov cx,$0040
;   mov es,cx

   mov ax,[es:$001A]
   mov bx,[es:$001C]

;   pop es

   cmp ax,bx
   jnz @endbow
   jmp @rest
@endbow:
  end;
Dirk
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Sehr interessant. Den "Trick" mit LEA SI,[SI+x] muss ich mir merken. Hast du da mal im Vergleich zu INC die Takte zur hand?
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: VGA-Karte und Interrupt?

Beitrag von freecrac »

Brueggi hat geschrieben:Sehr interessant. Den "Trick" mit LEA SI,[SI+x] muss ich mir merken. Hast du da mal im Vergleich zu INC die Takte zur hand?
Beide Befehle werden wohl nur mit einem Taktzyklus angegeben sein?

So wie ich weiss werden Adressberechnungen von anderen internen Einheiten vorgenommen, damit sie schneller erfolgen können als andere Integerberechnungen.
Und auch wenn Adressberechnungen direkt vor einen Speicherzugriff plaziert werden, dann sollen sie den Zugriff danach nicht verzögern.
Ob das auch schon bei den ersten x86 schon so ist, das weiss ich aber auch nicht. Sicherlich aber bei 80486 und Nachfolger.

"xchg" würde ich auch lieber durch drei "mov" ersetzen. Sprungziele nach Möglichkeit nicht auf ungerade Adressen legen, besser auf eine Adresse die durch 16 teilbar ist.

Für spezielle Fälle: Mit NOP-Befehle(es gibt verschiedene Varianten) dazischen kann der Prefetch-Buffer optimal an die jeweilige CPU angepasst mit unseren Befehlen häpchenweise gefüllt werden.
Denn wenn z.B. der Opcode eines Befehles am Ende eines Bufferbereiches liegt und der Operand von diesem Befehl am Anfang des nächsten Bereiches liegt, dann kann der Befehl erst durch erneutes Einladen in den Prefetch-Buffer vollständig verarbeitet werden, was eine günstige Funktionsweise des Prefetch-Buffers schon etwas beeinträchtigt.

Dirk
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Leider habe ich mein Assemblerbuch nicht zur Hand (verliehen). Was für NOPs gibt es denn noch? Ich kenne sowas nur vom 6510, wo es verschieden "lange" (von den Bytes her) NOPs gibt. Ok, solche Optimierungsmethoden sind für Grafik/Games sicher super, doch glaub ich nicht, dass es bei einer 08/15-Anwendung (oder einem DOS) sinn macht, wenn 99% der Zeit damit verbracht wird, auf Eingaben zu warten. Ich bin mir sicher, das ich da das ein oder andere noch stark optimieren kann - doch das sind dann meistens stellen, die nur einmal (bei FileOpen) am Anfang aufgerufen werden, während die Zeit dann wieder drauf geht, von Datenträger zu lesen :-) Und da alles am 80286 laufen soll, macht eine Optimierung auf 386/486 usw. auch keinen sinn. Wie reagiert eigentlich ein 386er auf einen für 286er optimierten Code, stichwort Prefetch-Queue z. B. ? Gibts dann einen Einbruch?

Trotzdem: Ich finds äußert interessant - Du könntest zum Thema optimierung ja mal eine Art "Trickkiste" zusammenstellen (falls es die nicht schon hier gibt und ich es nicht bemerkt hab). Echt cool, was Du so drauf hast :-)
Brueggi

Re: VGA-Karte und Interrupt?

Beitrag von Brueggi »

Leider habe ich mein Assemblerbuch nicht zur Hand (verliehen). Was für NOPs gibt es denn noch? Ich kenne sowas nur vom 6510, wo es verschieden "lange" (von den Bytes her) NOPs gibt. Ok, solche Optimierungsmethoden sind für Grafik/Games sicher super, doch glaub ich nicht, dass es bei einer 08/15-Anwendung (oder einem DOS) sinn macht, wenn 99% der Zeit damit verbracht wird, auf Eingaben zu warten. Ich bin mir sicher, das ich da das ein oder andere noch stark optimieren kann - doch das sind dann meistens stellen, die nur einmal (bei FileOpen) am Anfang aufgerufen werden, während die Zeit dann wieder drauf geht, von Datenträger zu lesen :-) Und da alles am 80286 laufen soll, macht eine Optimierung auf 386/486 usw. auch keinen sinn. Wie reagiert eigentlich ein 386er auf einen für 286er optimierten Code, stichwort Prefetch-Queue z. B. ? Gibts dann einen Einbruch?

Trotzdem: Ich finds äußert interessant - Du könntest zum Thema optimierung ja mal eine Art "Trickkiste" zusammenstellen (falls es die nicht schon hier gibt und ich es nicht bemerkt hab). Echt cool, was Du so drauf hast :-)
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: VGA-Karte und Interrupt?

Beitrag von freecrac »

Brueggi hat geschrieben:Leider habe ich mein Assemblerbuch nicht zur Hand (verliehen). Was für NOPs gibt es denn noch?
"Wolfgang Kern" in Newsgroup "alt.lang.asm":
http://coding.derkeiler.com/Archive/Ass ... 00073.html
X86 code optimisation guide, App F /NOP (latency=0):
Note 7: These instructions have an effective latency of that which is
listed.
They map to internal NOPs that can be executed at a rate of three per cycle
and do not occupy execution resources.
____________________________________________
Software Optimisation Guide Athlon 10-Family App C2 /NOP(latency~0):
Note 4: The NOP instruction does not consume any execution resources.
________________________________________________
Software Optimization Guide for AMD64 Processors
Chapter 4.12:
Code Padding with Operand-Size Override and NOP
(applies to 32-bit code as well)

NOP1_OVERRIDE_NOP TEXTEQU <DB 090h>
NOP2_OVERRIDE_NOP TEXTEQU <DB 066h,090h>
NOP3_OVERRIDE_NOP TEXTEQU <DB 066h,066h,090h>
NOP4_OVERRIDE_NOP TEXTEQU <DB 066h,066h,066h,090h>
NOP5_OVERRIDE_NOP TEXTEQU <DB 066h,066h,090h,066h,090h>
NOP6_OVERRIDE_NOP TEXTEQU <DB 066h,066h,090h,066h,066h,090h>
NOP7_OVERRIDE_NOP TEXTEQU <DB 066h,066h,066h,090h,066h,066h,090h>
NOP8_OVERRIDE_NOP TEXTEQU <DB 066h,066h,066h,090h,066h,066h,066h,090h>
NOP9_OVERRIDE_NOP TEXTEQU <DB 066h,066h,090h,066h,066h,090h,066h,066h,090h>
James Harris:
* 0x66 prefix bytes are not generally the way to go on Intel CPUs,
* it would be good to get to the bottom of why 3, 4 and, to some
extent, 6 nops improved code speed.
Question regarding the (x86) assembler's use of NOP
http://mail.openjdk.java.net/pipermail/ ... 03881.html
The Intel Arch Optimization Guide recommends the following regarding NOPs:

3.5.1.8 Using NOPs
Code generators generate a no-operation (NOP) to align instructions.
Examples of NOPs of different lengths in 32-bit mode are shown below:

1-byte: XCHG EAX, EAX
2-byte: 66 NOP
3-byte: LEA REG, 0 (REG) (8-bit displacement)
4-byte: NOP DWORD PTR [EAX + 0] (8-bit displacement)
5-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (8-bit displacement)
6-byte: LEA REG, 0 (REG) (32-bit displacement)
7-byte: NOP DWORD PTR [EAX + 0] (32-bit displacement)
8-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
9-byte: NOP WORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
Ich kenne sowas nur vom 6510, wo es verschieden "lange" (von den Bytes her) NOPs gibt. Ok, solche Optimierungsmethoden sind für Grafik/Games sicher super, doch glaub ich nicht, dass es bei einer 08/15-Anwendung (oder einem DOS) sinn macht, wenn 99% der Zeit damit verbracht wird, auf Eingaben zu warten.
Beim Warten auf eine Eingabe macht es bestimmt keinen Sinn, aber in Anwendung wo zeitkritische Routinen verwendet werden.
Ich bin mir sicher, das ich da das ein oder andere noch stark optimieren kann - doch das sind dann meistens stellen, die nur einmal (bei FileOpen) am Anfang aufgerufen werden, während die Zeit dann wieder drauf geht, von Datenträger zu lesen :-) Und da alles am 80286 laufen soll, macht eine Optimierung auf 386/486 usw. auch keinen sinn.
Nachdem man es am Anfang überprüft hat welche CPU vorhanden ist, könnte man für wenige zeitkritische Routinen für 80286 einen anderen optimierten Code verwenden, als für 80386 und beide solcher optimierten Routinen zur Auswahl mitbringen. Ich denke besonders auf älteren Rechnern macht eine Optimierung für verschiedene CPU-Modelle Sinn.

Subroutine zum Ermitteln der CPU:

Code: Alles auswählen

                Cpu86    =   0 
                Cpu286   =   4
                Cpu386   =   8
                Cpu486   =  12
                Cpu586   =  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
Über prefetch queue:
http://www.phatcode.net/res/224/files/h ... 11-02.html

http://www.rcollins.org/secrets/PrefetchQueue.html
The 80386 is documented as having a 16-byte prefetch queue. At one time, it did, but due to a bug in the pipelining architecture, Intel had to abandon the 16-byte queue, and only use a 12-byte queue. The change occurred (I believe) between the D0, and D1 step of the '386. The '386SX wasn't affected by the bug, and therefore hasn't changed.
What is prefetch queue in 8086?
http://wiki.answers.com/Q/What_is_prefe ... ue_in_8086
To speed up the program execution, the B.I.U fetches six instructions byte ahead of time from memory and stores in FIFO registers called "queue".
Wie reagiert eigentlich ein 386er auf einen für 286er optimierten Code, stichwort Prefetch-Queue z. B. ? Gibts dann einen Einbruch?
Ich vermute ein für den 286er optimierten Code wird auch auf einem 386er schneller ausgeführt, als ein 286er Code der nicht optimiert wurde.

Example program to detect the size of the PIQ.
http://en.wikipedia.org/wiki/Prefetch_input_queue
This is an example NASM-syntax self-modifying x86-assembly algorithm that determines the size of the PIQ:

Code: Alles auswählen

ode_starts_here:
   xor cx, cx                  ; zero register cx
   xor ax, ax                  ; zero register ax

   mov dx, cs
   mov [code_segment], dx      ; "calculate" codeseg in the far jump below (edx here too)

around:
   cmp ax, 1                   ; check if ax has been alterd
   je found_size

   mov [nop_field+cx], 0x90    ; 0x90 = opcode "nop" (NO oPeration)
   inc cx

   db 0xEA                     ; 0xEA = opcode "far jump"
   dw flush_queue              ; should be followed by offset (rm = "dw", pm = "dd")
code_segment:
   dw 0                        ; and then the code segment (calculated above)
flush_queue:
  
   mov [nop_field+cx], 0x40    ; 0x40 = opcode "inc ax" (INCrease ax)

nop_field:
   nop times 256
   jmp around
found_size:
   ;
   ;    register cx now contains the size of the PIQ
   ;    this code is for real mode and 16-bit protected mode, but it could easily be changed into 
   ;    running for 32-bit protected mode as well. just change the "dw" for 
   ;    the offset to "dd". you need also change dx to edx at the top as
   ;    well. (dw and dx = 16 bit addressing, dd and edx = 32 bit addressing)
   ;
Leistungssteigerung durch das Pipelining.
http://de.wikipedia.org/wiki/Pipeline_(Prozessor)
Trotzdem: Ich finds äußert interessant - Du könntest zum Thema optimierung ja mal eine Art "Trickkiste" zusammenstellen (falls es die nicht schon hier gibt und ich es nicht bemerkt hab). Echt cool, was Du so drauf hast :-)
Ja stimmt so eine "Trickkiste" wäre nicht schlecht.

Dirk
Antworten