Skip to content

Commit b6c1929

Browse files
runer112Matt Waltz
authored and
Matt Waltz
committed
Improve and optimize random functions (#74)
Summary: * Add random and srandom, uint32_t variants of rand and srand. * random implements XSadd with shift parameters (19, 21, 8). This is a fast PRNG with a period of 2^128-1 which passes the dieharder tests (at least, no tests fail; some passes are weak). * rand, srand, and randInt use random as the underlying generator. * A complete random call takes 579 cycles. * A complete rand call takes 647 cycles. * A complete rand call previously took 4213 cycles and undoubtedly produced pseudorandom numbers of poorer quality. * Add random example and autotester configuration.
1 parent ad5cbef commit b6c1929

File tree

12 files changed

+258
-43
lines changed

12 files changed

+258
-43
lines changed

examples/random/autotester.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"rom": "84pce_515.rom",
3+
"transfer_files": [
4+
"bin/DEMO.8xp"
5+
],
6+
"target": {
7+
"name": "DEMO",
8+
"isASM": true
9+
},
10+
"sequence": [
11+
"action|launch",
12+
"hashWait|1",
13+
"key|enter",
14+
"hashWait|2"
15+
],
16+
"hashes": {
17+
"1": {
18+
"description": "VRAM filled with output of random()",
19+
"start": "vram_start",
20+
"size": "vram_16_size",
21+
"expected_CRCs": [ "5FB4A617" ]
22+
},
23+
"2": {
24+
"description": "Back to the home screen (exit check)",
25+
"start": "vram_start",
26+
"size": "vram_16_size",
27+
"expected_CRCs": [ "FFAF89BA", "101734A5", "9DA19F44" ]
28+
}
29+
}
30+
}

examples/random/makefile

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# ----------------------------
2+
# Set NAME to the program name
3+
# Set DEBUGMODE to "DEBUG" to use debug functions
4+
# Set ICON to the png icon file name
5+
# Set DESCRIPTION to display within a compatible shell
6+
# Set COMPRESSED to "YES" to create a compressed program
7+
# ** Add all shared library names to L **
8+
# ----------------------------
9+
10+
NAME ?= DEMO
11+
DEBUGMODE ?= NDEBUG
12+
COMPRESSED ?= NO
13+
ICON ?= iconc.png
14+
DESCRIPTION ?= "C SDK Demo"
15+
16+
L ?=
17+
18+
# ----------------------------
19+
# Specify source and output locations
20+
# ----------------------------
21+
22+
SRCDIR ?= src
23+
OBJDIR ?= obj
24+
BINDIR ?= bin
25+
GFXDIR ?= src/gfx
26+
27+
# ----------------------------
28+
# Use OS helper functions (Advanced)
29+
# ----------------------------
30+
31+
USE_FLASH_FUNCTIONS ?= YES
32+
33+
include $(CEDEV)/include/.makefile

examples/random/readme.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Random Fill Screen Demo
2+
3+
This is a simple demo to demonstrate filling the screen with random colors.
4+
5+
![Screenshot](screenshot.png)
6+
7+
---
8+
9+
This demo is a part of the C SDK Toolchain for use on the CE.

examples/random/screenshot.png

208 KB
Loading

examples/random/src/main.c

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdbool.h>
2+
#include <stddef.h>
3+
#include <stdint.h>
4+
#include <tice.h>
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
10+
void main(void) {
11+
/* Fill VRAM with random data */
12+
uint32_t *lcd_Ram_i, *lcd_Ram_end = (uint32_t *) ((int) lcd_Ram + LCD_SIZE);
13+
for (lcd_Ram_i = (uint32_t *) lcd_Ram; lcd_Ram_i < lcd_Ram_end; lcd_Ram_i++) {
14+
*lcd_Ram_i = random();
15+
}
16+
17+
/* Wait for a key press */
18+
while (!os_GetCSC());
19+
}

examples/random/test/expected.bin

150 KB
Binary file not shown.

src/ce/random.src

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
.def _random
2+
.def __state
3+
.assume adl=1
4+
5+
; uint32_t random(void);
6+
7+
; https://github.com/MersenneTwister-Lab/XSadd/blob/master/xsadd.h#L75
8+
; using shift parameters (19, 21, 8) instead of (15, 18, 11)
9+
10+
; uint32_t xsadd(uint32_t state[static 4])
11+
; {
12+
; uint32_t s0, s1, s2, t0, t1, t2, t3, z, result;
13+
; t0 = state[0];
14+
; state[0] = state[1]; state[1] = state[2]; state[2] = state[3];
15+
; s0 = t0 << 19;
16+
; t1 = t0 ^ s0;
17+
; s1 = t1 >> 21;
18+
; t2 = t1 ^ s1;
19+
; z = state[3];
20+
; s2 = z << 8;
21+
; t3 = t2 ^ s2;
22+
; state[3] = t3;
23+
; result = t3 + state[2];
24+
; return result;
25+
; }
26+
27+
SEGMENT DATA
28+
__state:
29+
dl 0d0e0f10h,090a0b0ch,05060708h,01020304h
30+
31+
SEGMENT CODE
32+
_random:
33+
; Read state[0] and perform state shifting.
34+
ld iy,__state ; iy = &state[0]
35+
ld hl,(iy+0*4+0) ; hl = hl(state[0])
36+
push hl
37+
ld hl,(iy+0*4+2) ; hl = eu(state[0])
38+
push hl
39+
lea hl,iy+1*4 ; hl = &state[1]
40+
lea de,iy+0*4 ; de = &state[0]
41+
ld bc,3*4
42+
ldir ; state[0] = state[1]
43+
; state[1] = state[2]
44+
; state[2] = state[3]
45+
pop bc
46+
pop de ; bcde = state[0] == t0
47+
;
48+
; s0 = t0 << 19 ==> s0h == 0 ==> t1h = t0h
49+
; s0l == 0 ==> t1l = t0l
50+
;
51+
; s1 = t1 >> 21 ==> s1e == 0 ==> t2e = t1e
52+
; s1u == 0 ==> t2u = t1u
53+
;
54+
; s2 = z << 8 ==> s2e == zu ==> t3e == t2e ^ s2e == t1e ^ s2e == t0e ^ s0e ^ s2e
55+
; s2u == zh ==> t3u == t2u ^ s2u == t1u ^ s2u == t0u ^ s0u ^ s2u
56+
; s2h == zl ==> t3h == t2h ^ s2h == t1h ^ s1h ^ s2h == t0h ^ s1h ^ s2h
57+
; s2l == 0 ==> t3l == t2l == t1l ^ s1l == t0l ^ s1l
58+
;
59+
; Calculate s0.
60+
ld h,d
61+
ld l,e ; hl = t0hl == t0 << 16
62+
add hl,hl
63+
add hl,hl
64+
add hl,hl ; hl = t0 << 19 = s0eu
65+
; h = s0e
66+
; l = s0u
67+
; Calculate t1e and t3e.
68+
ld a,b ; a = t0e
69+
xor a,h ; a = t0e ^ s0e == t1e
70+
ld h,a ; h = t1e
71+
xor a,(iy+3*4+2) ; a = t1e ^ zu == t2e ^ s2e == t3e
72+
ld (iy+3*4+3),a ; e(state[3]) = t3e
73+
ld b,a ; b = t3e
74+
; Calculate t1u and t3u.
75+
ld a,c ; a = t0u
76+
xor a,l ; a = t0u ^ s0u == t1u
77+
ld l,a ; l = t1u
78+
; hl = t1eu == t1 >> 16
79+
xor a,(iy+3*4+1) ; a = t1u ^ zh == t2u ^ s2u == t3u
80+
ld (iy+3*4+2),a ; u(state[3]) = t3u
81+
; Calculate s1.
82+
xor a,a ; a = 0
83+
add.s hl,hl
84+
adc a,a
85+
add.s hl,hl
86+
adc a,a
87+
add.s hl,hl
88+
adc a,a ; ahl = (t1 >> 16) << 3
89+
; ah = ((t1 >> 16) << 3) >> 8 == t1 >> 21 == s1hl
90+
; a = s1h
91+
; h = s1l
92+
; Calculate t3h.
93+
xor a,d ; a = s1h ^ t0h === s1h ^ t1h == t2h
94+
xor a,(iy+3*4+0) ; a = t2h ^ zl == t2h ^ s2h == t3h
95+
ld (iy+3*4+1),a ; h(state[3]) = t3h
96+
; Calculate t3l.
97+
ld a,e ; a = t0l == t1l
98+
xor a,h ; a = t1l ^ s1l == t2l == t3l
99+
ld (iy+3*4+0),a ; l(state[3]) = t3l
100+
; Calculate result.
101+
ld hl,(iy+3*4)
102+
ld a,b ; auhl = t3
103+
ld de,(iy+2*4)
104+
ld c,(iy+2*4+3) ; cude = state[2]
105+
add hl,de
106+
adc a,c ; auhl = t3 + state[2] = result
107+
ld e,a ; euhl = result
108+
ret

src/ce/srandom.src

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.ref __state
2+
.def _srandom
3+
.def __setstate
4+
.assume adl=1
5+
6+
_MemClear equ 00210E0h
7+
8+
; void srandom(uint32_t seed);
9+
10+
_srandom:
11+
pop bc
12+
pop de
13+
ex (sp),hl ; lude = seed
14+
push de
15+
push bc
16+
ex de,hl
17+
ld a,e ; auhl = seed
18+
__setstate:
19+
ld (__state),hl
20+
ld hl,__state+3
21+
ld (hl),a
22+
ld b,12
23+
__setstateloop:
24+
inc hl
25+
ld (hl),b
26+
djnz __setstateloop
27+
ret

src/ce/tice.h

+17-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,25 @@ extern "C" {
2121
*/
2222

2323
/**
24-
* Creates a random integer value
24+
* Returns a pseudo-random 32-bit integer.
25+
*
26+
* @return the random integer
27+
*/
28+
uint32_t random(void);
29+
30+
/**
31+
* Seeds the pseudo-random number generator used by random() and rand() with the
32+
* value seed.
33+
*
34+
* @param seed the seed value
35+
*/
36+
void srandom(uint32_t seed);
37+
38+
/**
39+
* Returns a pseudo-random integer in the range of min to max-1.
2540
*/
2641
#define randInt(min, max) \
27-
((unsigned)rand() % ((max) - (min) + 1) + (min))
42+
((unsigned)random() % ((max) - (min) + 1) + (min))
2843

2944
/**
3045
* Delays for a number of milliseconds.

src/std/shared/rand.src

+8-32
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
1-
.ref __lmulu
2-
.ref __ladd
3-
.ref __lshru
4-
.ref __land
1+
.ref _random
52
.def _rand
6-
.def __next
73
.assume adl=1
8-
9-
; int rand(void);
104

11-
SEGMENT DATA
12-
__next:
13-
dl 1
5+
; int rand(void);
146

15-
SEGMENT CODE
167
_rand:
17-
ld a,(__next+3)
18-
ld e,a
19-
ld a,65
20-
ld hl,(__next)
21-
ld bc,12996205
22-
call __lmulu
23-
ld bc,12345
24-
xor a,a
25-
call __ladd
26-
ld (__next),hl
27-
ld a,e
28-
ld (__next+3),a
29-
push hl
30-
pop bc
31-
ld l,16
32-
call __lshru
33-
ld e,a
34-
ld hl,bc
35-
ld bc,32767
36-
xor a,a
37-
jp __land
8+
call _random
9+
ld de,1<<23
10+
sbc hl,de
11+
ret p
12+
add hl,de
13+
ret

src/std/shared/srand.src

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
.ref __next
2+
.ref __setstate
23
.def _srand
34
.assume adl=1
45

56
; void srand(unsigned int seed);
6-
7+
78
_srand:
8-
pop de
9-
pop hl
10-
push hl
11-
push de
9+
pop bc
10+
ex (sp),hl
11+
push bc
1212
xor a,a
13-
ld (__next),hl
14-
ld (__next+3),a
15-
ret
13+
jp __setstate

src/std/stdlib.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ typedef union header _HEADER;
4949
extern double _huge_val;
5050
#define HUGE_VAL _huge_val /* overflow error */
5151

52-
#define RAND_MAX 32767 /* maximum value returned by rand() */
52+
#define RAND_MAX 8388607 /* maximum value returned by rand() */
5353

5454
#ifndef SIZE_T_DEFINED
5555
#define SIZE_T_DEFINED

0 commit comments

Comments
 (0)