Change bold code snippets to inline code blocks
This commit is contained in:
parent
f658bfbb40
commit
3c76d884ef
185 changed files with 1772 additions and 1772 deletions
58
06-02.md
58
06-02.md
|
|
@ -14,7 +14,7 @@ The two approaches are functionally interchangeable but *not* equivalent
|
|||
from a performance standpoint, and which is better depends on the
|
||||
particular context. If it's a one-shot memory access, it's best to let
|
||||
the processor perform the addition; it's generally faster at doing this
|
||||
than a separate **ADD** instruction would be. If it's a memory access
|
||||
than a separate `ADD` instruction would be. If it's a memory access
|
||||
within a loop, however, it's advantageous on the 8088 CPU to perform the
|
||||
addition outside the loop, if possible, reducing effective address
|
||||
calculation time inside the loop, as in the following:
|
||||
|
|
@ -27,13 +27,13 @@ LoopTop:
|
|||
loop LoopTop
|
||||
```
|
||||
|
||||
Here, **MOV AL,[BX]** is two cycles faster than **MOV AL,[BX+SI]**.
|
||||
Here, `MOV AL,[BX]` is two cycles faster than `MOV AL,[BX+SI]`.
|
||||
|
||||
On a 286 or 386, however, the balance shifts. **MOV AL,[BX+SI]** takes
|
||||
no longer than **MOV AL,[BX]** on these processors because effective
|
||||
On a 286 or 386, however, the balance shifts. `MOV AL,[BX+SI]` takes
|
||||
no longer than `MOV AL,[BX]` on these processors because effective
|
||||
address calculations generally take no extra time at all. (According to
|
||||
the MASM manual, one extra clock is required if three memory addressing
|
||||
components, as in **MOV AL,[BX+SI+1]**, are used. I have not been able
|
||||
components, as in `MOV AL,[BX+SI+1]`, are used. I have not been able
|
||||
to confirm this from Intel publications, but then I haven't looked all
|
||||
that hard.) If you're optimizing for the 286 or 386, then, you can take
|
||||
advantage of the processor's ability to perform arithmetic as part of
|
||||
|
|
@ -59,15 +59,15 @@ instructions, at that.
|
|||
|
||||
How?
|
||||
|
||||
With **LEA**, the only instruction that performs memory addressing
|
||||
calculations but doesn't actually address memory. **LEA** accepts a
|
||||
With `LEA`, the only instruction that performs memory addressing
|
||||
calculations but doesn't actually address memory. `LEA` accepts a
|
||||
standard memory addressing operand, but does nothing more than store the
|
||||
calculated memory offset in the specified register, which may be any
|
||||
general-purpose register. The operation of **LEA** is illustrated in
|
||||
general-purpose register. The operation of `LEA` is illustrated in
|
||||
Figure 6.1, which also shows the operation of register-to-register
|
||||
**ADD**, for comparis on.
|
||||
`ADD`, for comparis on.
|
||||
|
||||
What does that give us? Two things that **ADD** doesn't provide: the
|
||||
What does that give us? Two things that `ADD` doesn't provide: the
|
||||
ability to perform addition with either two or three operands, and the
|
||||
ability to store the result in *any* register, not just in one of the
|
||||
source operands.
|
||||
|
|
@ -102,20 +102,20 @@ or:
|
|||
lea di,[si+2]
|
||||
```
|
||||
|
||||
Mind you, the only components **LEA** can add are BX or BP, SI or DI,
|
||||
and a constant displacement, so it's not going to replace **ADD** most
|
||||
of the time. Also, **LEA** is considerably slower than **ADD** on an
|
||||
8088, although it is just as fast as **ADD** on a 286 or 386 when fewer
|
||||
than three memory addressing components are used. **LEA** is 1 cycle
|
||||
slower than **ADD** on a 486 if the sum of two registers is used to
|
||||
point to memory, but no slower than **ADD** on a Pentium. On both a 486
|
||||
and Pentium, **LEA** can also be slowed down by addressing interlocks.
|
||||
Mind you, the only components `LEA` can add are BX or BP, SI or DI,
|
||||
and a constant displacement, so it's not going to replace `ADD` most
|
||||
of the time. Also, `LEA` is considerably slower than `ADD` on an
|
||||
8088, although it is just as fast as `ADD` on a 286 or 386 when fewer
|
||||
than three memory addressing components are used. `LEA` is 1 cycle
|
||||
slower than `ADD` on a 486 if the sum of two registers is used to
|
||||
point to memory, but no slower than `ADD` on a Pentium. On both a 486
|
||||
and Pentium, `LEA` can also be slowed down by addressing interlocks.
|
||||
|
||||

|
||||
|
||||
#### The Wonders of LEA on the 386 {#Heading5}
|
||||
|
||||
**LEA** really comes into its own as a "super-ADD" instruction on the
|
||||
`LEA` really comes into its own as a "super-ADD" instruction on the
|
||||
386, 486, and Pentium, where it can take advantage of the enhanced
|
||||
memory addressing modes of those processors. (The 486 and Pentium offer
|
||||
the same modes as the 386, so I'll refer only to the 386 from now on.)
|
||||
|
|
@ -129,15 +129,15 @@ that's good for.
|
|||
Well, the obvious advantage is that any two 32-bit registers, or any
|
||||
32-bit register and any constant, or any two 32-bit registers and any
|
||||
constant, can be added together, with the result stored in any register.
|
||||
This makes the 32-bit **LEA** much more generally useful than the
|
||||
standard 16-bit **LEA** in the role of an **ADD** with an independent
|
||||
This makes the 32-bit `LEA` much more generally useful than the
|
||||
standard 16-bit `LEA` in the role of an `ADD` with an independent
|
||||
destination.
|
||||
|
||||
![**Figure 6.2** *Operation of the 32-bit LEA reg,[Addr].*](images/06-02.jpg)
|
||||
|
||||
But what else can **LEA** do on a 386, besides add?
|
||||
But what else can `LEA` do on a 386, besides add?
|
||||
|
||||
It can multiply any register used as an index. **LEA** can multiply only
|
||||
It can multiply any register used as an index. `LEA` can multiply only
|
||||
by the power-of-two values 2, 4, or 8, but that's useful more often than
|
||||
you might imagine, especially when dealing with pointers into tables.
|
||||
Besides, multiplying by 2, 4, or 8 amounts to a left shift of 1, 2, or 3
|
||||
|
|
@ -162,8 +162,8 @@ when pointing to an entry in a doubly indexed table.
|
|||
|
||||
### Multiplication with LEA Using Non-Powers of Two {#Heading6}
|
||||
|
||||
Are you impressed yet with all that **LEA** can do on the 386? Believe
|
||||
it or not, one more feature still awaits us. **LEA** can actually
|
||||
Are you impressed yet with all that `LEA` can do on the 386? Believe
|
||||
it or not, one more feature still awaits us. `LEA` can actually
|
||||
perform a fast multiply of a 32-bit register by some values *other* than
|
||||
powers of two. You see, the same 32-bit register can be both base and
|
||||
index on the 386, and can be scaled as the index while being used
|
||||
|
|
@ -174,8 +174,8 @@ EBX by 5 with:
|
|||
lea ebx,[ebx+ebx*4]
|
||||
```
|
||||
|
||||
Without **LEA** and scaling, multiplication of EBX by 5 would require
|
||||
either a relatively slow **MUL**, along with a set-up instruction or
|
||||
Without `LEA` and scaling, multiplication of EBX by 5 would require
|
||||
either a relatively slow `MUL`, along with a set-up instruction or
|
||||
two, or three separate instructions along the lines of the following
|
||||
|
||||
```nasm
|
||||
|
|
@ -192,11 +192,11 @@ cycles is a pretty neat trick, even though it works only on a 386 or
|
|||
486.
|
||||
|
||||
> 
|
||||
> The full list of values that **LEA** can multiply a register by on a 386
|
||||
> The full list of values that `LEA` can multiply a register by on a 386
|
||||
> or 486 is: 2, 3, 4, 5, 8, and 9. That list doesn't include every
|
||||
> multiplier you might want, but it covers some commonly used ones, and
|
||||
> the performance is hard to beat.
|
||||
|
||||
I'd like to extend my thanks to Duane Strong of Metagraphics for his
|
||||
help in brainstorming uses for the 386 version of **LEA** and for
|
||||
help in brainstorming uses for the 386 version of `LEA` and for
|
||||
pointing out the complications of 486 instruction timings.
|
||||
Loading…
Reference in a new issue