Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
34
11-03.md
34
11-03.md
|
|
@ -6,7 +6,7 @@ In short, a close relative of our old friend the 8-bit bus
|
|||
cycle-eater—the system memory wait state cycle-eater—haunts us still on
|
||||
all but zero-wait-state 286 and 386 computers, and that means that the
|
||||
prefetch queue cycle-eater is alive and well. (The system memory wait
|
||||
state cycle-eater isn’t really a new cycle-eater, but rather a variant
|
||||
state cycle-eater isn't really a new cycle-eater, but rather a variant
|
||||
of the general wait state cycle-eater, of which the display adapter
|
||||
cycle-eater is yet another variant.) While the 286 in the AT can fetch
|
||||
instructions much faster than can the 8088 in the PC, it can execute
|
||||
|
|
@ -21,7 +21,7 @@ outrun even zero—5 cycles longer than the official execution time.)
|
|||
|
||||
To summarize:
|
||||
|
||||
- Memory-accessing instructions don’t run at their official speeds on
|
||||
- Memory-accessing instructions don't run at their official speeds on
|
||||
non-zero-wait-state 286/386 computers.
|
||||
- The prefetch queue cycle-eater reduces performance on 286/386
|
||||
computers, particularly when non-zero-wait-state memory is used.
|
||||
|
|
@ -31,21 +31,21 @@ To summarize:
|
|||
performance varies from one 286/386 computer to another, making
|
||||
precise optimization impossible.
|
||||
|
||||
What’s to be learned from all this? Several things:
|
||||
What's to be learned from all this? Several things:
|
||||
|
||||
- Keep your instructions short.
|
||||
- Keep it in the registers; avoid memory, since memory generally can’t
|
||||
- Keep it in the registers; avoid memory, since memory generally can't
|
||||
keep up with the processor.
|
||||
- Don’t jump.
|
||||
- Don't jump.
|
||||
|
||||
Of course, those are exactly the rules that apply to 8088 optimization
|
||||
as well. Isn’t it convenient that the same general rules apply across
|
||||
as well. Isn't it convenient that the same general rules apply across
|
||||
the board?
|
||||
|
||||
#### Data Alignment {#Heading7 align="center"}
|
||||
|
||||
Thanks to its 16-bit bus, the 286 can access word-sized memory variables
|
||||
just as fast as byte-sized variables. There’s a catch, however: That’s
|
||||
just as fast as byte-sized variables. There's a catch, however: That's
|
||||
only true for word-sized variables that start at even addresses. When
|
||||
the 286 is asked to perform a word-sized access starting at an odd
|
||||
address, it actually performs two separate accesses, each of which
|
||||
|
|
@ -62,20 +62,20 @@ address is easy to calculate: Two accesses take twice as long as one
|
|||
access.
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *In other words, the effective capacity of the 286’s external data bus is* *halved* *when a word-sized access to an odd address is performed.*
|
||||
 *In other words, the effective capacity of the 286's external data bus is* *halved* *when a word-sized access to an odd address is performed.*
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
That, in a nutshell, is the data alignment cycle-eater, the one new
|
||||
cycle-eater of the 286 and 386. (The data alignment cycle-eater is a
|
||||
close relative of the 8088’s 8-bit bus cycle-eater, but since it behaves
|
||||
close relative of the 8088's 8-bit bus cycle-eater, but since it behaves
|
||||
differently—occurring only at odd addresses—and is avoided with a
|
||||
different workaround, we’ll consider it to be a new cycle-eater.)
|
||||
different workaround, we'll consider it to be a new cycle-eater.)
|
||||
|
||||
\
|
||||
**Figure 11.1** *The data alignment cycle-eater.*
|
||||
|
||||
The way to deal with the data alignment cycle-eater is straightforward:
|
||||
*Don’t perform word-sized accesses to odd addresses on the 286 if you
|
||||
*Don't perform word-sized accesses to odd addresses on the 286 if you
|
||||
can help it*. The easiest way to avoid the data alignment cycle-eater is
|
||||
to place the directive **EVEN** before each of your word-sized
|
||||
variables. **EVEN** forces the offset of the next byte assembled to be
|
||||
|
|
@ -85,7 +85,7 @@ by the 286 simply by preceding it with **EVEN**.
|
|||
|
||||
Listing 11.2, which accesses memory a word at a time with each word
|
||||
starting at an odd address, runs on a 10 MHz AT clone in 1.27 ms per
|
||||
repetition of **MOVSW**, or 0.64 ms per word-sized memory access. That’s
|
||||
repetition of **MOVSW**, or 0.64 ms per word-sized memory access. That's
|
||||
6-plus cycles per word-sized access, which breaks down to two separate
|
||||
memory accesses—3 cycles to access the high byte of each word and 3
|
||||
cycles to access the low byte of each word, the inevitable result of
|
||||
|
|
@ -115,7 +115,7 @@ refresh.
|
|||
On the other hand, Listing 11.3, which is exactly the same as Listing
|
||||
11.2 save that the memory accesses are word-aligned (start at even
|
||||
addresses), runs in 0.64 ms per repetition of **MOVSW**, or 0.32 µs per
|
||||
word-sized memory access. That’s 3 cycles per word-sized access—exactly
|
||||
word-sized memory access. That's 3 cycles per word-sized access—exactly
|
||||
twice as fast as the non-word-aligned accesses of Listing 11.2, just as
|
||||
we predicted.
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ The data alignment cycle-eater has intriguing implications for speeding
|
|||
up 286/386 code. The expenditure of a little care and a few bytes to
|
||||
make sure that word-sized variables and memory blocks are word-aligned
|
||||
can literally double the performance of certain code running on the 286.
|
||||
Even if it doesn’t double performance, word alignment usually helps and
|
||||
Even if it doesn't double performance, word alignment usually helps and
|
||||
never hurts.
|
||||
|
||||
#### Code Alignment {#Heading8}
|
||||
|
|
@ -150,11 +150,11 @@ never hurts.
|
|||
Lack of word alignment can also interfere with instruction fetching on
|
||||
the 286, although not to the extent that it interferes with access to
|
||||
word-sized memory variables. The 286 prefetches instructions a word at a
|
||||
time; even if a given instruction doesn’t begin at an even address, the
|
||||
time; even if a given instruction doesn't begin at an even address, the
|
||||
286 simply fetches the first byte of that instruction at the same time
|
||||
that it fetches the last byte of the previous instruction, as shown in
|
||||
Figure 11.2, then separates the bytes internally. That means that in
|
||||
most cases, instructions run just as fast whether they’re word-aligned
|
||||
most cases, instructions run just as fast whether they're word-aligned
|
||||
or not.
|
||||
|
||||
There is, however, a non-word-alignment penalty on *branches* to odd
|
||||
|
|
@ -163,7 +163,7 @@ addresses. On a branch to an odd address, the 286 is only able to fetch
|
|||
shown in Figure 11.3. In other words, lack of word alignment of the
|
||||
target instruction for any branch effectively cuts the
|
||||
instruction-fetching power of the 286 in half for the first instruction
|
||||
fetch after that branch. While that may not sound like much, you’d be
|
||||
fetch after that branch. While that may not sound like much, you'd be
|
||||
surprised at what it can do to tight loops; in fact, a brief story is in
|
||||
order.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue