141 lines
6.9 KiB
Markdown
141 lines
6.9 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](09-05.html) [Table of Contents](index.html) [Next](09-07.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
**LISTING 9.5 L9-5.ASM**
|
||
|
||
; Divides an arbitrarily long unsigned dividend by a 16-bit unsigned
|
||
; divisor. C near-callable as:
|
||
; unsigned int Div(unsigned int * Dividend,
|
||
; int DividendLength, unsigned int Divisor,
|
||
; unsigned int * Quotient);
|
||
;
|
||
; Returns the remainder of the division.
|
||
;
|
||
; Tested with TASM 2.
|
||
|
||
parms struc
|
||
dw 2 dup (?) ;pushed BP & return address
|
||
Dividend dw ? ;pointer to value to divide, stored in Intel
|
||
; order, with lsb at lowest address, msb at
|
||
; highest. Must be composed of an integral
|
||
; number of words
|
||
DividendLength dw ? ;# of bytes in Dividend. Must be a multiple
|
||
; of 2
|
||
Divisor dw ? ;value by which to divide. Must not be zero,
|
||
; or a Divide By Zero interrupt will occur
|
||
Quotient dw ? ;pointer to buffer in which to store the
|
||
; result of the division, in Intel order.
|
||
; The quotient returned is of the same
|
||
; length as the dividend
|
||
parmsends
|
||
|
||
.model small
|
||
.code
|
||
public _Div
|
||
_Divprocnear
|
||
push bp ;preserve caller’s stack frame
|
||
mov bp,sp ;point to our stack frame
|
||
push si ;preserve caller’s register variables
|
||
push di
|
||
|
||
std ;we’re working from msb to lsb
|
||
mov ax,ds
|
||
mov es,ax ;for STOS
|
||
mov cx,[bp+DividendLength]
|
||
sub cx,2
|
||
mov si,[bp+Dividend]
|
||
add si,cx ;point to the last word of the dividend
|
||
; (the most significant word)
|
||
mov di,[bp+Quotient]
|
||
add di,cx ;point to the last word of the quotient
|
||
; buffer (the most significant word)
|
||
mov bx,[bp+Divisor]
|
||
shr cx,1
|
||
inc cx ;# of words to process
|
||
sub dx,dx ;convert initial divisor word to a 32-bit
|
||
;value for DIV
|
||
DivLoop:
|
||
lod sw ;get next most significant word of divisor
|
||
div bx
|
||
sto sw ;save this word of the quotient
|
||
;DX contains the remainder at this point,
|
||
; ready to prepend to the next divisor word
|
||
loop DivLoop
|
||
mov ax,dx ;return the remainder
|
||
cld ;restore default Direction flag setting
|
||
pop di ;restore caller’s register variables
|
||
pop si
|
||
pop bp ;restore caller’s stack frame
|
||
ret
|
||
_Divendp
|
||
end
|
||
|
||
**LISTING 9.6 L9-6.C**
|
||
|
||
/* Sample use of Div function to perform division when the result
|
||
doesn’t fit in 16 bits */
|
||
|
||
#include <stdio.h>
|
||
|
||
extern unsigned int Div(unsigned int * Dividend,
|
||
int DividendLength, unsigned int Divisor,
|
||
unsigned int * Quotient);
|
||
|
||
main() {
|
||
unsigned long m, i = 0x20000001;
|
||
unsigned int k, j = 0x10;
|
||
|
||
k = Div((unsigned int *)&i, sizeof(i), j, (unsigned int *)&m);
|
||
printf(“%lu / %u = %lu r %u\n”, i, j, m, k);
|
||
}
|
||
|
||
#### Sweet Spot Revisited {#Heading9}
|
||
|
||
Way back in Volume 1, Number 1 of *PC TECHNIQUES*, (April/May 1990) I
|
||
wrote the very first of that magazine’s HAX (\#1), which extolled the
|
||
virtues of placing your most commonly-used automatic (stack-based)
|
||
variables within the stack’s “sweet spot,” the area between +127 to -128
|
||
bytes away from BP, the stack frame pointer. The reason was that the
|
||
8088 can store addressing displacements that fall within that range in a
|
||
single byte; larger displacements require a full word of storage,
|
||
increasing code size by a byte per instruction, and thereby slowing down
|
||
performance due to increased instruction fetching time.
|
||
|
||
This takes on new prominence in 386 native mode, where straying from the
|
||
sweet spot costs not one, but two or three bytes. Where the 8088 had two
|
||
possible displacement sizes, either byte or word, on the 386 there are
|
||
three possible sizes: byte, word, or dword. In native mode (32-bit
|
||
protected mode), however, a prefix byte is needed in order to use a
|
||
word-sized displacement, so a variable located outside the sweet spot
|
||
requires either two extra bytes (an extra displacement byte plus a
|
||
prefix byte) or three extra bytes (a dword displacement rather than a
|
||
byte displacement). Either way, instructions grow alarmingly.
|
||
|
||
Performance may or may not suffer from missing the sweet spot, depending
|
||
on the processor, the memory architecture, and the code mix. On a 486,
|
||
prefix bytes often cost a cycle; on a 386SX, increased code size often
|
||
slows performance because instructions must be fetched through the
|
||
half-pint 16-bit bus; on a 386, the effect depends on the instruction
|
||
mix and whether there’s a cache.
|
||
|
||
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------
|
||
 *On balance, though, it’s as important to keep your most-used variables in the stack’s sweet spot in 386 native mode as it was on the 8088.*
|
||
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
In assembly, it’s easy to control the organization of your stack frame.
|
||
In C, however, you’ll have to figure out the allocation scheme your
|
||
compiler uses to allocate automatic variables, and declare automatics
|
||
appropriately to produce the desired effect. It can be done: I did it in
|
||
Turbo C some years back, and trimmed the size of a program (admittedly,
|
||
a large one) by several K—not bad, when you consider that the “sweet
|
||
spot” optimization is essentially free, with no code reorganization,
|
||
change in logic, or heavy thinking involved.
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](09-05.html) [Table of Contents](index.html) [Next](09-07.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|