diff --git a/section_2/bitfields/README.md b/section_2/bitfields/README.md index c810934..4ef8657 100644 --- a/section_2/bitfields/README.md +++ b/section_2/bitfields/README.md @@ -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 diff --git a/section_2/bitfields/review.md b/section_2/bitfields/review.md index 32b7b9a..8582fc3 100644 --- a/section_2/bitfields/review.md +++ b/section_2/bitfields/review.md @@ -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 +```