Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
40
11-06.md
40
11-06.md
|
|
@ -2,32 +2,32 @@
|
|||
[Previous](11-05.html) [Table of Contents](index.html) [Next](11-07.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
Finally, it’s possible in real mode to use the 386’s new addressing
|
||||
Finally, it's possible in real mode to use the 386's new addressing
|
||||
modes, in which *any* 32-bit general-purpose register or pair of
|
||||
registers can be used to address memory. What’s more, multiplication of
|
||||
registers can be used to address memory. What's more, multiplication of
|
||||
memory-addressing registers by 2, 4, or 8 for look-ups in word,
|
||||
doubleword, or quadword tables can be built right into the memory
|
||||
addressing mode. (The 32-bit addressing modes are discussed further in
|
||||
later chapters.) In protected mode, these new addressing modes allow you
|
||||
to address a full 4 gigabytes per segment, but in real mode you’re still
|
||||
to address a full 4 gigabytes per segment, but in real mode you're still
|
||||
limited to 64K, even with 32-bit registers and the new addressing modes,
|
||||
unless you play some unorthodox tricks with the segment registers.
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *Note well: Those tricks don’t necessarily work with system software such as Windows, so I’d recommend against using them. If you want 4-gigabyte segments, use a 32-bit environment such as Win32.*
|
||||
 *Note well: Those tricks don't necessarily work with system software such as Windows, so I'd recommend against using them. If you want 4-gigabyte segments, use a 32-bit environment such as Win32.*
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#### Optimization Rules: The More Things Change... {#Heading15 align="center"}
|
||||
|
||||
Let’s see what we’ve learned about 286/386 optimization. Mostly what
|
||||
we’ve learned is that our familiar PC cycle-eaters still apply, although
|
||||
Let's see what we've learned about 286/386 optimization. Mostly what
|
||||
we've learned is that our familiar PC cycle-eaters still apply, although
|
||||
in somewhat different forms, and that the major optimization rules for
|
||||
the PC hold true on ATs and 386-based computers. You won’t go wrong on
|
||||
the PC hold true on ATs and 386-based computers. You won't go wrong on
|
||||
any of these computers if you keep your instructions short, use the
|
||||
registers heavily and avoid memory, don’t branch, and avoid accessing
|
||||
registers heavily and avoid memory, don't branch, and avoid accessing
|
||||
display memory like the plague.
|
||||
|
||||
Although we haven’t touched on them, repeated string instructions are
|
||||
Although we haven't touched on them, repeated string instructions are
|
||||
still desirable on the 286 and 386 since they provide a great deal of
|
||||
functionality per instruction byte and eliminate both the prefetch queue
|
||||
cycle-eater and branching. However, string instructions are not quite so
|
||||
|
|
@ -35,8 +35,8 @@ spectacularly superior on the 286 and 386 as they are on the 8088 since
|
|||
non-string memory-accessing instructions have been speeded up
|
||||
considerably on the newer processors.
|
||||
|
||||
There’s one cycle-eater with new implications on the 286 and 386, and
|
||||
that’s the data alignment cycle-eater. From the data alignment
|
||||
There's one cycle-eater with new implications on the 286 and 386, and
|
||||
that's the data alignment cycle-eater. From the data alignment
|
||||
cycle-eater we get a new rule: Word-align your word-sized variables, and
|
||||
start your subroutines at even addresses.
|
||||
|
||||
|
|
@ -58,8 +58,8 @@ calculation time. Where an 8088 takes from 5 to 12 cycles to calculate
|
|||
an EA, a 286 or 386 usually takes no time whatsoever to perform the
|
||||
calculation. If a base+index+displacement addressing mode, such as **MOV
|
||||
AX,[WordArray+bx+si]**, is used on a 286 or 386, 1 cycle is taken to
|
||||
perform the EA calculation, but that’s both the worst case and the only
|
||||
case in which there’s any EA overhead at all.
|
||||
perform the EA calculation, but that's both the worst case and the only
|
||||
case in which there's any EA overhead at all.
|
||||
|
||||
The elimination of EA calculation time means that the EU execution time
|
||||
of memory-addressing instructions is much closer to the EU execution
|
||||
|
|
@ -69,10 +69,10 @@ time of register-only instructions. For instance, on the 8088 **ADD
|
|||
**ADD [WordVar],100H** is a 7-cycle instruction, while **ADD DX,100H**
|
||||
is a 3-cycle instruction—a ratio of just 2.3 to 1.
|
||||
|
||||
It would seem, then, that it’s less necessary to use the registers on
|
||||
the 286 than it was on the 8088, but that’s simply not the case, for
|
||||
reasons we’ve already seen. The key is this: The 286 can execute
|
||||
memory-addressing instructions so fast that there’s no spare instruction
|
||||
It would seem, then, that it's less necessary to use the registers on
|
||||
the 286 than it was on the 8088, but that's simply not the case, for
|
||||
reasons we've already seen. The key is this: The 286 can execute
|
||||
memory-addressing instructions so fast that there's no spare instruction
|
||||
prefetching time during those instructions, so the prefetch queue runs
|
||||
dry, especially on the AT, with its one-wait-state memory. On the AT,
|
||||
the 6-byte instruction **ADD [WordVar],100H** is effectively at least a
|
||||
|
|
@ -82,15 +82,15 @@ and write the result back to memory.
|
|||
|
||||
Granted, the register-only instruction **ADD DX,100H** also slows
|
||||
down—to 6 cycles—because of instruction prefetching, leaving a ratio of
|
||||
2.5 to 1. Now, however, let’s look at the performance of the same code
|
||||
2.5 to 1. Now, however, let's look at the performance of the same code
|
||||
on an 8088. The register-only code would run in 16 cycles (4 instruction
|
||||
bytes at 4 cycles per byte), while the memory-accessing code would run
|
||||
in 40 cycles (6 instruction bytes at 4 cycles per byte, plus 2
|
||||
word-sized memory accesses at 8 cycles per word). That’s a ratio of 2.5
|
||||
word-sized memory accesses at 8 cycles per word). That's a ratio of 2.5
|
||||
to 1, *exactly the same as on the 286*.
|
||||
|
||||
This is all theoretical. We put our trust not in theory but in actual
|
||||
performance, so let’s run this code through the Zen timer. On a PC,
|
||||
performance, so let's run this code through the Zen timer. On a PC,
|
||||
Listing 11.4, which performs register-only addition, runs in 3.62 ms,
|
||||
while Listing 11.5, which performs addition to a memory variable, runs
|
||||
in 10.05 ms. On a 10 MHz AT clone, Listing 11.4 runs in 0.64 ms, while
|
||||
|
|
|
|||
Loading…
Reference in a new issue