blob: 8a70029627a34ccbec53a104f879c94ec6498234 [file] [log] [blame]
#include <stdio.h>
#include "lfsr.h"
/*
* From table 3 of
*
* http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
*/
static struct lfsr_taps lfsr_taps[] = {
{
.length = 16,
.taps = { 16, 15, 13, 4, },
},
{
.length = 17,
.taps = { 17, 14, },
},
{
.length = 18,
.taps = { 18, 11, },
},
{
.length = 19,
.taps = { 19, 6, 2, 1, },
},
{
.length = 20,
.taps = { 20, 17, },
},
{
.length = 21,
.taps = { 21, 19, },
},
{
.length = 22,
.taps = { 22, 21, },
},
{
.length = 23,
.taps = { 23, 18, },
},
{
.length = 24,
.taps = { 24, 23, 22, 17, },
},
{
.length = 25,
.taps = { 25, 22, },
},
{
.length = 26,
.taps = {26, 6, 2, 1, },
},
{
.length = 27,
.taps = { 27, 5, 2, 1, },
},
{
.length = 28,
.taps = { 28, 25, },
},
{
.length = 29,
.taps = {29, 27, },
},
{
.length = 30,
.taps = { 30, 6, 4, 1, },
},
{
.length = 31,
.taps = { 31, 28, },
},
{
.length = 32,
.taps = { 32, 22, 2, 1, },
},
{
.length = 33,
.taps = { 33, 20, },
},
{
.length = 34,
.taps = { 34, 27, 2, 1, },
},
{
.length = 35,
.taps = { 35, 33, },
},
{
.length = 36,
.taps = { 36, 25, },
},
{
.length = 37,
.taps = { 37, 5, 4, 3, 2, 1, },
},
{
.length = 38,
.taps = { 38, 6, 5, 1, },
},
{
.length = 39,
.taps = { 39, 35, },
},
{
.length = 40,
.taps = { 40, 38, 21, 19, },
},
{
.length = 41,
.taps = { 41, 38, },
},
{
.length = 42,
.taps = { 42, 41, 20, 19, },
},
{
.length = 43,
.taps = { 43, 42, 38, 37, },
},
{
.length = 44,
.taps = { 44, 43, 38, 37, },
},
{
.length = 45,
.taps = { 45, 44, 42, 41, },
},
{
.length = 46,
.taps = { 46, 45, 26, 25, },
},
{
.length = 47,
.taps = { 47, 42, },
},
{
.length = 48,
.taps = { 48, 47, 21, 20, },
},
{
.length = 49,
.taps = { 49, 40, },
},
{
.length = 50,
.taps = { 50, 49, 36, 35, },
},
{
.length = 51,
.taps = { 51, 50, 36, 35, },
},
{
.length = 52,
.taps = { 52, 49, },
},
{
.length = 53,
.taps = { 53, 52, 38, 37 },
},
{
.length = 54,
.taps = { 54, 53, 18, 17 },
},
{
.length = 55,
.taps = { 55, 31, },
},
{
.length = 56,
.taps = { 56, 55, 35, 34, },
},
{
.length = 57,
.taps = { 57, 50, },
},
{
.length = 58,
.taps = { 58, 39, },
},
{
.length = 59,
.taps = { 59, 58, 38, 37, },
},
{
.length = 60,
.taps = { 60, 59, },
},
{
.length = 61,
.taps = { 61, 60, 46, 45, },
},
{
.length = 62,
.taps = { 62, 61, 6, 5, },
},
{
.length = 63,
.taps = { 63, 62, },
},
};
#define FIO_LFSR_CRANKS 128
static uint64_t __lfsr_next(uint64_t v, struct lfsr_taps *lt)
{
uint64_t xor_mask = 0;
int i;
for (i = 0; lt->taps[i]; i++)
xor_mask ^= (v << (lt->taps[i] - 1));
xor_mask &= ~(~0UL << 1) << (lt->length - 1);
return xor_mask | (v >> 1);
}
int lfsr_next(struct fio_lfsr *fl, uint64_t *off)
{
if (fl->num_vals > fl->max_val)
return 1;
do {
fl->last_val = __lfsr_next(fl->last_val, &fl->taps);
if (fl->last_val - 1 <= fl->max_val)
break;
} while (1);
*off = fl->last_val - 1;
fl->num_vals++;
return 0;
}
static struct lfsr_taps *find_lfsr(uint64_t size)
{
int i;
for (i = 0; lfsr_taps[i].length; i++)
if (((1UL << lfsr_taps[i].length) + FIO_LFSR_CRANKS) >= size)
return &lfsr_taps[i];
return NULL;
}
int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed)
{
struct lfsr_taps *tap;
int i;
tap = find_lfsr(size);
if (!tap)
return 1;
fl->last_val = seed;
fl->max_val = size - 1;
fl->num_vals = 0;
fl->taps.length = tap->length;
for (i = 0; i < FIO_MAX_TAPS; i++) {
fl->taps.taps[i] = tap->taps[i];
if (!fl->taps.taps[i])
break;
}
for (i = 0; i < FIO_LFSR_CRANKS; i++)
fl->last_val = __lfsr_next(fl->last_val, &fl->taps);
return 0;
}