📄 xmain.asm
字号:
mov [_SplitScrnActive],TRUE
mov ax,[Line]
jns @@NotNeg ; Check that Split Scrn start scan line is +ve
mov ax,0 ; Since -ve set to 0
@@NotNeg:
mov [_SplitScrnScanLine],ax ; save the scanline
or [DoubleScanFlag],0
jz @@NotDoubleScanned
shl ax,1
dec ax
@@NotDoubleScanned:
;mov cl,[DoubleScanFlag]
;shl ax,cl ; Mode X 200 and 240 line modes are actually
; 400 and 480 lines that are double scanned
; so for start scanline multiply required ModeX
; scan line by 2 if its a double scanned mode
mov bx,ax ; save the scanline
WaitVsyncStart ; wait for vertical retrace
cli ; Dont allow register setting to be interrupted
mov dx,CRTC_INDEX
mov ah,bl
mov al,LINE_COMPARE
out dx,ax ; Bits 7-0 of the split screen scan line
mov ah,bh
and ah,1
shl ah,4
mov al,OVERFLOW ; Bit 4 of overflow register = Bit 8 of split
out dx,al ; screen scan line,
inc dx ; So using readability of VGA registers
in al,dx ; Read the OVERFLOW register, and set the
and al, not 10h ; bit corresponding to Bit 8 (above)
or al,ah
out dx,al
dec dx
mov ah,bh
and ah,2
ror ah,3
mov al,MAX_SCAN_LINE ; Bit 6 of max scan line register =
out dx,al ; Bit 9 of split screen scan line
inc dx ; As we did before, update the apropriate
in al,dx ; bit without disturbing the rest
and al, not 40h
or al,ah
out dx,al
sti ; Registers are set, so interrupts are safe
mov ax,[_ScrnPhysicalHeight] ; Determine where the first byte
sub ax,[_SplitScrnScanLine] ; of the non split screen video ram
mov [_SplitScrnVisibleHeight],ax ; starts and store it for reference
mov bx,[_ScrnLogicalByteWidth]
mul bx
mov [_Page0_Offs],ax
mov [_Page1_Offs],ax
mov [_Page2_Offs],ax
; calculate no. non split screen rows in video ram
mov cx,0ffffh ; cx = Maximum video ram offset
sub cx,ax ; cx = cx - _Page0_Offs
xchg cx,ax ; swap cx and ax
sub dx,dx ; DX:AX is divide operand, set DX = 0
div bx ; divide ax (prev cx) by
; ScrnLogicalByteWidth
mov [_ScrnLogicalHeight],ax ; Save Screen Logical Height
cmp ax,[_BottomClip]
jle @@BottomClipOK ; Adjust Clip Rectangle if necessary
mov [_BottomClip],ax
@@BottomClipOK:
sub ax,[_SplitScrnScanLine] ; Update the maximum Y position of
mov [_MaxScrollY],ax ; Physical screen in logical screen
xchg cx,ax ; restore original ax (MainScrnOfs)
mov bh,al ; Set the visible screen start address
mov ch,ah ; to the top left corner of the virtual
jmp StartAddrEntry ; screen
_x_set_splitscreen endp
;-----------------------------------------------------------------------
; Mode X (256 color mode) Page flip primer
; No clipping is performed.
; C near-callable as:
;
; void x_page_flip(unsigned int x, unsigned int y);
;
; Swaps visible and hidden page offsets and then executes the SetStartAddr
; to achieve a page flip.
;
; SEE x_set_start_addr below
;
; Written by Themie Gouthas
;------------------------------------------------------------------------
_x_page_flip proc
ARG x:word,y:word
push bp ;preserve caller's stack frame
mov bp,sp ;point to local stack frame
push si
mov si,[x]
mov ax,[_ScrnLogicalByteWidth] ; Calculate Offset increment
mov cx,[y]
mul cx ; for Y
cmp [_DoubleBufferActive],TRUE ; Do we have double buffering ?
je @@DoubleBuffer
cmp [_TrippleBufferActive],TRUE
jne PageFlipEntry1
; TrippleBuffer
mov bx,[_HiddenPageOffs]
xchg bx,[_VisiblePageOffs]
xchg bx,[_WaitingPageOffs]
mov [_HiddenPageOffs],bx
mov bx,[_VisiblePageIdx]
inc bx
cmp bx,3
jne @@IdxOk
xor bx,bx
@@IdxOk:
mov [_VisiblePageIdx],bx
jmp short PageFlipEntry2
@@DoubleBuffer:
mov bx,[_HiddenPageOffs]
xchg bx,[_VisiblePageOffs] ; Swap the Page Offsete
xchg [_HiddenPageOffs],bx
xor [_VisiblePageIdx],01h ; Set the Visible page index
jmp short PageFlipEntry2
_x_page_flip endp
;-----------------------------------------------------------------------
; Mode X (256 color mode) Set Mode X non split screen start address
; of logical screen.
; C near-callable as:
;
; void x_set_start_addr(unsigned int x, unsigned int y);
;
; Params: StartOffset is offset of first byte of logical screen ram
; (Useful if you want to double buffer by splitting your non
; split screen video ram into 2 pages)
; X,Y coordinates of the top left hand corner of the physical screen
; within the logical screen
; X must not exceed (Logical screen width - Physical screen width)
; Y must not exceed (Logical screen height - Physical screen height)
;
;
; Written by Themie Gouthas,
; Parts addapted from M. Abrash code published in DDJ Mag.
;------------------------------------------------------------------------
_x_set_start_addr proc
ARG x:word,y:word
push bp
mov bp,sp
push si
mov si,[x]
mov ax,[_ScrnLogicalByteWidth] ; Calculate Offset increment
mov cx,[y] ; for Y
mul cx
cmp [_DoubleBufferActive],TRUE ; Do we have double buffering ?
je @@PageResolution
cmp [_TrippleBufferActive],TRUE
je @@PageResolution
PageFlipEntry1:
add ax,[_Page0_Offs] ; no - add page 0 offset
jmp short @@AddColumn
PageFlipEntry2:
mov [_PhysicalStartPixelX],si
mov [_PhysicalStartY],cx
@@PageResolution:
add ax,[_VisiblePageOffs] ; Add visible page offset
@@AddColumn:
mov cx,si
shr cx,2
mov [_PhysicalStartByteX],cx
add ax,cx ; add the column offset for X
mov bh,al ; setup CRTC start addr regs and
; values in word registers for
mov ch,ah ; fast word outs
StartAddrEntry:
mov bl,ADDR_LOW
mov cl,ADDR_HIGH
and si,0003h ; select pel pan register value for the
mov ah,PelPanMask[si] ; required x coordinate
mov al,PEL_PANNING+20h
mov si,ax
cmp [_VsyncHandlerActive],TRUE
jne @@NoVsyncHandler
; NEW STUFF
@@WaitLast:
cmp [_StartAddressFlag],0
jne @@WaitLast
cli
mov [_WaitingStartLow],bx
mov [_WaitingStartHigh],cx
mov [_WaitingPelPan],si
mov [_StartAddressFlag],1
sti
jmp short @@Return
@@NoVsyncHandler:
mov dx,INPUT_STATUS_0 ;Wait for trailing edge of Vsync pulse
@@WaitDE:
in al,dx
test al,01h
jnz @@WaitDE ;display enable is active low (0 = active)
mov dx,CRTC_INDEX
mov ax,bx
cli
out dx,ax ;start address low
mov ax,cx
out dx,ax ;start address high
sti
; Now wait for vertical sync, so the other page will be invisible when
; we start drawing to it.
mov dx,INPUT_STATUS_0 ;Wait for trailing edge of Vsync pulse
@@WaitVS:
in al,dx
test al,08h
jz @@WaitVS ;display enable is active low (0 = active)
mov dx,AC_INDEX
mov ax,si ; Point the attribute controller to pel pan
cli
out dx,al ; reg. Bit 5 also set to prevent blanking
mov al,ah
out dx,al ; load new Pel Pan setting.
sti
@@Return:
mov [_ErrorValue],OK
pop si
pop bp
ret
_x_set_start_addr endp
;-----------------------------------------------------------------------
; Mode X (256 color mode) Mode X split screen hide
; C near-callable as:
;
; void x_hide_splitscreen()
;
; Hides an existing split screen by setting its starting scan line to
; the last physical screen scan line
;
; WARNING: Only to be used if SplitScrnLine has been previously called
; WARNING: DO NOT USE with mode 5-11 (320x400-376x564). The memory for
; the initial split screen is reserved and the size limitations
; of these modes means any change in the split screen scan line
; will encroach on the split screen ram
;
; Written by Themie Gouthas
;------------------------------------------------------------------------
_x_hide_splitscreen proc
push bp
mov bp,sp
cmp [_SplitScrnActive],TRUE
je @@SplitScreenEnabled
@@error:
mov [_ErrorValue],ERROR
pop bp
ret
@@SplitScreenEnabled:
cmp [_CurrXMode],4 ; Do nothing for Modes > 2
jg @@error
mov bx,[_ScrnPhysicalHeight]
mov ax,[_ScrnLogicalHeight]
sub ax,bx
mov [_MaxScrollY],ax
xor ax,ax
mov [_SplitScrnVisibleHeight],ax
or [DoubleScanFlag],0
jz @@NotDoubleScanned
shl bx,1
dec bx
@@NotDoubleScanned:
;mov cl,[DoubleScanFlag] ; Compensate for double scanned modes
;shl bx,cl
WaitVsyncStart ; wait for vertical retrace
cli ; Dont allow register setting to be interrupted
mov dx,CRTC_INDEX
mov ah,bl
mov al,LINE_COMPARE
out dx,ax ; Bits 7-0 of the split screen scan line
mov ah,bh
and ah,1
shl ah,4
mov al,OVERFLOW ; Bit 4 of overflow register = Bit 8 of split
out dx,al ; screen scan line,
inc dx ; So using readability of VGA registers
in al,dx ; Read the OVERFLOW register, and set the
and al, not 10h ; bit corresponding to Bit 8 (above)
or al,ah
out dx,al
dec dx
mov ah,bh
and ah,2
ror ah,3
mov al,MAX_SCAN_LINE ; Bit 6 of max scan line register =
out dx,al ; Bit 9 of split screen scan line
inc dx ; As we did before, update the apropriate
in al,dx ; bit without disturbing the rest
and al, not 40h
or al,ah
out dx,al
sti ; Registers are set, so interrupts are safe
@@done:
mov [_ErrorValue],OK
pop bp
ret
_x_hide_splitscreen endp
;-----------------------------------------------------------------------
; Mode X (256 color mode) Mode X split screen show
; C near-callable as:
;
; void x_show_splitscreen()
;
; Restores split screen start scan line to the initial split screen
; starting scan line as set by SplitScrnLine.
;
; WARNING: Only to be used if SplitScrnLine has been previously called
; WARNING: DO NOT USE with mode 5-11 (320x400-376x564). The memory for
; the initial split screen is reserved and the size limitations
; of these modes means any change in the split screen scan line
; will encroach on the split screen ram
; Update: Now disabled for these modes
;
; Written by Themie Gouthas
;------------------------------------------------------------------------
_x_show_splitscreen proc
push bp
mov bp,sp
cmp [_SplitScrnActive],TRUE
je @@SplitScreenEnabled
@@error:
mov [_ErrorValue],ERROR
pop bp
ret
@@SplitScreenEnabled:
cmp [_CurrXMode],4 ; Do nothing for Modes > 2
jg @@error
mov bx,[_SplitScrnScanLine]
mov ax,[_ScrnLogicalHeight] ; Update Max Scroll Y
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -