mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
17 KiB
497 lines
17 KiB
title "V7 hardware pointer routines"
|
|
|
|
;-----------------------------Module-Header-----------------------------;
|
|
; Module Name: V7CURSOR.ASM
|
|
;
|
|
; This file contains the pointer shape routines to support the Video-
|
|
; Seven hardware pointer.
|
|
;
|
|
; Copyright (c) 1983-1992 Microsoft Corporation
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.386p
|
|
.model small,c
|
|
|
|
include i386\egavga.inc
|
|
include i386\v7vga.inc
|
|
include callconv.inc
|
|
|
|
; Mirrors structure in V7.H.
|
|
|
|
HW_POINTER_SHIFT_INFO struc
|
|
ulXShift dd ?
|
|
ulYShift dd ?
|
|
ulShiftedFlag dd ?
|
|
HW_POINTER_SHIFT_INFO ends
|
|
|
|
.code
|
|
|
|
page
|
|
;--------------------------Public-Routine-------------------------------;
|
|
; draw_pointer
|
|
;
|
|
; Draw a cursor based at (ulVptlX,ulVptlY) (upper left corner).
|
|
;
|
|
; The currently defined cursor/icon is drawn. If the old
|
|
; cursor/icon is currently on the screen, it is removed.
|
|
;
|
|
; Note: restores all standard VGA registers used to original state.
|
|
;
|
|
; Entry:
|
|
; Passed parameters on stack:
|
|
; (vptlX,vptlY) = location to which to move pointer
|
|
; pointerLoadAddress -> virtual address of V7 display memory into
|
|
; which to load pointer masks
|
|
; pointerLoadAddress -> V7 bank into which to load pointer masks
|
|
; Returns:
|
|
; None
|
|
; Error Returns:
|
|
; None
|
|
; Registers Preserved:
|
|
; EBX,ESI,EDI,EBP,DS,ES
|
|
; Registers Destroyed:
|
|
; EAX,ECX,EDX,flags
|
|
; Calls:
|
|
; load_cursor
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cPublicProc V7DrawPointer,6,< \
|
|
uses esi edi ebx, \
|
|
lVptlX: dword, \
|
|
lVptlY: dword, \
|
|
pLoadAddress: dword, \
|
|
ulLoadBank: dword, \
|
|
pAndMask: ptr, \
|
|
pShiftInfo: ptr >
|
|
|
|
; Save the state of the banking and set the read and write banks to access the
|
|
; pointer bitmap.
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov al,SEQ_BANK
|
|
out dx,al
|
|
inc edx
|
|
in al,dx
|
|
push eax
|
|
mov al,byte ptr ulLoadBank
|
|
shl al,2 ;CPU read bank
|
|
or al,0c0h ;line compare reset & counter bank enab
|
|
or al,byte ptr ulLoadBank ;CPU write bank
|
|
out dx,al
|
|
dec edx
|
|
|
|
; See if the masks need to be shifted; if they do, shift and
|
|
; load them. If the default masks can be used but the last masks
|
|
; loaded were shifted, load the default masks.
|
|
|
|
mov eax,lVptlX
|
|
mov ebx,lVptlY
|
|
mov ecx,ebx
|
|
or ecx,eax ;is either coordinate negative?
|
|
jns draw_cursor_unshifted ;no-make sure the unshifted masks
|
|
; are loaded
|
|
;yes-make sure the right shift
|
|
; pattern is loaded
|
|
|
|
; Determine the extent of the needed adjustment to the masks.
|
|
|
|
; If X is positive, no X shift is needed; if it is negative,
|
|
; then its absolute value is the X shift amount.
|
|
|
|
and eax,eax
|
|
jns short dcs_p1
|
|
neg eax ;required X shift
|
|
jmp short dcs_p2
|
|
|
|
align 4
|
|
dcs_p1:
|
|
sub eax,eax ;no X shift required
|
|
dcs_p2:
|
|
|
|
; If Y is positive, no Y shift is needed; if it is negative,
|
|
; then its absolute value is the Y shift amount.
|
|
|
|
and ebx,ebx
|
|
jns short dcs_p3
|
|
neg ebx ;required Y shift
|
|
jmp short dcs_p4
|
|
|
|
align 4
|
|
dcs_p3:
|
|
sub ebx,ebx
|
|
dcs_p4:
|
|
cmp ebx,PTR_HEIGHT ;keep Y in the range 1-PTR_HEIGHT
|
|
jbe short ck_x_overflow
|
|
mov ebx,PTR_HEIGHT
|
|
ck_x_overflow:
|
|
cmp eax,(PTR_WIDTH * 8) ;keep X in the range
|
|
; 0 through ( PTR_WIDTH * 8 )
|
|
jb short ck_current_shift
|
|
mov ebx,PTR_HEIGHT ;if X is fully off the screen,
|
|
; simply move Y off the screen, which
|
|
; is simpler to implement below
|
|
|
|
; Shifted masks are required. If the currently loaded masks are shifted in the
|
|
; same way as the new masks, don't need to do anything; otherwise, the shifted
|
|
; masks have to be generated and loaded.
|
|
|
|
ck_current_shift:
|
|
mov edi,pShiftInfo
|
|
cmp [edi].ulShiftedFlag,1 ;if there are no currently loaded
|
|
; masks or the currently loaded masks
|
|
; are unshifted, must load shifted
|
|
; masks
|
|
mov edi,pShiftInfo
|
|
jnz short generate_shifted_masks ;no currently loaded shifted masks
|
|
cmp eax,[edi].ulXShift ;if X and Y shifts are both the
|
|
jnz short generate_shifted_masks ; same as what's already loaded
|
|
cmp ebx,[edi].ulYShift ; memory, then there's no need
|
|
; to do anything
|
|
jz draw_cursor_set_location ;Don't need to do anything
|
|
|
|
; Load the V7 cursor with the masks, shifted as required by
|
|
; the current X and Y.
|
|
|
|
generate_shifted_masks:
|
|
|
|
mov [edi].ulXShift,eax
|
|
mov [edi].ulYShift,ebx
|
|
|
|
pushfd ;save direction flag
|
|
std ;count down
|
|
|
|
mov edi,eax ;preserve X shift value
|
|
|
|
; Save the original latches.
|
|
|
|
mov al,SEQ_LATCH0
|
|
out dx,al
|
|
inc edx
|
|
in al,dx
|
|
push eax
|
|
dec edx
|
|
mov al,SEQ_LATCH1
|
|
out dx,al
|
|
inc edx
|
|
in al,dx
|
|
push eax
|
|
dec edx
|
|
mov al,SEQ_LATCH2
|
|
out dx,al
|
|
inc edx
|
|
in al,dx
|
|
push eax
|
|
dec edx
|
|
mov al,SEQ_LATCH3
|
|
out dx,al
|
|
inc edx
|
|
in al,dx
|
|
push eax
|
|
|
|
; Set the Map Mask to enable all planes.
|
|
|
|
mov eax,SEQ_MAP_MASK + 00f00h
|
|
out dx,ax
|
|
|
|
; Set the Bit Mask to write the latches only.
|
|
|
|
mov edx,EGA_BASE + GRAF_ADDR
|
|
mov eax,GRAF_BIT_MASK + 00000h
|
|
out dx,ax
|
|
|
|
mov eax,edi ;retrieve X shift value
|
|
|
|
; Load the masks.
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
xchg al,bl ;BL=X shift value, AL=Y shift value
|
|
cbw
|
|
cwde
|
|
neg eax
|
|
add eax,PTR_HEIGHT ;unpadded length of cursor
|
|
mov cl,bl
|
|
and cl,7 ;X partial byte portion (bit shift)
|
|
neg bl
|
|
add bl,(PTR_WIDTH * 8) ;convert to number of full bytes
|
|
shr bl,1 ; still on screen
|
|
shr bl,1
|
|
shr bl,1 ;X full byte portion (full byte shift)
|
|
|
|
mov edi,pLoadAddress ;start of cursor load area
|
|
add edi,HW_POINTER_LOAD_LEN-1 ;EDI points to the end of the
|
|
; cursor load area in VEGAVGA memory
|
|
mov esi,pAndMask
|
|
add esi,(PTR_HEIGHT*PTR_WIDTH*2)-1
|
|
;ESI points to the end of the default
|
|
; XOR mask
|
|
push ebp
|
|
sub ebp,ebp ;pad XOR mask with 0
|
|
call shift_mask ;generate shifted XOR mask
|
|
pop ebp
|
|
|
|
mov esi,pAndMask
|
|
add esi,(PTR_HEIGHT*PTR_WIDTH)-1
|
|
; AND mask
|
|
push ebp
|
|
mov ebp,-1 ;pad AND mask with 0ffh
|
|
call shift_mask ;generate shifted AND mask
|
|
pop ebp
|
|
|
|
; Restore default Bit Mask setting.
|
|
|
|
mov edx,EGA_BASE + GRAF_ADDR
|
|
mov eax,GRAF_BIT_MASK + 0ff00h
|
|
out dx,ax
|
|
|
|
; Restore original latch contents.
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov al,SEQ_LATCH3
|
|
out dx,al
|
|
inc edx
|
|
pop eax
|
|
out dx,al
|
|
dec edx
|
|
mov al,SEQ_LATCH2
|
|
out dx,al
|
|
inc edx
|
|
pop eax
|
|
out dx,al
|
|
dec edx
|
|
mov al,SEQ_LATCH1
|
|
out dx,al
|
|
inc edx
|
|
pop eax
|
|
out dx,al
|
|
dec edx
|
|
mov al,SEQ_LATCH0
|
|
out dx,al
|
|
inc edx
|
|
pop eax
|
|
out dx,al
|
|
|
|
mov esi,pShiftInfo
|
|
mov [esi].ulShiftedFlag,1 ;mark that the currently loaded
|
|
; masks are shifted
|
|
popfd ;restore direction flag
|
|
|
|
jmp short draw_cursor_set_location
|
|
|
|
|
|
; Default masks can be used. See if any masks are loaded into V7 memory; if so
|
|
; see if they were shifted: if they were, load unshifted masks; if they
|
|
; weren't, the masks are already properly loaded into V7 memory.
|
|
align 4
|
|
draw_cursor_unshifted:
|
|
mov esi,pShiftInfo
|
|
cmp [esi].ulShiftedFlag,0 ;are there any currently loaded masks,
|
|
; and if so, are they shifted?
|
|
jz short draw_cursor_set_location ;no-all set
|
|
;yes-load unshifted masks
|
|
mov esi,pAndMask ;ESI points to default masks
|
|
|
|
; Copy the cursor patterns into V7 mask memory, one plane at a time.
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov al,SEQ_MAP_MASK
|
|
out dx,al ;point SC Index to Map Mask
|
|
inc edx ;point to SC Data
|
|
mov al,8 ;start with plane 3
|
|
mov ebx,esi
|
|
add ebx,3
|
|
load_cursor_plane_loop:
|
|
out dx,al ;enable selected plane
|
|
mov ecx,PTR_HEIGHT*2 ;move 1 byte per scan line of each mask
|
|
mov esi,ebx ;point to next pattern portion to load
|
|
mov edi,pLoadAddress ;start of cursor load area
|
|
load_cursor_mask_loop:
|
|
movsb
|
|
add esi,3 ;skip data for other 3 planes
|
|
dec ecx
|
|
jnz load_cursor_mask_loop
|
|
dec ebx ;point to pattern for previous plane
|
|
shr al,1
|
|
jnc load_cursor_plane_loop
|
|
|
|
; Restore the default Map Mask.
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov eax,SEQ_MAP_MASK + 00f00h
|
|
out dx,ax
|
|
|
|
mov esi,pShiftInfo
|
|
mov [esi].ulShiftedFlag,0 ;mark that the currently loaded masks
|
|
; are unrotated
|
|
; Set the new cursor location.
|
|
|
|
draw_cursor_set_location:
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov ecx,lVptlX ;set X coordinate
|
|
and ecx,ecx
|
|
jns short set_x_coord ;if negative, force to 0 (the masks in
|
|
sub ecx,ecx ; V7 memory have already been shifted
|
|
; to compensate)
|
|
set_x_coord:
|
|
|
|
mov ebx,lVptlY ;set Y coordinate
|
|
and ebx,ebx
|
|
jns short set_y_coord ;if negative, force to 0 (the masks in
|
|
sub ebx,ebx ; V7 memory have already been shifted
|
|
; to compensate)
|
|
set_y_coord:
|
|
|
|
mov ah,ch
|
|
mov al,SEQ_PXH
|
|
out dx,ax
|
|
mov ah,cl
|
|
mov al,SEQ_PXL
|
|
out dx,ax
|
|
|
|
mov ah,bh
|
|
mov al,SEQ_PYH
|
|
out dx,ax
|
|
mov ah,bl
|
|
mov al,SEQ_PYL
|
|
out dx,ax
|
|
|
|
; Restore V7 registers to their original states.
|
|
|
|
pop eax
|
|
mov ah,al
|
|
mov al,SEQ_BANK
|
|
out dx,ax ;restore original banking state
|
|
|
|
mov edx,EGA_BASE + SEQ_ADDR
|
|
mov al,SEQ_MAP_MASK
|
|
out dx,al ;restore default sequencer index
|
|
|
|
stdRET V7DrawPointer
|
|
|
|
stdENDP V7DrawPointer
|
|
|
|
page
|
|
;--------------------------------------------------------------------;
|
|
; shift_mask
|
|
;
|
|
; Loads a shifted cursor mask.
|
|
;
|
|
; Input: EAX = unpadded mask length (vertical shift)
|
|
; EBX = # of full unpadded mask bytes to use per scan line
|
|
; upper word *must* be 0!
|
|
; CL = amount of shift to left (horizontal shift)
|
|
; DX = SC index port
|
|
; DS:ESI = --> to last byte of unshifted mask to load
|
|
; ES:EDI = --> to last byte of V7 mask memory to load
|
|
; EBP = pad value
|
|
; DF set (STD, to increment toward lower addresses)
|
|
;
|
|
; Output: DS:ESI = --> to byte before start of unshifted mask loaded
|
|
; ES:EDI = --> to byte before start of V7 mask memory loaded
|
|
;
|
|
; BH, CH destroyed.
|
|
; Latches destroyed.
|
|
; Map Mask must enable all planes.
|
|
;--------------------------------------------------------------------;
|
|
|
|
align 4
|
|
shift_mask proc near
|
|
|
|
push eax ;save unpadded mask height
|
|
push ecx ;preserve X shift amount
|
|
|
|
; Load the latches with the pad value, then write all cursor scan
|
|
; lines off the bottom with those pad-filled latches.
|
|
|
|
neg eax
|
|
add eax,PTR_HEIGHT ;get pad length at bottom of cursor
|
|
mov ecx,eax
|
|
mov eax,ebp ;get pad value
|
|
mov al,SEQ_LATCH3 ;set latch 3 to pad value
|
|
out dx,ax
|
|
mov al,SEQ_LATCH2 ;set latch 2 to pad value
|
|
out dx,ax
|
|
mov al,SEQ_LATCH1 ;set latch 1 to pad value
|
|
out dx,ax
|
|
mov al,SEQ_LATCH0 ;set latch 0 to pad value
|
|
out dx,ax
|
|
|
|
and ecx,ecx ;if there's nothing to pad vertically,
|
|
jz short @F ; don't modify the cursor pattern (but
|
|
; still needed to load the latches, for
|
|
; padding below)
|
|
rep stosb ;write the pad values for all scan lines
|
|
; off the bottom
|
|
@@:
|
|
pop ecx ;restore X shift amount
|
|
pop eax ;retrieve unpadded cursor height
|
|
|
|
; Copy the lower part of the default mask to the top of the shifted
|
|
; mask, shifting in the X coordinate and padding the right edge
|
|
; of the mask with the specified value (in AH).
|
|
|
|
and eax,eax ;is the cursor fully off the top of the
|
|
; screen?
|
|
jz short end_shift_mask ;yes, cursor is blank, so done
|
|
|
|
push eax ;save unpadded mask height
|
|
|
|
shift_mask_line_loop:
|
|
push eax ;save remaining unpadded mask length
|
|
|
|
mov ch,SEQ_LATCH0-1 ;load high latch to low latch (high latch 1st)
|
|
add ch,bl ;add # of full bytes
|
|
and cl,cl ;any partial byte?
|
|
jz short @F ;no
|
|
inc ch ;yes-do the partial byte
|
|
mov eax,ebp ;get the pad value
|
|
lodsb ;get the partial byte
|
|
rol ax,cl ;shift the partial byte, bringing the
|
|
; pad value in as the lsb(s)
|
|
xchg ah,al ;put the shifted partial byte in AH
|
|
xchg al,ch ;put the latch index in AL
|
|
out dx,ax ;write partial byte
|
|
dec eax ;point to the previous latch index
|
|
xchg al,ch ;put the latch index in CH
|
|
xchg al,ah ;put the shifted partial byte in AX
|
|
shr eax,cl ;put the partial byte back to byte alignment
|
|
@@:
|
|
and bl,bl
|
|
jz short shift_mask_write_line ;see if there are any full bytes
|
|
mov bh,bl ;working full byte count
|
|
|
|
shift_mask_byte_loop:
|
|
mov ah,[esi] ;get current mask byte
|
|
dec esi ;point to next mask byte
|
|
rol ax,cl ;prepare the shifted byte
|
|
xchg al,ch ;get latch index
|
|
out dx,ax ;put shifted byte in latch
|
|
dec eax ;point to the previous latch index
|
|
xchg al,ch ;put the latch index in CH
|
|
ror ax,cl ;put this byte back to byte alignment
|
|
mov al,ah ;make this the previous byte
|
|
dec bh ;count down full bytes
|
|
jnz shift_mask_byte_loop
|
|
|
|
shift_mask_write_line:
|
|
stosb ;any remaining latches are already loaded
|
|
; with the pad value, so write this scan
|
|
; line of the mask
|
|
sub esi,4 ;point 1 byte back past the start of the next
|
|
; scan in source
|
|
add esi,ebx ;point to the last byte of scan in source
|
|
cmp cl,1
|
|
sbb esi,-1 ;advance 1 more if partial byte
|
|
shift_mask_no_partial_adjust:
|
|
pop eax ;retrieve remaining unpadded mask length
|
|
dec eax
|
|
jnz shift_mask_line_loop
|
|
|
|
pop eax ;restore unpadded mask height
|
|
|
|
end_shift_mask:
|
|
ret
|
|
shift_mask endp
|
|
|
|
end
|
|
|