abrash-black-book/11-05.md
2013-12-30 20:26:41 +11:00

132 lines
No EOL
8.1 KiB
Markdown

Under ideal conditions, a 286 can access memory much, much faster than
an 8088. A 10 MHz 286 is capable of accessing a word of system memory
every 0.20 ms with **REP MOVSW**, dwarfing the 1 byte every 1.31 µs that
the 8088 in a PC can manage. However, access to display memory is
anything but ideal for a 286. For one thing, most display adapters are
8-bit devices, although newer adapters are 16-bit in nature. One
consequence of that is that only 1 byte can be read or written per
access to display memory; word-sized accesses to 8-bit devices are
automatically split into 2 separate byte-sized accesses by the AT's bus.
Another consequence is that accesses are simply slower; the AT's bus
inserts additional wait states on accesses to 8-bit devices since it
must assume that such devices were designed for PCs and may not run
reliably at AT speeds.
However, the 8-bit size of most display adapters is but one of the two
factors that reduce the speed with which the 286 can access display
memory. Far more cycles are eaten by the inherent memory-access
limitations of display adapters—that is, the limited number of display
memory accesses that display adapters make available to the 286. Look at
it this way: If **REP MOVSW** on a PC can use more than half of all
available accesses to display memory, then how much faster can code
running on a 286 or 386 possibly run when accessing display memory?
That's right—less than twice as fast.
In other words, instructions that access display memory won't run a
whole lot faster on ATs and faster computers than they do on PCs. That
explains one of the two viewpoints expressed at the beginning of this
section: The display adapter cycle-eater is just about the same on
high-end computers as it is on the PC, in the sense that it allows
instructions that access display memory to run at just about the same
speed on all computers.
Of course, the picture is quite a bit different when you compare the
performance of instructions that access display memory to the *maximum*
performance of those instructions. Instructions that access display
memory receive many more wait states when running on a 286 than they do
on an 8088. Why? While the 286 is capable of accessing memory much more
often than the 8088, we've seen that the frequency of access to display
memory is determined not by processor speed but by the display adapter
itself. As a result, both processors are actually allowed just about the
same maximum number of accesses to display memory in any given time. By
definition, then, the 286 must spend many more cycles waiting than does
the 8088.
And that explains the second viewpoint expressed above regarding the
display adapter cycle-eater vis-a-vis the 286 and 386. The display
adapter cycle-eater, as measured in cycles lost to wait states, is
indeed much worse on AT-class computers than it is on the PC, and it's
worse still on more powerful computers.
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *How bad is the display adapter cycle-eater on an AT? It's this bad: Based on my (not inconsiderable) experience in timing display adapter access, I've found that the display adapter cycle-eater can slow an AT—or even a 386 computer—to near-PC speeds when display memory is accessed.*
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
I know that's hard to believe, but the display adapter cycle-eater gives
out just so many display memory accesses in a given time, and no more,
no matter how fast the processor is. In fact, the faster the processor,
the more the display adapter cycle-eater hurts the performance of
instructions that access display memory. The display adapter cycle-eater
is not only still present in 286/386 computers, it's worse than ever.
What can we do about this new, more virulent form of the display adapter
cycle-eater? The workaround is the same as it was on the PC: Access
display memory as little as you possibly can.
#### New Instructions and Features: The 286 {#Heading13}
The 286 and 386 offer a number of new instructions. The 286 has a
relatively small number of instructions that the 8088 lacks, while the
386 has those instructions and quite a few more, along with new
addressing modes and data sizes. We'll discuss the 286 and the 386
separately in this regard.
The 286 has a number of instructions designed for protected-mode
operations. As I've said, we're not going to discuss protected mode in
this book; in any case, protected-mode instructions are generally used
only by operating systems. (I should mention that the 286's protected
mode brings with it the ability to address 16 MB of memory, a
considerable improvement over the 8088's 1 MB. In real mode, however,
programs are still limited to 1 MB of addressable memory on the 286. In
either mode, each segment is still limited to 64K.)
There are also a handful of 286-specific real-mode instructions, and
they can be quite useful. **BOUND** checks array bounds. **ENTER** and
**LEAVE** support compact and speedy stack frame construction and
removal, ideal for interfacing to high-level languages such as C and
Pascal (although these instructions are actually relatively slow on the
386 and its successors, and should be used with caution when performance
matters). **INS** and **OUTS** are new string instructions that support
efficient data transfer between memory and I/O ports. Finally, **PUSHA**
and **POPA** push and pop all eight general-purpose registers.
A couple of old instructions gain new features on the 286. For one, the
286 version of **PUSH** is capable of pushing a constant on the stack.
For another, the 286 allows all shifts and rotates to be performed for
not just 1 bit or the number of bits specified by CL, but for *any*
constant number of bits.
#### New Instructions and Features: The 386 {#Heading14}
The 386 is somewhat more complex than the 286 regarding new features.
Once again, we won't discuss protected mode, which on the 386 comes with
the ability to address up to 4 gigabytes per segment and 64 terabytes in
all. In real mode (and in virtual-86 mode, which allows the 386 to
multitask MS-DOS applications, and which is identical to real mode so
far as MS-DOS programs are concerned), programs running on the 386 are
still limited to 1 MB of addressable memory and 64K per segment.
The 386 has many new instructions, as well as new registers, addressing
modes and data sizes that have trickled down from protected mode. Let's
take a quick look at these new real-mode features.
Even in real mode, it's possible to access many of the 386's new and
extended registers. Most of these registers are simply 32-bit extensions
of the 16-bit registers of the 8088. For example, EAX is a 32-bit
register containing AX as its lower 16 bits, EBX is a 32-bit register
containing BX as its lower 16 bits, and so on. There are also two new
segment registers: FS and GS.
The 386 also comes with a slew of new real-mode instructions beyond
those supported by the 8088 and 286. These instructions can scan data on
a bit-by-bit basis, set the Carry flag to the value of a specified bit,
sign-extend or zero-extend data as it's moved, set a register or memory
variable to 1 or 0 on the basis of any of the conditions that can be
tested with conditional jumps, and more. (Again, beware: Many of these
complex 386-specific instructions are slower than equivalent sequences
of simple instructions on the 486 and especially on the Pentium.) What's
more, both old and new instructions support 32-bit operations on the
386. For example, it's relatively simple to copy data in chunks of 4
bytes on a 386, even in real mode, by using the **MOVSD** ("move string
double") instruction, or to negate a 32-bit value with **NEG eax**.