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

📄 dynamic.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 2 页
字号:
	PUSH	DI

;
;	SI:DI are used to accumulate the 32-bit offset of the array element.
;	CX is the loop counter for each index of the array access.
;	BX points to within the array descriptor.
;	BP points to within the stack frame.
;	DX:AX are used for intermediate calculations (including MUL).
;
;	Clear the offset accumulation in SI:DI and get and check the
;	number of indices in the array.
;
	XOR	SI,SI		;clear the running...
	MOV	DI,SI		;...accumulator for the offset
	MOV	CX,ci		; get number of indices from stack
	CMP	CL,[BX].AD_cDims ;test against dimensions in the AD
	JNE	HAryError	;if not the same, then jump to error
;
;	Within the offset calculation loop for each index, BP points
;	to the current index in the stack frame and BX points to the
;	current dimension count in the array descriptor.  Indices are
;	processed from last to first.
;
	PUSH	BX		;save registers again...
	PUSH	BP		;(save BP last for error routines)

	ADD	BP,8		;point to last index in the frame
	ADD	BX,AD_tDM	; points to first DM, last dim count...
	JMP	SHORT HAryStart ;jump to start within the loop
;
;	Calculation loop.  Adjust BP and BX to point to the next
;	index in the array.
;
HAryLoop:

	INC	BP		;point BP to next word...
	INC	BP		;...up the frame on the stack
	ADD	BX,SIZE DM	; point BX to the next index in the AD

;	Multiply SI:DI by the new dimension count.  Since each
;	index is in legal range in the AD, overflow is not possible.

	MOV	AX,DI		;get low word of accumulator
	MUL	[BX].DM_cElements ;multiply by current dimension count
	MOV	DI,AX		;put low word of product in accumulator
	MOV	AX,SI		;get high word of accumulator
	MOV	SI,DX		;accumulator SI:DI has first product
	MUL	[BX].DM_cElements ;multiply high word by count
	ADD	SI,AX		;add low word to high word of accumulator

;	Start within loop.  Get the array index and check if it is
;	within the bounds specified in the AD.	If not, report an error.

HAryStart:
	MOV	AX,[BP] 	;get the array index
	SUB	AX,[BX].DM_iLbound ;subtract lower bound to get index offset
	JL	HAryErrorPopBP	;if negative, then error
	CMP	AX,[BX].DM_cElements ;test if equal or larger than count
	JGE	HAryErrorPopBP	;if so, then error

;	Add array index offset to the accumulator in SI:DI.
;	Loop if more dimensions to process.

	ADD	DI,AX		;add index offset to DI...
	ADC	SI,0		;...and propagate carry to SI
	LOOP	HAryLoop	;loop on CX if more to process

	POP	BP		;restore registers saved before loop
	POP	BX

;	Finish the offset calculation by multiplying by the element
;	size and adding the AD offset.

	MOV	AX,DI		;get low word of accumulator
	MUL	[BX].AD_cbElement ;multiply by element byte count
	MOV	DI,AX		;put low word of product in accumulator
	MOV	AX,SI		;get high word of accumulator
	MOV	SI,DX		;accumulator SI:DI has first product
	MUL	[BX].AD_cbElement ;multiply high word by count
	ADD	SI,AX		;add low word to high word of accumulator

	ADD	DI,[BX].AD_fhd.FHD_oData ;add offset to accumulator...
Finish: 			
	ADC	SI,CX		;...and propagate the carry (CX=0 from LOOP)

;	From the 32-bit offset in SI:DI, compute the far pointer in ES:BX.

	GETSEG	AX,[BX].AD_fhd.FHD_hData,BX	;get segment from the AD
	OR	AX,AX		;test if segment is zero
	JZ	BadSubError	;if so, then array is unallocated
	MOV	CL,b$HugeShift ;get OS dependent shift count...
;	MOV	CL,12		;conversion count from 64K to 16...
	SHL	SI,CL		;...to calculate segment
	ADD	AX,SI		;segment is calculated (far ptr in AX:DI)

;	Move far pointer in AX:DI to ES:BX.

	MOV	ES,AX		;move segment of pointer
NearArray:			
	MOV	BX,DI		;move offset of pointer

	MOV	AX,ci		; AX = number of dimensions on stack
	INC	AX		; 1 extra parameter
	SHL	AX,1		; number of parameter bytes <dim #>*2 + 2
	MOV	b$Buf1,AX	; save # of bytes of parms to clear

	POP	DI		;restore registers
	POP	SI
	POP	DX
	POP	CX
	POP	AX

cEnd	nogen			; fall into CleanStack

;*** 
; CleanStack -- Common return for B$HARY and DIM_COMMON.  Added with [18].
;
;Purpose:
;	Clears variable number of bytes off the stack that are below BP and
;	a return address. Restores BP and jumps to the desired return address.
;
;Entry:
;	b$Buf1 = number of bytes to clear
;Exit:
;	None
;Uses:
;	b$Buf1
;Preserves:
;	All
;Exceptions:
;	None
;
;******************************************************************************
CleanStack:
	POP	BP		; restore BP
	POP	[b$Buf1+2]	; [b$Buf1+2] = far return address
	POP	[b$Buf1+4]
	ADD	SP,b$Buf1	; clean parameters from stack
	JMP	DWORD PTR [b$Buf1+2] ; return far

BadSubError:			
	JMP	B$ERR_BS	;process bad subscript error

	SUBTTL	B$LBND and B$UBND - LBOUND and UBOUND Functions
	PAGE
;***
; B$LBND and B$UBND - LBOUND and UBOUND Functions
; Added rev [11]
;
; Function:
;	Return the lowest or highest legal index for a
;	specified array dimension.
;
; NOTE: In the interpeter (QB), the pointer to the array descriptor is actually
; a pointer into the variable heap. This heap cannot move during this
; operation.
;
; Inputs:
;	pAd	ds relative array descriptor offset
;		(FV_LONGPTR only: pAd is a long ptr to the Ad)
;	iDim	1 relative index to array dimension
;
; Ouputs:
;	ax	lower or upper bound of the indicated dimension
;
; Registers:
;	none
;
;******************************************************************************

cProc	B$LBND,<FAR,PUBLIC>
cBegin	nogen
	XOR	CX,CX				;cx = 0 == LBOUND
	SKIP	2
cEnd	nogen					;fall OVER MOV CX,SP

cProc	B$UBND,<FAR,PUBLIC>
cBegin	nogen
	MOV	CX,SP				;cx <> 0 == UBOUND
cEnd	nogen					;fall INTO common routine

cProc	ULbound,FAR				;common routine to fall into
parmW	pAd					;pointer to array descriptor
parmW	iDim					;Index to desired dimension
cBegin

	MOV	DX,iDim
	mov	bx,pAd				;get pAD into register
	XOR	AX,AX				;Assume iDim out of range case
	CMP	[bx].AD_fhd.FHD_hData,AX	;test if segment is zero
	JZ	BadSubError			; Branch if unallocated
	SUB	DL,[BX].AD_cDims		;not this many dimensions?
	JA	BadSubError			; out of range: bad sub
						; treats negs as out of range
.errnz	(SIZE DM)-4
	NEG	DL				;Index to DIM info
						; Zero relative, always +
	SHL	DX,1				;To word offset
	SHL	DX,1				;2 word fields in DM
	ADD	BX,DX				;Index to dim iDim information
	MOV	AX,[BX.AD_tDM.DM_iLbound]	;Lower bound
	JCXZ	BOUNDX				;Return LBOUND
	ADD	AX,[BX.AD_tDM.DM_cElements]	;Count of elements
	DEC	AX				;To highest index
BOUNDX:

cEnd

	SUBTTL	B$ERAS - erase an array
	PAGE
;***
; B$ERAS - erase an array
; B$IErase - erase an array, but do not try to reclaim dgroup.
;
;Purpose:
; With the array descriptor given, erase the array.  For dynamic arrays, the
; space is deallocated. For static arrays, the array is only cleared. For
; static string arrays, the strings are deallocated.
;
; NOTE: In the interpeter (QB), the pointer to the array descriptor is actually
; a pointer into the variable heap. This heap cannot move during this
; operation.
;
;Entry:
;	pAd	ds relative array descriptor offset
;		(FV_LONGPTR only: pAd is a long ptr to the Ad)
;Exit:
;	None.
;Uses:
;	AX, BX, CX, DX.
;Exceptions:
;	None.
;******************************************************************************
cProc	B$ERAS,<FAR,PUBLIC>	
cBegin	nogen			


	MOV	AX,1		; nz to allow heap movement
	SKIP	2		

cEnd	nogen			

cProc	B$IErase,<FAR,PUBLIC>	
cBegin	nogen			

	XOR	AX,AX		; z to disable heap movement


cEnd	nogen			

cProc	ERASE_COMMON,FAR,<SI,DI>
parmW	pAd			
cBegin				

;	Get the array descriptor and test if array is static or dynamic.

	mov	bx,pAd			;get pAD into register
	mov	cx,[bx].AD_fhd.FHD_hData 
	jcxz	ErasReturn		 ; nothing to do if unalloc'd

	TEST	[bx].AD_fFeatures,FADF_STATIC ;test if a static array
	JNZ	ErasStatic		;if static, then jump

;	Dynamic array.	If not allocated, then just return.  Then test
;	if it is a string array.

	xor	si,si			
	MOV	[bx].AD_fhd.FHD_cPara,si;clear size field
	xchg	si,[bx].AD_fhd.FHD_hData;Get segment/SB, mark deallocated
	TEST	[bx].AD_fFeatures,FADF_SD;test if a string array
	JZ	ErasDynNumAry		;if not, dealloc dynamic numeric array

;	Dynamic string array.  Get the array offset and deallocate it.

	MOV	SI,[bx].AD_fhd.FHD_oData   ;get offset of array from AD
	PUSH	AX		; Save compaction flag
	CALL	B$LHDALC	; deallocate heap entry and compact heap
	POP	CX		; [CX] = compaction flag
	JCXZ	ErasReturn	
	CALL	B$LH_CPCT	; Compact when we're allowed to
	JMP	SHORT ErasReturn ;done - jump to return

;	Dynamic numeric array.	Deallocate it through its descriptor.

ErasDynNumAry:
	PUSH	AX		; Save movement flag
	cCall	B$FHDealloc	; deallocate the FH entry
	POP	CX		
	JCXZ	ErasReturn	; if movement not allowed, just return
	cCall	B$FHTestRaiseBottom ; Else try to reclaim DGROUP
	JMP	SHORT ErasReturn ;done - jump to return

;	Static array.  First get the base offset and compute its size.
;	Test if string or numeric.

ErasStatic:
	CALL	B$ADArraySize	; get the array size in bytes in DX:AX
	MOV	CX,AX		;put the size into CX
	MOV	DI,[bx].AD_fhd.FHD_oData   ;get the base offset from the AD
	TEST	[bx].AD_fFeatures,FADF_SD  ;test if string array
	JZ	ErasStatNumAry	;if not, then numeric and jump

;	Static string array.  Deallocate all strings referenced in
;	loop with BX pointing to each descriptor in the entry.

	SHR	CX,1		;divide byte count to get word count

	SHR	CX,1		;divide word count to get number of strings
	PUSH	BX		; Save array pointer
	MOV	BX,DI		;point to start of entry
ErasStatLoop:
	CALL	B$STDALC	;deallocate the string pointed by desc at BX
	ADD	BX,4		;point to the next descriptor
	LOOP	ErasStatLoop	;loop until done with entry
        MOV     CX,AX           ;get the length of entry back
	POP	BX		; get AD pointer back

;       Static array.  Clear the array entry of CX bytes at offset DI.

ErasStatNumAry:
	INC	CX		; Round up length if odd.
	SHR	CX,1		;Number of words to be cleared.
        XOR     AX,AX           ;value to clear entry
	GETSEG	ES,[bx].AD_fhd.FHD_hData,,<SIZE,LOAD>	;get seg from the AD
        REP     STOSW           ;clear the entry

;	Done - restore and return.

ErasReturn:

cEnd				

sEnd				
	END

⌨️ 快捷键说明

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