; This code was originally found in Prism. Originally written on 2016-12-18; updated on 2018-08-18 with a bug fix.
; Since I never bothered with a license header, I'm hereby placing it in the public domain as of 2019-01-04.
StableRandom::
; in: hl: pointer to 8-byte RNG state
; out: a: random value; other registers preserved
push bc
push de
push hl
call .advance_left_register
call .check_right_register_cycles
call .advance_right_register
inc hl
inc hl
inc hl
call .advance_selector_register
pop hl
push hl
rlca
rlca
ld c, a
and 3
ld e, a
ld d, 0
add hl, de
ld b, [hl]
pop hl
push hl
ld e, 5
add hl, de
ld a, c
ld c, [hl]
rlca
rlca
and 3
call .combine_register_values
pop hl
pop de
pop bc
ret
.advance_left_register
; in: hl: pointer to left register
; out: hl: pointer to RIGHT register
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld c, a
ld a, [hld]
ld b, a
or c
or d
or e
call z, .reseed_left_register
ld a, e
xor d
ld e, a
ld a, d
xor c
ld d, a
ld a, c
xor b
ld c, a
ld a, c
ld [hld], a
ld a, d
ld [hld], a
ld [hl], e
sla e
rl d
rl c
inc hl
ld a, [hl]
xor e
ld [hli], a
ld a, [hl]
xor d
ld [hli], a
ld a, [hl]
xor c
ld [hld], a
ld b, a
ld c, [hl]
sla c
rl b
sbc a
and 1
dec hl
xor [hl]
ld [hld], a
ld a, [hl]
xor b
ld [hli], a
inc hl
inc hl
inc hl
ret
.reseed_left_register
; in: hl: pointer to left register + 2
; out: hl preserved; bcde new seed
ld de, 5
push hl
add hl, de
call .advance_selector_register
ld b, a
call .advance_selector_register
ld c, a
call .advance_selector_register
ld d, a
call .advance_selector_register
ld e, a
pop hl
inc hl
ld a, b
ld [hld], a ;only b needs to be written back, since the rest will be handled by the main function
ret
.check_right_register_cycles
; in: hl: pointer to right register
; out: hl preserved
inc hl
inc hl
ld a, [hld]
ld c, a
ld a, [hld]
ld d, a
or c
ld e, [hl]
push hl
jr z, .check_long_cycles
ld hl, .right_register_short_cycles - 1
ld b, (.right_register_short_cycles_end - .right_register_short_cycles) / 3 + 1
.short_cycle_handle_loop
inc hl
dec b
jr z, .pop_ret
.short_cycle_loop
ld a, [hli]
cp c
ld a, [hli]
jr nz, .short_cycle_handle_loop
cp d
jr nz, .short_cycle_handle_loop
ld a, e
cp [hl]
jr nz, .short_cycle_handle_loop
inc hl
.copy_right_register_state
ld a, [hli]
ld c, a
ld a, [hli]
ld b, [hl]
pop hl
inc hl
ld [hli], a
ld a, c
ld [hld], a
dec hl
ld [hl], b
ret
.check_long_cycles
ld hl, .right_register_long_cycles
.long_cycle_loop
ld a, [hli]
and a
jr z, .pop_ret
cp e
jr nz, .long_cycle_loop
ld a, [hl]
and a
jr z, .start_short_cycles
pop hl
ld [hl], a
ret
.start_short_cycles
pop hl
push hl
inc hl
inc hl
inc hl
call .advance_selector_register
ld hl, .right_register_short_cycles
jr .copy_right_register_state
.pop_ret
pop hl
ret
.right_register_short_cycles
db $72, $4f, $9f
db $7b, $1a, $7b
db $84, $e5, $56
db $8d, $b0, $32
.right_register_short_cycles_end
db 0, 0
.right_register_long_cycles
db 1, 2, 4, 8, 13, 17, 23, 26, 29, 58
db 0
.advance_right_register
; in: hl: pointer to right register
; out: hl preserved
ld a, [hli]
cp 210
jr c, .right_carry_OK
sub 210
.right_carry_OK
ld d, a
ld a, [hli]
ld e, a
ld c, [hl]
or c
or d
jr z, .right_register_needs_reseed
ld a, c
and e
inc a
jr nz, .right_register_OK
ld a, d
cp 209
jr nz, .right_register_OK
.right_register_needs_reseed
call .reseed_right_register
.right_register_OK
ld a, e
ld [hld], a
push hl
ld b, 0
ld h, b
ld l, d
ld a, 210
rst AddNTimes
ld a, l
ld b, h
pop hl
ld [hld], a
ld [hl], b
ret
.reseed_right_register
; in: hl: pointer to right register + 2
; out: hl preserved, cde new seed
inc hl
call .advance_selector_register
ld c, a
call .advance_selector_register
ld d, a
sub 210
jr c, .carry_reseed_OK
ld d, a
.carry_reseed_OK
call .advance_selector_register
ld e, a
dec hl
ret
.advance_selector_register
; in: hl: pointer to selector register
; out: all registers but a preserved; a = new selector
push bc
ld a, [hl]
ld b, 0
rra
rr b
rra
rr b
ld a, [hl]
swap a
rrca
and $f8
add a, b
add a, [hl]
add a, 29
ld [hl], a
pop bc
ret
.combine_register_values
and a
jr z, .add_registers
dec a
jr z, .xor_registers
dec a
jr z, .subtract_registers
ld a, c
sub b
ret
.subtract_registers
ld a, b
sub c
ret
.add_registers
ld a, b
add a, c
ret
.xor_registers
ld a, b
xor c
ret
Comments