Change bold code snippets to inline code blocks

This commit is contained in:
James Gregory 2013-12-31 17:12:29 +11:00
commit 3c76d884ef
185 changed files with 1772 additions and 1772 deletions

View file

@ -14,19 +14,19 @@ pages: 185-188
Next, we come to an item that cycle counters will love, especially since
it involves apparently incorrect documentation on Intel's part.
According to Intel's documents, all **RCR** and **RCL** instructions,
According to Intel's documents, all `RCR` and `RCL` instructions,
which perform rotations through the Carry flag, as shown in Figure 9.4,
take 9 cycles on the 386 when working with a register operand. My
measurements indicate that the 9-cycle execution time almost holds true
for *multibit* rotate-through-carries, which I've timed at 8 cycles
apiece; for example, **RCR AX,CL** takes 8 cycles on *my* 386, as does
**RCL DX,2**. Contrast that with **ROR** and **ROL**, which can rotate
apiece; for example, `RCR AX,CL` takes 8 cycles on *my* 386, as does
`RCL DX,2`. Contrast that with `ROR` and `ROL`, which can rotate
the contents of a register any number of bits in just 3 cycles.
However, rotating by one bit through the Carry flag does *not* take 9
cycles, contrary to Intel's *80386 Programmer's Reference Manual*, or
even 8 cycles. In fact, **RCR** *reg*,1 and **RCL** *reg*,1 take 3
cycles, just like **ROR, ROL, SHR,** and **SHL**. At least, that's how
even 8 cycles. In fact, `RCR` *reg*,1 and `RCL` *reg*,1 take 3
cycles, just like `ROR`, `ROL`, `SHR`, and `SHL`. At least, that's how
fast they run on my 386, and I very much doubt that you'll find
different execution times on other 386s. (Please let me know if you do,
though!)
@ -34,12 +34,12 @@ though!)
![**Figure 9.4**  *Performing rotate instructions using the Carry flag.*](images/09-04.jpg)
Interestingly, according to Intel's *i486 Microprocessor Programmer's
Reference Manual*, the 486 can **RCR** or **RCL** a register by one bit
Reference Manual*, the 486 can `RCR` or `RCL` a register by one bit
in 3 cycles, but takes between 8 and 30 cycles to perform a multibit
register **RCR** or **RCL**!
register `RCR` or `RCL`!
No great lesson here, just a caution to be leery of multibit **RCR** and
**RCL** when performance matters—and to take cycle-time documentation
No great lesson here, just a caution to be leery of multibit `RCR` and
`RCL` when performance matters—and to take cycle-time documentation
with a grain of salt.
#### Hardwired Far Jumps {#Heading11}
@ -47,8 +47,8 @@ with a grain of salt.
Did you ever wonder how to code a far jump to an absolute address in
assembly language? Probably not, but if you ever do, you're going to be
glad for this next item, because the obvious solution doesn't work. You
might think all it would take to jump to, say, 1000:5 would be **JMP FAR
PTR 1000:5**, but you'd be wrong. That won't even assemble. You might
might think all it would take to jump to, say, 1000:5 would be `JMP FAR
PTR 1000:5`, but you'd be wrong. That won't even assemble. You might
then think to construct in memory a far pointer containing 1000:5, as in
the following:
@ -60,9 +60,9 @@ Ptr dd ?
jmp [Ptr]
```
That will work, but at a price in performance. On an 8088, **JMP DWORD
PTR [*mem*]** (an indirect far jump) takes at least 37 cycles; **JMP
DWORD PTR *label*** (a direct far jump) takes only 15 cycles (plus,
That will work, but at a price in performance. On an 8088, `JMP DWORD
PTR [*mem*]` (an indirect far jump) takes at least 37 cycles; `JMP
DWORD PTR *label*` (a direct far jump) takes only 15 cycles (plus,
almost certainly, some cycles for instruction fetching). On a 386, an
indirect far jump is documented to take at least 43 cycles in real mode
(31 in protected mode); a direct far jump is documented to take at least
@ -81,7 +81,7 @@ preferable.
Listing 9.7 shows a short program that performs a direct far call to
1000:5. (Don't run it, unless you want to crash your system!) It does
this by creating a dummy segment at 1000H, so that the label
**FarLabel** can be created with the desired far attribute at the proper
`FarLabel` can be created with the desired far attribute at the proper
location. (Segments created with "AT" don't cause the generation of any
actual bytes or the allocation of any memory; they're just templates.)
It's a little kludgey, but at least it does work. There may be a better
@ -132,8 +132,8 @@ mov eax,1
```
takes only 2 cycles to execute, but is 5 bytes long (because native mode
constants are dwords and the **MOV** instruction doesn't sign-extend).
Both code fragments are ways to set **EAX** to 1 (although the first
constants are dwords and the `MOV` instruction doesn't sign-extend).
Both code fragments are ways to set `EAX` to 1 (although the first
affects the flags and the second doesn't); this is a classic trade-off
of speed for space. Second,
@ -148,15 +148,15 @@ move bx,-1
```
takes 2 cycles to execute and is 5 bytes long. Both instructions set
**EBX** to -1; this is a classic trade-off of—gee, it's not a trade-off
at all, is it? **OR** is a better way to set a 32-bit register to all
1-bits, just as **SUB** or **XOR** is a better way to set a register to
`EBX` to -1; this is a classic trade-off of—gee, it's not a trade-off
at all, is it? `OR` is a better way to set a 32-bit register to all
1-bits, just as `SUB` or `XOR` is a better way to set a register to
all 0-bits. Who woulda thunk it? Just goes to show how the 32-bit
displacements and constants of 386 native mode change the familiar
landscape of 80x86 optimization.
Be warned, though, that I've found **OR, AND, ADD**, and the like to be
a cycle slower than **MOV** when working with immediate operands on the
Be warned, though, that I've found `OR`, `AND`, `ADD`, and the like to be
a cycle slower than `MOV` when working with immediate operands on the
386 under some circumstances, for reasons that thus far escape me. This
just reinforces the first rule of optimization: Measure your code in
action, and place not your trust in documented cycle times.