⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 llegasup.asm

📁 Microsoft MS-DOS6.0 完整源代码
💻 ASM
📖 第 1 页 / 共 5 页
字号:
	xchg	ah,al		
	ror	ax,cl		;align to video
	sub	bp,8		;8 bits done
	ja	NWrLoop 	;go if bit count not exhausted
	add	bp,8		;restore BP to #bits in last byte
	cmp	cx,bp		;did we use any of the second byte?
	jb	NWrLast 	;go if so
	or	si,si		;at start of segment?
	jnz	NWrUnfl 	;go if not
	call	B$DecDS	;backup to previous segment
NWrUnfl:			
	dec	si		;move ptr back
NWrLast:
	push	ax
	and	dh,dl		;combine first|middle mask with end mask
	mov	ah,dh		;last byte bit mask
	MOV	DX,GRPADD	;address graphics controller
	mov	al,BMKREG	;  bit mask register
	EGAINT10CLI		;disable ints for direct EGA manipulation
	OUT	DX,AL		
	XCHG	AL,AH		
	INC	DX		
	OUT	DX,AL		;output bit mask
	DEC	DX		
	pop	ax
.erre	ID_SSEQDS		;assumes ss = ds
	call	bx		;put the last byte
	EGAINT10STI		;reenable ints if using EGAINT10
cEnd

NWrOvfl3:			
	call	B$BumpDS	;move array pointer over segment boundary
	jmp	short NWrOvfl2	;back to loop

	ASSUME	DS:DGROUP

;***
; B$EgaNSetC
;
;Purpose:
;	Set a horizontal line of pixels to the current attribute for EGA
;	modes.	The line starts at the current cursor position and moves right.
;
;	This becomes a bit of a mess with EGAINT10 and QCG support.  Here's
;	the current approach:
;	    No EGAINT10 (QCG or not, doesn't matter) --
;		No problem, just execute straight code, modifying the EGA
;		hardware directly where needed.
;	    EGAINT10 and no QCG --
;		Disable ints at the beginning and reenable them at the end.
;		This will work because in the worst case the entire routine
;		takes approx. 1500 clock cycles, and we are using a ceiling
;		of 1800 clock cycles between CLI/STI.
;	    EGAINT10 and QCG --
;		Now things get ugly.  We can't just disable ints over the
;		whole routine because it would exceed the 1800 clock max.
;		Instead, we use a combination of writing regs through the
;		EGAINT10 interface (like setting RWMReg, because it's needed
;		for the entire routine), and modifying regs directly within
;		small CLI/STI brackets (like setting BMKReg for a byte and
;		then restoring it before reenabling ints).
;Entry:
;	b$AddrC specifies start pixel
;	b$PenC = cursor mask and attribute
;	BX	= number of pixels to set
;Exit:
;	None
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaNSetC,<PUBLIC,NEAR>,<ES,DI>
cBegin
	EGAINT10CLI		;disable ints for entire routine if EGAINT10
	MOV	DX,GRPADD	;address of graphics index register
	MOV	AL,RWMREG	;r/w mode register
	OUT	DX,AL		;index the mode register
	MOV	AL,b$EgaWrMd	;write mode 2; odd/even or sequential addr.
	INC	DX		;to data port
	OUT	DX,AL		
	DEC	DX		;back to index port
	MOV	AL,BMKREG	
	OUT	DX,AL		;index the mask register
	INC	DX		;to data port
	les	di,b$AddrC	;graphics cursor address
	mov	cx,b$PenC	;ch = desired attribute
				;cl = cursor mask
	or	cl,cl		;left aligned in byte?
	js	NSet2a		;go if so, skip single-bit start
NSet1:
	xor	ah,ah		;zero out new mask accumulator
NSet2:
	or	ah,cl		;include this pixel in mask
	dec	bx		;decrement pixel count
	jz	NSet4		;treat as last byte if bit count exhausted
	ror	cl,1		;move 1 pixel right
	jnb	NSet2		;continue if not right-most bit
	mov	al,ah		;mask to AL for OUT
	out	dx,al		;set bit mask
	mov	al,ch		;copy desired attribute
	xchg	al,es:[di]	;set the byte
	inc	di		;bump cursor byte pointer
NSet2a:
	push	cx
	mov	al,0FFH 	;set bit mask for full bytes
	out	dx,al
	mov	ax,bx		;remaining bit count
	mov	cl,b$DivShift	;pixels/byte divisor shift
	shr	ax,cl		;compute full byte count
	jz	NSet3		;go do remaining bits if no full bytes
	xchg	ax,cx		;byte count to cx
	mov	al,ah		;attribute byte
	rep	stosb		;block write full bytes
NSet3:
	pop	cx
	and	bx,b$ModMask	;mask in remaining bit count
	jnz	NSet1		;go do remaining bits
	jmp	short NSet5	;no bits remaining - exit
NSet4:				;update last byte
	mov	al,ah		;mask to AL for OUT
	out	dx,al		;set bit mask
	xchg	ch,es:[di]	;set the byte
NSet5:
	EGAINT10STI		;reenable ints if using EGAINT10
	CALL	B$ResetEGA	;call routine to reset write mode for BIOS
cEnd


;***
; B$EgaPaintBound_11
;
;Purpose:
;	Called by PAINT before painting each scan line for
;	Screen 11 to facilitate fast viewport edge detection.
;	Set VIEW left and right cursor addresses and masks.
;Entry:
;	b$OffC = address of current pixel
;Exit:
;	B$LEOFST = left edge offset
;	B$REOFST = right edge offset
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaPaintBound_11,<PUBLIC,NEAR>
cBegin
	mov	AX,b$OffC	;video offset
	MOV	CX,80		;divisor = 80
	XOR	DX,DX
	DIV	CX		;quotient in AX = row # (INT(b$OffC/80))
	SHL	AX,1		;row * 2
	JMP	SHORT PntBndCommon ;finish the math and store the results
cEnd	<nogen>

;***
; B$EgaPaintBound_D
;
;Purpose:
;	Called by PAINT before painting each scan line for
;	Screen 7 to facilitate fast viewport edge detection.
;	Set VIEW left and right cursor addresses and masks.
;Entry:
;	b$OffC = address of current pixel
;Exit:
;	B$LEOFST = left edge offset
;	B$REOFST = right edge offset
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaPaintBound_D,<PUBLIC,NEAR>
cBegin
	mov	ax,b$OffC	;video offset
	MOV	CX,40		;divisor = 40
	XOR	DX,DX
	DIV	CX		;quotient in AX = INT(CLOC/40) -- this is row
	CALL	PntBndCommon	;finish the math and store the results
	JMP	SHORT SetColorBits ;set up ColorBits array and exit
cEnd	<nogen>

;***
; B$EgaPaintBound
;
;Purpose:
;	Called by PAINT before painting each scan line for
;	EGA modes to facilitate fast viewport edge detection.
;	Set VIEW left and right cursor addresses and masks.
;Entry:
;	b$OffC = address of current pixel
;Exit:
;	B$LEOFST = left edge offset
;	B$REOFST = right edge offset
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaPaintBound,<PUBLIC,NEAR>
cBegin
	mov	ax,b$OffC	;video offset
	MOV	CX,80		;divisor = 80
	XOR	DX,DX
	DIV	CX		;quotient in AX = INT(CLOC/80) -- this is row
	SHL	AX,1		;row * 2
	CALL	PntBndCommon	;finish the math and store the results

;	In order for SCANL and SCANR to be able to check whether any tiles
;	will actually change, we need bit-specific information about the
;	tile pattern for the current byte.  This is collected as binary
;	representations of the colors of each bit, and stored in the array
;	ColorBits.
;
;	At this point, the SetTile routine has set up the AttrTile array
;	with the tile pattern for this row. Now calculate the ColorBits
;	array.

SetColorBits:
	PUSH	DI
	PUSH	SI
	PUSH	BX
	MOV	SI,7		;offset to color array
	MOV	DI,3		;offset into AttrTile
SHFTBT:
	XOR	BH,BH		;clear byte for isolating one color
GETCOL:
	ROR	AttrTile[DI],1	;plane 3 bit
	RCL	BH,1		;rotate carry into color accumulator
	DEC	DI		;next plane
	TEST	b$Planes,2	;if 2-plane graphics --
	JZ	GETCL1		;we need to pass up next plane down --
	DEC	DI		;to find color bit for odd/even mode
	ROR	AttrTile[DI],1	;get bit for low plane
	RCL	BH,1		;rotate carry
	JMP	SHORT STTIL3
GETCL1:
	ROR	AttrTile[DI],1	;plane 2 bit
	RCL	BH,1		;rotate carry
	DEC	DI		;for 4-plane, repeat down through 0
	ROR	AttrTile[DI],1	;plane 1 bit
	RCL	BH,1
	DEC	DI
	ROR	AttrTile[DI],1	;plane 0 bit
	RCL	BH,1
STTIL3:
	MOV	ColorBits[SI],BH ;store color in array element
	MOV	DI,3		;go back to plane 3 pattern
	DEC	SI		;next lower offset in color array
	JNS	SHFTBT		;and shift out next color
	POP	BX
	POP	SI
	POP	DI
cEnd

cProc	PntBndCommon,<NEAR>
cBegin
	SHL	AX,1		;row * 2 (or row * 4)
	SHL	AX,1		;    * 4 (or row * 8)
	SHL	AX,1		;    * 8 (or row * 16)
	MOV	DX,AX		;save (row * 8) or (row * 16)
	SHL	AX,1		;row * 16 (or row * 32)
	SHL	AX,1		;row * 32 (or row * 64)
	ADD	AX,DX		;(row*32) + (row*8) = row*40 = byte address
				;(or (row*64)+(row*16)=row*80 = byte address)
				;left margin of screen at this row
	MOV	DX,AX		;two copies of this value
	ADD	AX,B$VLOFST	;byte address at (x=0) + offset to viewport
	MOV	B$LEOFST,AX	;left margin = byte address of left margin
	ADD	DX,B$VROFST	;byte address at (x=0) + offset to viewport
	MOV	B$REOFST,DX	;right margin = byte address of right margin
cEnd

;***
; B$EgaSetTile
;
;Purpose:
;	This routine stores the internal form of the current tile attribute.
;	This routine is called each time a row is to be painted.
;Entry:
;	BL = internal form of the tile attribute
;	BH = which plane the attribute is for
;Exit:
;	AttrTile[plane] = attribute
;	b$AttrC	= attribute
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaSetTile,<PUBLIC,NEAR>,<AX,DI>
cBegin
	MOV	AL,BH
	XOR	AH,AH
	MOV	DI,AX		;DI = 1 based plane number
	CMP	b$Planes,2	;2 plane system?
	JA	FOUR_PLANE
	SHL	DI,1		;plane now 2 or 4
	DEC	DI
	MOV	AttrTile[DI],BL
FOUR_PLANE:
	DEC	DI		;0 based
	MOV	AttrTile[DI],BL
	MOV	b$AttrC,BL	;set attribute to the tile attribute
cEnd

;***
; B$EgaScanInit
;
;Purpose:
;	This routine does some initialization for both ScanL and ScanR
;	for EGA modes.	Set up EGA Read/Write Mode register for color
;	compare read and EGA Color Compare register with b$PaintBorder.
;Entry:
;	None
;Exit:
;	ES:SI = Video segment address (b$AddrC)
;	CH = cursor mask	      (b$MaskC)
;	CL = flag for pixels changed  (0)
;	BX = count of pixels changed  (0)
;Uses:
;	per conv.
;Exceptions:
;******************************************************************************
cProc	B$EgaScanInit,<PUBLIC,NEAR>,<DX>
cBegin
	les	si,b$AddrC	;di=cursor offset, es=video seg
	mov	ch,b$MaskC	;ch=cursor mask
	MOV	DX,GRPADD	;address of graphics index register
	MOV	AL,RWMREG
	OUT	DX,AL		;index the mode register
	MOV	AL,8H		;set read mode 1 for color compare
	INC	DX		;to data port
	OUT	DX,AL		
	DEC	DX		;back to index port
	MOV	AL,LOW CLCREG
	OUT	DX,AL		;index the color compare register
	MOV	AL,b$PaintBorder ;set up color compare with border attribute
	INC	DX		;to data port
	OUT	DX,AL
	XOR	CL,CL		;flag for pixels changed
	XOR	BX,BX		;count of pixels changed initialized to 0
cEnd

;***
; B$EgaPAINPX
;Purpose:
;	Paint first byte (and) last byte (and) whole bytes in between
;	Fast write is left to right or v.v. depending on whether SCANR, SCANL.
;	Call has reset or set direction flag.
;
;	This becomes a bit of a mess with EGAINT10 and QCG support.  Here's
;	the current approach:
;	    No EGAINT10 (QCG or not, doesn't matter) --
;		No problem, just execute straight code, modifying the EGA
;		hardware directly where needed.
;	    EGAINT10 and no QCG --
;		Disable ints at the beginning and reenable them at the end.
;		This will work because in the worst case the entire routine
;		takes approx. 1500 clock cycles, and we are using a ceiling
;		of 1800 clock cycles between CLI/STI.  TILING is an exception:
;		If tiling is used then the routine takes too long, but there
;		is an opportune point in the middle to reenable ints and then
;		disable them again without too much of a speed hit.
;	    EGAINT10 and QCG --
;		Now things get ugly.  We can't just disable ints over the
;		whole routine because it would exceed the 1800 clock max.
;		Instead, we use a combination of writing regs through the
;		EGAINT10 interface (like setting RWMReg, because it's needed
;		for the entire routine), and modifying regs directly within
;		small CLI/STI brackets (like setting BMKReg for a byte and
;		then restoring it before reenabling ints).
;Entry:
;	DI = first byte
;	SI = last byte,
;	BL = bit mask for first byte
;	BH = bit mask for last byte
;	BP = count of whole bytes to paint in between first and last
;	CH = 00 if SCANR (for INC DI before REP) or
;	   = FF if SCANL (for DEC DI before REP)
;Exit:
;	CL = non-zero to flag pixels changed
;Uses:
;Exceptions:
;******************************************************************************

;	Now to write the whole line from [DI], first pixel, to [SI],
;	final pixel first set up for write mode 2, if solid color PAINT,
;	or 0, if tile PAINT.

cProc	B$EgaPAINPX,<PUBLIC,NEAR>,<DX>
cBegin
	MOV	DX,GRPADD
	MOV	AH,b$EgaWrMd
	CMP	b$Tiling,0
	JZ	PAINT1
	AND	AH,10H		;if TILE write, use write mode 0
PAINT1:
	MOV	AL,LOW RWMREG
	EGAINT10CLI		;disable interrupts if using EGAINT10
	OUT	DX,AL		;index the mode register
	XCHG	AL,AH		;set write mode
	INC	DX		;to data port
	OUT	DX,AL		
	DEC	DX		;back to index port

;	Set up bit mask.

	MOV	AL,LOW BMKREG
	OUT	DX,AL		;index the bit mask register
	MOV	AL,BL		
	INC	DX		;to data port
	OUT	DX,AL		
	DEC	DX		;back to index port

;	Latch

	MOV	AL,ES:[DI]
	CMP	b$Tiling,0
	JZ	NOTIL1		;tiling not on, write solid color b$AttrC
	CALL	WRTTIL		;else call routine for writing partial tile
	JMP	SHORT CHKLST	;proceed to check for a last byte
NOTIL1:

;	Write first byte.

	MOV	BL,b$AttrC
	MOV	ES:[DI],BL
CHKLST:
	OR	BH,BH		;see if a last byte to write
	JNZ	MORWRT
	CALL	CLRMSK		;all done -- clear bit mask
	JMP	SHORT WHLBYT
MORWRT:

;	Set up bit mask for last byte.

	MOV	AL,LOW BMKREG
	OUT	DX,AL		;index the bit mask register
	MOV	AL,BH		;set mask
	INC	DX		;to data port
	OUT	DX,AL		
	DEC	DX		;back to index port

;	Latch

	MOV	AL,ES:[SI]
	CMP	b$Tiling,0
	JZ	NOTIL2
	XCHG	DI,SI		;WRTTIL addresses screen with DI
	CALL	WRTTIL		;if tiling is on, set [partial] last byte
	XCHG	DI,SI		;restore DI for whole-byte write
	JMP	SHORT CLRBT1
NOTIL2:
	MOV	ES:[SI],BL	;write last byte
CLRBT1:
	CALL	CLRMSK
WHLBYT:
	OR	BP,BP		;check if intermediate whole bytes
	JZ	CLRBT2

;	Set up to write all whole bytes.

	INC	DI		;if SCANR, go right
	OR	CH,CH
	JZ	BYTE2
	DEC	DI
	DEC	DI		;else start to left of first byte
BYTE2:
	MOV	BH,CH		;may need INC/DEC flag for 2-plane write
	MOV	CX,BP		;whole-byte counter in CX
	MOV	AL,BL		;attribute in AL for no-tile speed routine
	CMP	b$Tiling,0	;see whether tiling is on
	JZ	WRITE4

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -