; Illustre l'interaction entre la division d'écran et le scrolling pixel ; par pixel horizontal. Sur VGA, effectue en premier un scrolling directement ; vers la moitié supérieure alors que la division d'écran est saccadée, car la ; suppression du scrolling pixel par pixel de la division d'écran est désactivée ; puis active la suppression de du scrolling pixel par pixel de ; la division d'écran et effectue un scrolling directement vers la partie ; supérieure alors que la division d'écran reste stable ; Sur EGA, la division d'écran est saccadée dans les deux cas, ; car EGA ne supporte pas la suppression du srolling pixel par pixel ; de la division d'écran. ; Les saccades se produisent dans la division d'écran parce qu'un scrolling pixel ; par pixel est réalisé dans la division d'écran (le scrolling pixel par pixel ; est effectué en intraoctet),mais un scrolling octet par octet n'est pas ou ; ne pas peut être effectué dans la division d'écran (scrolling octet par octet ; est effectué en extraoctet) car l'adresse de départ de la division d'écran ; est toujours fixée à 0. ; ; Assemblé avec TASM 4.0, liée avec TLINK 6.10 ; Testé par Jim Mischel 11/21/94 ;********************************************************************* IS_VGA equ 1 ;à 0 pour assembler EGA ; VGA_SEGMENT equ 0a000h LOGICAL_SCREEN_WIDTH equ 1024 ;nombre de pixels dans l'écran virtuel ;dans lequel nous allons scroller SCREEN_HEIGHT equ 350 SPLIT_SCREEN_START equ 200 ;ligne d'affichage de départ de ;la division d'écran SPLIT_SCREEN_HEIGHT equ SCREEN_HEIGHT-SPLIT_SCREEN_START-1 CRTC_INDEX equ 3d4h ;registre Controller Index CRTC AC_INDEX equ 3c0h ;registre Attribute Controller Index OVERFLOW equ 7 ;index du registre Overflow dans CRTC MAXIMUM_SCAN_LINE equ 9 ;index du registre Maximum Scan Line ;dans CRTC START_ADDRESS_HIGH equ 0ch ;index du registre Start Address High ;dans CRTC START_ADDRESS_LOW equ 0dh ;index du registre Start Address Low ;dans CRTC HOFFSET equ 13h ;index du registre Horizontal Offset ;dans CRTC LINE_COMPARE equ 18h ;index du registre Line Compare (les ;bits 7-0 de la ligne d'affichage ;de départ de la division d'écran) ;dans CRTC AC_MODE_CONTROL equ 10h ;index du registre Mode Control dans ;AC PEL_PANNING equ 13h ;index du registre Pel Panning dans ;AC INPUT_STATUS_0 equ 3dah ;registre Input Status 0 WORD_OUTS_OK equ 1 ;à 0 pour assembler pour les ordinateurs ;ne pouvant traiter des outs de mot ; sur des registres indexés VGA ;********************************************************************* ; Macro pour diriger une valeur 16 bits sur un port. ; OUT_WORD macro if WORD_OUTS_OK out dx,ax else out dx,al inc dx xchg ah,al out dx,al dec dx xchg ah,al endif endm ;********************************************************************* MyStack segment para stack 'STACK' db 512 dup (0) MyStack ends ;********************************************************************* Data segment SplitScreenLine dw ? ;la division d'écran commence après cette ;ligne StartAddress dw ? ;offset de la mémoire vidéo à partir ;duquel le parcours des données vidéo ;commencent PelPan db ? ;paramètrage courant du scrolling ;horizontal pixel par pixel ;intraoctet Data ends ;********************************************************************* Code segment assume cs:Code, ds:Data ;********************************************************************* Start proc near mov ax,Data mov ds,ax ; ; Sélectionne le mode 10h, mode graphique 640x350 en 16 couleurs. ; mov ax,0010h ;AH=0 fonction de sélection de mode ;AL=10h mode à sélectionner, ;mode graphique 640x350 en 16 couleurs int 10h ; Notez que le registre Offset est programmé avec la largeur de l'écran logique ; en mots, et non en octets, de là la division par 2. mov dx,CRTC_INDEX mov ax,(LOGICAL_SCREEN_WIDTH/8/2 shl 8) or HOFFSET ; OUT_WORD ; ; Paramètre l'adresse de départ pour afficher la mémoire juste après la mémoire ; de la division d'écran. ; mov [StartAddress],SPLIT_SCREEN_HEIGHT*;(LOGICAL_SC REEN_WIDTH/8) call SetStartAddress ; ;Paramètre la ligne d'affichage de départ de la division d'écran. ; mov [SplitScreenLine],SPLIT_SCREEN_START call SetSplitScreenScanLine ; ; Remplit la partie de la division d'écran de la mémoire vidéo (commençant à ; l'offset 0) avec un motif diagonal incliné sur la gauche. ; mov ax,VGA_SEGMENT mov es,ax sub di,di mov dx,SPLIT_SCREEN_HEIGHT ;remplit toutes les lignes dans la division ;d'écran mov ax,0FF0h ;motif de remplissage de départ cld RowLoop: mov cx,LOGICAL_SCREEN_WIDTH/8/4 ;remplit une ligne d'affichage ColumnLoop: stosw ;affiche une partie de la ligne diagonale mov word ptr es:[di],0 ;fait des espaces ;vides afin que les effets produits ;par le scrolling puissent être facilement ;perceptibles inc di inc di loop ColumnLoop rol ax,1 ;décale le mot du motif dec dx jnz RowLoop ; ; Remplit la partie de la mémoire vidéo qui sera affichée dans l'écran ; normal (la partie non-divisée de l'écran de la mémoire) avec un motif ; en diagonal incliné à droite. ; mov di,SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8 ;) mov dx,SCREEN_HEIGHT ;remplit toutes les lignes mov ax,0c510h ;motif de remplissage de départ cld RowLoop2: mov cx,LOGICAL_SCREEN_WIDTH/8/4 ;remplit 1 ligne d'affichage ColumnLoop2: stosw ;affiche une partie de la ligne diagonale mov word ptr es:[di],0 ;fait des espaces ;vides afin que les effets ;produits par le scrolling ;puissent être facilement ;perceptibles inc di inc di loop ColumnLoop2 ror ax,1 ;décale un mot du motif dec dx jnz RowLoop2 ; ; Réalise un scrolling dans la partie non divisée de l'écran de la mémoire; ; car la suppression du scrolling pixel par pixel de la division d'écran ; n'est pas activée, l'image dans la division d'écran est saccadée ; mov cx,200 ;panoramique de 200 pixels vers la gauche call PanRight ; ; Attend une touche clavier (il n'y a pas d'écho du caractère). ; mov ah,8 ;fonction d'entrée console sans écho ;de DOS int 21h ; ; Retourne à l'emplacement de l'écran d'origine, le scrolling pixel par pixel ; est désactivé. ; mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SC ;REEN_WIDTH/8) call SetStartAddress mov [PelPan],0 call SetPelPan ; ; Active la suppression du srolling pixel par pixel de la division d'écran, aussi ; la division d'écran ne sera pas affectée par le scrolling. ; Ne se fait pas sur EGA car la carte EGA ne supporte ni les registres lisibles ; ni le bit de la suppression du scrolling pixel par pixel de la division d'écran ; if IS_VGA mov dx,INPUT_STATUS_0 in al,dx ;reinitialise AC Index/Data sur ;Index mov al,20h+AC_MODE_CONTROL ;le bit 5 est à 1 pour garder active la vidéo mov dx,AC_INDEX ;pointe sur le registre AC ; Index/Data out dx,al inc dx ;pointe sur le registre AC Data ( ;seulement pour les lectures) in al,dx ;récupère le registre courant AC ;Mode Control or al,20h ;active la suppression du scrolling ;pixel par pixel de la ;division d'écran dec dx ;pointe sur le registre AC Index/Data ;(Data pour seulement les écritures) out dx,al ;écrit le nouveau paramétrage de AC ;Mode Control avec la suppression ;du scrolling pixel par pixel ;de la division d'écran activée endif ; mov cx,200 ;scrolling de 200 pixels vers la ;gauche call PanRight ; ; Attend une touche clavier (il n'y a pas d'écho de caractère). ; mov ah,8 ;fonction d'entrée console sans écho ;de DOS int 21h ; ; Revient en mode texte et à DOS. ; mov ax,0003h ;AH=0 fonction de sélection de mode ;AL=3 mode à sélectionner, le mode ;texte int 10h ;revient en mode texte mov ah,4ch int 21h ;revient à DOS Start endp ;********************************************************************* ; Attend le SSV. ; ; Entrée: aucune ; ; Sortie: aucune ; ; Registres altérés: AL, DX ; WaitForVerticalSyncStart proc near mov dx,INPUT_STATUS_0 WaitNotVerticalSync: in al,dx test al,08h jnz WaitNotVerticalSync WaitVerticalSync: in al,dx test al,08h jz WaitVerticalSync ret WaitForVerticalSyncStart endp ;********************************************************************* ; Attend le début du signal de synchronisation verticale ; Entrée: aucune ; ; Sortie: aucune ; ; Registres altérés: AL, DX ; WaitForVerticalSyncEnd proc near mov dx,INPUT_STATUS_0 WaitVerticalSync2: in al,dx test al,08h jz WaitVerticalSync2 WaitNotVerticalSync2: in al,dx test al,08h jnz WaitNotVerticalSync2 ret WaitForVerticalSyncEnd endp ;********************************************************************* ; Paramètre l'adresse de départ à la valeur spécifiée par StartAddress. ; Attend le début du signal de synchronisation verticale avant de ; Entrée: aucune ; ; Sortie: aucune ; ; Registres altérés: AX, DX ; SetStartAddress proc near call WaitForVerticalSyncEnd mov dx,CRTC_INDEX mov al,START_ADDRESS_HIGH mov ah,byte ptr [StartAddress+1] cli ;assure que les deux registres soient ;positionnés en une seule fois OUT_WORD mov al,START_ADDRESS_LOW mov ah,byte ptr [StartAddress] OUT_WORD sti ret SetStartAddress endp ;********************************************************************* ; Met le paramétrage du scrolling horizontal à la valeur spécifiée par ; PelPan. Attend le début du signal de synchronisation verticale, ; ; Entrée: aucune ; ; Sortie: aucune ; ; Registres altérés: AL, DX ; SetPelPan proc near call WaitForVerticalSyncStart ;réinitialise ;également AC ; Index/Data à ; l'état Index mov dx,AC_INDEX mov al,PEL_PANNING+20h ;le bit 5 est à 1 pour garder la vidéo active out dx,al ;AC Index pointe sur le registre ;Pel Pan mov al,[PelPan] out dx,al ;charge le nouveau paramétrage ;Pel Pan ret SetPelPan endp ;********************************************************************* ;Paramètre la ligne d'affichage après laquelle commence la division d'écran sur la ;ligne d'affichage spécifiée par SplitScreenLine. ; ; Entrée: aucune ; ; Sortie: aucune ; ; Tous les registres sont préservés ; SetSplitScreenScanLine proc near push ax push cx push dx call WaitForVerticalSyncStart ; ; Paramètre la ligne d'affichage de la division d'écran. ; mov dx,CRTC_INDEX mov ah,byte ptr [SplitScreenLine] mov al,LINE_COMPARE cli ;assure que tous les registres sont positionnés ;en une seule fois OUT_WORD ;paramètre les bits 7-0 de la ligne d'affichage ;de la division d'écran mov ah,byte ptr [SplitScreenLine+1] and ah,1 mov cl,4 shl ah,cl ;met le bit 8 de la ligne ;d'affichage de la division d'écran ;en position pour le registre Overflow mov al,OVERFLOW if IS_VGA ; ; Les registres Split Screen, Overflow, et Line Compare contiennent tous ; une partie de la ligne d'affichage de départ de la division d'écran sur VGA. ; Nous bénéficierons des registres lisibles du VGA pour laisser tels quels les ; autres bits dans les registres auxquels nous accédons. ; out dx,al ;le registre Index CRTC pointe sur ;Overflow inc dx ;pointe sur le registre Data CRTC in al,dx ;récupère le paramétrage courant du ;registre Overflow and al,not 10h ;désactive le bit 8 de la ;division d'écran or al,ah ;insère le nouveau bit 8 de la ;division d'écran (fonctionne en tout ;mode) out dx,al ;paramètre le nouveau bit 8 de la ;division d 'écran dec dx ;pointe sur le registre Index CRTC mov ah,byte ptr [SplitScreenLine+1] and ah,2 mov cl,3 ror ah,cl ;met le bit 9 de la ligne ;d'affichage de la division d'écran ;en position pour le registre Maximum Scan Line mov al,MAXIMUM_SCAN_LINE out dx,al ;le registre Index CRTC pointe sur ;Maximum Scan Line inc dx ;pointe sur le registre Data CRTC in al,dx ;récupère le paramétrage courant ;Maximum Scan Line and al,not 40h ;désactive le bit 9 de la ; division d'écran or al,ah ;insère le nouveau bit 9 de la ;division d'écran (fonctionne en tout ;mode) out dx,al ;paramètre le nouveau bit 9 de la ; divsion d'écran else ; ; Seuls les registres Split Screen et Overflow contiennent une partie ; de la ligne d'affichage de départ Split Screen et doivent être sur EGA. ; Les registres EGA ne sont pas lisibles, aussi nous devons paramétrer les bits de ; l'écran non divisé du registre Overflow sur une valeur preset, dans ce cas ; la valeur des modes 350 lignes d'affichage. ; or ah,0fh ;insère le nouveau bit 8 de la ;division d'écran (fonctionne ;seulement dans les modes 350 lignes ;d'affichage d'EGA OUT_WORD ;paramètre le nouveau bit 8 de la ;division d'écran endif sti pop dx pop cx pop ax ret SetSplitScreenScanLine endp ;********************************************************************* ; Réalise un scrolling horizontal vers la droite dont le nombre de pixels est ; spécifié par CX. ; ; Entrée: CX = nombre de pixels pour effectuer le panoramique horizontal ; ; Sortie: aucune ; ; Registres altérés: AX, CX, DX ; PanRight proc near PanLoop: inc [PelPan] and [PelPan],07h jnz DoSetStartAddress inc [StartAddress] DoSetStartAddress: call SetStartAddress call SetPelPan loop PanLoop ret PanRight endp ;********************************************************************* Code ends end Start