_80x86 OPTIMIZATION_
by Michael Abrash


[LISTING ONE]

; Copies one string to another string, converting all characters to
; uppercase in the process, using a loop containing LODSB and STOSB.
; Adapted from Zen of Assembly Language, by Michael Abrash; not a
; standalone program, but designed to be used with the Zen timer from
; that book via the Zen timer's PZTIME.BAT batch file: ZTimerOn starts
; the clock, ZTimerOff stops it, and the test-bed program linked in by
; PZTIME.BAT starts the program, reports the results, and ends.

	jmp	Skip		;skip over data in CS and subroutine

SourceString	label	word		;sample string to copy
	db	'This space intentionally left not blank',0
DestString	db	100 dup (?)	;destination for copy

; Copies one zero-terminated string to another string,
; converting all characters to uppercase.
; Input: DS:SI = start of source string; DS:DI = start of destination buffer
; Output: none
; Registers altered: AX, BX, SI, DI, ES
; Direction flag cleared

CopyStringUpper:
	mov	ax,ds
	mov	es,ax	;for STOS
	mov	bl,'a'	;set up for fast register-register
	mov	bh,'z'	; comparisons
	cld
StringUpperLoop:
	lodsb		;get next character and point to following character
	cmp	al,bl	;below 'a'?
	jb	IsUpper	;yes, not lowercase
	cmp	al,bh	;above 'z'?
	ja	IsUpper	;yes, not lowercase
	and	al,not 20h ;is lowercase-make uppercase
IsUpper:
	stosb		;put character into new string and point to 
                        ; following location
	and	al,al	;is this the zero that marks end of the string?
	jnz	StringUpperLoop ;no, do the next character
	ret

; Calls CopyStringUpper to copy & convert SourceString->DestString.
Skip:
	call	ZTimerOn		;start timing
	mov	si,offset SourceString	;point SI to the string to copy from
	mov	di,offset DestString	;point DI to the string to copy to
	call	CopyStringUpper		;copy & convert to uppercase
	call	ZTimerOff		;stop timing


[LISTING TWO]

; Copies one string to another string, converting all characters to
; uppercase in the process, using no string instructions.
; Not a standalone program, but designed to be used with the Zen
; timer, as described in Listing 1.

	jmp	Skip		;skip over data in CS and subroutine

SourceString	label	word		;sample string to copy
	db	'This space intentionally left not blank',0
DestString	db	100 dup (?)	;destination for copy

; Copies one zero-terminated string to another string,
; converting all characters to uppercase. 
; Input: DS:SI = start of source string; DS:DI = start of destination string
; Output: none
; Registers altered: AL, BX, SI, DI

CopyStringUpper:
	mov	bl,'a'	;set up for fast register-register
	mov	bh,'z'	; comparisons
StringUpperLoop:
	mov	al,[si]	;get the next character and
	inc	si	; point to the following character
	cmp	al,bl	;below 'a'?
	jb	IsUpper	;yes, not lowercase
	cmp	al,bh	;above 'z'?
	ja	IsUpper	;yes, not lowercase
	and	al,not 20h ;is lowercase-make uppercase
IsUpper:
	mov	[di],al	;put the character into the new string and
	inc	di	; point to the following location
	and	al,al	;is this the zero that marks the end of the string?
	jnz	StringUpperLoop ;no, do the next character
	ret

; Calls CopyStringUpper to copy & convert SourceString->DestString.
Skip:
	call	ZTimerOn
	mov	si,offset SourceString	;point SI to the string to copy from
	mov	di,offset DestString	;point DI to the string to copy to
	call	CopyStringUpper		;copy & convert to uppercase
	call	ZTimerOff


[LISTING THREE]

; Clears a buffer using MOV/ADD in a loop.
; Not a standalone program, but designed to be used with the Zen
; timer, as described in Listing 1.

	mov	dx,2		;repeat the test code twice, to make
				; sure it's in the cache (if there is one)
	mov	bx,dx		;distance from the start of one word
				; to the start of the next
	sub	ax,ax		;set buffer to zeroes
TestTwiceLoop:
	mov	cx,1024		;clear 1024 words starting at address
	mov	di,8000h	; DS:8000h (this is just unused memory
				; past the end of the program)
	call	ZTimerOn	;start timing (resets timer to 0)
StoreLoop:
	mov	[di],ax		;clear the current word
	add	di,bx		;point to the next word
	dec	cx		;count off words to clear until none
	jnz	StoreLoop	; remain
	call	ZTimerOff	;stop timing
	dec	dx		;count off passes through test code
	jz	StoreDone	;that was the second pass; we're done
	jmp	TestTwiceLoop	;that was first pass; do second pass with all 
                                ; instructions and data in the cache
StoreDone:


[LISTING FOUR]

; Clears a buffer using MOV/ADD in an unrolled loop.
; Not a standalone program, but designed to be used with the Zen
; timer, as described in Listing 1.

	mov	dx,2		;repeat the test code twice, to make
				; sure it's in the cache (if there is one)
	mov	bx,dx		;distance from the start of one word
				; to the start of the next
	sub	ax,ax		;set buffer to zeroes
TestTwiceLoop:
	mov	si,1024		;clear 1024 words starting at address
	mov	di,8000h	; DS:8000h (this is just unused memory
				; past the end of the program)
	call	ZTimerOn	;start timing (resets timer to 0)
	mov	cl,4		;divide the count of words to clear by
	shr	si,cl		; 16, because we'll clear 16 words
				; each time through the loop
StoreLoop:
	REPT	16		;clear 16 words in a row without looping
	mov	[di],ax		;clear the current word
	add	di,bx		;point to the next word
	ENDM
	dec	si		;count off blocks of 16 words to clear
	jnz	StoreLoop	; until none remain
	call	ZTimerOff	;stop timing
	dec	dx		;count off passes through test code
	jz	StoreDone	;that was the second pass; we're done
	jmp	TestTwiceLoop	;that was the first pass; do the second pass 
                                ; with all instructions and data in the cache
StoreDone:

