perfect_dark/src/lib/rng.s

75 lines
1.4 KiB
ArmAsm

#include "macros.inc"
.set noat
.set noreorder
.set gp=64
.data
glabel g_RngSeed
.dword 0xab8d9f7781280783
.text
/**
* u32 random(void)
*
* Generate a random number between 0 and 4294967295.
*/
glabel random
lui $a0, %hi(g_RngSeed)
ld $a0, %lo(g_RngSeed)($a0)
lui $at, %hi(g_RngSeed)
dsll32 $a2, $a0, 31
dsll $a1, $a0, 31
dsrl $a2, $a2, 31
dsrl32 $a1, $a1, 0
dsll32 $a0, $a0, 12
or $a2, $a2, $a1
dsrl32 $a0, $a0, 0
xor $a2, $a2, $a0
dsrl $a0, $a2, 20
andi $a0, $a0, 0xfff
xor $a0, $a0, $a2
dsll32 $v0, $a0, 0
sd $a0, %lo(g_RngSeed)($at)
jr $ra
dsra32 $v0, $v0, 0
/**
* void rngSetSeed(u32 seed)
*
* Set the given seed as the RNG seed. Add 1 to make sure it isn't 0.
*/
glabel rngSetSeed
daddiu $a0, $a0, 1
lui $at, %hi(g_RngSeed)
sd $a0, %lo(g_RngSeed)($at)
jr $ra
li $a0, 0
/**
* u32 rngRotateSeed(u64 *value);
*
* Rotate the given seed using the same algorithm as random().
*
* Store the new 64-bit seed at the pointed address and return the same seed
* cast as a u32.
*/
glabel rngRotateSeed
ld $a3, 0($a0)
dsll32 $a2, $a3, 31
dsll $a1, $a3, 31
dsrl $a2, $a2, 31
dsrl32 $a1, $a1, 0
dsll32 $a3, $a3, 12
or $a2, $a2, $a1
dsrl32 $a3, $a3, 0
xor $a2, $a2, $a3
dsrl $a3, $a2, 20
andi $a3, $a3, 0xfff
xor $a3, $a3, $a2
dsll32 $v0, $a3, 0
sd $a3, 0($a0)
jr $ra
dsra32 $v0, $v0, 0