home *** CD-ROM | disk | FTP | other *** search
- ;
- ; *** Listing 1 ***
- ;
- ; Demonstrates the VGA/EGA split screen in action.
- ;
- ;*********************************************************************
- IS_VGA equ 1 ;set to 0 to assemble for EGA
- ;
- VGA_SEGMENT equ 0a000h
- SCREEN_WIDTH equ 640
- SCREEN_HEIGHT equ 350
- CRTC_INDEX equ 3d4h ;CRT Controller Index register
- OVERFLOW equ 7 ;index of Overflow reg in CRTC
- MAXIMUM_SCAN_LINE equ 9 ;index of Maximum Scan Line register
- ; in CRTC
- START_ADDRESS_HIGH equ 0ch ;index of Start Address High register
- ; in CRTC
- START_ADDRESS_LOW equ 0dh ;index of Start Address Low register
- ; in CRTC
- LINE_COMPARE equ 18h ;index of Line Compare reg (bits 7-0
- ; of split screen start scan line)
- ; in CRTC
- INPUT_STATUS_0 equ 3dah ;Input Status 0 register
- WORD_OUTS_OK equ 1 ;set to 0 to assemble for
- ; computers that can't handle
- ; word outs to indexed VGA registers
- ;*********************************************************************
- ; Macro to output a word value to a 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 ? ;line the split screen currently
- ; starts after
- StartAddress dw ? ;display memory offset at which
- ; scanning for video data starts
- ; Message displayed in split screen.
- SplitScreenMsg db 'Split screen text row #'
- DigitInsert dw ?
- db '...$'
- Data ends
- ;*********************************************************************
- Code segment
- assume cs:Code, ds:Data
- ;*********************************************************************
- Start proc near
- mov ax,Data
- mov ds,ax
- ;
- ; Select mode 10h, 640x350 16-color graphics mode.
- ;
- mov ax,0010h ;AH=0 is select mode function
- ;AL=10h is mode to select,
- ; 640x350 16-color graphics mode
- int 10h
- ;
- ; Put text into display memory starting at offset 0, with each row
- ; labelled as to number. This is the part of memory that will be
- ; displayed in the split screen portion of the display.
- ;
- mov cx,25 ;# of lines of text we'll draw into
- ; the split screen part of memory
- FillSplitScreenLoop:
- mov ah,2 ;set cursor location function #
- sub bh,bh ;set cursor in page 0
- mov dh,25
- sub dh,cl ;calculate row to draw in
- sub dl,dl ;start in column 0
- int 10h ;set the cursor location
- mov al,25
- sub al,cl ;calculate row to draw in again
- sub ah,ah ;make the value a word for division
- mov dh,10
- div dh ;split the row # into two digits
- add ax,'00' ;convert the digits to ASCII
- mov [DigitInsert],ax ;put the digits into the text
- ; to be displayed
- mov ah,9
- mov dx,offset SplitScreenMsg
- int 21h ;print the text
- loop FillSplitScreenLoop
- ;
- ; Fill display memory starting at 8000h with a diagonally striped
- ; pattern.
- ;
- mov ax,VGA_SEGMENT
- mov es,ax
- mov di,8000h
- mov dx,SCREEN_HEIGHT ;fill all lines
- mov ax,8888h ;starting fill pattern
- cld
- RowLoop:
- mov cx,SCREEN_WIDTH/8/2 ;fill 1 scan line a word at a time
- rep stosw ;fill the scan line
- ror ax,1 ;shift pattern word
- dec dx
- jnz RowLoop
- ;
- ; Set the start address to 8000h and display that part of memory.
- ;
- mov [StartAddress],8000h
- call SetStartAddress
- ;
- ; Slide the split screen half way up the screen and then back down
- ; a quarter of the screen.
- ;
- mov [SplitScreenLine],SCREEN_HEIGHT-1
- ;set the initial line just off
- ; the bottom of the screen
- mov cx,SCREEN_HEIGHT/2
- call SplitScreenUp
- mov cx,SCREEN_HEIGHT/4
- call SplitScreenDown
- ;
- ; Now move up another half a screen and then back down a quarter.
- ;
- mov cx,SCREEN_HEIGHT/2
- call SplitScreenUp
- mov cx,SCREEN_HEIGHT/4
- call SplitScreenDown
- ;
- ; Finally move up to the top of the screen.
- ;
- mov cx,SCREEN_HEIGHT/2-2
- call SplitScreenUp
- ;
- ; Wait for a key press (don't echo character).
- ;
- mov ah,8 ;DOS console input without echo function
- int 21h
- ;
- ; Turn the split screen off.
- ;
- mov [SplitScreenLine],0ffffh
- call SetSplitScreenScanLine
- ;
- ; Wait for a key press (don't echo character).
- ;
- mov ah,8 ;DOS console input without echo function
- int 21h
- ;
- ; Display the memory at 0 (the same memory the split screen displays).
- ;
- mov [StartAddress],0
- call SetStartAddress
- ;
- ; Flip between the split screen and the normal screen every 10th
- ; frame until a key is pressed.
- ;
- FlipLoop:
- xor [SplitScreenLine],0ffffh
- call SetSplitScreenScanLine
- mov cx,10
- CountVerticalSyncsLoop:
- call WaitForVerticalSyncEnd
- loop CountVerticalSyncsLoop
- mov ah,0bh ;DOS character available status
- int 21h
- and al,al ;character available?
- jz FlipLoop ;no, toggle split screen on/off status
- mov ah,1
- int 21h ;clear the character
- ;
- ; Return to text mode and DOS.
- ;
- mov ax,0003h ;AH=0 is select mode function
- ;AL=3 is mode to select, text mode
- int 10h ;return to text mode
- mov ah,4ch
- int 21h ;return to DOS
- Start endp
- ;*********************************************************************
- ; Waits for the leading edge of the vertical sync pulse.
- ;
- ; Input: none
- ;
- ; Output: none
- ;
- ; Registers altered: 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
- ;*********************************************************************
- ; Waits for the trailing edge of the vertical sync pulse.
- ;
- ; Input: none
- ;
- ; Output: none
- ;
- ; Registers altered: 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
- ;*********************************************************************
- ; Sets the start address to the value specifed by StartAddress.
- ; Wait for the trailing edge of vertical sync before setting so that
- ; one half of the address isn't loaded before the start of the frame
- ; and the other half after, resulting in flicker as one frame is
- ; displayed with mismatched halves. The new start address won't be
- ; loaded until the start of the next frame; that is, one full frame
- ; will be displayed before the new start address takes effect.
- ;
- ; Input: none
- ;
- ; Output: none
- ;
- ; Registers altered: AX, DX
- ;
- SetStartAddress proc near
- call WaitForVerticalSyncEnd
- mov dx,CRTC_INDEX
- mov al,START_ADDRESS_HIGH
- mov ah,byte ptr [StartAddress+1]
- cli ;make sure both registers get set at once
- OUT_WORD
- mov al,START_ADDRESS_LOW
- mov ah,byte ptr [StartAddress]
- OUT_WORD
- sti
- ret
- SetStartAddress endp
- ;*********************************************************************
- ; Sets the scan line the split screen starts after to the scan line
- ; specified by SplitScreenLine.
- ;
- ; Input: none
- ;
- ; Output: none
- ;
- ; All registers preserved
- ;
- SetSplitScreenScanLine proc near
- push ax
- push cx
- push dx
- ;
- ; Wait for the leading edge of the vertical sync pulse. This ensures
- ; that we don't get mismatched portions of the split screen setting
- ; while setting the two or three split screen registers (register 18h
- ; set but register 7 not yet set when a match occurs, for example),
- ; which could produce brief flickering.
- ;
- call WaitForVerticalSyncStart
- ;
- ; Set the split screen scan line.
- ;
- mov dx,CRTC_INDEX
- mov ah,byte ptr [SplitScreenLine]
- mov al,LINE_COMPARE
- cli ;make sure all the registers get set at once
- OUT_WORD ;set bits 7-0 of the split screen scan line
- mov ah,byte ptr [SplitScreenLine+1]
- and ah,1
- mov cl,4
- shl ah,cl ;move bit 8 of the split split screen scan
- ; line into position for the Overflow reg
- mov al,OVERFLOW
- if IS_VGA
- ;
- ; The Split Screen, Overflow, and Line Compare registers all contain
- ; part of the split screen start scan line on the VGA. We'll take
- ; advantage of the readable registers of the VGA to leave other bits
- ; in the registers we access undisturbed.
- ;
- out dx,al ;set CRTC Index reg to point to Overflow
- inc dx ;point to CRTC Data reg
- in al,dx ;get the current Overflow reg setting
- and al,not 10h ;turn off split screen bit 8
- or al,ah ;insert the new split screen bit 8
- ; (works in any mode)
- out dx,al ;set the new split screen bit 8
- dec dx ;point to CRTC Index reg
- mov ah,byte ptr [SplitScreenLine+1]
- and ah,2
- mov cl,3
- ror ah,cl ;move bit 9 of the split split screen scan
- ; line into position for the Maximum Scan
- ; Line register
- mov al,MAXIMUM_SCAN_LINE
- out dx,al ;set CRTC Index reg to point to Maximum
- ; Scan Line
- inc dx ;point to CRTC Data reg
- in al,dx ;get the current Maximum Scan Line setting
- and al,not 40h ;turn off split screen bit 9
- or al,ah ;insert the new split screen bit 9
- ; (works in any mode)
- out dx,al ;set the new split screen bit 9
- else
- ;
- ; Only the Split Screen and Overflow registers contain part of the
- ; Split Screen start scan line and need to be set on the EGA.
- ; EGA registers are not readable, so we have to set the non-split
- ; screen bits of the Overflow register to a preset value, in this
- ; case the value for 350-scan-line modes.
- ;
- or ah,0fh ;insert the new split screen bit 8
- ; (only works in 350-scan-line EGA modes)
- OUT_WORD ;set the new split screen bit 8
- endif
- sti
- pop dx
- pop cx
- pop ax
- ret
- SetSplitScreenScanLine endp
- ;*********************************************************************
- ; Moves the split screen up the specified number of scan lines.
- ;
- ; Input: CX = # of scan lines to move the split screen up by
- ;
- ; Output: none
- ;
- ; Registers altered: CX
- ;
- SplitScreenUp proc near
- SplitScreenUpLoop:
- dec [SplitScreenLine]
- call SetSplitScreenScanLine
- loop SplitScreenUpLoop
- ret
- SplitScreenUp endp
- ;*********************************************************************
- ; Moves the split screen down the specified number of scan lines.
- ;
- ; Input: CX = # of scan lines to move the split screen down by
- ;
- ; Output: none
- ;
- ; Registers altered: CX
- ;
- SplitScreenDown proc near
- SplitScreenDownLoop:
- inc [SplitScreenLine]
- call SetSplitScreenScanLine
- loop SplitScreenDownLoop
- ret
- SplitScreenDown endp
- ;*********************************************************************
- Code ends
- end Start