finished discussion of newly introduced instructions

This commit is contained in:
Perry Kivolowitz 2022-07-13 11:24:33 -05:00
parent fe34c2a9fd
commit 2614ef9ae4
2 changed files with 94 additions and 37 deletions

View file

@ -12,8 +12,7 @@ Bit bashing is the manipulation of individual bits. Bit
bashing goes to the very core of the C language. Remember that C is a
high level assembly language, as we argue in Section 1 of this book.
And C is the (later) language in which Unix was implemented and indeed,
C was
developed specifically to implement Unix.
C was developed specifically to implement Unix.
Since an operating system directly
interfaces with hardware - the C language grew to have features
@ -45,7 +44,7 @@ Consider a data structure for which there will be potentially millions of
instances in RAM. Or, perhaps billions of instances on disc. Suppose you
need 8 boolean members in every instance. The C++ standard does not
define the size of a `bool` instead leaving it to be implementation
dependent. Some implementations equate `bool` to `int`, four bytes in
dependent. Some implementations equate `bool` to `int`, four bytes in
length. Some implement `bool` with a `char`, or 1 byte in length.
Let's assume the smallest case and equate a `bool` with `char`. Our
@ -250,7 +249,7 @@ Some might argue that instructions like `bfi` (and `ubfiz` described
below) is an example of `ISA creep` where ISA's get
more and more cumbersome with the latest instructions du jure. This is
definitely true in the x86 ISA. Perhaps this is true in the AARCH64 ISA
as well, but certainly not to the extent of the x86.
as well, but certainly not to the extent of the x86.
Remember that the ARM
family of processors are examples of RISC machines - *reduced instruction
@ -338,7 +337,7 @@ The remainder is as expected.
## Summary
In this chapter we saw was life was like without bit fields. We saw that
In this chapter we saw was life was like without bit fields. We saw that
we had to implement our own bit bashing functions to do things like:
* Ensure parameters are in the right range

View file

@ -2,15 +2,19 @@
## Overview
Our discussion of implementing ourselves what the C / C++ compiler gives us
led us to use six new instructions. This chapter reviews those instructions.
Our discussion of implementing ourselves what the C / C++ compiler gives
us led us to use six new instructions. This chapter reviews those
instructions. In addition to describing what an instruction does, we
will try to indicate what the instruction is "good for."
## `and`
The `and` instruction is pretty much what you would expect. It implements
the `&` operator from C and C++. That is, the bitwise and operator.
The `and` instruction is pretty much what you would expect. It
implements the `&` operator from C and C++. That is, the bitwise and
operator.
The `and` instruction comes in a number of flavors
The `and` instruction comes in a number of flavors including for
use with immediate values.
### `and` Immediate
@ -27,20 +31,19 @@ There are limits to the bit width of `imm` because it has to fit within
the `and` instruction. If you exceed the allowable width of `imm`, the
assembler will be glad to insult you.
It is possible that a `mov`
instruction will allow your immediate value. You'd follow up with an
`and` using a register than an immediate value.
It is possible that a `mov` instruction will allow your immediate value.
You'd follow up with an `and` using a register than an immediate value.
If your immediate value is too large for a `mov` then put the value
in RAM and `ldr` it into a register and proceed.
If your immediate value is too large for a `mov` then put the value in
RAM and `ldr` it into a register and proceed.
We would love to tell you what the rules are for an immediate value in
the `and` instruction, but they are not obvious and in fact are very
complex. Our advice, try the immediate value you have in mind and if
it works, great. Otherwise, see above.
complex. Our advice, try the immediate value you have in mind and if it
works, great. Otherwise, see above.
A slight variation on this `and` instruction uses a register where
the preceding one uses an immediate value.
A slight variation on this `and` instruction uses a register where the
preceding one uses an immediate value.
```asm
and rd, rs, rm
@ -65,18 +68,29 @@ These mean:
| `asr` | arithmetic shift right | shifts right introducing duplicates of the previous most significant bit |
| `ror` | rotate right | shifts right introducing the bits shifted out back in from the left |
There are other two similar `and` instructions. These are the immediate and
the register versions of `ands`. `ands` is the same as `and` with the addition
that the CPU's condition bits are updated by the instruction permitting a
conditional branch to follow the instruction.
There are other two similar `and` instructions. These are the immediate
and the register versions of `ands`. `ands` is the same as `and` with
the addition that the CPU's condition bits are updated by the
instruction permitting a conditional branch to follow the instruction.
*`and` is the basis of bit bashing and is used to clear bits.
Put `and` together with the or instructions and a couple of other basic
logic instructions, out pops a computer.*
A shorthand way of clearing specific bits is the `bic` instruction.
Use of `bic` can avoid having to negate the bits in a mask prior to
and'ing.
## `bfi`
This instruction mnemonic stands for Bit Field Insert. The word *Insert* should
really be copy. The official ARM [documentation](https://developer.arm.com/documentation/dui0801/g/A64-General-Instructions/BFI) explains this instruction
very well so we'll repeat it here:
This instruction mnemonic stands for Bit Field Insert. The word *Insert*
should really be copy. The official ARM
[documentation](https://developer.arm.com/documentation/dui0801/g/A64-General-Instructions/BFI)
explains this instruction very well so we'll repeat it here:
*Bit Field Insert copies any number of low-order bits from a source register into the same number of adjacent bits at any position in the destination register, leaving other bits unchanged.*
*Bit Field Insert copies any number of low-order bits from a source
register into the same number of adjacent bits at any position in the
destination register, leaving other bits unchanged.*
The instruction has the following format:
@ -84,16 +98,29 @@ The instruction has the following format:
bfi rd, rs, lsb, width
```
Starting at bit 0 of `rs`, `width` bits are copied to `rd` starting at bit
`lsb`.
Starting at bit 0 of `rs`, `width` bits are copied to `rd` starting at
bit `lsb`.
The `bfi` instruction replaces as many as three instructions: likely a shift,
an `and` and an `orr`.
The `bfi` instruction replaces as many as three instructions: likely a
shift, an `and` and an `orr`.
*The preceding has described what `bfi` does but what is it for? Suppose
you have a multiple bit field in a device register. Using `bfi` makes
it easy to copy the right number of bits from a source directly into
the bits in the middle of the destination without need of other
bit-bashing.*
The *opposite* of `bfi` is `bfx`.
`ubfiz` first zeros the destination register then copies in the
specified bits from the source. The `u` means don't consider the
sign bit as special. The `z` is what causes the zero fill first and
sets it apart from `bfi`.
## `mvn`
This instruction takes only takes two operands (but permits an optional shift
to be explained below).
This instruction takes only takes two operands (but permits an optional
shift to be explained below).
The basic syntax is:
@ -101,7 +128,8 @@ The basic syntax is:
mvn rd, rs
```
This flips all the bits in the source and copies them to the destination.
This flips all the bits in the source and copies them to the
destination.
In addition to the basic instruction, there is also:
@ -109,11 +137,41 @@ In addition to the basic instruction, there is also:
mvn rd, rs, *shift* num_bits
```
The *shift* and `num_bits` function the same way as described above including
the option to use `*shift*` as one of `lsl`, `lsr`, `asr` or `ror`.
The *shift* and `num_bits` function the same way as described above
including the option to use `*shift*` as one of `lsl`, `lsr`, `asr` or
`ror`.
*Note the `mvn` is different from `neg` in that `mvn` is a bitwise
operation while `neg` is aware of what makes a negative integer value.
That is, if your goal is to turn a positive integer into a negative
integer, use `neg`. If your goal is to negate bits for bit bashing
purposes, use `mvn`.*
## `lsl`
**Logical Shift Left** moves bits to the left shifting 0 into any
vacated positions.
```asm
lsl rd, rs, *number of bits*
```
*`lsl` is most often used for bit bashing as well as for a fast
multiplication by a power of 2.*
The instruction `asl` is a synonym for `lsl`. The `a` is `asl` means
"arithmetic". There is no difference between a logical and
an arithmetic shift in the **leftward** direction. There is, however,
a difference in the **rightward** direction in that `asr` replicates
the sign bit where `lsr` still moves in zeros in any bit positions
vacated.
## `orr`
## `ubfiz`
This is the plain vanilla *or* instruction. It is used extensively
for bit bashing as it is how bits can be set to 1.
```asm
orr rd, rs, rm # rm is another register
orr rd, rs, imm
```