asm_book/projects/snow/main.s
Perry Kivolowitz 66a92ec762 finished
2022-12-11 20:22:44 -06:00

245 lines
5.9 KiB
ArmAsm

.global main
.align 2
.text
.equ NUM_FLAKES, 250
.equ MAX_COLUMN, 80
.equ MAX_LINE, 24
.equ MAX_LINE_X2, 48
storm .req x27 // base address of storm
estorm .req x28 // end of storm
main: stp x29, x30, [sp, -16]!
stp x27, x28, [sp, -16]!
// Seed the RNG with the current time.
mov w0, wzr
bl time
bl srand
// Allocate the storm.
mov x0, NUM_FLAKES // Calculate space needed.
mov x1, Flake.size
mul x0, x0, x1
str x0, [sp, -16]! // Save for memset.
bl malloc // Attempt the allocation.
cbnz x0, 1f // Branch if successful.
add sp, sp, 16 // Undo stack change.
ldr x0, =bad_malloc // Inform user of tragedy.
bl puts
mov w0, 1
b bye
1: mov storm, x0 // The base address of the
// allocated memory will be
// preserved in x27.
mov estorm, x0 // prep end of storm calculation
ldr x2, [sp], 16 // Restore the allocation size.
add estorm, estorm, x2 // Preserve end-of-storm.
mov w1, wzr // Fill with zero.
bl memset // x0 still had base address.
bl InitializeStorm
10: bl Erase
bl StepAll
bl RenderAll
mov w0, 1
mov w1, 1
bl Move
ldr x0, =nl
bl printf
bl Delay
b 10b
99: mov x0, storm
bl free
mov w0, wzr
bye: ldp x27, x28, [sp], 16
ldp x20, x30, [sp], 16
ret
/* line comes to us in w0
column comes to us in w1
*/
Move: stp x20, x30, [sp, -16]!
mov w2, w1
mov w1, w0
ldr x0, =move_str
bl printf
ldp x20, x30, [sp], 16
ret
Erase: stp x20, x30, [sp, -16]!
mov w0, 1
mov w1, 1
bl Move
ldr x0, =erase_str
bl printf
ldp x20, x30, [sp], 16
ret
/* Address of flake to render comes to us in x0.
*/
RenderOne:
str x30, [sp, -16]!
ldr w1, [x0]
ldr w2, [x0, 4]
// Ensure 1 <= w1 <= MAX_LINE
mov w3, 1
mov w4, MAX_LINE
mov w5, MAX_COLUMN
cmp w3, w1
bgt 99f
cmp w4, w1
blt 99f
// Ensure 1 <= w2 <= MAX_COLUMN
cmp w3, w2
bgt 99f
cmp w5, w2
blt 99f
ldr x0, =move_str
bl printf
ldr x0, =char_str
bl printf
99: ldr x30, [sp], 16
ret
/* Iterate through the storm rendering each particle
*/
RenderAll:
stp x20, x30, [sp, -16]!
mov x20, storm
1: mov x0, x20
bl RenderOne
add x20, x20, Flake.size
cmp estorm, x20
bgt 1b
ldp x20, x30, [sp], 16
ret
Delay:
str x30, [sp, -16]!
mov x0, 1
lsl x0, x0, 17
bl usleep
ldr x30, [sp], 16
ret
/* Address of flake to step arrives in x0.
*/
StepOne:
stp x20, x30, [sp, -16]!
mov x20, x0
ldr w1, [x0]
add w1, w1, 1
str w1, [x0]
mov w2, MAX_LINE
cmp w2, w1
bge 1f
bl ResetFlake
1: bl rand
mov w1, 3
bl mod
sub x0, x0, 1
ldr w1, [x20, 4]
add w0, w0, w1
str w0, [x20, 4]
ldp x20, x30, [sp], 16
ret
StepAll:
stp x20, x30, [sp, -16]!
mov x20, storm
1: mov x0, x20
bl StepOne
add x20, x20, Flake.size
cmp estorm, x20
bgt 1b
ldp x20, x30, [sp], 16
ret
InitializeStorm:
stp x20, x30, [sp, -16]!
mov x20, storm
1: mov x0, x20
bl ResetFlake
add x20, x20, Flake.size
cmp estorm, x20
bne 1b
ldp x20, x30, [sp], 16
ret
/* x0 contains the address of a Flake in need of being reset.
The column number of a Flake is anywhere from 1 to 80 (a
default terminal). The starting line is anywhere from 1 to
48 (24 x 2) lines ABOVE the screen. This allows the flakes to
drift downward without apparent gaps or bunches.
*/
ResetFlake:
stp x20, x30, [sp, -16]!
mov x20, x0
// Initialize Column --- 1 <= random value <= 80
bl rand
mov x1, MAX_COLUMN
bl mod
add w0, w0, 1
str w0, [x20, 4]
// Initialize Line --- -(1 <= random value <= 48)
bl rand
mov x1, MAX_LINE_X2
bl mod
add w0, w0, 1
neg w0, w0
str w0, [x20]
ldp x20, x30, [sp], 16
ret
/* mod(a, b) - implements a % b - AARCH64 lacks a mod instruction.
A strange place to economize, but there you have it.
a comes to us in x0
b comes to us in x1
method:
* integer divide a by b
for example - 5 % 3 would need 5 // 3 yielding 1
* multiply result by b
1 * 3 is 3
* subtract result from a
5 - 3 is 2 and that's our return value.
*/
mod: sdiv x2, x0, x1 // x2 gets a // b
msub x0, x2, x1, x0 // x0 gets a - a // b * b
ret
.data
bad_malloc: .asciz "Allocation of flakes has failed"
move_str: .asciz "\033[%d;%dH"
erase_str: .asciz "\033[2J"
char_str: .asciz "*"
nl: .asciz "\n"
.section Flake
.struct 0
Flake.line: .struct Flake.line + 4
Flake.col: .struct Flake.col + 4
Flake.size: