Re: Random-number generation
Posted: Tue May 30, 2023 3:38 pm
Arlet wrote:
It's possible to optimize in various directions. Using more/less ZP, code size, cycles, or period/quality. Let me know what you care about most.
Code: Select all
CLC
LDA #$45
ADC s+0
STA s+0
ADC s+1
STA s+1
ADC s+2
STA s+2
ADC s+3
STA s+3
LDA s+4
ROL A
ROL A
STA s+4
ADC s+2
STA o+0
ADC s+4
STA s+4
ADC s+3
STA o+1
ADC s+1
ADC s+4
STA s+4
ADC o+0
STA o+0
ADC s+4
STA s+4
RTS
Code: Select all
CLC
LDA #$45
ADC s+0
STA s+0
ADC s+1
STA s+1
ADC s+2
STA s+2
ADC s+3
STA s+3
LDA s+4
ROL A
STA s+4
ADC s+2
STA o+0
ADC s+3
STA o+1
ADC s+1
ROL A
ADC o+0
STA o+0
ADC s+4
STA s+4
ADC o+1
STA o+1
RTS
Code: Select all
LDA s+4
ROL A
STA s+4Code: Select all
ROL s+4
LDA s+4Code: Select all
CLC
LDA #1 ; any odd value
ADC s+0
STA s+0
ADC s+1
STA s+1
ASL A
ADC s+0
TAX
EOR s+0
RTS
Code: Select all
CLC
LDA #1 ; any odd value
ADC s+0
STA s+0
ADC s+1
STA s+1
ASL A
ADC s+0
TAX
EOR s+0
RTS
Code: Select all
batari8 (0)
Type: galois8 lfsr
6502 author: Fred Quimby
RAM: 1 byte
Size: 9 bytes
Cycles: 11-12
Period: 255
References: https://github.com/batari-Basic
Notes: This is the rand routine included with the 2600 development
language batari Basic. It's main strength is it's compactness
and speed.
Sample: (2a) 15 be 5f 9b f9 c8 64 32 ...
Code:
LDA randv0
LSR
BCC noeor
EOR #$B4
noeor:
STA randv0
batari8rev (1)
Type: galois8 lfsr
6502 author: (forward) Fred Quimby, (reversal) Mike Saarna
RAM: 1 byte
Size: 9 bytes
Cycles: 11-12
Period: 255
References: https://github.com/batari-Basic
Notes: This is a reversed version of the LFSR included with batari
Basic. Reversal allows the pseudorandom sequence to be
rewound at any point, without requiring additional storage.
Sample: (32) 64 c8 f9 9b 5f be 15 2a ...
Code:
LDA randv0
ASL
BCC noeor
EOR #$69
noeor:
STA randv0
batari16 (2)
Type: galois8 extended to 16 bits
6502 author: Fred Quimby
RAM: 2 bytes
Size: 13 bytes
Cycles: 19-20
Period: 65535
References: https://github.com/batari-Basic
Notes: This is the rand16 routine included with the 2600 development
language batari Basic, and the default rand routine in
7800basic. Its quick and compact for a 16-bit LFSR.
Sample: (2a2a) 41 a3 e3 fd d2 d8 ba 19 ...
Code:
LDA randv0
LSR
ROL randv1
BCC noeor
EOR #$B4
noeor:
STA randv0
EOR randv1
batari16rev (3)
Type: galois8 extended to 16 bits
6502 author: (forward) Fred Quimby, (reversal) bogax
RAM: 2 bytes
Size: 16 bytes
Cycles: 22-23
Period: 65535
References: https://github.com/batari-Basic
Notes: This is the rand16 routine included with the 2600 development
language batari Basic, and the default rand routine in
7800basic, run backwards
Sample: (a124) 19 ba d8 d2 fd e3 a3 41 ...
Code:
LDA randv1
LSR
LDA randv0
ROL
BCC skip_eor16
EOR #$68
skip_eor16:
STA randv0
ROR randv1
EOR randv1
pitfall8left (4)
Type: fibonacci8 lfsr
6502 author: David Crane
RAM: 1 byte
Size: 18 bytes
Cycles: 30
Period: 255
References: https://samiam.org/blog/20130606.html
Notes: This is the left-travelling LFSR from the Atari 2600
game Pitfall. It's at the core of the game's algorithmic
level generation.
Sample: (2a) 95 4a a5 52 29 14 8a 45 ...
Code:
LDA randv0
ASL
EOR randv0
ASL
EOR randv0
ASL
ASL
ROL
EOR randv0
LSR
ROR randv0
LDA randv0
pitfall8right (5)
Type: fibonacci8 lfsr
6502 author: David Crane
RAM: 1 byte
Size: 17 bytes
Cycles: 30
Period: 255
References: https://samiam.org/blog/20130606.html
Notes: This is the right-travelling LFSR from the Atari 2600
game Pitfall. It's at the core of the game's algorithmic
level generation.
Sample: (45) 8a 14 29 52 a5 4a 95 2a ...
Code:
LDA randv0
ASL
EOR randv0
ASL
EOR randv0
ASL
ASL
EOR randv0
ASL
ROL randv0
LDA randv0
xorshift16 (6)
Type: xorshift16 lfsr
6502 author: Veikko
RAM: 2 bytes
Size: 17 bytes
Cycles: 30
Period: 65535
References: http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html
Notes: This is an efficient 6502 implementation of the xorshift16
algorithm.
Sample: (2a2a) 0a ad 77 8b 50 37 06 75 ...
Code:
LDA randv1
LSR
LDA randv0
ROR
EOR randv1
STA randv1
ROR
EOR randv0
STA randv0
EOR randv1
STA randv1
xhybrid24 (7)
Type: hybrid xorshift16+galois8
6502 author: (hybrid code) Mike Saarna, (base xorshift16) Veikko
RAM: 3 bytes
Size: 34 bytes
Cycles: 48-50
Period: 16711425
References:
Notes: A bit sampling on the xorshift16 upper-byte cranks a galois8
lfsr forward. This results in an atypical lfsr period.
xhybrid24 passes and scores well on most "dieharder"
randomness quality checks. This level of rand quality probably
isn't needed on 6502 based systems, but it's nice that it can
be done with relative efficiency.
Sample: (010101) f4 c5 d0 ae 75 6b 70 d2 ...
Code:
BIT randv1
BVS skipupperlfsr
LDA randv2
LSR
BCC skipuppereor
EOR #$B4
skipuppereor:
STA randv2
skipupperlfsr:
LDA randv1
LSR
LDA randv0
ROR
EOR randv1
STA randv1
ROR
EOR randv0
STA randv0
EOR randv1
STA randv1
EOR randv2
overlap24 (8)
Type: ??
6502 author: ??
RAM: 3 bytes
Size: 38 bytes
Cycles: 73
Period: 16777215
References: https://wiki.nesdev.com/w/index.php/Random_number_generator/Linear_feedback_shift_register_(advanced)
Notes: Has an XOR-feedback that contains only four bits, but by
shifting and feeding back 8 bits at once, a more complex
overlapped result is obtained.
Sample: (010203) 1b 36 2d 45 8a d4 81 43 ...
Code:
LDY randv1
LDA randv2
LSR
LSR
LSR
LSR
STA randv1
LSR
LSR
EOR randv1
LSR
EOR randv1
EOR randv0
STA randv1
LDA randv2
ASL
EOR randv2
ASL
ASL
EOR randv2
ASL
EOR randv2
STY randv2
STA randv0
riverraid16 (9)
Type: ??
6502 author: Carol Shaw
RAM: 2 bytes
Size: 14 bytes
Cycles: 27
Period: 57337
References: http://www.bjars.com/source/RiverRaid.asm
Notes: "randomHi is very random, randomLo is NOT when more than one
bit is used, because: randomLo[x+1] = randomLo[x]*2 + 0/1, but
randomLo is used more often [in the game] [...]"
--Thomas Jentzsch
Sample: (a814) 0a 05 b6 5b 99 f8 7c 3e ...
Code:
LDA randv1
ASL
ASL
ASL
EOR randv1
ASL
ROL randv0
ROL randv1
LDA randv1Code: Select all
CLC
LDA #$45
ADC s+0
STA s+0
ADC s+1
STA s+1
ADC s+2
STA s+2
ADC s+3
STA s+3
ADC s+4
STA s+4
ADC s+5
STA s+5
ADC s+3
STA o+0 ; first output byte
ADC s+6
ASL A
STA s+6
ADC s+2
STA o+1 ; second output byte
ADC s+6
ASL A
STA s+6
ADC s+4
STA o+2 ; third output byte
ADC s+5
STA o+3 ; fourth output byte
RTS
Code: Select all
RNG_test using PractRand version 0.94
RNG = RNG_stdin8, seed = unknown
test set = core, folding = standard (8 bit)
rng=RNG_stdin8, seed=unknown
length= 8 megabytes (2^23 bytes), time= 2.9 seconds
no anomalies in 76 test result(s)
rng=RNG_stdin8, seed=unknown
length= 16 megabytes (2^24 bytes), time= 6.5 seconds
no anomalies in 84 test result(s)
rng=RNG_stdin8, seed=unknown
length= 32 megabytes (2^25 bytes), time= 12.9 seconds
no anomalies in 93 test result(s)
rng=RNG_stdin8, seed=unknown
length= 64 megabytes (2^26 bytes), time= 24.8 seconds
no anomalies in 99 test result(s)
rng=RNG_stdin8, seed=unknown
length= 128 megabytes (2^27 bytes), time= 47.7 seconds
no anomalies in 108 test result(s)
rng=RNG_stdin8, seed=unknown
length= 256 megabytes (2^28 bytes), time= 92.1 seconds
no anomalies in 118 test result(s)
rng=RNG_stdin8, seed=unknown
length= 512 megabytes (2^29 bytes), time= 180 seconds
no anomalies in 126 test result(s)
rng=RNG_stdin8, seed=unknown
length= 1 gigabyte (2^30 bytes), time= 355 seconds
no anomalies in 135 test result(s)
rng=RNG_stdin8, seed=unknown
length= 2 gigabytes (2^31 bytes), time= 706 seconds
no anomalies in 144 test result(s)
rng=RNG_stdin8, seed=unknown
length= 4 gigabytes (2^32 bytes), time= 1406 seconds
no anomalies in 151 test result(s)
rng=RNG_stdin8, seed=unknown
length= 8 gigabytes (2^33 bytes), time= 2821 seconds
no anomalies in 159 test result(s)
rng=RNG_stdin8, seed=unknown
length= 16 gigabytes (2^34 bytes), time= 5661 seconds
no anomalies in 167 test result(s)
rng=RNG_stdin8, seed=unknown
length= 32 gigabytes (2^35 bytes), time= 11312 seconds
no anomalies in 173 test result(s)
rng=RNG_stdin8, seed=unknown
length= 64 gigabytes (2^36 bytes), time= 22845 seconds
no anomalies in 181 test result(s)
rng=RNG_stdin8, seed=unknown
length= 128 gigabytes (2^37 bytes), time= 45338 seconds
no anomalies in 189 test result(s)
rng=RNG_stdin8, seed=unknown
length= 256 gigabytes (2^38 bytes), time= 91090 seconds
no anomalies in 195 test result(s)
rng=RNG_stdin8, seed=unknown
length= 512 gigabytes (2^39 bytes), time= 186524 seconds
no anomalies in 202 test result(s)
rng=RNG_stdin8, seed=unknown
length= 1 terabyte (2^40 bytes), time= 366013 seconds
no anomalies in 208 test result(s)
rng=RNG_stdin8, seed=unknown
length= 2 terabytes (2^41 bytes), time= 729582 seconds
no anomalies in 213 test result(s)
rng=RNG_stdin8, seed=unknown
length= 4 terabytes (2^42 bytes), time= 1470769 seconds
no anomalies in 218 test result(s)
rng=RNG_stdin8, seed=unknown
length= 8 terabytes (2^43 bytes), time= 2981457 seconds
no anomalies in 222 test result(s)
rng=RNG_stdin8, seed=unknown
length= 16 terabytes (2^44 bytes), time= 6061817 seconds
no anomalies in 225 test result(s)