2014-02-24 01:41:38 +04:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014 Mellanox Technologies, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
* $COPYRIGHT$
|
2015-06-24 06:59:57 +03:00
|
|
|
*
|
2014-02-24 01:41:38 +04:00
|
|
|
* Additional copyrights may follow
|
2015-06-24 06:59:57 +03:00
|
|
|
*
|
2014-02-24 01:41:38 +04:00
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "opal_config.h"
|
|
|
|
|
2016-08-03 02:54:24 +03:00
|
|
|
#include <string.h>
|
|
|
|
|
2014-02-24 01:41:38 +04:00
|
|
|
#include "alfg.h"
|
|
|
|
|
2015-06-24 06:59:57 +03:00
|
|
|
/* Mask corresponding to the primitive polynomial
|
|
|
|
*---------------------------------------------------
|
|
|
|
*
|
2014-02-24 01:41:38 +04:00
|
|
|
* p(x) = 1 + x^25 + x^27 + x^29 + x^30 + x^31 + x^32
|
|
|
|
*
|
2015-06-24 06:59:57 +03:00
|
|
|
*---------------------------------------------------
|
|
|
|
*/
|
2014-02-24 01:41:38 +04:00
|
|
|
#define MASK 0x80000057U
|
|
|
|
|
|
|
|
/* Additive lagged Fibonacci parameters:
|
2015-06-24 06:59:57 +03:00
|
|
|
*---------------------------------------------------
|
2014-02-24 01:41:38 +04:00
|
|
|
*
|
|
|
|
* x_n = (x_(n - TAP1) + x_(n - TAP2) ) mod M
|
|
|
|
*
|
2015-06-24 06:59:57 +03:00
|
|
|
*---------------------------------------------------
|
|
|
|
*/
|
2014-02-24 01:41:38 +04:00
|
|
|
#define TAP1 127
|
|
|
|
#define TAP2 97
|
|
|
|
#define CBIT 21 /* Canonical bit */
|
|
|
|
|
|
|
|
|
2015-06-24 06:59:57 +03:00
|
|
|
/**
|
2014-02-24 01:41:38 +04:00
|
|
|
* @brief Galois shift register: Used to seed the ALFG's
|
|
|
|
* canonical rectangle
|
2015-06-24 06:59:57 +03:00
|
|
|
*
|
|
|
|
* @param[in] unsigned int *seed: used to seed the Galois register
|
|
|
|
* @param[out] uint32_t lsb: least significant bit of the Galois
|
|
|
|
* register after shift
|
|
|
|
*/
|
2014-02-24 01:41:38 +04:00
|
|
|
static uint32_t galois(unsigned int *seed){
|
|
|
|
|
|
|
|
uint32_t lsb;
|
|
|
|
lsb = (*seed & 1) ? 1 : 0;
|
|
|
|
*seed >>= 1;
|
|
|
|
/* tap it with the mask */
|
|
|
|
*seed = *seed ^ (lsb*MASK);
|
|
|
|
|
|
|
|
return lsb;
|
|
|
|
}
|
|
|
|
|
2016-08-03 02:54:24 +03:00
|
|
|
/* OPAL global rng buffer */
|
|
|
|
static opal_rng_buff_t alfg_buffer;
|
|
|
|
|
2015-06-24 06:59:57 +03:00
|
|
|
/**
|
2014-02-24 01:41:38 +04:00
|
|
|
* @brief Routine to seed the ALFG register
|
2015-06-24 06:59:57 +03:00
|
|
|
*
|
2014-02-24 01:41:38 +04:00
|
|
|
* @param[in] uint32_t seed
|
2014-02-25 03:18:35 +04:00
|
|
|
* @param[out] opal_rng_buff_t *buff: handle to ALFG buffer state
|
2014-02-24 01:41:38 +04:00
|
|
|
*/
|
2014-02-25 03:18:35 +04:00
|
|
|
int opal_srand(opal_rng_buff_t *buff, uint32_t seed) {
|
2014-02-24 01:41:38 +04:00
|
|
|
|
|
|
|
int i, j;
|
|
|
|
uint32_t seed_cpy = seed;
|
|
|
|
buff->tap1 = TAP1 - 1;
|
|
|
|
buff->tap2 = TAP2 - 1;
|
|
|
|
|
|
|
|
/* zero out the register */
|
|
|
|
for( i = 0; i < TAP1; i++){
|
|
|
|
buff->alfg[i] = 0;
|
|
|
|
}
|
|
|
|
/* set the canonical bit */
|
|
|
|
buff->alfg[CBIT] = 1;
|
|
|
|
|
|
|
|
/* seed the ALFG register by blasting
|
|
|
|
* the canonical rectangle with bits
|
|
|
|
*/
|
|
|
|
for ( j = 1; j < TAP1; j++){
|
|
|
|
for( i = 1; i < 32; i++){
|
|
|
|
buff->alfg[j] = buff->alfg[j] ^ ((galois(&seed_cpy))<<i);
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 02:54:24 +03:00
|
|
|
/* copy the ALFG to the global buffer */
|
|
|
|
memcpy(&alfg_buffer, buff, sizeof(alfg_buffer));
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2014-02-24 01:41:38 +04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-06-24 06:59:57 +03:00
|
|
|
/**
|
2014-02-24 01:41:38 +04:00
|
|
|
* @brief The additive lagged Fibonnaci PRNG
|
|
|
|
*
|
2014-02-25 03:18:35 +04:00
|
|
|
* @param[in] opal_rng_buff_t *buff: handle to ALFG buffer state
|
2014-02-24 01:41:38 +04:00
|
|
|
* @param[out] 32-bit unsigned random integer
|
2015-06-24 06:59:57 +03:00
|
|
|
*/
|
2014-02-24 01:41:38 +04:00
|
|
|
|
2014-02-25 03:18:35 +04:00
|
|
|
uint32_t opal_rand(opal_rng_buff_t *buff){
|
2014-02-24 01:41:38 +04:00
|
|
|
|
|
|
|
int *tap1 = &(buff->tap1);
|
|
|
|
int *tap2 = &(buff->tap2);
|
|
|
|
uint64_t overflow;
|
|
|
|
uint32_t temp;
|
|
|
|
|
|
|
|
/* prevent overflow */
|
|
|
|
overflow = (uint64_t) buff->alfg[*tap1] + (uint64_t) buff->alfg[*tap2];
|
|
|
|
/* circular buffer arithmetic */
|
|
|
|
temp = (*tap1 + 1) == TAP1 ? 0 : (*tap1 + 1);
|
|
|
|
/* Division modulo 2^32 */
|
|
|
|
buff->alfg[temp] = (uint32_t) ( overflow & ((1ULL<<32) -1));
|
|
|
|
|
|
|
|
/* increment tap points */
|
|
|
|
*tap1 = (*tap1 + 1)%TAP1;
|
|
|
|
*tap2 = (*tap2 + 1)%TAP1;
|
|
|
|
|
|
|
|
return buff->alfg[temp];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-08-03 02:54:24 +03:00
|
|
|
/**
|
|
|
|
* @brief A wrapper for opal_rand() with our global ALFG buffer;
|
|
|
|
*
|
|
|
|
* @param[in] none
|
|
|
|
* @param[out] int, the same as normal rand(3)
|
|
|
|
*/
|
|
|
|
int opal_random(void){
|
|
|
|
return (int)opal_rand(&alfg_buffer);
|
|
|
|
}
|