diff --git a/section_2/float/fmov.md b/section_2/float/fmov.md index 0028533..6ab7af7 100644 --- a/section_2/float/fmov.md +++ b/section_2/float/fmov.md @@ -2,27 +2,23 @@ The `fmov` instruction is used to move floating point values in and out of floating point registers and to some degree, moving data between -integer and floating point registers. +integer and floating point registers. ## Loading Floating Point Numbers as Immediate Values -Just as we saw with integer -registers, some values can be used as immediate values and some cannot. +Just as we saw with integer registers, some values can be used as +immediate values and some cannot. It comes down to how many bits are +necessary to encode the value. Too many bits... not enough room to fit +in a 4 byte instruction plus the opcode. For example, this works: -`mov x0, 65536` +`mov x0, 65535` but this does not: `mov x0, 65537` -The reason is that all AARCH64 instructions must fit within a 32 bit -instruction that must hold the instruction's op code, its flags and -other bits and bobs plus any immediate value. In the above example we -can see that the `mov` instruction provides up to 16 bits for an -immediate value. - The constraints placed on immediate values for `fmov` are much tighter because floating point numbers are far more complex than integers. @@ -40,7 +36,7 @@ Let's take a look at some code: fmov d0, 1.96875 // Zoinks! ``` -From this we can see that an immediate value for an `fmov` seems to have +From this we can see that an immediate value for an `fmov` has 4 bits available for the mantissa. In fact, the only values that work as immediate values will be those floating point values whose fractional values are combinations of: @@ -56,6 +52,9 @@ values are combinations of: As far as exponents go, `fmov` can accommodate 3 bits. So, exponents of plus or minus 2**7 can be used. +A sign bit makes the total number of bits available for immediate moves +to be 8. + ## Loading / Storing Floating Point Numbers in General When in doubt, load fixed floating point numbers from memory. This is @@ -64,11 +63,16 @@ covered [in this chapter](./literals.md). ## SIMD `fmov` can also deal with the more complicated special cases induced by -SIMD instructions. +SIMD instructions. `fmov` is able to move values between the various +register widths such as single precision to double precision. **However, +no conversion of value is performed - `fmov` just copies bits.** + +If you need to change the precision of a floating point value, the +`fcvt` family of instructions must be used instead. ## Movement To / From Integer Registers -`fmov` can *bits* between the integer and floating point registers. We -emphasize the *bits*. No conversions are done using `fmov`. There exist -other instructions for that. See [this chapter](./rounding.md) for more -information. +`fmov` can copy *bits* between the integer and floating point registers. +We emphasize the *bits*. No conversions are done using `fmov`. There +exist other instructions for that. See [this chapter](./rounding.md) for +more information. diff --git a/section_2/float/fmov.pdf b/section_2/float/fmov.pdf index 20d5dee..8c9e9f4 100644 Binary files a/section_2/float/fmov.pdf and b/section_2/float/fmov.pdf differ diff --git a/section_2/float/literals.md b/section_2/float/literals.md index 3466976..89673c3 100644 --- a/section_2/float/literals.md +++ b/section_2/float/literals.md @@ -20,30 +20,32 @@ To load a `float`, you could translate the value to binary and do as the following: ```asm - .text // 1 - .global main // 2 - .align 2 // 3 - // 4 -main: str x30, [sp, -16]! // 5 - ldr s0, =0x3fc00000 // 6 - fcvt d0, s0 // 7 - ldr x0, =fmt // 8 - bl printf // 9 - ldr x30, [sp], 16 // 10 - mov w0, wzr // 11 - ret // 12 - // 13 - .data // 14 -fmt: .asciz "%f\n" // 15 - .end // 16 + .text // 1 + .global main // 2 + .align 2 // 3 + // 4 +main: str x30, [sp, -16]! // 5 + ldr s0, =0x3fc00000 // 6 + fcvt d0, s0 // 7 + ldr x0, =fmt // 8 + bl printf // 9 + ldr x30, [sp], 16 // 10 + mov w0, wzr // 11 + ret // 12 + // 13 + .data // 14 +fmt: .asciz "%f\n" // 15 + .end // 16 ``` -The above code is found [here](./t.s). +The above code is kind of found [here](./t.s) - the file is used +for miscellaneous testing. -`Line 6` puts the translated value of 1.5 into `s0` (since the value -is a `float` it goes in an `s` register). The assembler performs some -magic getting a 32 bit value seemingly fit into a 32 bit instruction. -See [below](./literals.md#fitting-32-bits-into-a-32-bit-bag). +`Line 6` puts the translated value of 1.5 into `s0` (since we are +thinking of the value as a `float` it goes in an `s` register). The +assembler performs some magic getting a 32 bit value seemingly fit into +a 32 bit instruction. See +[below](./literals.md#fitting-32-bits-into-a-32-bit-bag). `Line 7` converts the single precision number into a double precision number for printing. @@ -136,6 +138,9 @@ Cool huh? ## Fitting 32 bits into a 32 bit bag +**This section is currently LINUX-centric - in the future it will +address both native Apple and Linux equally.*** + AARCH64 instructions are 32 bits in width. Yet, `line 6` from [this](./t.s) program reads: @@ -195,15 +200,16 @@ Scan downward to find `0x7a0`: 0x7a0 .inst 0x3fc00000 ; undefined ``` -Hey look! Here's our literal float. The `.inst` is an ARM -specific GNU assembler directive what allows the programmer -to encode their own instruction. Note, the encoded instruction does not -have to make any sense - instead the compiler has emitted a make believe -instruction that happens to have the value of our literal. +Hey look! Here's our literal float. The `.inst` is an ARM specific GNU +assembler directive says: `¯\_(-)_/¯`. + +Note, the encoded "instruction" does not have to make any sense - +instead the compiler has emitted a make believe instruction that happens +to have the value of our literal. What we're seeing the actual `line 6` doing is reaching ahead a short -distance to load the value of another "instruction" when really it is -our constant. +distance to load the value of another location in memory where our +constant is really found. Let us take this explanation further. Notice we see: diff --git a/section_2/float/literals.pdf b/section_2/float/literals.pdf index 8090205..1a2ac50 100644 Binary files a/section_2/float/literals.pdf and b/section_2/float/literals.pdf differ diff --git a/section_2/float/t.s b/section_2/float/t.s index 645b851..135c68e 100644 --- a/section_2/float/t.s +++ b/section_2/float/t.s @@ -1,12 +1,16 @@ .text - .global main - .align 2 + .global _main + .align 2 -main: str x30, [sp, -16]! +_main: + str x30, [sp, -16]! + mov x0, 0xFFFFFFFF +/* ldr s0, =0x3fc00000 fcvt d0, s0 ldr x0, =fmt bl printf +*/ ldr x30, [sp], 16 mov w0, wzr ret