Normal quotes

This commit is contained in:
James Gregory 2013-12-30 18:34:31 +11:00
commit 18011c595a
352 changed files with 6040 additions and 6040 deletions

View file

@ -21,19 +21,19 @@ of PC programmers to pedal-to-the-metal optimization.
This chapter focuses almost entirely on the first popular x86-family
processor, the 8088. Some of the specific features and results that I
cite in this chapter are no longer applicable to modern x86-family
processors such as the 486 and Pentium, as I’ll point out later on when
processors such as the 486 and Pentium, as I'll point out later on when
we discuss those processors. Nonetheless, the overall theme of this
chapter—that understanding dimly-seen and poorly-documented code
gremlins called cycle-eaters that lurk in your system is essential to
performance programming—is every bit as valid today. Also, later
chapters often refer back to the basic cycle-eaters described in this
chapter, so this chapter is the foundation for the discussions of
x86-family optimization to come. What’s more, the Zen timer remains an
x86-family optimization to come. What's more, the Zen timer remains an
excellent tool with which to flush out and examine cycle-eaters, as
we’ll see in later chapters, and this chapter is as good an illustration
of how to use the Zen timer as you’re likely to find.
we'll see in later chapters, and this chapter is as good an illustration
of how to use the Zen timer as you're likely to find.
So, don’t take either the absolute or the relative execution times
So, don't take either the absolute or the relative execution times
presented in this chapter as gospel for newer processors, and read on to
later chapters to see how the cycle-eaters and optimization rules have
changed over time, but do take the time to at least skim through this
@ -46,8 +46,8 @@ Programming has many levels, ranging from the familiar (high-level
languages, DOS calls, and the like) down to the esoteric things that lie
on the shadowy edge of hardware-land. I call these *cycle-eaters*
because, like the monsters in a bad 50s horror movie, they lurk in those
shadows, taking their share of your program’s performance without regard
to the forces of goodness or the U.S. Army. In this chapter, we’re going
shadows, taking their share of your program's performance without regard
to the forces of goodness or the U.S. Army. In this chapter, we're going
to jump right in at the lowest level by examining the cycle-eaters that
live beneath the programming interface; that is, beneath your
application, DOS, and BIOS—in fact, beneath the instruction set itself.
@ -55,15 +55,15 @@ application, DOS, and BIOS—in fact, beneath the instruction set itself.
Why start at the lowest level? Simply because cycle-eaters affect the
performance of all assembler code, and yet are almost unknown to most
programmers. A full understanding of code optimization requires an
understanding of cycle-eaters and their implications. That’s no simple
understanding of cycle-eaters and their implications. That's no simple
task, and in fact it is in precisely that area that most books and
articles about assembly programming fall short.
Nearly all literature on assembly programming discusses only the
programming interface: the instruction set, the registers, the flags,
and the BIOS and DOS calls. Those topics cover the functionality of
assembly programs most thoroughly—but it’s performance above all else
that we’re after. No one ever tells you about the raw stuff of
assembly programs most thoroughly—but it's performance above all else
that we're after. No one ever tells you about the raw stuff of
performance, which lies *beneath* the programming interface, in the
dimly-seen realm—populated by instruction prefetching, dynamic RAM
refresh, and wait states—where software meets hardware. This area is the
@ -78,56 +78,56 @@ Which brings us to cycle-eaters.
Cycle-eaters are gremlins that live on the bus or in peripherals (and
sometimes within the CPU itself), slowing the performance of PC code so
that it doesn’t execute at full speed. Most cycle-eaters (and all of
those haunting the older Intel processors) live outside the CPU’s
that it doesn't execute at full speed. Most cycle-eaters (and all of
those haunting the older Intel processors) live outside the CPU's
Execution Unit, where they can *only* affect the CPU when the CPU
performs a bus access (a memory or I/O read or write). Once your code
and data are already inside the CPU, those cycle-eaters can no longer be
a problem. Only on the 486 and Pentium CPUs will you find cycle-eaters
inside the chip, as we’ll see in later chapters.
inside the chip, as we'll see in later chapters.
The nature and severity of the cycle-eaters vary enormously from
processor to processor, and (especially) from memory architecture to
memory architecture. In order to understand them all, we need first to
understand the simplest among them, those that haunted the original
8088-based IBM PC. Later on in this book, I’ll be better able to explain
8088-based IBM PC. Later on in this book, I'll be better able to explain
the newer generation of cycle-eaters in terms of those ancestral
cycle-eaters—but we have to get the groundwork down first.
#### The 8088’s Ancestral Cycle-Eaters {#Heading5}
#### The 8088's Ancestral Cycle-Eaters {#Heading5}
Internally, the 8088 is a 16-bit processor, capable of running at full
speed at all times—unless external data is required. External data must
traverse the 8088’s external data bus and the PC’s data bus one byte at
traverse the 8088's external data bus and the PC's data bus one byte at
a time to and from peripherals, with cycle-eaters lurking along every
step of the way. What’s more, external data includes not only memory
step of the way. What's more, external data includes not only memory
operands *but also instruction bytes,* so even instructions with no
memory operands can suffer from cycle-eaters. Since some of the 8088’s
fastest instructions are register-only instructions, that’s important
memory operands can suffer from cycle-eaters. Since some of the 8088's
fastest instructions are register-only instructions, that's important
indeed.
The major cycle-eaters are:
- The 8088’s 8-bit external data bus.
- The 8088's 8-bit external data bus.
- The prefetch queue.
- Dynamic RAM refresh.
- Wait states, notably display memory wait states and, in the AT and
80386 computers, system memory wait states.
The locations of these cycle-eaters in the primordial 8088-based PC are
shown in Figure 4.1. We’ll cover each of the cycle-eaters in turn in
this chapter. The material won’t be easy since cycle-eaters are among
shown in Figure 4.1. We'll cover each of the cycle-eaters in turn in
this chapter. The material won't be easy since cycle-eaters are among
the most subtle aspects of assembly programming. By the same token,
however, this will be one of the most important and rewarding chapters
in this book. Don’t worry if you don’t catch everything in this chapter,
in this book. Don't worry if you don't catch everything in this chapter,
but do read it all even if the going gets a bit tough. Cycle-eaters play
a key role in later chapters, so some familiarity with them is highly
desirable.
### The 8-Bit Bus Cycle-Eater {#Heading6}
*Look! Down on the motherboard! It’s a 16-bit processor! It’s an 8-bit
processor! It’s...*
*Look! Down on the motherboard! It's a 16-bit processor! It's an 8-bit
processor! It's...*
...an 8088!
@ -138,7 +138,7 @@ processor.
The 8088 is internally a full 16-bit processor, equivalent to an 8086.
(In fact, the 8086 is identical to the 8088, except that it has a full
16-bit bus. The 8088 is basically the poor man’s 8086, because it allows
16-bit bus. The 8088 is basically the poor man's 8086, because it allows
a cheaper—albeit slower—system to be built, thanks to the half-sized
bus.) In terms of the instruction set, the 8088 is clearly a 16-bit
processor, capable of performing any given 16-bit operation—addition,