141 lines
No EOL
7.3 KiB
Markdown
141 lines
No EOL
7.3 KiB
Markdown
Chapter 11\
|
|
Pushing the 286 and 386 {#Heading1}
|
|
------------------------
|
|
|
|
### New Registers, New Instructions, New Timings, New Complications {#Heading2}
|
|
|
|
This chapter, adapted from my earlier book *Zen of Assembly Language*
|
|
(1989; now out of print), provides an overview of the 286 and 386, often
|
|
contrasting those processors with the 8088. At the time I originally
|
|
wrote this, the 8088 was the king of processors, and the 286 and 386
|
|
were the new kids on the block. Today, of course, all three processors
|
|
are past their primes, but many millions of each are still in use, and
|
|
the 386 in particular is still well worth considering when optimizing
|
|
software.
|
|
|
|
This chapter provides an interesting look at the evolution of the x86
|
|
architecture, to a greater degree than you might expect, for the x86
|
|
family came into full maturity with the 386; the 486 and the Pentium are
|
|
really nothing more than faster 386s, with very little in the way of new
|
|
functionality. In contrast, the 286 added a number of instructions,
|
|
respectable performance, and protected mode to the 8088's capabilities,
|
|
and the 386 added more instructions and a whole new set of addressing
|
|
modes, and brought the x86 family into the 32-bit world that represents
|
|
the future (and, increasingly, the present) of personal computing. This
|
|
chapter also provides insight into the effects on optimization of the
|
|
variations in processors and memory architectures that are common in the
|
|
PC world. So, although the 286 and 386 no longer represent the
|
|
mainstream of computing, this chapter is a useful mix of history lesson,
|
|
x86 overview, and details on two workhorse processors that are still in
|
|
wide use.
|
|
|
|
#### Family Matters {#Heading3}
|
|
|
|
While the x86 family is a large one, only a few members of the
|
|
family—which includes the 8088, 8086, 80188, 80186, 286, 386SX, 386DX,
|
|
numerous permutations of the 486, and now the Pentium—really matter.
|
|
|
|
The 8088 is now all but extinct in the PC arena. The 8086 was used
|
|
fairly widely for a while, but has now all but disappeared. The 80186
|
|
and 80188 never really caught on for use in PC and don't require further
|
|
discussion.
|
|
|
|
That leaves us with the high-end chips: the 286, the 386SX, the 386, the
|
|
486, and the Pentium. At this writing, the 386SX is fast going the way
|
|
of the 8088; people are realizing that its relatively small cost
|
|
advantage over the 386 isn't enough to offset its relatively large
|
|
performance disadvantage. After all, the 386SX suffers from the same
|
|
debilitating problem that looms over the 8088—a too-small bus.
|
|
Internally, the 386SX is a 32-bit processor, but externally, it's a
|
|
16-bit processor, a non-optimal architecture, especially for 32-bit
|
|
code.
|
|
|
|
I'm not going to discuss the 386SX in detail. If you do find yourself
|
|
programming for the 386SX, follow the same general rules you should
|
|
follow for the 8088: use short instructions, use the registers as
|
|
heavily as possible, and don't branch. In other words, avoid memory,
|
|
since the 386SX is by definition better at processing data internally
|
|
than it is at accessing memory.
|
|
|
|
The 486 is a world unto itself for the purposes of optimization, and the
|
|
Pentium is a *universe* unto itself. We'll treat them separately in
|
|
later chapters.
|
|
|
|
This leaves us with just two processors: the 286 and the 386. Each was
|
|
*the* PC standard in its day. The 286 is no longer used in new systems,
|
|
but there are millions of 286-based systems still in daily use. The 386
|
|
is still being used in new systems, although it's on the downhill leg of
|
|
its lifespan, and it is in even wider use than the 286. The future
|
|
clearly belongs to the 486 and Pentium, but the 286 and 386 are still
|
|
very much a part of the present-day landscape.
|
|
|
|
#### Crossing the Gulf to the 286 and the 386 {#Heading4}
|
|
|
|
Apart from vastly improved performance, the biggest difference between
|
|
the 8088 and the 286 and 386 (as well as the later Intel CPUs) is that
|
|
the 286 introduced protected mode, and the 386 greatly expanded the
|
|
capabilities of protected mode. We're only going to talk about real-mode
|
|
operation of the 286 and 386 in this book, however. Protected mode
|
|
offers a whole new memory management scheme, one that isn't supported by
|
|
the 8088. Only code specifically written for protected mode can run in
|
|
that mode; it's an alien and hostile environment for MS-DOS programs.
|
|
|
|
In particular, segments are different creatures in protected mode.
|
|
They're *selectors*—indexes into a table of segment descriptors—rather
|
|
than plain old registers, and can't be set to arbitrary values. That
|
|
means that segments can't be used for temporary storage or as part of a
|
|
fast indivisible 32-bit load from memory, as in
|
|
|
|
les ax,dword ptr [LongVar]
|
|
mov dx,es
|
|
|
|
which loads **LongVar** into DX:AX faster than this:
|
|
|
|
mov ax,word ptr [LongVar]
|
|
mov dx,word ptr [LongVar+2]
|
|
|
|
Protected mode uses those altered segment registers to offer access to a
|
|
great deal more memory than real mode: The 286 supports 16 megabytes of
|
|
memory, while the 386 supports 4 gigabytes (4K megabytes) of physical
|
|
memory and 64 *terabytes* (64K gigabytes!) of virtual memory.
|
|
|
|
In protected mode, your programs generally run under an operating system
|
|
(OS/2, Unix, Windows NT or the like) that exerts much more control over
|
|
the computer than does MS-DOS. Protected mode operating systems can
|
|
generally run multiple programs simultaneously, and the performance of
|
|
any one program may depend far less on code quality than on how
|
|
efficiently the program uses operating system services and how often and
|
|
under what circumstances the operating system preempts the program.
|
|
Protected mode programs are often mostly collections of operating system
|
|
calls, and the performance of whatever code *isn't* operating-system
|
|
oriented may depend primarily on how large a time slice the operating
|
|
system gives that code to run in.
|
|
|
|
In short, taken as a whole, protected mode programming is a different
|
|
kettle of fish altogether from what I've been describing in this book.
|
|
There's certainly a knack to optimizing specifically for protected mode
|
|
under a given operating system...but it's not what we've been learning,
|
|
and now is not the time to pursue it further. In general, though, the
|
|
optimization strategies discussed in this book still hold true in
|
|
protected mode; it's just issues specific to protected mode or a
|
|
particular operating system that we won't discuss.
|
|
|
|
#### In the Lair of the Cycle-Eaters, Part II {#Heading5}
|
|
|
|
Under the programming interface, the 286 and 386 differ considerably
|
|
from the 8088. Nonetheless, with one exception and one addition, the
|
|
cycle-eaters remain much the same on computers built around the 286 and
|
|
386. Next, we'll review each of the familiar cycle-eaters I covered in
|
|
Chapter 4 as they apply to the 286 and 386, and we'll look at the new
|
|
member of the gang, the data alignment cycle-eater.
|
|
|
|
The one cycle-eater that vanishes on the 286 and 386 is the 8-bit bus
|
|
cycle-eater. The 286 is a 16-bit processor both internally and
|
|
externally, and the 386 is a 32-bit processor both internally and
|
|
externally, so the Execution Unit/Bus Interface Unit size mismatch that
|
|
plagues the 8088 is eliminated. Consequently, there's no longer any need
|
|
to use byte-sized memory variables in preference to word-sized
|
|
variables, at least so long as word-sized variables start at even
|
|
addresses, as we'll see shortly. On the other hand, access to byte-sized
|
|
variables still isn't any *slower* than access to word-sized variables,
|
|
so you can use whichever size suits a given task best. |