Assembly-02: Bullseyes and Branches
Throwing darts in assembly meeting floating point operations.
Another day, another low-level challenge. This time, we’re implementing a darts scoring function in NASM, focusing on floating-point math and precision branching.
The prompt as usual comes from Exercism.com.
Darts Scoring in x64 Assembly: Bullseyes and Branches
Today’s target: darts scoring in NASM. Continuing from our Collatz warmup, this one blends floating-point operations, score-banding, and a taste for conditional jump logic.
From Exercism—throw a dart at a (virtual) target, get your coordinates as doubles, and output the score:
- Inside radius 1.0 — 10 points
- Inside radius 5.0 — 5 points
- Inside radius 10.0 — 1 point
- Else — 0 points
Input: two doubles (x, y). Output: integer score via rax.
Requirements
- No runtime I/O—pure function: accepts
xmm0,xmm1(x/y floats), returns score inrax - All math done in x64 vector registers (welcome to the FPU!)
- Compute distance: Pythagoras, vectorized—
sqrt(x^2 + y^2). - No
CALLs, no stack spills. - Judgement zone: chain of
comisd+jbefor score bands. - Magic score constants loaded from
.data.
Register Rationalization
| xmm0 | x (input) or distance (result) |
| xmm1 | y (input) |
| xmm2 | band limit |
The Code
section .data
one dq 1.0
five dq 5.0
ten dq 10.0
section .text
global score
score:
mulsd xmm0, xmm0 ; x*x
mulsd xmm1, xmm1 ; y*y
addsd xmm0, xmm1 ; x*x + y*y
sqrtsd xmm0, xmm0 ; sqrt(x*x + y*y) = distance
movsd xmm2, [rel one]
comisd xmm0, xmm2
jbe score10
movsd xmm2, [rel five]
comisd xmm0, xmm2
jbe score5
movsd xmm2, [rel ten]
comisd xmm0, xmm2
jbe score1
jmp score0
score10:
mov rax, 10
jmp exit
score5:
mov rax, 5
jmp exit
score1:
mov rax, 1
jmp exit
score0:
mov rax, 0
jmp exit
exit:
ret
%ifidn __OUTPUT_FORMAT__,elf64
section .note.GNU-stack noalloc noexec nowrite progbits
%endif
Next up: maybe go rogue and write a full-on assembly darts game?
Until then: aim true, code tight.
Props (again) to Exercism for the relentless CPU puzzles!