More VGA tests
This commit is contained in:
parent
13eeef57d9
commit
aa3c978517
2 changed files with 791 additions and 0 deletions
372
tests/pc/vga/L30-1.ASM
Normal file
372
tests/pc/vga/L30-1.ASM
Normal file
|
|
@ -0,0 +1,372 @@
|
||||||
|
; 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
|
||||||
419
tests/pc/vga/L30-2.ASM
Normal file
419
tests/pc/vga/L30-2.ASM
Normal file
|
|
@ -0,0 +1,419 @@
|
||||||
|
; Demonstrates the interaction of the split screen and
|
||||||
|
; horizontal pel panning. On a VGA, first pans right in the top
|
||||||
|
; half while the split screen jerks around, because split screen
|
||||||
|
; pel panning suppression is disabled, then enables split screen
|
||||||
|
; pel panning suppression and pans right in the top half while the
|
||||||
|
; split screen remains stable. On an EGA, the split screen jerks
|
||||||
|
; around in both cases, because the EGA doesn't support split
|
||||||
|
; screen pel panning suppression.
|
||||||
|
;
|
||||||
|
; The jerking in the split screen occurs because the split screen
|
||||||
|
; is being pel panned (panned by single pixels--intrabyte panning),
|
||||||
|
; but is not and cannot be byte panned (panned by single bytes--
|
||||||
|
; "extrabyte" panning) because the start address of the split screen
|
||||||
|
; is forever fixed at 0.
|
||||||
|
;*********************************************************************
|
||||||
|
IS_VGA equ 1 ;set to 0 to assemble for EGA
|
||||||
|
;
|
||||||
|
VGA_SEGMENT equ 0a000h
|
||||||
|
LOGICAL_SCREEN_WIDTH equ 1024 ;# of pixels across virtual
|
||||||
|
; screen that we'll pan across
|
||||||
|
SCREEN_HEIGHT equ 350
|
||||||
|
SPLIT_SCREEN_START equ 200 ;start scan line for split screen
|
||||||
|
SPLIT_SCREEN_HEIGHT equ SCREEN_HEIGHT-SPLIT_SCREEN_START-1
|
||||||
|
CRTC_INDEX equ 3d4h ;CRT Controller Index register
|
||||||
|
AC_INDEX equ 3c0h ;Attribute Controller Index reg
|
||||||
|
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
|
||||||
|
HOFFSET equ 13h ;index of Horizontal Offset register
|
||||||
|
; in CRTC
|
||||||
|
LINE_COMPARE equ 18h ;index of Line Compare reg (bits 7-0
|
||||||
|
; of split screen start scan line)
|
||||||
|
; in CRTC
|
||||||
|
AC_MODE_CONTROL equ 10h ;index of Mode Control reg in AC
|
||||||
|
PEL_PANNING equ 13h ;index of Pel Panning reg in AC
|
||||||
|
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
|
||||||
|
PelPan db ? ;current intrabyte horizontal pel
|
||||||
|
; panning setting
|
||||||
|
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
|
||||||
|
;
|
||||||
|
; Set the Offset register to make the offset from the start of one
|
||||||
|
; scan line to the start of the next the desired number of pixels.
|
||||||
|
; This gives us a virtual screen wider than the actual screen to
|
||||||
|
; pan across.
|
||||||
|
; Note that the Offset register is programmed with the logical
|
||||||
|
; screen width in words, not bytes, hence the final division by 2.
|
||||||
|
;
|
||||||
|
mov dx,CRTC_INDEX
|
||||||
|
mov ax,(LOGICAL_SCREEN_WIDTH/8/2 shl 8) or HOFFSET
|
||||||
|
OUT_WORD
|
||||||
|
;
|
||||||
|
; Set the start address to display the memory just past the split
|
||||||
|
; screen memory.
|
||||||
|
;
|
||||||
|
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||||
|
call SetStartAddress
|
||||||
|
;
|
||||||
|
; Set the split screen start scan line.
|
||||||
|
;
|
||||||
|
mov [SplitScreenLine],SPLIT_SCREEN_START
|
||||||
|
call SetSplitScreenScanLine
|
||||||
|
;
|
||||||
|
; Fill the split screen portion of display memory (starting at
|
||||||
|
; offset 0) with a choppy diagonal pattern sloping left.
|
||||||
|
;
|
||||||
|
mov ax,VGA_SEGMENT
|
||||||
|
mov es,ax
|
||||||
|
sub di,di
|
||||||
|
mov dx,SPLIT_SCREEN_HEIGHT
|
||||||
|
;fill all lines in the split screen
|
||||||
|
mov ax,0FF0h ;starting fill pattern
|
||||||
|
cld
|
||||||
|
RowLoop:
|
||||||
|
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||||
|
;fill 1 scan line
|
||||||
|
ColumnLoop:
|
||||||
|
stosw ;draw part of a diagonal line
|
||||||
|
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||||
|
; panning effects can be seen easily
|
||||||
|
inc di
|
||||||
|
inc di
|
||||||
|
loop ColumnLoop
|
||||||
|
rol ax,1 ;shift pattern word
|
||||||
|
dec dx
|
||||||
|
jnz RowLoop
|
||||||
|
;
|
||||||
|
; Fill the portion of display memory that will be displayed in the
|
||||||
|
; normal screen (the non-split screen part of the display) with a
|
||||||
|
; choppy diagonal pattern sloping right.
|
||||||
|
;
|
||||||
|
mov di,SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||||
|
mov dx,SCREEN_HEIGHT ;fill all lines
|
||||||
|
mov ax,0c510h ;starting fill pattern
|
||||||
|
cld
|
||||||
|
RowLoop2:
|
||||||
|
mov cx,LOGICAL_SCREEN_WIDTH/8/4
|
||||||
|
;fill 1 scan line
|
||||||
|
ColumnLoop2:
|
||||||
|
stosw ;draw part of a diagonal line
|
||||||
|
mov word ptr es:[di],0 ;make vertical blank spaces so
|
||||||
|
; panning effects can be seen easily
|
||||||
|
inc di
|
||||||
|
inc di
|
||||||
|
loop ColumnLoop2
|
||||||
|
ror ax,1 ;shift pattern word
|
||||||
|
dec dx
|
||||||
|
jnz RowLoop2
|
||||||
|
;
|
||||||
|
; Pel pan the non-split screen portion of the display; because
|
||||||
|
; split screen pel panning suppression is not turned on, the split
|
||||||
|
; screen jerks back and forth as the pel panning setting cycles.
|
||||||
|
;
|
||||||
|
mov cx,200 ;pan 200 pixels to the left
|
||||||
|
call PanRight
|
||||||
|
;
|
||||||
|
; Wait for a key press (don't echo character).
|
||||||
|
;
|
||||||
|
mov ah,8 ;DOS console input without echo function
|
||||||
|
int 21h
|
||||||
|
;
|
||||||
|
; Return to the original screen location, with pel panning turned off.
|
||||||
|
;
|
||||||
|
mov [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
|
||||||
|
call SetStartAddress
|
||||||
|
mov [PelPan],0
|
||||||
|
call SetPelPan
|
||||||
|
;
|
||||||
|
; Turn on split screen pel panning suppression, so the split screen
|
||||||
|
; won't be affected by pel panning. Not done on EGA because both
|
||||||
|
; readable registers and the split screen pel panning suppression bit
|
||||||
|
; aren't supported by EGAs.
|
||||||
|
;
|
||||||
|
if IS_VGA
|
||||||
|
mov dx,INPUT_STATUS_0
|
||||||
|
in al,dx ;reset the AC Index/Data toggle to
|
||||||
|
; Index state
|
||||||
|
mov al,20h+AC_MODE_CONTROL
|
||||||
|
;bit 5 set to 1 to keep video on
|
||||||
|
mov dx,AC_INDEX ;point to AC Index/Data register
|
||||||
|
out dx,al
|
||||||
|
inc dx ;point to AC Data reg (for reads only)
|
||||||
|
in al,dx ;get the current AC Mode Control reg
|
||||||
|
or al,20h ;enable split screen pel panning
|
||||||
|
; suppression
|
||||||
|
dec dx ;point to AC Index/Data reg (Data for
|
||||||
|
; writes only)
|
||||||
|
out dx,al ;write the new AC Mode Control setting
|
||||||
|
; with split screen pel panning
|
||||||
|
; suppression turned on
|
||||||
|
endif
|
||||||
|
;
|
||||||
|
; Pel pan the non-split screen portion of the display; because
|
||||||
|
; split screen pel panning suppression is turned on, the split
|
||||||
|
; screen will not move as the pel panning setting cycles.
|
||||||
|
;
|
||||||
|
mov cx,200 ;pan 200 pixels to the left
|
||||||
|
call PanRight
|
||||||
|
;
|
||||||
|
; Wait for a key press (don't echo character).
|
||||||
|
;
|
||||||
|
mov ah,8 ;DOS console input without echo function
|
||||||
|
int 21h
|
||||||
|
;
|
||||||
|
; 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 horizontal pel panning setting to the value specified
|
||||||
|
; by PelPan. Waits until the start of vertical sync to do so, so
|
||||||
|
; the new pel pan setting can be loaded during non-display time
|
||||||
|
; and can be ready by the start of the next frame.
|
||||||
|
;
|
||||||
|
; Input: none
|
||||||
|
;
|
||||||
|
; Output: none
|
||||||
|
;
|
||||||
|
; Registers altered: AL, DX
|
||||||
|
;
|
||||||
|
SetPelPan proc near
|
||||||
|
call WaitForVerticalSyncStart ;also resets the AC
|
||||||
|
; Index/Data toggle
|
||||||
|
; to Index state
|
||||||
|
mov dx,AC_INDEX
|
||||||
|
mov al,PEL_PANNING+20h
|
||||||
|
;bit 5 set to 1 to keep video on
|
||||||
|
out dx,al ;point the AC Index to Pel Pan reg
|
||||||
|
mov al,[PelPan]
|
||||||
|
out dx,al ;load the new Pel Pan setting
|
||||||
|
ret
|
||||||
|
SetPelPan 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
|
||||||
|
;*********************************************************************
|
||||||
|
; Pan horizontally to the right the number of pixels specified by CX.
|
||||||
|
;
|
||||||
|
; Input: CX = # of pixels by which to pan horizontally
|
||||||
|
;
|
||||||
|
; Output: none
|
||||||
|
;
|
||||||
|
; Registers altered: 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
|
||||||
Loading…
Reference in a new issue