From 0fa841036f516d73afc861e793448877c3df1883 Mon Sep 17 00:00:00 2001 From: Henk Muller <henk@xmos.com> Date: Fri, 20 Oct 2017 12:07:10 +0100 Subject: [PATCH 01/10] First effort at extracting true random bits - horribly broken at the moment --- .../AN002xx_random_number_generation/Makefile | 10 ++++ .../README.rst | 34 ++++++++++++ .../config.xscope | 23 ++++++++ .../doc/rst/AN002xx.rst | 11 ++++ .../doc/rst/xdoc.conf | 2 + .../src/random_numbers.xc | 25 +++++++++ lib_random/api/random.h | 13 +++++ lib_random/src/true_random.xc | 53 +++++++++++++++++++ 8 files changed, 171 insertions(+) create mode 100644 examples/AN002xx_random_number_generation/Makefile create mode 100644 examples/AN002xx_random_number_generation/README.rst create mode 100644 examples/AN002xx_random_number_generation/config.xscope create mode 100644 examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst create mode 100644 examples/AN002xx_random_number_generation/doc/rst/xdoc.conf create mode 100644 examples/AN002xx_random_number_generation/src/random_numbers.xc create mode 100644 lib_random/src/true_random.xc diff --git a/examples/AN002xx_random_number_generation/Makefile b/examples/AN002xx_random_number_generation/Makefile new file mode 100644 index 0000000..504dbff --- /dev/null +++ b/examples/AN002xx_random_number_generation/Makefile @@ -0,0 +1,10 @@ +TARGET = SMART-MIC-4-TILE-1V0 +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -O2 -g -fxscope -Wunused +XCORE_ARM_PROJECT = 0 +VERBOSE = 0 + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/examples/AN002xx_random_number_generation/README.rst b/examples/AN002xx_random_number_generation/README.rst new file mode 100644 index 0000000..a92471e --- /dev/null +++ b/examples/AN002xx_random_number_generation/README.rst @@ -0,0 +1,34 @@ +Noise Suppression and Automatic Gain Control example +==================================================== + +.. version:: 0.0.1 + +Summary +------- + +This example demonstrates how to use the automatic gain control library, +the noise suppression library, and the microphone array library in order to +create a meaningful AGC + +Required tools and libraries +............................ + +.. appdeps:: + +Required hardware +................. + +A smart microphone board. + +Prerequisites +............. + + * This document assumes familiarity with the XMOS xCORE architecture, + the XMOS tool chain and the xC language. Documentation related to these + aspects which are not specific to this application note are linked to in + the references appendix. + + * For a description of XMOS related terms found in this document + please see the XMOS Glossary [#]_. + +.. [#] http://www.xmos.com/published/glossary diff --git a/examples/AN002xx_random_number_generation/config.xscope b/examples/AN002xx_random_number_generation/config.xscope new file mode 100644 index 0000000..6436587 --- /dev/null +++ b/examples/AN002xx_random_number_generation/config.xscope @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- ======================================================= --> +<!-- The 'ioMode' attribute on the xSCOPEconfig --> +<!-- element can take the following values: --> +<!-- "none", "basic", "timed" --> +<!-- --> +<!-- The 'type' attribute on Probe --> +<!-- elements can take the following values: --> +<!-- "STARTSTOP", "CONTINUOUS", "DISCRETE", "STATEMACHINE" --> +<!-- --> +<!-- The 'datatype' attribute on Probe --> +<!-- elements can take the following values: --> +<!-- "NONE", "UINT", "INT", "FLOAT" --> +<!-- ======================================================= --> + +<xSCOPEconfig ioMode="basic" enabled="false"> + + <!-- For example: --> + <Probe name="CH0" type="CONTINUOUS" datatype="INT" units="Value" enabled="true"/> + <!-- From the target code, call: xscope_int(PROBE_NAME, value); --> + +</xSCOPEconfig> diff --git a/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst b/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst new file mode 100644 index 0000000..08592a2 --- /dev/null +++ b/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst @@ -0,0 +1,11 @@ +.. include:: ../../README.rst + +|newpage| + +Overview +-------- + +Introduction +............ + +This demo application shows how to use random numbers. diff --git a/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf b/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf new file mode 100644 index 0000000..cb5aab6 --- /dev/null +++ b/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf @@ -0,0 +1,2 @@ +XMOSNEWSTYLE=1 +SOURCE_INCLUDE_DIRS=../../src diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc new file mode 100644 index 0000000..eb804e2 --- /dev/null +++ b/examples/AN002xx_random_number_generation/src/random_numbers.xc @@ -0,0 +1,25 @@ +// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved + +#include <stdint.h> +#include <stdio.h> +#include <xs1.h> +#include "random.h" + +#define N 32 + +int main(void) { + int n[N], rand[N]; + timer tmr; + int t0; + printf("Hello\n"); + random_true_init(); + for(int i = 0; i < N; i++) { + tmr :> t0; + tmr when timerafter(t0 + 10000) :> void; + {n[i], rand[i]} = random_true_get_bits(); + } + for(int i = 0; i < N; i++) { + printf("** %d %d\n", n[i], rand[i]); + } + return 0; +} diff --git a/lib_random/api/random.h b/lib_random/api/random.h index 72efee2..de79329 100644 --- a/lib_random/api/random.h +++ b/lib_random/api/random.h @@ -47,4 +47,17 @@ random_get_random_number(REFERENCE_PARAM(random_generator_t, g)); void random_get_random_bytes(REFERENCE_PARAM(random_generator_t, g), uint8_t in_buffer[], size_t byte_count); +#ifdef __XC__ +/** Function that produces a number of random bits. It returns two + * integers, the number of random bits, and the actual random bits. At most + * 16 random bits are returned. To get a large number of random bits this + * function should be called regularly. Calling it too quickly since a + * previous call will return 0. + * + * \returns Number of bits, and random bits. + */ +{uint32_t,uint32_t} random_true_get_bits(); +void random_true_init(); +#endif + #endif // __RANDOM_H__ diff --git a/lib_random/src/true_random.xc b/lib_random/src/true_random.xc new file mode 100644 index 0000000..5a37b19 --- /dev/null +++ b/lib_random/src/true_random.xc @@ -0,0 +1,53 @@ +#include <platform.h> +#include <stdio.h> +#include <xs1.h> +#include <xclib.h> +#include "random.h" + +#define MIN_RANDOM_BITS 8 + +{int,int} static getro() { + int time; + asm("gettime %0" : "=r" (time)); + setps(0x60B, 0); + short x = getps(0x70B); + setps(0x60B, 3); + return {time, x}; +} + +static int last_used_time, last_used_ro; +static unsigned current_ro_per_tick; + +void random_true_init() { + int time, ro, time2, ro2; + timer tmr; + {time, ro} = getro(); + tmr when timerafter(time+1000) :> void; + {time2, ro2} = getro(); + last_used_time = time; + last_used_ro = ro; + current_ro_per_tick = (ro2 - last_used_ro) * 0x10000LL / (time2 - last_used_time); +// printf("%9u %5u %08x\n", last_used_time, last_used_ro & 0xFFFFU, current_ro_per_tick); +} + +static inline int cls(int x) { + return x < 0 ? clz(-x) : clz(x); +} + +{uint32_t,uint32_t} random_true_get_bits() { + int time, ro; + {time, ro} = getro(); + int dtime = time - last_used_time; + short expectedro = last_used_ro + ((dtime * (long long) current_ro_per_tick) >> 16); + short dro = ro - expectedro; + int random_bits = dro >> MIN_RANDOM_BITS; + int nbits = 31 - cls(random_bits); + if (nbits > 0) { + current_ro_per_tick = (expectedro + dro - last_used_ro) * 0x10000LL / (time - last_used_time); + last_used_time = time; + last_used_ro = ro; + printf("%9u %5u %08x\n", last_used_time, last_used_ro & 0xFFFFU, current_ro_per_tick); + return {nbits, dro & (1 << nbits) - 1}; + } + return {0, 0}; +} From 1bab77672a844739574db5dc3219274e9aa7b1e0 Mon Sep 17 00:00:00 2001 From: Henk Muller <henk@xmos.com> Date: Mon, 23 Oct 2017 16:55:21 +0100 Subject: [PATCH 02/10] First version of true random that does something that appears alrightish --- .../AN002xx_random_number_generation/Makefile | 2 +- .../src/random_numbers.xc | 111 ++++++++++++++++-- lib_random/src/true_random.xc | 38 +++--- 3 files changed, 126 insertions(+), 25 deletions(-) diff --git a/examples/AN002xx_random_number_generation/Makefile b/examples/AN002xx_random_number_generation/Makefile index 504dbff..48cf165 100644 --- a/examples/AN002xx_random_number_generation/Makefile +++ b/examples/AN002xx_random_number_generation/Makefile @@ -2,7 +2,7 @@ TARGET = SMART-MIC-4-TILE-1V0 APP_NAME = USED_MODULES = lib_random -XCC_FLAGS = -O2 -g -fxscope -Wunused +XCC_FLAGS = -O2 -g -Wunused -fxscope XCORE_ARM_PROJECT = 0 VERBOSE = 0 diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc index eb804e2..93082b5 100644 --- a/examples/AN002xx_random_number_generation/src/random_numbers.xc +++ b/examples/AN002xx_random_number_generation/src/random_numbers.xc @@ -2,24 +2,115 @@ #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <xs1.h> #include "random.h" -#define N 32 +#define MAXX 256 +#define MAXY 256 +#define MAXBITS (MAXX * MAXY) -int main(void) { - int n[N], rand[N]; +unsigned char bits[MAXBITS]; + +void blocktest(int n) { + int hist[256]; + for(int i = 0; i < 256; i++) { + hist[i] = 0; + } + for(int i = 0; i < MAXBITS - n; i++) { + int val = 0; + for(int j = 0; j < n; j++) { + val = val << 1 | bits[i+j]; + } + hist[val]++; + } + printf("Blocktest %d\n", n); + for(int i = 0; i < (1<<n); i++) { + printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i]-(MAXBITS >> n)) < MAXX ? "Ok" : "Hmm"); + } + printf("\n"); +} + +void runtest() { + int hist[200]; + int old = 0; + int run = 0; + for(int i = 0; i < 200; i++) { + hist[i] = 0; + } + for(int i = 0; i < MAXBITS; i++) { + if(bits[i] == old) { + run++; + } else { + hist[run]++; + run = 1; + } + } + printf("Runtest:\n"); + for(int i = 1; i < 10; i++) { + printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i] - (MAXBITS >> (i+1))) < (MAXX >> (i/2)) ? "Ok" : "Hmm" ); + } + printf("\n"); +} + +void xmain(void) { + int n, rand; timer tmr; int t0; - printf("Hello\n"); + int sum = 0; + int ns = 0; + int ticks = 1500; random_true_init(); - for(int i = 0; i < N; i++) { - tmr :> t0; - tmr when timerafter(t0 + 10000) :> void; - {n[i], rand[i]} = random_true_get_bits(); + while(sum < MAXBITS) { +// tmr when timerafter(t0 + ticks) :> void; + {n, rand} = random_true_get_bits(); + if (n == 0) { + tmr :> t0; + tmr when timerafter(t0 + 10 + 0 * rand) :> void; + } else { + for(int i = 0; i < n && sum < MAXBITS; i++) { + bits[sum] = rand & 1; + rand >>= 1; + sum++; + } + ns++; + } + } + printf("Average bits per call %f at %d ticks\n", sum/(float)ns, ticks); + blocktest(1); + blocktest(2); + blocktest(3); + runtest(); +// printf("P2\n%d %d\n1\n", MAXX, MAXY); + for(int i = 0; i < MAXX; i++) { + for(int j = 0; j < MAXY; j++) { +// printf("%d ", bits[i*MAXY+j]); + } +// printf("\n"); + } +} + +int busy(int x) { + return 0; + for(int j = 0; j < 100; j++) { + for(int i = 0; i < 100000000; i++) { + x = x * 1234567 + 1; + } } - for(int i = 0; i < N; i++) { - printf("** %d %d\n", n[i], rand[i]); + printf("%d\n", x); + return x; +} + +int main(void) { + par { + busy(0x3); + busy(0x4); + busy(0x5); + busy(0x6); + busy(0x7); + busy(0x8); + busy(0x9); + xmain(); } return 0; } diff --git a/lib_random/src/true_random.xc b/lib_random/src/true_random.xc index 5a37b19..3b6de2b 100644 --- a/lib_random/src/true_random.xc +++ b/lib_random/src/true_random.xc @@ -4,30 +4,36 @@ #include <xclib.h> #include "random.h" -#define MIN_RANDOM_BITS 8 +#define MIN_RANDOM_BITS 12 {int,int} static getro() { int time; - asm("gettime %0" : "=r" (time)); setps(0x60B, 0); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); short x = getps(0x70B); + asm("gettime %0" : "=r" (time)); setps(0x60B, 3); return {time, x}; } static int last_used_time, last_used_ro; static unsigned current_ro_per_tick; +static int scanning = 0; +static int final_time = 0; void random_true_init() { int time, ro, time2, ro2; timer tmr; {time, ro} = getro(); - tmr when timerafter(time+1000) :> void; + tmr when timerafter(time+5000) :> void; {time2, ro2} = getro(); last_used_time = time; last_used_ro = ro; - current_ro_per_tick = (ro2 - last_used_ro) * 0x10000LL / (time2 - last_used_time); -// printf("%9u %5u %08x\n", last_used_time, last_used_ro & 0xFFFFU, current_ro_per_tick); + current_ro_per_tick = ((short)(ro2 - last_used_ro)) * 0x10000LL / (time2 - last_used_time); + scanning = 1; } static inline int cls(int x) { @@ -37,17 +43,21 @@ static inline int cls(int x) { {uint32_t,uint32_t} random_true_get_bits() { int time, ro; {time, ro} = getro(); + int dtime = time - last_used_time; - short expectedro = last_used_ro + ((dtime * (long long) current_ro_per_tick) >> 16); + int expectedro = last_used_ro + ((dtime * (long long) current_ro_per_tick) >> 16); short dro = ro - expectedro; - int random_bits = dro >> MIN_RANDOM_BITS; - int nbits = 31 - cls(random_bits); - if (nbits > 0) { - current_ro_per_tick = (expectedro + dro - last_used_ro) * 0x10000LL / (time - last_used_time); - last_used_time = time; - last_used_ro = ro; - printf("%9u %5u %08x\n", last_used_time, last_used_ro & 0xFFFFU, current_ro_per_tick); + int nbits = 32 - cls(dro) - MIN_RANDOM_BITS; + if (scanning) { + if (nbits <= 0) { + return {0, 10000}; // called much too early + } + final_time = time + dtime; + scanning = 0; + return {0, dtime}; // call again in dtime; + } else if ((time - final_time) > 0) { + random_true_init(); return {nbits, dro & (1 << nbits) - 1}; } - return {0, 0}; + return {0,final_time - time}; } From 07c4ed0d73956951c345976bc809668134841d48 Mon Sep 17 00:00:00 2001 From: Henk Muller <henk@xmos.com> Date: Mon, 23 Oct 2017 16:59:54 +0100 Subject: [PATCH 03/10] First version of true random that does something that appears alrightish --- .../src/random_numbers.xc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc index 93082b5..4576973 100644 --- a/examples/AN002xx_random_number_generation/src/random_numbers.xc +++ b/examples/AN002xx_random_number_generation/src/random_numbers.xc @@ -10,7 +10,15 @@ #define MAXY 256 #define MAXBITS (MAXX * MAXY) -unsigned char bits[MAXBITS]; +unsigned char thebits[MAXBITS/8]; + +unsigned int getbit(int i) { + return (thebits[i>>3] >> (i&7)) & 1; +} + +unsigned int setbit(int i) { + return thebits[i>>3] |= 1 << (i&7); +} void blocktest(int n) { int hist[256]; @@ -20,7 +28,7 @@ void blocktest(int n) { for(int i = 0; i < MAXBITS - n; i++) { int val = 0; for(int j = 0; j < n; j++) { - val = val << 1 | bits[i+j]; + val = val << 1 | getbit(i+j); } hist[val]++; } @@ -39,7 +47,7 @@ void runtest() { hist[i] = 0; } for(int i = 0; i < MAXBITS; i++) { - if(bits[i] == old) { + if(getbit(i) == old) { run++; } else { hist[run]++; @@ -69,7 +77,7 @@ void xmain(void) { tmr when timerafter(t0 + 10 + 0 * rand) :> void; } else { for(int i = 0; i < n && sum < MAXBITS; i++) { - bits[sum] = rand & 1; + setbit(sum, rand & 1); rand >>= 1; sum++; } From 4307eefe431de0ecaa530a1968c3b82b412f6cb4 Mon Sep 17 00:00:00 2001 From: Henk Muller <henk@xmos.com> Date: Wed, 1 Nov 2017 12:11:28 +0000 Subject: [PATCH 04/10] TOok all the clever bits out as they reduced randomness. Left with a simple implementation that will produce random if the attacker does not have physical access to the chip --- .../src/random_numbers.xc | 86 ++++++++++++------- lib_random/api/random.h | 31 +++++-- lib_random/src/true_random.xc | 75 +++++++--------- 3 files changed, 112 insertions(+), 80 deletions(-) diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc index 4576973..e369c94 100644 --- a/examples/AN002xx_random_number_generation/src/random_numbers.xc +++ b/examples/AN002xx_random_number_generation/src/random_numbers.xc @@ -6,8 +6,8 @@ #include <xs1.h> #include "random.h" -#define MAXX 256 -#define MAXY 256 +#define MAXX 1024 +#define MAXY 1024 #define MAXBITS (MAXX * MAXY) unsigned char thebits[MAXBITS/8]; @@ -16,8 +16,8 @@ unsigned int getbit(int i) { return (thebits[i>>3] >> (i&7)) & 1; } -unsigned int setbit(int i) { - return thebits[i>>3] |= 1 << (i&7); +unsigned int setbit(int i, int val) { + return thebits[i>>3] |= val << (i&7); } void blocktest(int n) { @@ -61,64 +61,92 @@ void runtest() { printf("\n"); } -void xmain(void) { +void fillmepseudo(void) { + random_generator_t rt = random_create_generator_from_seed(0); + int sum = 0; + random_true_init(); + while(sum < MAXBITS) { + unsigned rand = random_get_random_number(rt); + for(int i = 0; i < 32 && sum < MAXBITS; i++) { + setbit(sum, rand & 1); + rand >>= 1; + sum++; + } + } +} + +void fillmetrue(void) { int n, rand; timer tmr; - int t0; + int t0, t1; int sum = 0; - int ns = 0; - int ticks = 1500; random_true_init(); + tmr :> t0; while(sum < MAXBITS) { -// tmr when timerafter(t0 + ticks) :> void; {n, rand} = random_true_get_bits(); if (n == 0) { - tmr :> t0; - tmr when timerafter(t0 + 10 + 0 * rand) :> void; + // tmr when timerafter(rand) :> void; } else { for(int i = 0; i < n && sum < MAXBITS; i++) { setbit(sum, rand & 1); rand >>= 1; sum++; } - ns++; + if ((sum & 0xffff) == 0) { + int time; + asm volatile ("gettime %0" : "=r" (time)); + printf("%11d %d\n", time, sum); + } } } - printf("Average bits per call %f at %d ticks\n", sum/(float)ns, ticks); + tmr :> t1; + printf("Ticks taken: %d, %d per bit\n", t1-t0, (t1-t0)/sum); +} + +void xmain(chanend done[7]) { + for(int i = 0; i < 7; i++) { + done[i] <: 0; + } + fillmetrue(); blocktest(1); blocktest(2); blocktest(3); runtest(); -// printf("P2\n%d %d\n1\n", MAXX, MAXY); + return; + printf("P2\n%d %d\n1\n", MAXX, MAXY); for(int i = 0; i < MAXX; i++) { for(int j = 0; j < MAXY; j++) { -// printf("%d ", bits[i*MAXY+j]); + printf("%d ", getbit(i*MAXY+j)); } -// printf("\n"); + printf("\n"); } } -int busy(int x) { - return 0; - for(int j = 0; j < 100; j++) { - for(int i = 0; i < 100000000; i++) { +int busy(int x, chanend y) { + while(1) { + for(int i = 0; i < 1000; i++) { x = x * 1234567 + 1; } + select { + case y :> int _: return x; + default: break; + } } - printf("%d\n", x); return x; } + int main(void) { + chan done[7]; par { - busy(0x3); - busy(0x4); - busy(0x5); - busy(0x6); - busy(0x7); - busy(0x8); - busy(0x9); - xmain(); + busy(0x3, done[0]); + busy(0x4, done[1]); + busy(0x5, done[2]); + busy(0x6, done[3]); + busy(0x7, done[4]); + busy(0x8, done[5]); + busy(0x9, done[6]); + xmain(done); } return 0; } diff --git a/lib_random/api/random.h b/lib_random/api/random.h index de79329..5a506fc 100644 --- a/lib_random/api/random.h +++ b/lib_random/api/random.h @@ -49,15 +49,34 @@ void random_get_random_bytes(REFERENCE_PARAM(random_generator_t, g), uint8_t in_ #ifdef __XC__ /** Function that produces a number of random bits. It returns two - * integers, the number of random bits, and the actual random bits. At most - * 16 random bits are returned. To get a large number of random bits this - * function should be called regularly. Calling it too quickly since a - * previous call will return 0. + * integers. * - * \returns Number of bits, and random bits. + * If random bits are available, then it returns the number of random bits, + * and the actual random bits. + * + * If no random bits are available, then it returns 0 (for no random bits) + * and the time in ticks at which new bits are available. The code can wait + * for this time (for example in a select statement), and then collect the + * random bits. + * + * At most 16 random bits are returned. To get a large number of random + * bits this function should be called regularly. Calling it too quickly + * since a previous call will return 0. + * + * \returns Number of bits, and random bits, or 0 and timestamp in the future. + */ +{uint32_t,int32_t} random_true_get_bits(); + +/** Function that initialises the true random number generator. Calling + * this function will start the free running oscillator. This will take a + * bit of extra power. */ -{uint32_t,uint32_t} random_true_get_bits(); void random_true_init(); + +/** Function that uninitialises the true random number generator. This will + * stop the ring oscillator, and reduce the power foot print a little. + */ +void random_true_uninit(); #endif #endif // __RANDOM_H__ diff --git a/lib_random/src/true_random.xc b/lib_random/src/true_random.xc index 3b6de2b..7dbc852 100644 --- a/lib_random/src/true_random.xc +++ b/lib_random/src/true_random.xc @@ -4,60 +4,45 @@ #include <xclib.h> #include "random.h" -#define MIN_RANDOM_BITS 12 +#define MIN_RANDOM_BITS 8 -{int,int} static getro() { - int time; +static void inline ro_on() { + setps(0x60B, 2); +} + +static void inline ro_off() { setps(0x60B, 0); - asm("nop"); - asm("nop"); - asm("nop"); - asm("nop"); - short x = getps(0x70B); - asm("gettime %0" : "=r" (time)); - setps(0x60B, 3); - return {time, x}; } -static int last_used_time, last_used_ro; -static unsigned current_ro_per_tick; -static int scanning = 0; -static int final_time = 0; -void random_true_init() { - int time, ro, time2, ro2; - timer tmr; - {time, ro} = getro(); - tmr when timerafter(time+5000) :> void; - {time2, ro2} = getro(); - last_used_time = time; - last_used_ro = ro; - current_ro_per_tick = ((short)(ro2 - last_used_ro)) * 0x10000LL / (time2 - last_used_time); - scanning = 1; -} -static inline int cls(int x) { - return x < 0 ? clz(-x) : clz(x); +#define TIME_FOR_ONE_BIT 20000 +static int last_time = 0; + +void random_true_init() { + asm("gettime %0" : "=r" (last_time)); + ro_on(); } -{uint32_t,uint32_t} random_true_get_bits() { +{uint32_t,int32_t} random_true_get_bits() { int time, ro; - {time, ro} = getro(); + + ro_off(); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + ro = getps(0x70B); + asm("gettime %0" : "=r" (time)); + ro_on(); - int dtime = time - last_used_time; - int expectedro = last_used_ro + ((dtime * (long long) current_ro_per_tick) >> 16); - short dro = ro - expectedro; - int nbits = 32 - cls(dro) - MIN_RANDOM_BITS; - if (scanning) { - if (nbits <= 0) { - return {0, 10000}; // called much too early - } - final_time = time + dtime; - scanning = 0; - return {0, dtime}; // call again in dtime; - } else if ((time - final_time) > 0) { - random_true_init(); - return {nbits, dro & (1 << nbits) - 1}; + if (((unsigned)(time - last_time)) > TIME_FOR_ONE_BIT) { + last_time = time; + return {1, ro & 1}; } - return {0,final_time - time}; + return {0, last_time + TIME_FOR_ONE_BIT}; +} + +void random_true_uninit() { + ro_off(); } From 456de3823d0cc844c6b3b52215769420040b6a17 Mon Sep 17 00:00:00 2001 From: Henk Muller <henk@xmos.com> Date: Wed, 1 Nov 2017 12:12:13 +0000 Subject: [PATCH 05/10] Added board file on which random number generator was developed - should probably be removed and replaced with ordinary EXPLORER-200. --- .../SMART-MIC-4-TILE-1V0.xn | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100755 examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn diff --git a/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn b/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn new file mode 100755 index 0000000..1bb07e9 --- /dev/null +++ b/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn @@ -0,0 +1,153 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Network xmlns="http://www.xmos.com" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.xmos.com http://www.xmos.com"> + <Type>Device</Type> + <Name>Mic Array Quad Tile</Name> + + <Declarations> + <Declaration>tileref tile[4]</Declaration> + <Declaration>tileref usb_tile</Declaration> + </Declarations> + + <Packages> + <Package id="0" Type="XS2-UFnA-512-TQ128"> + <Nodes> + <Node Id="0" InPackageId="0" Type="XS2-L16A-512" Oscillator="24MHz" SystemFrequency="500MHz" ReferenceFrequency="100MHz"> + + <Boot> + <Source Location="bootFlash0"/> + <Bootee NodeId="2"/> + </Boot> + <Tile Number="0" Reference="tile[0]"> + <!-- Quad flash ports --> + <Port Location="XS1_PORT_1B" Name="PORT_SQI_CS"/> + <Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK"/> + <Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO"/> + + <Port Location="XS1_PORT_1M" Name="PORT_PLL_MOD"/> + <Port Location="XS1_PORT_1P" Name="PORT_BGT_SPI_CLK"/> + <Port Location="XS1_PORT_1A" Name="PORT_BGT_SPI_CS_N"/> + <Port Location="XS1_PORT_1F" Name="PORT_BGT_SPI_MISO"/> + <Port Location="XS1_PORT_1E" Name="PORT_BGT_SPI_MOSI"/> + <Port Location="XS1_PORT_1D" Name="PORT_BGT_IRQ"/> + <Port Location="XS1_PORT_1O" Name="PORT_I2C_SCL"/> + <Port Location="XS1_PORT_1N" Name="PORT_I2C_SDA"/> + </Tile> + <Tile Number="1" Reference="tile[1]"> + <!-- USB --> + <Port Location="XS1_PORT_1H" Name="PORT_USB_TX_READYIN"/> + <Port Location="XS1_PORT_1J" Name="PORT_USB_CLK"/> + <Port Location="XS1_PORT_1K" Name="PORT_USB_TX_READYOUT"/> + <Port Location="XS1_PORT_1I" Name="PORT_USB_RX_READY"/> + <Port Location="XS1_PORT_1E" Name="PORT_USB_FLAG0"/> + <Port Location="XS1_PORT_1F" Name="PORT_USB_FLAG1"/> + <Port Location="XS1_PORT_1G" Name="PORT_USB_FLAG2"/> + <Port Location="XS1_PORT_8A" Name="PORT_USB_TXD"/> + <Port Location="XS1_PORT_8B" Name="PORT_USB_RXD"/> + + <!-- I2C --> + <!-- Note: Bit 1 of PORT 4E is I2C_SCL --> + <!-- Bit 2 of PORT 4E is I2C_SDA --> + <Port Location="XS1_PORT_4E" Name="PORT_I2C_SCL_SDA"/> + <Port Location="XS1_PORT_4F" Name="PORT_DAC_RST_N"/> + + <!-- I2S --> + <Port Location="XS1_PORT_1M" Name="PORT_I2S_BCLK"/> + <Port Location="XS1_PORT_1N" Name="PORT_I2S_LRCLK"/> + <Port Location="XS1_PORT_1O" Name="PORT_MCLK_IN"/> + <Port Location="XS1_PORT_1P" Name="PORT_I2S_DAC0"/> + <Port Location="XS1_PORT_1L" Name="PORT_I2S_DAC1"/> + <Port Location="XS1_PORT_1C" Name="PORT_I2S_ADC0"/> + <Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/> + </Tile> + </Node> + <Node Id="1" InPackageId="1" Type="periph:XS1-SU" Reference="usb_tile" Oscillator="24MHz"/> + </Nodes> + <Links> + <Link Encoding="5wire"> + <LinkEndpoint NodeId="0" Link="8" Delays="52clk,52clk"/> + <LinkEndpoint NodeId="1" Link="XL0" Delays="1clk,1clk"/> + </Link> + </Links> + </Package> + + <Package id="1" Type="XS2-LnA-512-TQ128"> + <Nodes> + <Node Id="2" InPackageId="0" Type="XS2-L16A-512" SystemFrequency="500MHz" Oscillator="24MHz" ReferenceFrequency="100MHz"> + <Boot> + <Source Location="LINK" BootMode="4"/> + </Boot> + <Tile Number="0" Reference="tile[2]"> + <!-- Mics --> + <!-- Notes: XS1_PORT_4C is for mics 0, 1, 6 and 7 --> + <!-- XS1_PORT_4D is for mics 2, 3, 4 and 5 --> + <Port Location="XS1_PORT_8B" Name="PORT_PDM_DATA"/> + <Port Location="XS1_PORT_1G" Name="PORT_PDM_MCLK"/> + <Port Location="XS1_PORT_1H" Name="PORT_PDM_CLK"/> + </Tile> + <Tile Number="1" Reference="tile[3]"> + <!-- Wireless LAN --> + <Port Location="XS1_PORT_1A" Name="PORT_WLAN_SPI_MOSI"/> + <Port Location="XS1_PORT_1B" Name="PORT_WLAN_SPI_MISO"/> + <Port Location="XS1_PORT_4A" Name="PORT_WLAN_WLAN_SPI_IRQ_N"/> + <!-- Note: Bit 1 of PORT 4B is WLAN_3V3_EN --> + <!-- Bit 2 of PORT 4B is WLAN_RST_N --> + <Port Location="XS1_PORT_4B" Name="PORT_WLAN_3V3_EN_RST_N"/> + <Port Location="XS1_PORT_1C" Name="PORT_WLAN_SPI_CLK"/> + <Port Location="XS1_PORT_1D" Name="PORT_WLAN_SPI_CS_N"/> + + <!-- Button ports --> + <Port Location="XS1_PORT_4C" Name="PORT_BUT_A_TO_D"/> + + <!-- LED ports --> + <Port Location="XS1_PORT_8C" Name="PORT_LED0_TO_7"/> + <!-- Note: Only bits 4-7 of PORT 8D are for LEDs --> + <Port Location="XS1_PORT_8D" Name="PORT_LED8_TO_11"/> + <Port Location="XS1_PORT_1J" Name="PORT_LED_12"/> + </Tile> + </Node> + </Nodes> + </Package> + </Packages> + + <Links> + <Link Encoding="2wire" Delays="3clk"> + <LinkEndpoint NodeId="0" Link="7"/> + <LinkEndpoint NodeId="2" Link="0"/> + </Link> + <Link Encoding="5wire" Delays="3clk"> + <LinkEndpoint NodeId="0" Link="4"/> + <LinkEndpoint NodeId="2" Link="3"/> + </Link> + </Links> + + <!-- XSCOPE --> + <Nodes> + <Node Id="3" Type="device:" RoutingId="0x8000"> + <Service Id="0" Proto="xscope_host_data(chanend c);"> + <Chanend Identifier="c" end="3"/> + </Service> + </Node> + </Nodes> + <Links> + <Link Encoding="2wire" Delays="4,4" Flags="XSCOPE"> + <LinkEndpoint NodeId="0" Link="XL0"/> + <LinkEndpoint NodeId="3" Chanend="1"/> + </Link> + </Links> + + <ExternalDevices> + <Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash0"> + <Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS"/> + <Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK"/> + <Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO"/> + </Device> + </ExternalDevices> + + <JTAGChain> + <JTAGDevice NodeId="0"/> + <JTAGDevice NodeId="2"/> + </JTAGChain> + +</Network> From 3a6a84d78748859ec2cd660f016fce92152a949e Mon Sep 17 00:00:00 2001 From: robert lytton <robert@xmos.com> Date: Wed, 22 Nov 2017 13:46:02 +0000 Subject: [PATCH 06/10] Added random_bit, random_pool, random_prng interfaces deprecated random_create_generator_from_hw_seed() making it's build conditional (add 'RANDOM_ENABLE_HW_SEED=1' to the Makefile) --- .../src/random_numbers.xc | 204 ++++++++---------- lib_random/api/random.h | 49 +---- lib_random/api/random_bit.h | 60 ++++++ lib_random/api/random_pool.h | 74 +++++++ lib_random/api/random_prng.h | 70 ++++++ lib_random/doc/rst/random.rst | 4 +- lib_random/module_build_info | 20 +- lib_random/src/random.xc | 15 +- lib_random/src/random_bit.xc | 71 ++++++ lib_random/src/random_deprecated.c | 21 ++ lib_random/src/random_impl.h | 20 ++ lib_random/src/random_init.c | 17 -- lib_random/src/random_pool.xc | 172 +++++++++++++++ lib_random/src/random_prng.xc | 166 ++++++++++++++ lib_random/src/true_random.xc | 48 ----- test/random/Makefile | 14 ++ test/random/expected.output | 4 + test/random/src/test.xc | 130 +++++++++++ test/random_bit/Makefile | 18 ++ test/random_bit/expected.output | 6 + test/random_bit/src/test.xc | 199 +++++++++++++++++ test/random_pool/Makefile | 11 + test/random_pool/expected.output | 6 + test/random_pool/src/test.xc | 201 +++++++++++++++++ test/random_prng/Makefile | 13 ++ test/random_prng/expected.output | 16 ++ test/random_prng/src/test.xc | 77 +++++++ test/runtests.py | 9 + test/test_random.py | 15 ++ test/test_random_bit.py | 15 ++ test/test_random_pool.py | 15 ++ test/test_random_prng.py | 15 ++ 32 files changed, 1535 insertions(+), 240 deletions(-) mode change 100644 => 100755 lib_random/api/random.h create mode 100755 lib_random/api/random_bit.h create mode 100755 lib_random/api/random_pool.h create mode 100755 lib_random/api/random_prng.h mode change 100644 => 100755 lib_random/module_build_info mode change 100644 => 100755 lib_random/src/random.xc create mode 100755 lib_random/src/random_bit.xc create mode 100755 lib_random/src/random_deprecated.c create mode 100755 lib_random/src/random_impl.h delete mode 100644 lib_random/src/random_init.c create mode 100755 lib_random/src/random_pool.xc create mode 100755 lib_random/src/random_prng.xc delete mode 100644 lib_random/src/true_random.xc create mode 100644 test/random/Makefile create mode 100644 test/random/expected.output create mode 100755 test/random/src/test.xc create mode 100755 test/random_bit/Makefile create mode 100644 test/random_bit/expected.output create mode 100755 test/random_bit/src/test.xc create mode 100644 test/random_pool/Makefile create mode 100644 test/random_pool/expected.output create mode 100755 test/random_pool/src/test.xc create mode 100644 test/random_prng/Makefile create mode 100644 test/random_prng/expected.output create mode 100755 test/random_prng/src/test.xc create mode 100755 test/runtests.py create mode 100755 test/test_random.py create mode 100755 test/test_random_bit.py create mode 100755 test/test_random_pool.py create mode 100755 test/test_random_prng.py diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc index e369c94..3c94404 100644 --- a/examples/AN002xx_random_number_generation/src/random_numbers.xc +++ b/examples/AN002xx_random_number_generation/src/random_numbers.xc @@ -4,7 +4,7 @@ #include <stdio.h> #include <stdlib.h> #include <xs1.h> -#include "random.h" +#include "random_bit.h" #define MAXX 1024 #define MAXY 1024 @@ -13,140 +13,124 @@ unsigned char thebits[MAXBITS/8]; unsigned int getbit(int i) { - return (thebits[i>>3] >> (i&7)) & 1; + return (thebits[i>>3] >> (i&7)) & 1; } unsigned int setbit(int i, int val) { - return thebits[i>>3] |= val << (i&7); + return thebits[i>>3] |= val << (i&7); } void blocktest(int n) { - int hist[256]; - for(int i = 0; i < 256; i++) { - hist[i] = 0; + int hist[256]; + for(int i = 0; i < 256; i++) { + hist[i] = 0; + } + for(int i = 0; i < MAXBITS - n; i++) { + int val = 0; + for(int j = 0; j < n; j++) { + val = val << 1 | getbit(i+j); } - for(int i = 0; i < MAXBITS - n; i++) { - int val = 0; - for(int j = 0; j < n; j++) { - val = val << 1 | getbit(i+j); - } - hist[val]++; - } - printf("Blocktest %d\n", n); - for(int i = 0; i < (1<<n); i++) { - printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i]-(MAXBITS >> n)) < MAXX ? "Ok" : "Hmm"); - } - printf("\n"); + hist[val]++; + } + printf("Blocktest %d\n", n); + for(int i = 0; i < (1<<n); i++) { + printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i]-(MAXBITS >> n)) < MAXX ? "Ok" : "Hmm"); + } + printf("\n"); } void runtest() { - int hist[200]; - int old = 0; - int run = 0; - for(int i = 0; i < 200; i++) { - hist[i] = 0; - } - for(int i = 0; i < MAXBITS; i++) { - if(getbit(i) == old) { - run++; - } else { - hist[run]++; - run = 1; - } - } - printf("Runtest:\n"); - for(int i = 1; i < 10; i++) { - printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i] - (MAXBITS >> (i+1))) < (MAXX >> (i/2)) ? "Ok" : "Hmm" ); - } - printf("\n"); -} - -void fillmepseudo(void) { - random_generator_t rt = random_create_generator_from_seed(0); - int sum = 0; - random_true_init(); - while(sum < MAXBITS) { - unsigned rand = random_get_random_number(rt); - for(int i = 0; i < 32 && sum < MAXBITS; i++) { - setbit(sum, rand & 1); - rand >>= 1; - sum++; - } + int hist[200]; + int old = 0; + int run = 0; + for(int i = 0; i < 200; i++) { + hist[i] = 0; + } + for(int i = 0; i < MAXBITS; i++) { + if(getbit(i) == old) { + run++; + } else { + hist[run]++; + run = 1; } + } + printf("Runtest:\n"); + for(int i = 1; i < 10; i++) { + printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i] - (MAXBITS >> (i+1))) < (MAXX >> (i/2)) ? "Ok" : "Hmm" ); + } + printf("\n"); } void fillmetrue(void) { - int n, rand; - timer tmr; - int t0, t1; - int sum = 0; - random_true_init(); - tmr :> t0; - while(sum < MAXBITS) { - {n, rand} = random_true_get_bits(); - if (n == 0) { - // tmr when timerafter(rand) :> void; - } else { - for(int i = 0; i < n && sum < MAXBITS; i++) { - setbit(sum, rand & 1); - rand >>= 1; - sum++; - } - if ((sum & 0xffff) == 0) { - int time; - asm volatile ("gettime %0" : "=r" (time)); - printf("%11d %d\n", time, sum); - } - } + timer tmr; + int t0, t1; + int sum = 0; + tmr :> t0; + random_bit_start(); + while(sum < MAXBITS) { + uint32_t bit_time; + if (random_bit(bit_time)) { + //assert((bit_time & ~1UL)==0); + setbit(sum, bit_time); + sum++; + if ((sum & 0xffff) == 0) { + int time; + asm volatile ("gettime %0" : "=r" (time)); + printf("%11d %d\n", time, sum); + } } - tmr :> t1; - printf("Ticks taken: %d, %d per bit\n", t1-t0, (t1-t0)/sum); + //else + // tmr when timerafter(bit_time) :> void; + } + random_bit_stop(); + tmr :> t1; + printf("Ticks taken: %d, %d per bit\n", t1-t0, (t1-t0)/sum); } void xmain(chanend done[7]) { - for(int i = 0; i < 7; i++) { - done[i] <: 0; - } - fillmetrue(); - blocktest(1); - blocktest(2); - blocktest(3); - runtest(); - return; - printf("P2\n%d %d\n1\n", MAXX, MAXY); - for(int i = 0; i < MAXX; i++) { - for(int j = 0; j < MAXY; j++) { - printf("%d ", getbit(i*MAXY+j)); - } - printf("\n"); + for(int i = 0; i < 7; i++) { + done[i] <: 0; + } + fillmetrue(); + blocktest(1); + blocktest(2); + blocktest(3); + runtest(); + return; + printf("P2\n%d %d\n1\n", MAXX, MAXY); + for(int i = 0; i < MAXX; i++) { + for(int j = 0; j < MAXY; j++) { + printf("%d ", getbit(i*MAXY+j)); } + printf("\n"); + } } int busy(int x, chanend y) { - while(1) { - for(int i = 0; i < 1000; i++) { - x = x * 1234567 + 1; - } - select { - case y :> int _: return x; - default: break; - } + while(1) { + for(int i = 0; i < 1000; i++) { + x = x * 1234567 + 1; + } + select { + case y :> int _: return x; + default: break; } - return x; + } + return x; } int main(void) { - chan done[7]; - par { - busy(0x3, done[0]); - busy(0x4, done[1]); - busy(0x5, done[2]); - busy(0x6, done[3]); - busy(0x7, done[4]); - busy(0x8, done[5]); - busy(0x9, done[6]); - xmain(done); - } - return 0; + chan done[7]; + par { + busy(0x3, done[0]); + busy(0x4, done[1]); + busy(0x5, done[2]); + busy(0x6, done[3]); + busy(0x7, done[4]); + busy(0x8, done[5]); + busy(0x9, done[6]); + xmain(done); + } + return 0; } diff --git a/lib_random/api/random.h b/lib_random/api/random.h old mode 100644 new mode 100755 index 5a506fc..fec5350 --- a/lib_random/api/random.h +++ b/lib_random/api/random.h @@ -13,6 +13,11 @@ #endif #endif +/** This is an alternative pseudo-random number generator to those offered by stdlib.h: + * rand, srand, rand_r, drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, seed48, srand48 + * It uses the built in crc32() instructions. + */ + /** Type representing a random number generator. */ typedef unsigned random_generator_t; @@ -26,15 +31,6 @@ typedef unsigned random_generator_t; random_generator_t random_create_generator_from_seed(unsigned seed); -/** Function that attempts to create a random number generator from - * a true random value into the seed, using - * an asynchronous timer. To use this function you must enable the - * ``RANDOM_ENABLE_HW_SEED`` define in your application's ``random_conf.h``. - * - * \returns a random number generator. - */ -random_generator_t random_create_generator_from_hw_seed(void); - /** Function that produces a random number. The number has a cycle of 2^32 * and is produced using a LFSR. * @@ -47,36 +43,13 @@ random_get_random_number(REFERENCE_PARAM(random_generator_t, g)); void random_get_random_bytes(REFERENCE_PARAM(random_generator_t, g), uint8_t in_buffer[], size_t byte_count); -#ifdef __XC__ -/** Function that produces a number of random bits. It returns two - * integers. - * - * If random bits are available, then it returns the number of random bits, - * and the actual random bits. - * - * If no random bits are available, then it returns 0 (for no random bits) - * and the time in ticks at which new bits are available. The code can wait - * for this time (for example in a select statement), and then collect the - * random bits. - * - * At most 16 random bits are returned. To get a large number of random - * bits this function should be called regularly. Calling it too quickly - * since a previous call will return 0. - * - * \returns Number of bits, and random bits, or 0 and timestamp in the future. - */ -{uint32_t,int32_t} random_true_get_bits(); -/** Function that initialises the true random number generator. Calling - * this function will start the free running oscillator. This will take a - * bit of extra power. - */ -void random_true_init(); +// The following function is deprecated. +// It is incompatible with the rest of the lib_random library. +// To use this function you must define in your Makefile: +// RANDOM_ENABLE_HW_SEED=1 +//__attribute__((deprecated)) // Use random_prng.h instead. +random_generator_t random_create_generator_from_hw_seed(void); -/** Function that uninitialises the true random number generator. This will - * stop the ring oscillator, and reduce the power foot print a little. - */ -void random_true_uninit(); -#endif #endif // __RANDOM_H__ diff --git a/lib_random/api/random_bit.h b/lib_random/api/random_bit.h new file mode 100755 index 0000000..0aaf87b --- /dev/null +++ b/lib_random/api/random_bit.h @@ -0,0 +1,60 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved +#ifndef __RANDOM_BIT_H__ +#define __RANDOM_BIT_H__ + +#include <stdint.h> +#include <stddef.h> + +#ifndef REFERENCE_PARAM +#ifdef __XC__ +#define REFERENCE_PARAM(type, name) type &name +#else +#define REFERENCE_PARAM(type, name) type *name +#endif +#endif + + +/** The random_bit.h library is NOT thread safe. + * + * There is one oscillator per tile, hence there may be one user of the library per tile. + * However, on a multi-tile device, each tile may have one thread calling the library. + */ + + +/** Functions used to claim and release the random_bit library. + * + * As is only one oscillator per tile, there may only be one user of the + * library per tile. + * + * random_bit_claim() returns 0 if the library has already been claimed on + * this tile. + * + * N.B. Ownership of the library does not prevent others from calling it! + */ +int random_bit_claim(); +void random_bit_release(); + +/** Functions that start & stop the random number generator. + * + * Calling this function will start/stop the free running oscillator. + * A running oscillator will increase power consumption by a few mW. + * + * N.B. There is no checking that the caller has previously claimed the library. + */ +void random_bit_start(); +void random_bit_stop(); + +/** Function that produces a random bit. + * + * If random bits are available, then it returns '1' and the random bit. + * + * If no random bits are available, then it returns 0 and the absolute + * time in ticks at which a bit will be available. + * The calling code may then wait until this time (for example in a select statement), + * recalling the function when the bit will be available. + * + * N.B. There is no checking that the caller has previously claimed the library. + */ +uint32_t random_bit(REFERENCE_PARAM(uint32_t, bit_time)); + +#endif // __RANDOM_BIT_H__ diff --git a/lib_random/api/random_pool.h b/lib_random/api/random_pool.h new file mode 100755 index 0000000..6ed6f2f --- /dev/null +++ b/lib_random/api/random_pool.h @@ -0,0 +1,74 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved +#ifndef __RANDOM_POOL_H__ +#define __RANDOM_POOL_H__ + +#include <stdint.h> +#include <stddef.h> +#include "random_impl.h" + +/** Interface for clients to request bits from a random pool. + * + * Multiple clients, situated on any tile, may receive bits from a server. + * There may be only one server per tile. + * + * The server task calls random_bit_claim() for the tile. + * If the claim fails, the task will exit immediately. + */ +interface random_pool { +/** Method that returns the maximum bits a pool can hold. */ + size_t capacity(); + +/** Method that returns the number of bits available in the pool. */ + size_t available(); + +/** Method that returns the approximate period until `bits` will be available. + * + * Clients may then callback or sleep whilst waiting for the pool to fill. + * The client will need to do multiple `fetch()` followed by waits if + * there are multiple clients calling `fetch() or if `bits` > `capacity()`. + */ + uint32_t timeUntil(size_t bits); + +/** Method that overwrites `value[ bitPos : bitPos+numBits ]` with random bits. + * + * The bit range will be truncated to fit within value[]. + * + * \returns The number of bits overwritten, starting at 'bitPos'. + * This will be the same as numBits if the bits are available. + */ + size_t insert(uint32_t& value, size_t bitPos, size_t numBits); + +/** Method exits the random_pool server task when all clients have released. + * + * This allows a combined-par to exit if/when the client owning tasks exits. + * random_bit_release() will be called, allowing another task to claim it. + */ + void release(); +}; + +/** Type represents an opaque bit pool size. */ +typedef size_t PoolSize_t; + +/** Helper function for turning the minimum number of bits into a `PoolSize_t` opaque value. + * + * N.B. As `PoolSize_t` values are opaque, they must be generated via this function! + * PoolSize_t bitsToPoolSize(size_t bits); + */ +#define bitsToPoolSize(bits) _bitsToPoolSize(bits) + +/** Server task that collects random bits into a pool. + * + * The server task may be combined with other tasks in a combined-par statement. + * There may be one server task per tile (as there is only one random_bit generator per tile). + * Clients may then request random bits from the sever task's pool via the `interface random_pool`. + * There may be multiple clients, situated on a mixture of tile. + * + * \param rpi Server end of an `interface random_pool`. + * \param n Number of `client interface random_pool`s being served. + * \param poolSize Size of random bit pool to create - N.B. use bitsToPoolSize() to generate the value. + */ +[[combinable]] +void random_pool_server(server interface random_pool rpi[n], static const size_t n, + static const PoolSize_t poolSize); + +#endif // __RANDOM_POOL_H__ diff --git a/lib_random/api/random_prng.h b/lib_random/api/random_prng.h new file mode 100755 index 0000000..83a22ec --- /dev/null +++ b/lib_random/api/random_prng.h @@ -0,0 +1,70 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved +#ifndef __RANDOM_PRNG_H__ +#define __RANDOM_PRNG_H__ + +#include <stdint.h> +#include <stddef.h> +#include "random_impl.h" +#include "random_pool.h" + + +/** Interface for a client to request pseudo-random numbers. */ +interface random_prng { + +/** Method that returns a pseudo-random number. + * + * ====== WARNING ==================================================== + * The PRNG is a simple CRC and hence is not cryptographically secure. + * Exposing a value outside of the chip exposes the entire sequence. + * See random_csprng for how to hash the PRNG to make it secure. + * + * If n > 1, the PRNG will be called mulitple times to retrived 32bit values. + */ + void value(uint32_t values[n], size_t n); + +/** The following methods perturbe the PRNG with bits from a random_pool of true random bits. + * Each returns the numbe of bits actually taken from the random_pool. + */ + size_t perturbe_nonBlocking(size_t numBits); // Returns the numBits actually used (available). + size_t perturbe_blocking(size_t numBits); // Blocks until 'numBits' are available to use. + size_t perturbe_halfAvailableBits(); // Uses half the available bits in the pool. + +/** Method exits the random_prng server task. + * + * This allows a combined-par to exit if/when the client owning task exits. + * N.B. The user owns the random_pool client (passed to the server) and + * they must call `rpi.release()` when they have finished with it. + */ + void release(); +}; + +/** A type that specifies the repeat range for the PRNG + * + * There are 3 choices offering 32bit sequences of ~2^57, ~2^88 and ~2^113 in length. + * The processing time will increase with the PrngSize. + * The enumerated value is the number of uint32_t required to 'seed' the generator. + */ +typedef enum {prng57=2, prng88=3, prng113=4} PrngSize; + +/** Server task that generates the pseudo-random number. + * + * This is a 1:1 relationship. + * The call to perturbe_blocking() will 'sleep' both the client and server. + * Being distributable, the server-code will be inlined into the client task. + * + * N.B. Using the same client (PRNG stream) for muliple consumers will result in + * the consumers recieving correlated numbers (shared state). + * If correlation is an issue, consumers must instantiate their own + * server-client pair with a unique seed. + * + * \param prngi Server end of an `interface random_PRNG`. + * \param rpi Client end of an `interface random_pool`. + * \param prngSize Either 'prng57', 'prng88' or 'prng113'. + * \param seed Optional seed for the PRNG (or null) + * N.B. each seed[] entry must be > 127, the default value is 128. + */ +[[distributable]] +void random_prng_server(server interface random_prng prngi, client interface random_pool rpi, + static const PrngSize prngSize, uint32_t (&?seed)[prngSize]); + +#endif // __RANDOM_PRNG_H__ diff --git a/lib_random/doc/rst/random.rst b/lib_random/doc/rst/random.rst index 57919d2..389f89a 100644 --- a/lib_random/doc/rst/random.rst +++ b/lib_random/doc/rst/random.rst @@ -15,7 +15,7 @@ include the ``random.h`` header. Known Issues ------------ -There are no known issues with this library. - +The deprecated random_create_generator_from_hw_seed() functionality will not work corrrectly +along side random_bit.h (and hence random_pool.h and random_prng.h) .. include:: ../../../CHANGELOG.rst diff --git a/lib_random/module_build_info b/lib_random/module_build_info old mode 100644 new mode 100755 index 2c8f3cc..0828bac --- a/lib_random/module_build_info +++ b/lib_random/module_build_info @@ -1,14 +1,10 @@ -# You can set flags specifically for your module by using the MODULE_XCC_FLAGS -# variable. So the following -# -# MODULE_XCC_FLAGS = $(XCC_FLAGS) -O3 -# -# specifies that everything in the modules should have the application -# build flags with -O3 appended (so the files will build at -# optimization level -O3). -# -# You can also set MODULE_XCC_C_FLAGS, MODULE_XCC_XC_FLAGS etc.. - MODULE_XCC_FLAGS = -g -Os +#MODULE_XCC_FLAGS += -save-temps -v + +# Enable deprecated features +ifneq ($(RANDOM_ENABLE_HW_SEED),) +MODULE_XCC_FLAGS += -DRANDOM_ENABLE_HW_SEED=$(RANDOM_ENABLE_HW_SEED) +endif -VERSION = 1.0.0 +DEPENDENT_MODULES = lib_locks lib_xassert +VERSION = 1.1.0 diff --git a/lib_random/src/random.xc b/lib_random/src/random.xc old mode 100644 new mode 100755 index 2bbc8ff..9d32dfe --- a/lib_random/src/random.xc +++ b/lib_random/src/random.xc @@ -2,18 +2,16 @@ #include "random.h" #include <xs1.h> -static const unsigned random_poly = 0xEDB88320; - unsigned random_get_random_number(random_generator_t &g) { + static const unsigned random_poly = 0xEDB88320; crc32(g, -1, random_poly); return (unsigned) g; } void random_get_random_bytes(random_generator_t &g, uint8_t in_buffer[], size_t byte_count) { - for (int i=0; i < byte_count; i++) - { + for (int i=0; i < byte_count; ++i) { in_buffer[i] = (uint8_t)random_get_random_number(g); } } @@ -24,12 +22,3 @@ random_generator_t random_create_generator_from_seed(unsigned seed) (void) random_get_random_number(gen); return gen; } - -static const unsigned XS1_L_RING_OSCILLATOR_VALUE_REG = 0x070B; - -random_generator_t random_create_generator_from_hw_seed(void) -{ - unsigned init_seed = getps(XS1_L_RING_OSCILLATOR_VALUE_REG); - return random_create_generator_from_seed(init_seed); -} - diff --git a/lib_random/src/random_bit.xc b/lib_random/src/random_bit.xc new file mode 100755 index 0000000..3b48acc --- /dev/null +++ b/lib_random/src/random_bit.xc @@ -0,0 +1,71 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved +#include "random_bit.h" +#include "hwlock.h" +#include "random_impl.h" + +// Optional thread protection... + +#define LOAD32(dst, ptr) asm("ldw %0, %1[0]" : "=r"(dst) : "r"(ptr)); +#define STORE32(src, ptr) asm("stw %0, %1[0]" : : "r"(src), "r"(ptr)); + +extern unsigned __libc_hwlock; +static int per_tile_available = 1; + +int random_bit_claim() { + int available; + hwlock_acquire(__libc_hwlock); + LOAD32(available, &per_tile_available); + if (available) { + int newValue = 0; + STORE32(newValue, &per_tile_available); + } + hwlock_release(__libc_hwlock); + return available; +} + +void random_bit_release() { + int newValue = 1; + STORE32(newValue, &per_tile_available); +} + + +// None thread safe code... + +static int per_tile_last_time = 0; + +void random_bit_start() { + int last_time; + timer tmr; + tmr :> last_time; + STORE32(last_time, &per_tile_last_time); + setps(0x60B, 2); +} + +void random_bit_stop() { + setps(0x60B, 0); +} + +uint32_t random_bit(uint32_t &bit_time) { + int last_time; + LOAD32(last_time, &per_tile_last_time); + timer tmr; + uint32_t time; + tmr :> time; + // If the timer wraps, we will miss the opportunity - tough! + // N.B. unsigned wrapping has defined behaviour. + if (time - last_time > TIME_FOR_ONE_BIT) { + random_bit_stop(); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + bit_time = getps(0x70B); + random_bit_start(); + bit_time &=1; + return 1; + } + else { + bit_time = last_time + TIME_FOR_ONE_BIT; + return 0; + } +} diff --git a/lib_random/src/random_deprecated.c b/lib_random/src/random_deprecated.c new file mode 100755 index 0000000..711102e --- /dev/null +++ b/lib_random/src/random_deprecated.c @@ -0,0 +1,21 @@ +// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved +#include "random.h" +#include <xs1.h> + +#if RANDOM_ENABLE_HW_SEED + +#warning "Building deprecated random_create_generator_from_hw_seed()" +#warning "N.B. random_create_generator_from_hw_seed() is incompatible with the rest of the lib_random library." +#warning "Did you mean to define `RANDOM_ENABLE_HW_SEED`?" + +__attribute__((constructor)) +void random_simple_init_seed() { + setps(0x060B, 0x3); +} + +random_generator_t random_create_generator_from_hw_seed(void) { + unsigned init_seed = getps(0x070B); + return random_create_generator_from_seed(init_seed); +} + +#endif diff --git a/lib_random/src/random_impl.h b/lib_random/src/random_impl.h new file mode 100755 index 0000000..1311e7a --- /dev/null +++ b/lib_random/src/random_impl.h @@ -0,0 +1,20 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved +#ifndef __RANDOM_IMPL_H__ +#define __RANDOM_IMPL_H__ + +#include <stdint.h> + +// Used by random_bit() & random_pool_server() +#define TIME_FOR_ONE_BIT 20000 + +// N.B. _rp_impl_type is NOT part of the interface. +// as part of the implementation it may change at any time. +typedef uint8_t _rp_impl_type; +// random_pool_server() : assert(sizeof(uint32_t) >= sizeof(_rp_impl_type) && "memcpy needs fixing"); + + +// N.B. The implementation requires an extra bit for indexing efficiency, +// hence we do NOT use `(b+(N-1))/N` rounding. +#define _bitsToPoolSize(bits) (((bits) / (sizeof(_rp_impl_type)*8)) + 1) + +#endif // __RANDOM_IMPL_H__ diff --git a/lib_random/src/random_init.c b/lib_random/src/random_init.c deleted file mode 100644 index a9a9a4b..0000000 --- a/lib_random/src/random_init.c +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved -#include "random.h" -#include <xs1.h> - -static const unsigned XS1_L_RING_OSCILLATOR_CONTROL_REG = 0x060B; -static const unsigned XS1_L_RING_OSCILLATOR_CONTROL_START = 0x3; - -__attribute__((constructor)) -void random_simple_init_seed() -{ -/* This constructor starts of the ring oscillator when the program loads. - This will run on an asynchronous time base to the main xCORE. By starting it - off now the later call to random_create_generator_from_hw_seed will pick up - a value later which has drifted to a random state */ - setps(XS1_L_RING_OSCILLATOR_CONTROL_REG, - XS1_L_RING_OSCILLATOR_CONTROL_START); -} diff --git a/lib_random/src/random_pool.xc b/lib_random/src/random_pool.xc new file mode 100755 index 0000000..14ca39b --- /dev/null +++ b/lib_random/src/random_pool.xc @@ -0,0 +1,172 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +#include "random_pool.h" +#include <xs1.h> +#include <string.h> +#include "xassert.h" +#include "random_bit.h" + +// We always want xassert(e) to trap. +#if !(XASSERT_ENABLE_ASSERTIONS0) +# undef xassert +# define xassert(e) do { if (!(e)) __builtin_trap();} while(0) +#endif + +// Internally, we use bit indexes into the pool (head, tail etc). +// To make head/tail handling easier and more efficient: +// head==tail means empty; +// we will always have at least one bit 'empty'. +// See _bitsToPoolSize() macro for extra bit calculation. + +static inline size_t poolSizeInBits(static const PoolSize_t poolSize) { + return poolSize * (sizeof(_rp_impl_type)*8); +} + +static inline size_t poolSizeCapacity(static const PoolSize_t poolSize) { + return poolSizeInBits(poolSize) - 1; // see comment above. +} + +static inline size_t available(size_t head, size_t tail, static const PoolSize_t poolSize) { + if (tail > head) + head += poolSizeInBits(poolSize); + return head - tail; +} + +// incrementor for bit position +static inline void incrementPos(size_t& pos, static const PoolSize_t poolSize) { + ++pos; + if (pos == poolSizeInBits(poolSize)) + pos = 0; +} + +// Convert the `head` and `tail` bit positions into `_rp_impl_type[]` accessors. +static inline size_t indexOffset(size_t pos) { + return pos / (sizeof(_rp_impl_type)*8); +} +static inline size_t bitOffset(size_t pos) { + return pos % (sizeof(_rp_impl_type)*8); +} + +static inline _rp_impl_type bitMask(size_t numBits) { + return (1ULL << numBits) - 1; +} + +static inline uint32_t poolFill(size_t& head, size_t& tail, + _rp_impl_type pool[poolSize], static const PoolSize_t poolSize) { + uint32_t bit_time; + while (random_bit(bit_time)) { + // xor the bit at 'head'. + pool[indexOffset(head)] ^= (bit_time << bitOffset(head)); + incrementPos(head, poolSize); + if (head == tail) { // We have a full pool. + // Throw away old bits and keep the newest (always one bit empty). + incrementPos(tail, poolSize); + } + } + return bit_time; // Time when next bit available. +} + +static inline void xorInsert(uint32_t& value, size_t bitPos, size_t numBits, + size_t& tail, _rp_impl_type pool[poolSize], static const PoolSize_t poolSize ) { + // asserted (bitPos+numBits <= 32), bits will map onto a single uint32_t 'value'. + + // Initialise the pool access variables, we will update them in the loop. + size_t tailIndex = indexOffset(tail); + size_t tailBit = bitOffset(tail); // zero on subsequent passes. + + // Update 'tail' assuming we will remove 'numBits'. + // asserted (numBits<=available() && numBits < poolSizeInBits), so we wont need to worry about head. + tail += numBits; + if (tail >= poolSizeInBits(poolSize)) + tail -= poolSizeInBits(poolSize); + + while (numBits) { + size_t allotted = (sizeof(_rp_impl_type)*8) - tailBit; // Initially grab all top bits... + size_t invalidTop = 0; // so we don't discard any top bits. + if (allotted > numBits) { + // We don't need them all (or they are not available). + allotted = numBits; + invalidTop = (sizeof(_rp_impl_type)*8) - (tailBit + allotted); + } + _rp_impl_type v = pool[tailIndex]; + v <<= invalidTop; // Mask top bits. + v >>= (tailBit + invalidTop); // Mask bottom bits. + v <<= bitPos; // Position bits ready for insertion. + value ^= v; // xor-ing does not affect the randomness quality. + + numBits -= allotted; + if (numBits) { + // Update loop variables. + bitPos += allotted; + ++tailIndex; + if (tailIndex == poolSize) + tailIndex = 0; + tailBit = 0; + } + } +} + +[[combinable]] +void random_pool_server(server interface random_pool rpi[numClients], static const size_t numClients, + static const PoolSize_t poolSize) { + if (!random_bit_claim()) { + xassert(0); // "You can have only one random_pool_server task per tile." + } + + // We will release when the last client has released us. + // All clients have implicitly claimed us, set the 'numClients' lowest bits. + xassert(numClients <= 32); // "The maximum number of clients is 32". + uint32_t activeClients = (1ULL<<numClients) - 1; + + _rp_impl_type pool[poolSize]; + size_t head = 0; // The fill point. + size_t tail = 0; // The removal point. + + uint32_t time = poolFill(head, tail, pool, poolSize); + timer tmr; + + while(1) { + select { + case rpi[unsigned id].capacity() -> size_t numBits: + numBits = poolSizeCapacity(poolSize); + break; + + case rpi[unsigned id].available() -> size_t numBits: + numBits = available(head, tail, poolSize); + break; + + case rpi[unsigned id].timeUntil(size_t numBits) -> uint32_t period: + if (numBits > poolSizeCapacity(poolSize)) + numBits = poolSizeCapacity(poolSize); + size_t bits = available(head, tail, poolSize); + period = (numBits < bits)? 0 : (numBits - bits) * TIME_FOR_ONE_BIT; + break; + + case rpi[unsigned id].insert(uint32_t& value, size_t bitPos, size_t numBits) -> size_t bits: + if (bitPos > 31) + numBits = 0; + if (numBits > sizeof(uint32_t)*8 - bitPos) + numBits = sizeof(uint32_t)*8 - bitPos; + size_t avail = available(head, tail, poolSize); + bits = (numBits > avail)? avail : numBits; + if (bits) { + uint32_t local = value; // Can't use remote-references as argument :-( + xorInsert(local, bitPos, bits, tail, pool, poolSize); + value = local; + } + break; + + case rpi[unsigned id].release(): + activeClients &= ~(1UL << id); + if (!activeClients) { + random_bit_release(); + return; + } + break; + + case tmr when timerafter(time) :> void: + time = poolFill(head, tail, pool, poolSize); + break; + } + } +} diff --git a/lib_random/src/random_prng.xc b/lib_random/src/random_prng.xc new file mode 100755 index 0000000..bf3d445 --- /dev/null +++ b/lib_random/src/random_prng.xc @@ -0,0 +1,166 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +#include "random_prng.h" +#include <xs1.h> +#include <string.h> +#include "xassert.h" +#include "random_pool.h" + +// We always want xassert(e) to trap. +#if !(XASSERT_ENABLE_ASSERTIONS0) +# undef xassert +# define xassert(e) do { if (!(e)) __builtin_trap();} while(0) +#endif + +// From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe Generators" +// Mathematics of Computation, 65, 213 (1996), 203--213: +// www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps +static uint32_t quickTaus(uint32_t state, uint32_t c, + uint32_t q, uint32_t s, uint32_t k_s) { + return (((state << q) ^ state) >> k_s) ^ ((state & c) << s); +} +#define QT_PARAMS(k,q,s) (uint32_t)(-(1UL<<(32-k))),q,s,(k-s) +// state[] seeds must be >= 2^(32-k) +#define QT_DEFAULT_SEED 128 + +// period ~ 2^57 +// N.B. seed with: state[0] > 7, state[1] > 15 +static uint32_t lfsr57(uint32_t state[2]) { + state[0] = quickTaus(state[0], QT_PARAMS(29, 2,18) ); + state[1] = quickTaus(state[1], QT_PARAMS(28, 9,14) ); + return state[0] ^ state[1]; +} + +// period ~ 2^88 +// N.B. seed with: state[0] > 1, state[1] > 7, state[2] > 15 +static uint32_t lfsr88(uint32_t state[3]) { + state[0] = quickTaus(state[0], QT_PARAMS(31,13,12) ); + state[1] = quickTaus(state[1], QT_PARAMS(29, 2, 4) ); + state[2] = quickTaus(state[2], QT_PARAMS(28, 3,17) ); + return state[0] ^ state[1] ^ state[2]; +} + +// period ~2^113 +// N.B. seed with: state[0] > 1, state[1] > 7, state[2] > 15, state[3] > 127 +static uint32_t lfsr113(uint32_t state[4]) { + // Alternative values of the QT_PARAMS 's' are listed in table 1 of: + // Tables Of Maximally Equidistributed Combined LFSR Generators: Pierre L'ecuyer + // www.ams.org/mcom/1999-68-225/S0025-5718-99-01039-X/S0025-5718-99-01039-X.pdf + state[0] = quickTaus(state[0], QT_PARAMS(31, 6,18) ); + state[1] = quickTaus(state[1], QT_PARAMS(29, 2, 2) ); + state[2] = quickTaus(state[2], QT_PARAMS(28,13, 7) ); + state[3] = quickTaus(state[3], QT_PARAMS(25, 3,13) ); + return state[0] ^ state[1] ^ state[2] ^ state[3]; +} + +static inline void sleepUntil(size_t numBits, client interface random_pool rpi) { + timer tmr; + uint32_t time; + tmr :> time; + time += rpi.timeUntil(numBits); + tmr when timerafter(time) :> void; +} + +static size_t perturbe(uint32_t state[prngSize], static const size_t prngSize, + size_t numBits, size_t& perturbeIndex, client interface random_pool rpi) { + + // Truncate large numbers. + const size_t maxBits = prngSize * (sizeof(uint32_t)*8); + if (numBits > maxBits) + numBits = maxBits; + + // Initialise state access variables, we will update them in the loop. + size_t bitsInserted = 0; // What the caller wants to know. + // These three variables track where 'perturbeIndex' needs to be set to. + size_t index = perturbeIndex / (sizeof(uint32_t)*8); + size_t bitPos = perturbeIndex % (sizeof(uint32_t)*8); + size_t inserted = 0; + + while (numBits) { + size_t tailBits = (sizeof(uint32_t)*8) - bitPos; + if (tailBits > numBits) + tailBits = numBits; + + inserted = rpi.insert(state[index], bitPos, tailBits); + if (state[index] < QT_DEFAULT_SEED) { + // N.B. The value of the state must be >= 2^(32-k) viz 'QT_DEFAULT_SEED' + // But the rpi pool may be empty. + state[index] ^= 0xffffffff; // Will this break our PRNG? + } + bitsInserted += inserted; + numBits -= inserted; + + if (numBits && // More to do. + inserted == tailBits) { // The pool is not empty. + // We need to move onto the next state[] value. + ++index; + if (index == prngSize) + index = 0; + bitPos = 0; + } + // else index, bitPos, inserted give where we got up to. + } + + perturbeIndex = (index * (sizeof(uint32_t)*8)) + bitPos + inserted; + return bitsInserted; +} + +[[distributable]] +void random_prng_server(server interface random_prng prngi, client interface random_pool rpi, + static const PrngSize prngSize, uint32_t (&?seed)[prngSize]) { + + xassert(prngSize >= prng57 && prngSize <= prng113); // "Invalid prngSize". + + size_t perturbeIndex = 0; // Track the next bit to be peturbed. + uint32_t state[prngSize]; // Can't initialise distributable variables. Why not? + if (!isnull(seed)) { + for (int i=0; i<prngSize; ++i) + xassert(seed[i] >= QT_DEFAULT_SEED); // "Invalid seed". + memcpy(state, seed, prngSize * sizeof(uint32_t)); + } + else { + memset(state, QT_DEFAULT_SEED, prngSize * sizeof(uint32_t)); + } + + while(1) { + select { + case prngi.value(uint32_t values[n], size_t n) : + switch (prngSize) { + case prng57: + for (size_t i = 0; i < n; ++i) + values[i] = lfsr57(state); + break; + case prng88: + for (size_t i = 0; i < n; ++i) + values[i] = lfsr88(state); + break; + case prng113: + for (size_t i = 0; i < n; ++i) + values[i] = lfsr113(state); + break; + } + break; + + case prngi.perturbe_nonBlocking(size_t numBits) -> size_t bitsUsed: + bitsUsed = perturbe(state, prngSize, numBits, perturbeIndex, rpi); + break; + + case prngi.perturbe_blocking(size_t numBits) -> size_t bitsUsed: + bitsUsed = numBits; + while (numBits) { + numBits -= perturbe(state, prngSize, numBits, perturbeIndex, rpi); + if (numBits) + sleepUntil(numBits, rpi); // N.B. Only one clients wanting to block. + } + break; + + case prngi.perturbe_halfAvailableBits() -> size_t bitsUsed: + bitsUsed = rpi.available() / 2; // We round down, so we can never use all bits. + (void) perturbe(state, prngSize, bitsUsed, perturbeIndex, rpi); + break; + + case prngi.release(): + return; + } + } +} diff --git a/lib_random/src/true_random.xc b/lib_random/src/true_random.xc deleted file mode 100644 index 7dbc852..0000000 --- a/lib_random/src/true_random.xc +++ /dev/null @@ -1,48 +0,0 @@ -#include <platform.h> -#include <stdio.h> -#include <xs1.h> -#include <xclib.h> -#include "random.h" - -#define MIN_RANDOM_BITS 8 - -static void inline ro_on() { - setps(0x60B, 2); -} - -static void inline ro_off() { - setps(0x60B, 0); -} - - - -#define TIME_FOR_ONE_BIT 20000 -static int last_time = 0; - -void random_true_init() { - asm("gettime %0" : "=r" (last_time)); - ro_on(); -} - -{uint32_t,int32_t} random_true_get_bits() { - int time, ro; - - ro_off(); - asm("nop"); - asm("nop"); - asm("nop"); - asm("nop"); - ro = getps(0x70B); - asm("gettime %0" : "=r" (time)); - ro_on(); - - if (((unsigned)(time - last_time)) > TIME_FOR_ONE_BIT) { - last_time = time; - return {1, ro & 1}; - } - return {0, last_time + TIME_FOR_ONE_BIT}; -} - -void random_true_uninit() { - ro_off(); -} diff --git a/test/random/Makefile b/test/random/Makefile new file mode 100644 index 0000000..b0ceab1 --- /dev/null +++ b/test/random/Makefile @@ -0,0 +1,14 @@ +TARGET = SLICEKIT-L16 +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -Os -g +#XCC_FLAGS += -save-temps -v + +# We will be testing the deprecated interface... +RANDOM_ENABLE_HW_SEED=1 + +VERBOSE = 0 + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/test/random/expected.output b/test/random/expected.output new file mode 100644 index 0000000..e22e136 --- /dev/null +++ b/test/random/expected.output @@ -0,0 +1,4 @@ +test-3 done. +test-2 done. +test-0 done. +test-1 done. diff --git a/test/random/src/test.xc b/test/random/src/test.xc new file mode 100755 index 0000000..6ba3ec1 --- /dev/null +++ b/test/random/src/test.xc @@ -0,0 +1,130 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <platform.h> +#include "random.h" + +///////////////////////////////////////////////////////// +// First some unit testing boiler plate +interface checker { + void str(const char str[100]); + void release(); +}; +static void checkerServer(server interface checker si[n], static const size_t n, uint32_t timeout) { + // We will release when the last client has released us. + // All clients have implicitly claimed us, set the 'n' lowest bits. + if (n > 32) { + fprintf(stderr, "Error checkerServer: The maximum number of clients is 32\n"); + return; + } + uint32_t activeClients = (1ULL<<n) - 1; + + // Attempt to spot hung tests. + timer tmr; + uint32_t start; + tmr :> start; + + while(1){ + select{ + case si[unsigned id].str(const char str[100]) : + char local[100]; + memcpy(local,str,100); + fprintf(stderr, "%s\n", local); + break; + case si[unsigned id].release(): + activeClients &= ~(1UL << id); + if (!activeClients) + return; + break; + case tmr when timerafter(start + timeout) :> void: + fprintf(stderr, "Error checkerServer: timout after %d tick, activeClients mask=0x%X\n", timeout, activeClients); + exit(1); + break; + } + } +} + +#define INFO(ci, ...) \ + do { \ + char _checker_buff[100]; \ + snprintf(_checker_buff, 100, __VA_ARGS__); \ + ci.str(_checker_buff); \ + } while(0) + +#define CHECK(c, ci, ...) \ + if (!(c)) INFO(ci, __VA_ARGS__) + +///////////////////////////////////////////////////////// + +typedef union { + uint32_t word[2]; + uint8_t byte[8]; +} Bytes; + + +void test(client interface checker ci, int id) { + + // Check '0' is valid. + random_generator_t gen1 = random_create_generator_from_seed(0); + unsigned v1 = random_get_random_number(gen1); + CHECK( v1, ci, "test-%d unexpexted zero returned", id ); + Bytes b1 = {{0,0}}; + random_get_random_bytes(gen1, b1.byte, 5); + // simple checks of the values returned... + CHECK( b1.word[0] && b1.word[1], ci, "test-%d unexpexted zero returned, %#08X%08x", id, b1.word[0], b1.word[1] ); + CHECK( (b1.word[1] & 0xffffff00) == 0, ci, "test-%d too many bytes read, %#08X%08x", id, b1.word[0], b1.word[1] ); + // We do not test for 'out of bounds array access' + // random_get_random_bytes(gen1, b1.byte, 11); + + // Check we get a different set of values. + random_generator_t gen2 = random_create_generator_from_seed(0x12345678); + unsigned v2 = random_get_random_number(gen2); + CHECK( v2 != v1, ci, "test-%d unexpexted same value", id ); + Bytes b2 = {{0,0}}; + random_get_random_bytes(gen2, b2.byte, 5); + CHECK( b2.word[0] != b1.word[0] && b2.word[1] != b1.word[1], ci, "unexpexted same bytes", id ); + + // We should get the same output as the first block. + random_generator_t gen3 = random_create_generator_from_seed(0); + unsigned v3 = random_get_random_number(gen3); + CHECK( v3 == v1, ci, "test-%d unexpexted different value", id ); + Bytes b3 = {{0,0}}; + random_get_random_bytes(gen3, b3.byte, 5); + CHECK( b3.word[0] == b1.word[0] && b3.word[1] == b1.word[1], ci, "unexpexted different bytes", id ); + + // All gernators are independant. + v1 = random_get_random_number(gen1); + v2 = random_get_random_number(gen2); + v3 = random_get_random_number(gen3); + CHECK( v2 != v1, ci, "test-%d unexpexted same value", id ); + CHECK( v3 == v1, ci, "test-%d unexpexted different value", id ); + + Bytes zero = {{0,0}}; + random_get_random_bytes(gen1, zero.byte, 0); + CHECK( !zero.word[0] && !zero.word[1], ci, "unexpexted bytes read", id ); + + // The following function is deprecated but still tested. + // We have add 'RANDOM_ENABLE_HW_SEED=1' to the Makefile. + // The build will generate a warning... which we ignore. + random_generator_t gen4 = random_create_generator_from_hw_seed(); + // No delay needed. + random_generator_t gen5 = random_create_generator_from_hw_seed(); + CHECK( gen4 != gen5, ci, "test-%d same hw seed generator", id ); + + INFO(ci, "test-%d done.", id); + ci.release(); +} + +int main() { + interface checker i[4]; + par { + on tile[0] : checkerServer(i, 4, 100000); + on tile[0] : test(i[0], 0); + on tile[0] : test(i[1], 1); + on tile[1] : test(i[2], 2); + on tile[1] : test(i[3], 3); + } + return 0; // failure; +} diff --git a/test/random_bit/Makefile b/test/random_bit/Makefile new file mode 100755 index 0000000..ef987ff --- /dev/null +++ b/test/random_bit/Makefile @@ -0,0 +1,18 @@ +TARGET = SLICEKIT-L16 +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -Os -g +#XCC_FLAGS += -save-temps -v + +# RANDOM_ENABLE_HW_SEED must either: +# not be declared at all +# or if it is, take the value '0'. +# We chose the second option here as an example, other tests do not declare it at all. +# N.B. We expect random_deprecated.c not to be built. +RANDOM_ENABLE_HW_SEED=0 + +VERBOSE = 0 + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/test/random_bit/expected.output b/test/random_bit/expected.output new file mode 100644 index 0000000..1364fd4 --- /dev/null +++ b/test/random_bit/expected.output @@ -0,0 +1,6 @@ +testClaimSimple-1 done. +testClaimSimple-0 done. +testClaimingParallel-1 done. +testClaimingParallel-0 done. +testBit-1 done. +testBit-0 done. diff --git a/test/random_bit/src/test.xc b/test/random_bit/src/test.xc new file mode 100755 index 0000000..1776e6b --- /dev/null +++ b/test/random_bit/src/test.xc @@ -0,0 +1,199 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <platform.h> +#include "random_bit.h" + +///////////////////////////////////////////////////////// +// First some unit testing boiler plate +interface checker { + void str(const char str[100]); + void release(); +}; +static void checkerServer(server interface checker si[n], static const size_t n, uint32_t timeout) { + // We will release when the last client has released us. + // All clients have implicitly claimed us, set the 'n' lowest bits. + if (n > 32) { + fprintf(stderr, "Error checkerServer: The maximum number of clients is 32\n"); + return; + } + uint32_t activeClients = (1ULL<<n) - 1; + + // Attempt to spot hung tests. + timer tmr; + uint32_t start; + tmr :> start; + + while(1){ + select{ + case si[unsigned id].str(const char str[100]) : + char local[100]; + memcpy(local,str,100); + fprintf(stderr, "%s\n", local); + break; + case si[unsigned id].release(): + activeClients &= ~(1UL << id); + if (!activeClients) + return; + break; + case tmr when timerafter(start + timeout) :> void: + fprintf(stderr, "Error checkerServer: timout after %d tick, activeClients mask=0x%X\n", timeout, activeClients); + exit(1); + break; + } + } +} + +#define INFO(ci, ...) \ + do { \ + char _checker_buff[100]; \ + snprintf(_checker_buff, 100, __VA_ARGS__); \ + ci.str(_checker_buff); \ + } while(0) + +#define CHECK(c, ci, ...) \ + if (!(c)) INFO(ci, __VA_ARGS__) + +///////////////////////////////////////////////////////// + +// Use 'TIME_FOR_ONE_BIT' from random_impl.h +#include "../../lib_random/src/random_impl.h" +#define UNCERTAINTY 200 + +static void sleep(uint32_t n) { + timer tmr; + uint32_t now; + tmr :> now; + tmr when timerafter(now+n) :> void; +} + +void testClaimSimple(client interface checker ci, int id) { + CHECK( random_bit_claim() == 1, ci, "testClaimSimple-%d step 1", id ); + random_bit_release(); + CHECK( random_bit_claim() == 1, ci, "testClaimSimple-%d step 2", id ); + CHECK( random_bit_claim() == 0, ci, "testClaimSimple-%d step 3", id ); + random_bit_release(); + INFO(ci, "testClaimSimple-%d done.", id); + ci.release(); +} + +static int canClaim(uint32_t n) { + sleep(n); + if (random_bit_claim()) { + sleep(100); // keep hold for a while. + random_bit_release(); + return 1; + } + return 0; +} + +void testClaimingParallel(client interface checker ci, int id) { + int ret[6]; + par { + // Only one logical core on a tile can claim. + ret[0] = canClaim(0); + ret[1] = canClaim(0); + ret[2] = canClaim(0); + // Once released (after 100), another logical core can claim (after 200) + ret[3] = canClaim(200); + ret[4] = canClaim(200); + ret[5] = canClaim(200); + } + CHECK( ret[0]+ret[1]+ret[2] == 1, // One of them succeeds. + ci, "testClaimingParallel-%d now", id ); + CHECK( ret[3]+ret[4]+ret[5] == 1, // One of them succeeds. + ci, "testClaimingParallel-%d delayed", id ); + INFO(ci, "testClaimingParallel-%d done.", id); + ci.release(); +} + +void testBit_notReady(client interface checker ci, int id, int step, uint32_t expectedTime) { + uint32_t time; + CHECK( random_bit(time) == 0, + ci, "testBit-%d step 1 should not be ready", id ); + CHECK( expectedTime-UNCERTAINTY < time && + expectedTime+UNCERTAINTY > time, + ci,"testBit-%d step %d expected time %d +- %d, acutal time %d\n", id, step, expectedTime, UNCERTAINTY, time); +} + +void testBit_ready(client interface checker ci, int id, int step) { + uint32_t bit; + CHECK( random_bit(bit) == 1, + ci, "testBit-%d step %d should be ready", id ,step ); + // We don't currently CHECK the bit - need to feed this into the simulator's "getps(0x70B)". +} + +void testBit(client interface checker ci, int id) { + // We don't need to call random_bit_claim() ... even if it is bad style :0 + timer tmr; + uint32_t t; + + random_bit_start(); + tmr :> t; + // Check at start. + t += TIME_FOR_ONE_BIT; // We expect it to be ready in 'TIME_FOR_ONE_BIT' ticks. + testBit_notReady(ci, id, 1, t); + + sleep(TIME_FOR_ONE_BIT/2); + + // Check at half way point. + testBit_notReady(ci, id, 2, t); + + sleep(TIME_FOR_ONE_BIT/2); + + // Check at ready time. + testBit_ready(ci, id, 3); + tmr :> t; // Time till next bit from when we read previous bit. + t += TIME_FOR_ONE_BIT; // We expect next bit ready in 'TIME_FOR_ONE_BIT' ticks from now. + + // Check next bit is not ready. + testBit_notReady(ci, id, 4, t); + + // Sleep extra long. + sleep(TIME_FOR_ONE_BIT*2); + + // We expect only one bit ready. + testBit_ready(ci, id, 5); + tmr :> t; // Time till next bit from when we read previous bit. + t += TIME_FOR_ONE_BIT; // We expect next bit ready in 'TIME_FOR_ONE_BIT' ticks from now. + + // Check next bit is not ready. + testBit_notReady(ci, id, 6, t); + + // stopping and starting will reset the time until ready. + sleep(TIME_FOR_ONE_BIT*2); + random_bit_stop(); + random_bit_start(); + tmr :> t; + t += TIME_FOR_ONE_BIT; // We expect it to be ready in 'TIME_FOR_ONE_BIT' ticks. + testBit_notReady(ci, id, 7, t); + + random_bit_stop(); + INFO(ci, "testBit-%d done.", id); + ci.release(); +} + +int main() { + interface checker i[6]; + par { + on tile[0] : checkerServer(i,6, TIME_FOR_ONE_BIT*6); + + on tile[0] : { + testClaimSimple(i[0], 0); + // Followed by. + testClaimingParallel(i[1] ,0); + } + on tile[0] : testBit(i[2], 0); + + // The tests on each tile are independant. + on tile[1] : { + testClaimSimple(i[3], 1); + // Followed by. + testClaimingParallel(i[4], 1); + } + on tile[1] : testBit(i[5], 1); + } + return 0; +} \ No newline at end of file diff --git a/test/random_pool/Makefile b/test/random_pool/Makefile new file mode 100644 index 0000000..fbb3bc9 --- /dev/null +++ b/test/random_pool/Makefile @@ -0,0 +1,11 @@ +TARGET = SLICEKIT-L16 +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -Os -g +#XCC_FLAGS += -save-temps -v + +VERBOSE = 0 + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/test/random_pool/expected.output b/test/random_pool/expected.output new file mode 100644 index 0000000..8717b1c --- /dev/null +++ b/test/random_pool/expected.output @@ -0,0 +1,6 @@ +testPool-3 done. +testPool-4 done. +testPool-5 done. +testPool-0 done. +testPool-1 done. +testPool-2 done. diff --git a/test/random_pool/src/test.xc b/test/random_pool/src/test.xc new file mode 100755 index 0000000..4c0be42 --- /dev/null +++ b/test/random_pool/src/test.xc @@ -0,0 +1,201 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <platform.h> +#include "random_pool.h" + +///////////////////////////////////////////////////////// +// First some unit testing boiler plate +interface checker { + void str(const char str[100]); + void release(); +}; +static void checkerServer(server interface checker si[n], static const size_t n, uint32_t timeout) { + // We will release when the last client has released us. + // All clients have implicitly claimed us, set the 'n' lowest bits. + if (n > 32) { + fprintf(stderr, "Error checkerServer: The maximum number of clients is 32\n"); + return; + } + uint32_t activeClients = (1ULL<<n) - 1; + + // Attempt to spot hung tests. + timer tmr; + uint32_t start; + tmr :> start; + + while(1){ + select{ + case si[unsigned id].str(const char str[100]) : + char local[100]; + memcpy(local,str,100); + fprintf(stderr, "%s\n", local); + break; + case si[unsigned id].release(): + activeClients &= ~(1UL << id); + if (!activeClients) + return; + break; + case tmr when timerafter(start + timeout) :> void: + fprintf(stderr, "Error checkerServer: timout after %d tick, activeClients mask=0x%X\n", timeout, activeClients); + exit(1); + break; + } + } +} + +#define INFO(ci, ...) \ + do { \ + char _checker_buff[100]; \ + snprintf(_checker_buff, 100, __VA_ARGS__); \ + ci.str(_checker_buff); \ + } while(0) + +#define CHECK(c, ci, ...) \ + if (!(c)) INFO(ci, __VA_ARGS__) + +///////////////////////////////////////////////////////// + +// Use 'TIME_FOR_ONE_BIT' from random_impl.h +#include "../../lib_random/src/random_impl.h" +#define DELAY 500 + +static void delay() { + timer tmr; + uint32_t now; + tmr :> now; + tmr when timerafter(now+DELAY) :> void; +} + +void testPool_timeuntil(client interface checker ci, int id, + client interface random_pool rpi, size_t numBits, size_t poolBits) { + uint32_t time = rpi.timeUntil(numBits); + + // How many bit are we waiting for. + size_t reportedBits = (numBits > rpi.capacity())? rpi.capacity() : numBits; + reportedBits = (reportedBits<poolBits)? 0 : reportedBits - poolBits; + uint32_t expected = TIME_FOR_ONE_BIT * reportedBits; // We know how it is caluclated! + + CHECK( expected == time, + ci,"testPool-%d %d bits : expected time %d, acutal time %d\n", id, numBits, expected, time); +} + +void testPool(client interface checker ci, int id, + client interface random_pool rpi) { + + size_t expectedCapacity = (id<3)? 7 : 15; // See random_pool_server(..., bitsToPoolSize). + CHECK( rpi.capacity() == expectedCapacity, + ci, "testPool-%d capacity %d not %d", id, rpi.capacity(), expectedCapacity ); + + CHECK( rpi.available() == 0, + ci, "testPool-%d expected 0, actual %d bits", id, rpi.available() ); + + timer tmr; + uint32_t now; + tmr :> now; + testPool_timeuntil(ci, id, rpi, 0, 0); + testPool_timeuntil(ci, id, rpi, 1, 0); + testPool_timeuntil(ci, id, rpi, 2, 0); + testPool_timeuntil(ci, id, rpi, 99, 0); + + tmr when timerafter(now + TIME_FOR_ONE_BIT) :> void; + CHECK( rpi.available() == 1, + ci, "testPool-%d expected 1, actual %d bits", id, rpi.available() ); + + // Retest, but the periods will be reduced as we have a bit in the pool + testPool_timeuntil(ci, id, rpi, 0, 1); + testPool_timeuntil(ci, id, rpi, 1, 1); + testPool_timeuntil(ci, id, rpi, 2, 1); + testPool_timeuntil(ci, id, rpi, 99, 1); + + tmr when timerafter(now + TIME_FOR_ONE_BIT*2) :> void; + CHECK( rpi.available() == 2, + ci, "testPool-%d expected 2, actual %d bits", id, rpi.available() ); + + delay(); // Allow all cores to check the pool before continuing. + + // Then allow one core to plunder the pool. + if (id==0 || id==3) { + // Retest, but the periods will be reduced as we have 2 bits in the pool + testPool_timeuntil(ci, id, rpi, 0, 2); + testPool_timeuntil(ci, id, rpi, 1, 2); + testPool_timeuntil(ci, id, rpi, 2, 2); + testPool_timeuntil(ci, id, rpi, 99, 2); + + uint32_t bits; + CHECK( rpi.insert(bits, 32, 1) == 0, // Outside of range. + ci, "testPool-%d incorrectly inserted bit32", id); + CHECK( rpi.available() == 2, + ci, "testPool-%d 2-0=2, actual %d bits", id, rpi.available() ); + + CHECK( rpi.insert(bits, 31, 5) == 1, // Truncate to last bit. + ci, "testPool-%d expected bit31 to be filled", id); + // We don't currently CHECK the bit - need to feed this into the simulator's "getps(0x70B)". + CHECK( rpi.available() == 1, + ci, "testPool-%d 2-1=1, actual %d bits", id, rpi.available() ); + + CHECK( rpi.insert(bits, 0, 999) == 1, // Request far too many bits! + ci, "testPool-%d expected only bit0 to be filled", id); + // We don't currently CHECK the bit - need to feed this into the simulator's "getps(0x70B)". + CHECK( rpi.available() == 0, + ci, "testPool-%d 1-1=0, actual %d bits", id, rpi.available() ); + + CHECK( rpi.insert(bits, 0, 1) == 0, // None available. + ci, "testPool-%d expected no bits to be filled", id); + CHECK( rpi.available() == 0, + ci, "testPool-%d 0-0=0, actual %d bits", id, rpi.available() ); + + // Retest now the pool is empty. + testPool_timeuntil(ci, id, rpi, 0, 0); + testPool_timeuntil(ci, id, rpi, 1, 0); + testPool_timeuntil(ci, id, rpi, 2, 0); + testPool_timeuntil(ci, id, rpi, 99, 0); + } + else { + // Wait for the pool to be plundered. + delay(); + + // The bit will have been taken by id 0. + CHECK( rpi.available() == 0, + ci, "testPool-%d pool contains %d bits", id, rpi.available() ); + uint32_t bits; + CHECK( rpi.insert(bits, 32, 1) == 0, // Outside of range. + ci, "testPool-%d bit32 expected no bits to be filled", id); + + CHECK( rpi.insert(bits, 31, 5) == 0, // Truncate to last bit. + ci, "testPool-%d bit31 expected no bits to be filled", id); + + CHECK( rpi.insert(bits, 0, 999) == 0, // Request far too many bits! + ci, "testPool-%d bit0 expected no bits to be filled", id); + + CHECK( rpi.insert(bits, 0, 1) == 0, // None available. + ci, "testPool-%d expected no bits to be filled", id); + } + rpi.release(); + + INFO(ci, "testPool-%d done.", id); + ci.release(); +} + +int main() { + interface checker i[6]; + interface random_pool rpi_0[3]; + interface random_pool rpi_1[3]; + + par { + on tile[0] : checkerServer(i, 6, TIME_FOR_ONE_BIT*3); + + on tile[0] : random_pool_server(rpi_0, 3, bitsToPoolSize(3)); // Rounded to 8. + on tile[0] : testPool(i[0], 0, rpi_0[0]); + on tile[0] : testPool(i[1], 1, rpi_0[1]); + on tile[0] : testPool(i[2], 2, rpi_0[2]); + + on tile[1] : random_pool_server(rpi_1, 3, bitsToPoolSize(11)); // Rounded to 16. + on tile[1] : testPool(i[3], 3, rpi_1[0]); + on tile[1] : testPool(i[4], 4, rpi_1[1]); + on tile[1] : testPool(i[5], 5, rpi_1[2]); + } + return 0; // failure; +} diff --git a/test/random_prng/Makefile b/test/random_prng/Makefile new file mode 100644 index 0000000..aee3fe4 --- /dev/null +++ b/test/random_prng/Makefile @@ -0,0 +1,13 @@ +TARGET = STARTKIT +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -Os -g + +#XCC_FLAGS += -save-temps -v + +XCORE_ARM_PROJECT = 0 +VERBOSE = 0 + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/test/random_prng/expected.output b/test/random_prng/expected.output new file mode 100644 index 0000000..c693646 --- /dev/null +++ b/test/random_prng/expected.output @@ -0,0 +1,16 @@ +Task-pool-client0 available=0 capacity=15 +Task-pool-client1 available=0 capacity=15 +subtask-A raw - 16C800B3 279E25 +subtask-A half 0 3589669D 4AF41D37 +Task-pool-client1 available=0 capacity=15 +Exit Task-pool-client1 +subtask-A nonblocking 2 7461669 8ABA72F6 +subtask-A blocking 1 8EDBF15A 2C5DF060 +Exit subtask-A +subtask-B raw - 505F0BD9 35375D85 +subtask-B half 0 783D9EC4 B0C1B1A0 +subtask-B nonblocking 2 47AE1A01 95AB4431 +subtask-B blocking 1 20AB0D85 B0E484A6 +Exit subtask-B +Exit Task-pool-client0 +Exit Task-pool-server diff --git a/test/random_prng/src/test.xc b/test/random_prng/src/test.xc new file mode 100755 index 0000000..65b9eee --- /dev/null +++ b/test/random_prng/src/test.xc @@ -0,0 +1,77 @@ + +#include "random_prng.h" +#include <stdio.h> +#include <xs1.h> + +#define PRINT(...) printf(__VA_ARGS__) +//#define PRINT(...) + +void test(const char*unsafe name, client interface random_prng prngi) { + uint32_t values[2]; + prngi.value(values, 2); + PRINT("%s raw - %X %X\n",name, values[0], values[1]); + + size_t done = prngi.perturbe_halfAvailableBits(); + prngi.value(values, 2); + PRINT("%s half %d %X %X\n", name, done, values[0], values[1]); + + done = prngi.perturbe_nonBlocking(2); + prngi.value(values, 2); + PRINT("%s nonblocking %d %X %X\n", name, done, values[0], values[1]); + + done = prngi.perturbe_blocking(1); + prngi.value(values, 2); + PRINT("%s blocking %d %X %X\n", name, done, values[0], values[1]); + + // Client prngi is no longer wanted. + prngi.release(); // This will allow the random_prng_server() to exit too. + PRINT("Exit %s\n", name); +} + +int main() { + interface random_pool rpi[2]; + par { + // Task-pool-server + random_pool_server(rpi, 2, bitsToPoolSize(11)); + + // Task-pool-client0 with subtasks. + { + PRINT("Task-pool-client0 available=%d capacity=%d\n", rpi[0].available(), rpi[0].capacity()); + uint32_t seed[prng57] = {1234,5678}; + interface random_prng prngi; + // subtask-A. + par { + [[distribute]] + random_prng_server(prngi, rpi[0], prng57, seed); + test("subtask-A", prngi); + } + // Follow with a sequential subtask-B. + // We can reuse the prngi interface object to start a new server & client. + // N.B. BUT ONLY IF THE INTERFACE IS THE SAME TYPE - both 'distribute' or not!! + par { + [[distribute]] + random_prng_server(prngi, rpi[0], prng113, null); // Use the default seed + test("subtask-B", prngi); + } + // Client rpi[0] is no longer wanted. + rpi[0].release(); // This will allow the random_pool_server() to exit too. + PRINT("Exit Task-pool-client0\n"); + } + + // Task-pool-client1 + { + PRINT("Task-pool-client1 available=%d capacity=%d\n", rpi[1].available(), rpi[1].capacity()); + timer tmr; + uint32_t time; + tmr :> time; + tmr when timerafter(time+20000) :> void; + PRINT("Task-pool-client1 available=%d capacity=%d\n", rpi[1].available(), rpi[1].capacity()); + // Client rpi[1] is no longer wanted. + rpi[1].release(); // This will allow the random_pool_server() to exit too. + PRINT("Exit Task-pool-client1\n"); + } + } + PRINT("Exit Task-pool-server\n"); + return 0; +} + diff --git a/test/runtests.py b/test/runtests.py new file mode 100755 index 0000000..d422f09 --- /dev/null +++ b/test/runtests.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +import xmostest, sys, subprocess + +if __name__ == "__main__": + xmostest.init() + xmostest.register_group("lib_random", "lib_random_tests", "lib_random library tests", "Tests random_bit.h, random_pool.h, random_prng.h and random.h") + xmostest.runtests() + xmostest.finish() + diff --git a/test/test_random.py b/test/test_random.py new file mode 100755 index 0000000..845222b --- /dev/null +++ b/test/test_random.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import xmostest + +def runtest(): + resources = xmostest.request_resource("xsim") + + tester = xmostest.ComparisonTester(open('random/expected.output'), + 'lib_random', + 'lib_random_tests', + 'random', {}) + + xmostest.run_on_simulator(resources['xsim'], + 'random/bin/random.xe', + tester=tester) + diff --git a/test/test_random_bit.py b/test/test_random_bit.py new file mode 100755 index 0000000..d593f10 --- /dev/null +++ b/test/test_random_bit.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import xmostest + +def runtest(): + resources = xmostest.request_resource("xsim") + + tester = xmostest.ComparisonTester(open('random_bit/expected.output'), + 'lib_random', + 'lib_random_tests', + 'random_bit', {}) + + xmostest.run_on_simulator(resources['xsim'], + 'random_bit/bin/random_bit.xe', + tester=tester) + diff --git a/test/test_random_pool.py b/test/test_random_pool.py new file mode 100755 index 0000000..3781d9d --- /dev/null +++ b/test/test_random_pool.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import xmostest + +def runtest(): + resources = xmostest.request_resource("xsim") + + tester = xmostest.ComparisonTester(open('random_pool/expected.output'), + 'lib_random', + 'lib_random_tests', + 'random_pool', {}) + + xmostest.run_on_simulator(resources['xsim'], + 'random_pool/bin/random_pool.xe', + tester=tester) + diff --git a/test/test_random_prng.py b/test/test_random_prng.py new file mode 100755 index 0000000..8fa443c --- /dev/null +++ b/test/test_random_prng.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import xmostest + +def runtest(): + resources = xmostest.request_resource("xsim") + + tester = xmostest.ComparisonTester(open('random_prng/expected.output'), + 'lib_random', + 'lib_random_tests', + 'random_prng', {}) + + xmostest.run_on_simulator(resources['xsim'], + 'random_prng/bin/random_prng.xe', + tester=tester) + From f6237d03717c36e8fbb433975cb886ae65066913 Mon Sep 17 00:00:00 2001 From: robert lytton <robert@xmos.com> Date: Thu, 23 Nov 2017 11:23:56 +0000 Subject: [PATCH 07/10] Add examples/dieharder for validating random_prng.h Make random_prng_server(...,client interface random_pool ?rpi,...) optinal --- .../AN002xx_random_number_generation/Makefile | 1 - examples/dieharder/Makefile | 10 ++ examples/dieharder/README | 11 ++ examples/dieharder/src/gen.xc | 135 ++++++++++++++++++ lib_random/api/random_prng.h | 4 +- lib_random/src/random_prng.xc | 2 +- test/random_prng/Makefile | 2 - 7 files changed, 159 insertions(+), 6 deletions(-) create mode 100755 examples/dieharder/Makefile create mode 100644 examples/dieharder/README create mode 100755 examples/dieharder/src/gen.xc diff --git a/examples/AN002xx_random_number_generation/Makefile b/examples/AN002xx_random_number_generation/Makefile index 48cf165..b0101e3 100644 --- a/examples/AN002xx_random_number_generation/Makefile +++ b/examples/AN002xx_random_number_generation/Makefile @@ -3,7 +3,6 @@ APP_NAME = USED_MODULES = lib_random XCC_FLAGS = -O2 -g -Wunused -fxscope -XCORE_ARM_PROJECT = 0 VERBOSE = 0 XMOS_MAKE_PATH ?= ../.. diff --git a/examples/dieharder/Makefile b/examples/dieharder/Makefile new file mode 100755 index 0000000..8f7774b --- /dev/null +++ b/examples/dieharder/Makefile @@ -0,0 +1,10 @@ +TARGET = STARTKIT +APP_NAME = +USED_MODULES = lib_random + +XCC_FLAGS = -Os -g -fcmdline-buffer-bytes=100 +#XCC_FLAGS += -save-temps -v + + +XMOS_MAKE_PATH ?= ../.. +-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/examples/dieharder/README b/examples/dieharder/README new file mode 100644 index 0000000..41214db --- /dev/null +++ b/examples/dieharder/README @@ -0,0 +1,11 @@ +This is a wrapper for testing the quality of the PRNG using dieharder. +http://webhome.phy.duke.edu/~rgb/General/dieharder.php + +It is slow as it runs the random_prng.h library code under simulation. + +If this is a problem, copy the lfsr57(), lfsr88(), & lfsr113() functions +into a host application and run nativly, viz test just the algorithm! + +The expected usage is: + axe --args bin/dieharder.xe -g prng57 -n -1 -o - -B | dieharder -g 200 -a +(see dieharder.xe and dieharder help files for details) diff --git a/examples/dieharder/src/gen.xc b/examples/dieharder/src/gen.xc new file mode 100755 index 0000000..de67dfe --- /dev/null +++ b/examples/dieharder/src/gen.xc @@ -0,0 +1,135 @@ +// Copyright (c) 2017, XMOS Ltd, All rights reserved + +// The expected usage is for validating against 'dieharder' +// axe --args bin/dieharder.xe -g prng57 -n -1 -o - -B | dieharder -g 200 -a + +// We want raw stdio.h, not the safe version. +#define UNSAFE_LIBC +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <xs1.h> +#include "random_prng.h" + +static const char*unsafe prngString(PrngSize prng) { + unsafe { + switch (prng) { + case prng57: return "prng57"; + case prng88: return "prng88"; + case prng113: return "prng113"; + default: return "prngInvalid"; + } + } +} + +unsigned readArgs(unsigned argC, char*unsafe argV[], + PrngSize& prng, unsigned& numValues, const char*unsafe& filename, unsigned& binary) { + unsigned found_g = 0; + unsigned found_n = 0; + unsigned found_o = 0; + binary = 0; + + if (argC == 7 || argC == 8) { + for(unsigned i=1; i<argC; i+=2) { + if (strcmp(argV[i], "-B") == 0) { + binary = 1; + --i; // Hack the incrementor. + } + if (strcmp(argV[i], "-n") == 0) { + numValues = atoi(argV[i+1]); + found_n = 1; + } + else if (strcmp(argV[i], "-o") == 0) { + filename = argV[i+1]; + found_o = 1; + } + else if (strcmp(argV[i], "-g") == 0) { + found_g = 1; + if (strcmp(argV[i+1], "prng57") == 0) + prng = prng57; + else if (strcmp(argV[i+1], "prng88") == 0) + prng = prng88; + else if (strcmp(argV[i+1], "prng113") == 0) + prng = prng113; + else + found_g = 0; + } + } + } + if (found_g && found_n && found_o && (argC == 7 || binary)) + return 1; + if (!argC) { + printf ("Usage: Rebuild .xe with `-fcmdline-buffer-bytes=<value>` set\n"); + printf (" and make sure you pass commandline arg using `xsim --args ...` or `axe --args ...`\n"); + } + else { + printf ("Usage: `axe --args %s -g <prng57|prng88|prng113> -n <numValues|-1> -o <outfile|-> [-B]`\n", argV[0]); + printf (" -g <prng57|prng88|prng113> see random_prng.h and PrngSize for details;\n"); + printf (" -n <numValues|-1> the number of 32bit values to generate, or -1 (with -B) for continuous;\n"); + printf (" -o <outfile|-> output file name, or '-' for stdout;\n"); + printf (" -B to turn on binary output, otherwise output will be in ASCII dieharder format.\n"); + } + return 0; +} + +FILE*unsafe openOutFile(const char*unsafe filename, unsigned numValues, unsigned prng, unsigned binary) { + FILE*unsafe fp = (strcmp(filename, "-") == 0) ? stdout : + fopen(filename, binary? "wb":"w"); + if (!fp) + printf ("Unable to open output file %s\n", filename); + else if (!binary) { + fprintf(fp, "#==================================================================\n"); + fprintf(fp, "# generator random_prng.h %s seed=null\n", prngString(prng)); + fprintf(fp, "#==================================================================\n"); + fprintf(fp, "type: d\n"); + fprintf(fp, "count: %u\n", numValues); + fprintf(fp, "numbit: 32\n"); + } + return fp; +} + +int main(unsigned argC, char*unsafe argV[argC]) { + PrngSize prng = 0; + unsigned numValues = 0; + const char*unsafe filename; + unsigned binary; + unsafe { + if (!readArgs(argC, argV, prng, numValues, filename, binary)) + return 1; + } + FILE*unsafe fp = openOutFile(filename, numValues, prng, binary); + + //interface random_pool rpi[1]; + par { + //random_pool_server(rpi, 1, bitsToPoolSize(1)); // We wont be using it. + { + interface random_prng prngi; + par { + [[distribute]] + random_prng_server(prngi, null, prng57, null); + // random_prng_server(prngi, rpi[0], prng57, null); + { + // Client task. + while (numValues) { + enum{blkLen=1000}; + uint32_t values[blkLen]; + unsigned len = (blkLen < numValues)? blkLen : numValues; + prngi.value(values, len); + if (binary) + fwrite(values, len, sizeof(uint32_t), fp); + else + for (unsigned i=0; i < len; ++i) + fprintf(fp, "%10u\n", values[i]); + if (!binary || numValues != (unsigned)(-1)) + numValues -= len; + } + fclose(fp); + prngi.release(); + } + } + //rpi[0].release(); + } + } + return 0; +} diff --git a/lib_random/api/random_prng.h b/lib_random/api/random_prng.h index 83a22ec..f45b375 100755 --- a/lib_random/api/random_prng.h +++ b/lib_random/api/random_prng.h @@ -58,13 +58,13 @@ typedef enum {prng57=2, prng88=3, prng113=4} PrngSize; * server-client pair with a unique seed. * * \param prngi Server end of an `interface random_PRNG`. - * \param rpi Client end of an `interface random_pool`. + * \param rpi Client end of an `interface random_pool`, null if perturbe_*() is never called. * \param prngSize Either 'prng57', 'prng88' or 'prng113'. * \param seed Optional seed for the PRNG (or null) * N.B. each seed[] entry must be > 127, the default value is 128. */ [[distributable]] -void random_prng_server(server interface random_prng prngi, client interface random_pool rpi, +void random_prng_server(server interface random_prng prngi, client interface random_pool ?rpi, static const PrngSize prngSize, uint32_t (&?seed)[prngSize]); #endif // __RANDOM_PRNG_H__ diff --git a/lib_random/src/random_prng.xc b/lib_random/src/random_prng.xc index bf3d445..dbc5166 100755 --- a/lib_random/src/random_prng.xc +++ b/lib_random/src/random_prng.xc @@ -106,7 +106,7 @@ static size_t perturbe(uint32_t state[prngSize], static const size_t prngSize, } [[distributable]] -void random_prng_server(server interface random_prng prngi, client interface random_pool rpi, +void random_prng_server(server interface random_prng prngi, client interface random_pool ?rpi, static const PrngSize prngSize, uint32_t (&?seed)[prngSize]) { xassert(prngSize >= prng57 && prngSize <= prng113); // "Invalid prngSize". diff --git a/test/random_prng/Makefile b/test/random_prng/Makefile index aee3fe4..526dc6f 100644 --- a/test/random_prng/Makefile +++ b/test/random_prng/Makefile @@ -3,10 +3,8 @@ APP_NAME = USED_MODULES = lib_random XCC_FLAGS = -Os -g - #XCC_FLAGS += -save-temps -v -XCORE_ARM_PROJECT = 0 VERBOSE = 0 XMOS_MAKE_PATH ?= ../.. From 3862bd60204cdafbde3a528c4a59e4f0c5304b35 Mon Sep 17 00:00:00 2001 From: Sam Chesney <samc@xmos.com> Date: Wed, 15 Aug 2018 11:35:10 +0100 Subject: [PATCH 08/10] Add Jenkins pipeline --- Jenkinsfile | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..986ea58 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,43 @@ +pipeline { + agent { + label 'x86&&macOS&&Apps' + } + environment { + VIEW = 'random' + REPO = 'lib_random' + } + options { + skipDefaultCheckout() + } + stages { + stage('Get view') { + steps { + prepareAppsSandbox("${VIEW}", "${REPO}") + } + } + stage('Library checks') { + steps { + xcoreLibraryChecks("${REPO}") + } + } + stage('Build') { + steps { + dir("${REPO}") { + xcoreAllAppsBuild('examples') + xcoreAllAppNotesBuild('examples') + } + } + } + stage('Test') { + steps { + runXmostest("${REPO}", "tests") + } + } + } + post { + always { + archiveArtifacts artifacts: "${REPO}/**/*.*", fingerprint: true + cleanWs() + } + } +} From 7b5e08d722872b16d043a3c68b1cda5c832cecec Mon Sep 17 00:00:00 2001 From: Sam Chesney <samc@xmos.com> Date: Wed, 15 Aug 2018 11:37:25 +0100 Subject: [PATCH 09/10] Rename dieharder -> app_dieharder Ensure CI system treats it as an xCORE application, and attempts a build. --- examples/{dieharder => app_dieharder}/Makefile | 0 examples/{dieharder => app_dieharder}/README | 0 examples/{dieharder => app_dieharder}/src/gen.xc | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/{dieharder => app_dieharder}/Makefile (100%) rename examples/{dieharder => app_dieharder}/README (100%) rename examples/{dieharder => app_dieharder}/src/gen.xc (100%) diff --git a/examples/dieharder/Makefile b/examples/app_dieharder/Makefile similarity index 100% rename from examples/dieharder/Makefile rename to examples/app_dieharder/Makefile diff --git a/examples/dieharder/README b/examples/app_dieharder/README similarity index 100% rename from examples/dieharder/README rename to examples/app_dieharder/README diff --git a/examples/dieharder/src/gen.xc b/examples/app_dieharder/src/gen.xc similarity index 100% rename from examples/dieharder/src/gen.xc rename to examples/app_dieharder/src/gen.xc From 7fedf481d868266b3ec073e15429fce42e4e279d Mon Sep 17 00:00:00 2001 From: robert lytton <robert@xmos.com> Date: Wed, 15 Aug 2018 12:31:06 +0100 Subject: [PATCH 10/10] Remove examples/AN002xx_... and random.h api fix magic numbers --- .../AN002xx_random_number_generation/Makefile | 9 -- .../README.rst | 34 ---- .../SMART-MIC-4-TILE-1V0.xn | 153 ------------------ .../config.xscope | 23 --- .../doc/rst/AN002xx.rst | 11 -- .../doc/rst/xdoc.conf | 2 - .../src/random_numbers.xc | 136 ---------------- lib_random/api/random.h | 55 ------- lib_random/doc/rst/random.rst | 15 +- lib_random/module_build_info | 5 - lib_random/src/random.xc | 24 --- lib_random/src/random_bit.xc | 16 +- lib_random/src/random_deprecated.c | 21 --- test/random/Makefile | 14 -- test/random/expected.output | 4 - test/random/src/test.xc | 130 --------------- test/random_bit/Makefile | 8 - test/runtests.py | 2 +- test/test_random.py | 15 -- 19 files changed, 21 insertions(+), 656 deletions(-) delete mode 100644 examples/AN002xx_random_number_generation/Makefile delete mode 100644 examples/AN002xx_random_number_generation/README.rst delete mode 100755 examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn delete mode 100644 examples/AN002xx_random_number_generation/config.xscope delete mode 100644 examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst delete mode 100644 examples/AN002xx_random_number_generation/doc/rst/xdoc.conf delete mode 100644 examples/AN002xx_random_number_generation/src/random_numbers.xc delete mode 100755 lib_random/api/random.h delete mode 100755 lib_random/src/random.xc delete mode 100755 lib_random/src/random_deprecated.c delete mode 100644 test/random/Makefile delete mode 100644 test/random/expected.output delete mode 100755 test/random/src/test.xc delete mode 100755 test/test_random.py diff --git a/examples/AN002xx_random_number_generation/Makefile b/examples/AN002xx_random_number_generation/Makefile deleted file mode 100644 index b0101e3..0000000 --- a/examples/AN002xx_random_number_generation/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -TARGET = SMART-MIC-4-TILE-1V0 -APP_NAME = -USED_MODULES = lib_random - -XCC_FLAGS = -O2 -g -Wunused -fxscope -VERBOSE = 0 - -XMOS_MAKE_PATH ?= ../.. --include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/examples/AN002xx_random_number_generation/README.rst b/examples/AN002xx_random_number_generation/README.rst deleted file mode 100644 index a92471e..0000000 --- a/examples/AN002xx_random_number_generation/README.rst +++ /dev/null @@ -1,34 +0,0 @@ -Noise Suppression and Automatic Gain Control example -==================================================== - -.. version:: 0.0.1 - -Summary -------- - -This example demonstrates how to use the automatic gain control library, -the noise suppression library, and the microphone array library in order to -create a meaningful AGC - -Required tools and libraries -............................ - -.. appdeps:: - -Required hardware -................. - -A smart microphone board. - -Prerequisites -............. - - * This document assumes familiarity with the XMOS xCORE architecture, - the XMOS tool chain and the xC language. Documentation related to these - aspects which are not specific to this application note are linked to in - the references appendix. - - * For a description of XMOS related terms found in this document - please see the XMOS Glossary [#]_. - -.. [#] http://www.xmos.com/published/glossary diff --git a/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn b/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn deleted file mode 100755 index 1bb07e9..0000000 --- a/examples/AN002xx_random_number_generation/SMART-MIC-4-TILE-1V0.xn +++ /dev/null @@ -1,153 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Network xmlns="http://www.xmos.com" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.xmos.com http://www.xmos.com"> - <Type>Device</Type> - <Name>Mic Array Quad Tile</Name> - - <Declarations> - <Declaration>tileref tile[4]</Declaration> - <Declaration>tileref usb_tile</Declaration> - </Declarations> - - <Packages> - <Package id="0" Type="XS2-UFnA-512-TQ128"> - <Nodes> - <Node Id="0" InPackageId="0" Type="XS2-L16A-512" Oscillator="24MHz" SystemFrequency="500MHz" ReferenceFrequency="100MHz"> - - <Boot> - <Source Location="bootFlash0"/> - <Bootee NodeId="2"/> - </Boot> - <Tile Number="0" Reference="tile[0]"> - <!-- Quad flash ports --> - <Port Location="XS1_PORT_1B" Name="PORT_SQI_CS"/> - <Port Location="XS1_PORT_1C" Name="PORT_SQI_SCLK"/> - <Port Location="XS1_PORT_4B" Name="PORT_SQI_SIO"/> - - <Port Location="XS1_PORT_1M" Name="PORT_PLL_MOD"/> - <Port Location="XS1_PORT_1P" Name="PORT_BGT_SPI_CLK"/> - <Port Location="XS1_PORT_1A" Name="PORT_BGT_SPI_CS_N"/> - <Port Location="XS1_PORT_1F" Name="PORT_BGT_SPI_MISO"/> - <Port Location="XS1_PORT_1E" Name="PORT_BGT_SPI_MOSI"/> - <Port Location="XS1_PORT_1D" Name="PORT_BGT_IRQ"/> - <Port Location="XS1_PORT_1O" Name="PORT_I2C_SCL"/> - <Port Location="XS1_PORT_1N" Name="PORT_I2C_SDA"/> - </Tile> - <Tile Number="1" Reference="tile[1]"> - <!-- USB --> - <Port Location="XS1_PORT_1H" Name="PORT_USB_TX_READYIN"/> - <Port Location="XS1_PORT_1J" Name="PORT_USB_CLK"/> - <Port Location="XS1_PORT_1K" Name="PORT_USB_TX_READYOUT"/> - <Port Location="XS1_PORT_1I" Name="PORT_USB_RX_READY"/> - <Port Location="XS1_PORT_1E" Name="PORT_USB_FLAG0"/> - <Port Location="XS1_PORT_1F" Name="PORT_USB_FLAG1"/> - <Port Location="XS1_PORT_1G" Name="PORT_USB_FLAG2"/> - <Port Location="XS1_PORT_8A" Name="PORT_USB_TXD"/> - <Port Location="XS1_PORT_8B" Name="PORT_USB_RXD"/> - - <!-- I2C --> - <!-- Note: Bit 1 of PORT 4E is I2C_SCL --> - <!-- Bit 2 of PORT 4E is I2C_SDA --> - <Port Location="XS1_PORT_4E" Name="PORT_I2C_SCL_SDA"/> - <Port Location="XS1_PORT_4F" Name="PORT_DAC_RST_N"/> - - <!-- I2S --> - <Port Location="XS1_PORT_1M" Name="PORT_I2S_BCLK"/> - <Port Location="XS1_PORT_1N" Name="PORT_I2S_LRCLK"/> - <Port Location="XS1_PORT_1O" Name="PORT_MCLK_IN"/> - <Port Location="XS1_PORT_1P" Name="PORT_I2S_DAC0"/> - <Port Location="XS1_PORT_1L" Name="PORT_I2S_DAC1"/> - <Port Location="XS1_PORT_1C" Name="PORT_I2S_ADC0"/> - <Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/> - </Tile> - </Node> - <Node Id="1" InPackageId="1" Type="periph:XS1-SU" Reference="usb_tile" Oscillator="24MHz"/> - </Nodes> - <Links> - <Link Encoding="5wire"> - <LinkEndpoint NodeId="0" Link="8" Delays="52clk,52clk"/> - <LinkEndpoint NodeId="1" Link="XL0" Delays="1clk,1clk"/> - </Link> - </Links> - </Package> - - <Package id="1" Type="XS2-LnA-512-TQ128"> - <Nodes> - <Node Id="2" InPackageId="0" Type="XS2-L16A-512" SystemFrequency="500MHz" Oscillator="24MHz" ReferenceFrequency="100MHz"> - <Boot> - <Source Location="LINK" BootMode="4"/> - </Boot> - <Tile Number="0" Reference="tile[2]"> - <!-- Mics --> - <!-- Notes: XS1_PORT_4C is for mics 0, 1, 6 and 7 --> - <!-- XS1_PORT_4D is for mics 2, 3, 4 and 5 --> - <Port Location="XS1_PORT_8B" Name="PORT_PDM_DATA"/> - <Port Location="XS1_PORT_1G" Name="PORT_PDM_MCLK"/> - <Port Location="XS1_PORT_1H" Name="PORT_PDM_CLK"/> - </Tile> - <Tile Number="1" Reference="tile[3]"> - <!-- Wireless LAN --> - <Port Location="XS1_PORT_1A" Name="PORT_WLAN_SPI_MOSI"/> - <Port Location="XS1_PORT_1B" Name="PORT_WLAN_SPI_MISO"/> - <Port Location="XS1_PORT_4A" Name="PORT_WLAN_WLAN_SPI_IRQ_N"/> - <!-- Note: Bit 1 of PORT 4B is WLAN_3V3_EN --> - <!-- Bit 2 of PORT 4B is WLAN_RST_N --> - <Port Location="XS1_PORT_4B" Name="PORT_WLAN_3V3_EN_RST_N"/> - <Port Location="XS1_PORT_1C" Name="PORT_WLAN_SPI_CLK"/> - <Port Location="XS1_PORT_1D" Name="PORT_WLAN_SPI_CS_N"/> - - <!-- Button ports --> - <Port Location="XS1_PORT_4C" Name="PORT_BUT_A_TO_D"/> - - <!-- LED ports --> - <Port Location="XS1_PORT_8C" Name="PORT_LED0_TO_7"/> - <!-- Note: Only bits 4-7 of PORT 8D are for LEDs --> - <Port Location="XS1_PORT_8D" Name="PORT_LED8_TO_11"/> - <Port Location="XS1_PORT_1J" Name="PORT_LED_12"/> - </Tile> - </Node> - </Nodes> - </Package> - </Packages> - - <Links> - <Link Encoding="2wire" Delays="3clk"> - <LinkEndpoint NodeId="0" Link="7"/> - <LinkEndpoint NodeId="2" Link="0"/> - </Link> - <Link Encoding="5wire" Delays="3clk"> - <LinkEndpoint NodeId="0" Link="4"/> - <LinkEndpoint NodeId="2" Link="3"/> - </Link> - </Links> - - <!-- XSCOPE --> - <Nodes> - <Node Id="3" Type="device:" RoutingId="0x8000"> - <Service Id="0" Proto="xscope_host_data(chanend c);"> - <Chanend Identifier="c" end="3"/> - </Service> - </Node> - </Nodes> - <Links> - <Link Encoding="2wire" Delays="4,4" Flags="XSCOPE"> - <LinkEndpoint NodeId="0" Link="XL0"/> - <LinkEndpoint NodeId="3" Chanend="1"/> - </Link> - </Links> - - <ExternalDevices> - <Device NodeId="0" Tile="0" Class="SQIFlash" Name="bootFlash0"> - <Attribute Name="PORT_SQI_CS" Value="PORT_SQI_CS"/> - <Attribute Name="PORT_SQI_SCLK" Value="PORT_SQI_SCLK"/> - <Attribute Name="PORT_SQI_SIO" Value="PORT_SQI_SIO"/> - </Device> - </ExternalDevices> - - <JTAGChain> - <JTAGDevice NodeId="0"/> - <JTAGDevice NodeId="2"/> - </JTAGChain> - -</Network> diff --git a/examples/AN002xx_random_number_generation/config.xscope b/examples/AN002xx_random_number_generation/config.xscope deleted file mode 100644 index 6436587..0000000 --- a/examples/AN002xx_random_number_generation/config.xscope +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- ======================================================= --> -<!-- The 'ioMode' attribute on the xSCOPEconfig --> -<!-- element can take the following values: --> -<!-- "none", "basic", "timed" --> -<!-- --> -<!-- The 'type' attribute on Probe --> -<!-- elements can take the following values: --> -<!-- "STARTSTOP", "CONTINUOUS", "DISCRETE", "STATEMACHINE" --> -<!-- --> -<!-- The 'datatype' attribute on Probe --> -<!-- elements can take the following values: --> -<!-- "NONE", "UINT", "INT", "FLOAT" --> -<!-- ======================================================= --> - -<xSCOPEconfig ioMode="basic" enabled="false"> - - <!-- For example: --> - <Probe name="CH0" type="CONTINUOUS" datatype="INT" units="Value" enabled="true"/> - <!-- From the target code, call: xscope_int(PROBE_NAME, value); --> - -</xSCOPEconfig> diff --git a/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst b/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst deleted file mode 100644 index 08592a2..0000000 --- a/examples/AN002xx_random_number_generation/doc/rst/AN002xx.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. include:: ../../README.rst - -|newpage| - -Overview --------- - -Introduction -............ - -This demo application shows how to use random numbers. diff --git a/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf b/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf deleted file mode 100644 index cb5aab6..0000000 --- a/examples/AN002xx_random_number_generation/doc/rst/xdoc.conf +++ /dev/null @@ -1,2 +0,0 @@ -XMOSNEWSTYLE=1 -SOURCE_INCLUDE_DIRS=../../src diff --git a/examples/AN002xx_random_number_generation/src/random_numbers.xc b/examples/AN002xx_random_number_generation/src/random_numbers.xc deleted file mode 100644 index 3c94404..0000000 --- a/examples/AN002xx_random_number_generation/src/random_numbers.xc +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <xs1.h> -#include "random_bit.h" - -#define MAXX 1024 -#define MAXY 1024 -#define MAXBITS (MAXX * MAXY) - -unsigned char thebits[MAXBITS/8]; - -unsigned int getbit(int i) { - return (thebits[i>>3] >> (i&7)) & 1; -} - -unsigned int setbit(int i, int val) { - return thebits[i>>3] |= val << (i&7); -} - -void blocktest(int n) { - int hist[256]; - for(int i = 0; i < 256; i++) { - hist[i] = 0; - } - for(int i = 0; i < MAXBITS - n; i++) { - int val = 0; - for(int j = 0; j < n; j++) { - val = val << 1 | getbit(i+j); - } - hist[val]++; - } - printf("Blocktest %d\n", n); - for(int i = 0; i < (1<<n); i++) { - printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i]-(MAXBITS >> n)) < MAXX ? "Ok" : "Hmm"); - } - printf("\n"); -} - -void runtest() { - int hist[200]; - int old = 0; - int run = 0; - for(int i = 0; i < 200; i++) { - hist[i] = 0; - } - for(int i = 0; i < MAXBITS; i++) { - if(getbit(i) == old) { - run++; - } else { - hist[run]++; - run = 1; - } - } - printf("Runtest:\n"); - for(int i = 1; i < 10; i++) { - printf(" Bin %d: %d %s\n", i, hist[i], abs(hist[i] - (MAXBITS >> (i+1))) < (MAXX >> (i/2)) ? "Ok" : "Hmm" ); - } - printf("\n"); -} - -void fillmetrue(void) { - timer tmr; - int t0, t1; - int sum = 0; - tmr :> t0; - random_bit_start(); - while(sum < MAXBITS) { - uint32_t bit_time; - if (random_bit(bit_time)) { - //assert((bit_time & ~1UL)==0); - setbit(sum, bit_time); - sum++; - if ((sum & 0xffff) == 0) { - int time; - asm volatile ("gettime %0" : "=r" (time)); - printf("%11d %d\n", time, sum); - } - } - //else - // tmr when timerafter(bit_time) :> void; - } - random_bit_stop(); - tmr :> t1; - printf("Ticks taken: %d, %d per bit\n", t1-t0, (t1-t0)/sum); -} - -void xmain(chanend done[7]) { - for(int i = 0; i < 7; i++) { - done[i] <: 0; - } - fillmetrue(); - blocktest(1); - blocktest(2); - blocktest(3); - runtest(); - return; - printf("P2\n%d %d\n1\n", MAXX, MAXY); - for(int i = 0; i < MAXX; i++) { - for(int j = 0; j < MAXY; j++) { - printf("%d ", getbit(i*MAXY+j)); - } - printf("\n"); - } -} - -int busy(int x, chanend y) { - while(1) { - for(int i = 0; i < 1000; i++) { - x = x * 1234567 + 1; - } - select { - case y :> int _: return x; - default: break; - } - } - return x; -} - - -int main(void) { - chan done[7]; - par { - busy(0x3, done[0]); - busy(0x4, done[1]); - busy(0x5, done[2]); - busy(0x6, done[3]); - busy(0x7, done[4]); - busy(0x8, done[5]); - busy(0x9, done[6]); - xmain(done); - } - return 0; -} diff --git a/lib_random/api/random.h b/lib_random/api/random.h deleted file mode 100755 index fec5350..0000000 --- a/lib_random/api/random.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved -#ifndef __RANDOM_H__ -#define __RANDOM_H__ - -#include <stdint.h> -#include <stddef.h> - -#ifndef REFERENCE_PARAM -#ifdef __XC__ -#define REFERENCE_PARAM(type, name) type &name -#else -#define REFERENCE_PARAM(type, name) type *name -#endif -#endif - -/** This is an alternative pseudo-random number generator to those offered by stdlib.h: - * rand, srand, rand_r, drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, seed48, srand48 - * It uses the built in crc32() instructions. - */ - -/** Type representing a random number generator. - */ -typedef unsigned random_generator_t; - -/** Function that creates a random number generator from a seed. - * - * \param seed seed for the generator. - * - * \returns a random number generator. - */ -random_generator_t random_create_generator_from_seed(unsigned seed); - - -/** Function that produces a random number. The number has a cycle of 2^32 - * and is produced using a LFSR. - * - * \param g the used generator to produce the seed. - * - * \returns a random 32 bit number. - */ -unsigned -random_get_random_number(REFERENCE_PARAM(random_generator_t, g)); - -void random_get_random_bytes(REFERENCE_PARAM(random_generator_t, g), uint8_t in_buffer[], size_t byte_count); - - -// The following function is deprecated. -// It is incompatible with the rest of the lib_random library. -// To use this function you must define in your Makefile: -// RANDOM_ENABLE_HW_SEED=1 -//__attribute__((deprecated)) // Use random_prng.h instead. -random_generator_t random_create_generator_from_hw_seed(void); - - -#endif // __RANDOM_H__ diff --git a/lib_random/doc/rst/random.rst b/lib_random/doc/rst/random.rst index 389f89a..ce74172 100644 --- a/lib_random/doc/rst/random.rst +++ b/lib_random/doc/rst/random.rst @@ -4,18 +4,19 @@ API --- To use the module you need to use ``lib_random`` in your application and -include the ``random.h`` header. - - - +include only one of the ``api`` header files. +The three APIs are nested, hence you should choose the one that gives you +the required level of functionality. +In most cases, you will want to be using the top level, ``random_prng.h``. +The top level is built upon the lower level, hence access to entropy. +For alternative PRNG see stdlib.h which includes: + rand, srand, rand_r, drand48, erand48, jrand48, lcong48, lrand48, + mrand48, nrand48, seed48, srand48. |appendix| Known Issues ------------ -The deprecated random_create_generator_from_hw_seed() functionality will not work corrrectly -along side random_bit.h (and hence random_pool.h and random_prng.h) - .. include:: ../../../CHANGELOG.rst diff --git a/lib_random/module_build_info b/lib_random/module_build_info index 0828bac..d2d3c17 100755 --- a/lib_random/module_build_info +++ b/lib_random/module_build_info @@ -1,10 +1,5 @@ MODULE_XCC_FLAGS = -g -Os #MODULE_XCC_FLAGS += -save-temps -v -# Enable deprecated features -ifneq ($(RANDOM_ENABLE_HW_SEED),) -MODULE_XCC_FLAGS += -DRANDOM_ENABLE_HW_SEED=$(RANDOM_ENABLE_HW_SEED) -endif - DEPENDENT_MODULES = lib_locks lib_xassert VERSION = 1.1.0 diff --git a/lib_random/src/random.xc b/lib_random/src/random.xc deleted file mode 100755 index 9d32dfe..0000000 --- a/lib_random/src/random.xc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved -#include "random.h" -#include <xs1.h> - -unsigned random_get_random_number(random_generator_t &g) -{ - static const unsigned random_poly = 0xEDB88320; - crc32(g, -1, random_poly); - return (unsigned) g; -} - -void random_get_random_bytes(random_generator_t &g, uint8_t in_buffer[], size_t byte_count) -{ - for (int i=0; i < byte_count; ++i) { - in_buffer[i] = (uint8_t)random_get_random_number(g); - } -} - -random_generator_t random_create_generator_from_seed(unsigned seed) -{ - random_generator_t gen = (random_generator_t) seed; - (void) random_get_random_number(gen); - return gen; -} diff --git a/lib_random/src/random_bit.xc b/lib_random/src/random_bit.xc index 3b48acc..cd7f748 100755 --- a/lib_random/src/random_bit.xc +++ b/lib_random/src/random_bit.xc @@ -3,6 +3,14 @@ #include "hwlock.h" #include "random_impl.h" +#if __XS2__ +# include "xs2a_registers.h" +#else +# include "xs1b_registers.h" +# define XS1_PS_RING_OSC_CTRL XS1_L_PS_RING_OSC_CTRL +# define XS1_PS_RING_OSC_DATA0 XS1_L_PS_RING_OSC_DATA0 +#endif + // Optional thread protection... #define LOAD32(dst, ptr) asm("ldw %0, %1[0]" : "=r"(dst) : "r"(ptr)); @@ -38,11 +46,11 @@ void random_bit_start() { timer tmr; tmr :> last_time; STORE32(last_time, &per_tile_last_time); - setps(0x60B, 2); + setps(XS1_PS_RING_OSC_CTRL, 2); } void random_bit_stop() { - setps(0x60B, 0); + setps(XS1_PS_RING_OSC_CTRL, 0); } uint32_t random_bit(uint32_t &bit_time) { @@ -58,8 +66,8 @@ uint32_t random_bit(uint32_t &bit_time) { asm("nop"); asm("nop"); asm("nop"); - asm("nop"); - bit_time = getps(0x70B); + asm("nop"); // Allow the data to stabilise. + bit_time = getps(XS1_PS_RING_OSC_DATA0); random_bit_start(); bit_time &=1; return 1; diff --git a/lib_random/src/random_deprecated.c b/lib_random/src/random_deprecated.c deleted file mode 100755 index 711102e..0000000 --- a/lib_random/src/random_deprecated.c +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2016-2017, XMOS Ltd, All rights reserved -#include "random.h" -#include <xs1.h> - -#if RANDOM_ENABLE_HW_SEED - -#warning "Building deprecated random_create_generator_from_hw_seed()" -#warning "N.B. random_create_generator_from_hw_seed() is incompatible with the rest of the lib_random library." -#warning "Did you mean to define `RANDOM_ENABLE_HW_SEED`?" - -__attribute__((constructor)) -void random_simple_init_seed() { - setps(0x060B, 0x3); -} - -random_generator_t random_create_generator_from_hw_seed(void) { - unsigned init_seed = getps(0x070B); - return random_create_generator_from_seed(init_seed); -} - -#endif diff --git a/test/random/Makefile b/test/random/Makefile deleted file mode 100644 index b0ceab1..0000000 --- a/test/random/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = SLICEKIT-L16 -APP_NAME = -USED_MODULES = lib_random - -XCC_FLAGS = -Os -g -#XCC_FLAGS += -save-temps -v - -# We will be testing the deprecated interface... -RANDOM_ENABLE_HW_SEED=1 - -VERBOSE = 0 - -XMOS_MAKE_PATH ?= ../.. --include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common diff --git a/test/random/expected.output b/test/random/expected.output deleted file mode 100644 index e22e136..0000000 --- a/test/random/expected.output +++ /dev/null @@ -1,4 +0,0 @@ -test-3 done. -test-2 done. -test-0 done. -test-1 done. diff --git a/test/random/src/test.xc b/test/random/src/test.xc deleted file mode 100755 index 6ba3ec1..0000000 --- a/test/random/src/test.xc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2017, XMOS Ltd, All rights reserved - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <platform.h> -#include "random.h" - -///////////////////////////////////////////////////////// -// First some unit testing boiler plate -interface checker { - void str(const char str[100]); - void release(); -}; -static void checkerServer(server interface checker si[n], static const size_t n, uint32_t timeout) { - // We will release when the last client has released us. - // All clients have implicitly claimed us, set the 'n' lowest bits. - if (n > 32) { - fprintf(stderr, "Error checkerServer: The maximum number of clients is 32\n"); - return; - } - uint32_t activeClients = (1ULL<<n) - 1; - - // Attempt to spot hung tests. - timer tmr; - uint32_t start; - tmr :> start; - - while(1){ - select{ - case si[unsigned id].str(const char str[100]) : - char local[100]; - memcpy(local,str,100); - fprintf(stderr, "%s\n", local); - break; - case si[unsigned id].release(): - activeClients &= ~(1UL << id); - if (!activeClients) - return; - break; - case tmr when timerafter(start + timeout) :> void: - fprintf(stderr, "Error checkerServer: timout after %d tick, activeClients mask=0x%X\n", timeout, activeClients); - exit(1); - break; - } - } -} - -#define INFO(ci, ...) \ - do { \ - char _checker_buff[100]; \ - snprintf(_checker_buff, 100, __VA_ARGS__); \ - ci.str(_checker_buff); \ - } while(0) - -#define CHECK(c, ci, ...) \ - if (!(c)) INFO(ci, __VA_ARGS__) - -///////////////////////////////////////////////////////// - -typedef union { - uint32_t word[2]; - uint8_t byte[8]; -} Bytes; - - -void test(client interface checker ci, int id) { - - // Check '0' is valid. - random_generator_t gen1 = random_create_generator_from_seed(0); - unsigned v1 = random_get_random_number(gen1); - CHECK( v1, ci, "test-%d unexpexted zero returned", id ); - Bytes b1 = {{0,0}}; - random_get_random_bytes(gen1, b1.byte, 5); - // simple checks of the values returned... - CHECK( b1.word[0] && b1.word[1], ci, "test-%d unexpexted zero returned, %#08X%08x", id, b1.word[0], b1.word[1] ); - CHECK( (b1.word[1] & 0xffffff00) == 0, ci, "test-%d too many bytes read, %#08X%08x", id, b1.word[0], b1.word[1] ); - // We do not test for 'out of bounds array access' - // random_get_random_bytes(gen1, b1.byte, 11); - - // Check we get a different set of values. - random_generator_t gen2 = random_create_generator_from_seed(0x12345678); - unsigned v2 = random_get_random_number(gen2); - CHECK( v2 != v1, ci, "test-%d unexpexted same value", id ); - Bytes b2 = {{0,0}}; - random_get_random_bytes(gen2, b2.byte, 5); - CHECK( b2.word[0] != b1.word[0] && b2.word[1] != b1.word[1], ci, "unexpexted same bytes", id ); - - // We should get the same output as the first block. - random_generator_t gen3 = random_create_generator_from_seed(0); - unsigned v3 = random_get_random_number(gen3); - CHECK( v3 == v1, ci, "test-%d unexpexted different value", id ); - Bytes b3 = {{0,0}}; - random_get_random_bytes(gen3, b3.byte, 5); - CHECK( b3.word[0] == b1.word[0] && b3.word[1] == b1.word[1], ci, "unexpexted different bytes", id ); - - // All gernators are independant. - v1 = random_get_random_number(gen1); - v2 = random_get_random_number(gen2); - v3 = random_get_random_number(gen3); - CHECK( v2 != v1, ci, "test-%d unexpexted same value", id ); - CHECK( v3 == v1, ci, "test-%d unexpexted different value", id ); - - Bytes zero = {{0,0}}; - random_get_random_bytes(gen1, zero.byte, 0); - CHECK( !zero.word[0] && !zero.word[1], ci, "unexpexted bytes read", id ); - - // The following function is deprecated but still tested. - // We have add 'RANDOM_ENABLE_HW_SEED=1' to the Makefile. - // The build will generate a warning... which we ignore. - random_generator_t gen4 = random_create_generator_from_hw_seed(); - // No delay needed. - random_generator_t gen5 = random_create_generator_from_hw_seed(); - CHECK( gen4 != gen5, ci, "test-%d same hw seed generator", id ); - - INFO(ci, "test-%d done.", id); - ci.release(); -} - -int main() { - interface checker i[4]; - par { - on tile[0] : checkerServer(i, 4, 100000); - on tile[0] : test(i[0], 0); - on tile[0] : test(i[1], 1); - on tile[1] : test(i[2], 2); - on tile[1] : test(i[3], 3); - } - return 0; // failure; -} diff --git a/test/random_bit/Makefile b/test/random_bit/Makefile index ef987ff..85cb9fd 100755 --- a/test/random_bit/Makefile +++ b/test/random_bit/Makefile @@ -3,14 +3,6 @@ APP_NAME = USED_MODULES = lib_random XCC_FLAGS = -Os -g -#XCC_FLAGS += -save-temps -v - -# RANDOM_ENABLE_HW_SEED must either: -# not be declared at all -# or if it is, take the value '0'. -# We chose the second option here as an example, other tests do not declare it at all. -# N.B. We expect random_deprecated.c not to be built. -RANDOM_ENABLE_HW_SEED=0 VERBOSE = 0 diff --git a/test/runtests.py b/test/runtests.py index d422f09..07130d4 100755 --- a/test/runtests.py +++ b/test/runtests.py @@ -3,7 +3,7 @@ if __name__ == "__main__": xmostest.init() - xmostest.register_group("lib_random", "lib_random_tests", "lib_random library tests", "Tests random_bit.h, random_pool.h, random_prng.h and random.h") + xmostest.register_group("lib_random", "lib_random_tests", "lib_random library tests", "Tests random_bit.h, random_pool.h and random_prng.h") xmostest.runtests() xmostest.finish() diff --git a/test/test_random.py b/test/test_random.py deleted file mode 100755 index 845222b..0000000 --- a/test/test_random.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import xmostest - -def runtest(): - resources = xmostest.request_resource("xsim") - - tester = xmostest.ComparisonTester(open('random/expected.output'), - 'lib_random', - 'lib_random_tests', - 'random', {}) - - xmostest.run_on_simulator(resources['xsim'], - 'random/bin/random.xe', - tester=tester) -