random: trying to find a reasonable random number generator

This commit is contained in:
Vince Weaver 2024-10-10 12:40:33 -04:00
parent 6cb3904828
commit 14bdb6cfa1
4 changed files with 191 additions and 0 deletions

26
random/Makefile Normal file
View File

@ -0,0 +1,26 @@
CC = gcc
CFLAGS = -O2 -Wall
LFLAGS =
all: random16 random8 #random15
###
random16: random16.o
$(CC) $(LFLAGS) -o random16 random16.o
random16.o: random16.c
$(CC) $(CFLAGS) -c random16.c
###
random8: random8.o
$(CC) $(LFLAGS) -o random8 random8.o
random8.o: random8.c
$(CC) $(CFLAGS) -c random8.c
###
clean:
rm -f *~ *.o random16 random8 random15

9
random/README Normal file
View File

@ -0,0 +1,9 @@
Trying to find a good pseudo-random number generator for 6502
I had been using the "random16" one here, but at least on Peasant's Quest
when used to generate a 0-31 random value it seemed to have "0" and "17"
come up way more than exected
the "random8" one here is better, but it's really only 7 bits as you can't
actually generate a 0 and code might fail if you never get a 0 result?

109
random/random16.c Normal file
View File

@ -0,0 +1,109 @@
#include <stdio.h>
// 16-bit 6502 Random Number Generator
// Linear feedback shift register PRNG by White Flame
// http://codebase64.org/doku.php?id=base:small_fast_16-bit_prng
// The Apple II KEYIN routine increments this field
//while waiting for keypress
//SEEDL = $4E
//SEEDH = $4F
//XOR_MAGIC = $7657 ; "vW"
static unsigned short xor_magic=0x7657;
//static unsigned short xor_magic=0x002d;
static unsigned short seed=0x0000;
// ;=============================
// ; random16
// ;=============================
unsigned short random16(void) {
if ((seed&0xff)!=0) {
if ((seed&0x8000)==0) {
// noEor
seed<<=1;
return seed;
}
else {
// doEor
seed<<=1;
seed=seed^xor_magic;
return seed;
}
}
else {
// if bottom 0
if (((seed>>8)&0xff)==0) {
seed<<=1;
seed=seed^xor_magic;
return seed;
}
else {
if ((seed & 0x8000)==0) {
seed<<=1;
return seed;
}
else {
seed<<=1;
seed=seed^xor_magic;
return seed;
}
}
}
}
int main(int argc, char **argv) {
int i,r;
for(i=0;i<65537;i++) {
r=random16();
printf("%04hx %04hx\n",r,r&0x1f);
}
return 0;
}
// lda SEEDL ; 3
// beq lowZero ; $0000 and $8000 are special values ; 2
// asl SEEDL ; Do a normal shift ; 5
// lda SEEDH ; 3
// rol ; 2
// bcc noEor ; 2
//doEor:
// ; high byte is in A
// eor #>XOR_MAGIC ; 2
// sta SEEDH ; 3
// lda SEEDL ; 3
// eor #<XOR_MAGIC ; 2
// sta SEEDL ; 3
// rts ; 6
//lowZero:
// ; 1
// lda SEEDH ; 3
// beq doEor ; High byte is also zero ; 3
// ; so apply the EOR
// ; -1
// ; wasn't zero, check for $8000
// asl ; 2
// beq noEor ; if $00 is left after the shift ; 2
// ; then it was $80
// bcs doEor ; else, do the EOR based on the carry ; 3
//noEor:
// ; 1
// sta SEEDH ; 3
// lda SEEDL ; always return SEEDL
// rts ; 6

47
random/random8.c Normal file
View File

@ -0,0 +1,47 @@
// http://www.6502.org/users/mycorner/6502/code/prng.html
//; returns pseudo random 8 bit number in A. Affects A. (r_seed) is the
//; byte from which the number is generated and MUST be initialised to a
//; non zero value or this function will always return zero. Also r_seed
//; must be in RAM, you can see why......
//rand_8
// LDA r_seed ; get seed
// ASL ; shift byte
// BCC no_eor ; branch if no carry
//
// EOR #$CF ; else EOR with $CF
//no_eor
// STA r_seed ; save number as next seed
// RTS ; done
//r_seed
// .byte 1 ; prng seed byte, must not be zero
#include <stdio.h>
unsigned char r_seed=1;
int rand8(void) {
if (r_seed&0x80) {
r_seed<<=1;
r_seed^=0xcf;
}
else {
r_seed<<=1;
}
return r_seed;
}
int main(int argc, char **argv) {
int i,r;
for(i=0;i<1024;i++) {
r=rand8();
printf("%02X m%02X\n",r,r&0x1f);
}
return 0;
}