code cleanup and benchmark and stuff
This commit is contained in:
parent
42e59d38c5
commit
572883b269
63
src/main.c
63
src/main.c
|
@ -4,8 +4,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <hardware/structs/bus_ctrl.h>
|
|
||||||
#include <hardware/structs/rosc.h>
|
|
||||||
#include <hardware/clocks.h>
|
#include <hardware/clocks.h>
|
||||||
#include <hardware/vreg.h>
|
#include <hardware/vreg.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
|
@ -16,9 +14,29 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DO_TIME_BENCH 0
|
||||||
|
#define DATA_TOTAL 1024*1024
|
||||||
|
|
||||||
|
#if DO_TIME_BENCH
|
||||||
|
static uint8_t time_bench[128*1024];
|
||||||
|
#else
|
||||||
|
static uint8_t data[32];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
vreg_set_voltage(VREG_VOLTAGE_1_15);
|
// high freq, high voltage
|
||||||
set_sys_clock_khz(250*1000, true);
|
//vreg_set_voltage(VREG_VOLTAGE_1_25);
|
||||||
|
//set_sys_clock_khz(250*1000, true);
|
||||||
|
// low freq, low voltage
|
||||||
|
//set_sys_clock_khz(48*1000, true);
|
||||||
|
//vreg_set_voltage(VREG_VOLTAGE_0_90);
|
||||||
|
// low freq, high voltage
|
||||||
|
//set_sys_clock_khz(48*1000, true);
|
||||||
|
//vreg_set_voltage(VREG_VOLTAGE_1_15);
|
||||||
|
// highish freq, low voltage
|
||||||
|
//vreg_set_voltage(VREG_VOLTAGE_1_00);
|
||||||
|
|
||||||
for (size_t i = 0; i < 0x100; ++i) asm volatile("nop");
|
for (size_t i = 0; i < 0x100; ++i) asm volatile("nop");
|
||||||
busy_wait_ms(16);
|
busy_wait_ms(16);
|
||||||
|
|
||||||
|
@ -27,28 +45,39 @@ int main() {
|
||||||
busy_wait_ms(16);
|
busy_wait_ms(16);
|
||||||
iprintf("hello world!\n");
|
iprintf("hello world!\n");
|
||||||
|
|
||||||
if ((clocks_hw->clk[clk_sys].ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) ==
|
int d = rorand_init(NULL);
|
||||||
(CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB)) {
|
if (d < 0) {
|
||||||
panic("System is running from ring oscillator. This makes it impossible to be used as randomness source.\n");
|
iprintf("rorand_init() returned %d\n", d);
|
||||||
|
panic("can't init rorand");
|
||||||
}
|
}
|
||||||
|
|
||||||
rorand_init();
|
#if DO_TIME_BENCH
|
||||||
uint8_t data[32];
|
memset(time_bench, 0, sizeof(time_bench));
|
||||||
|
iprintf("[---] throughput benchmark start\n");
|
||||||
|
|
||||||
|
absolute_time_t ta = get_absolute_time();
|
||||||
|
rorand_get(time_bench, count_of(time_bench)*CHAR_BIT);
|
||||||
|
absolute_time_t tb = get_absolute_time();
|
||||||
|
|
||||||
|
int64_t dt_us = absolute_time_diff_us(ta, tb);
|
||||||
|
uint32_t clk_hz = clock_get_hz(clk_sys);
|
||||||
|
int clk_mhz = clk_hz/(1000*1000);
|
||||||
|
|
||||||
|
int64_t bps = count_of(time_bench)*CHAR_BIT * (1000ull*1000ull) / dt_us;
|
||||||
|
int64_t cpb = clk_hz / bps;
|
||||||
|
|
||||||
|
iprintf("[===] throughput benchmark done, took %lld us at %d MHz -> average %lli bits/second i.e. %lli cycles/bit\n",
|
||||||
|
dt_us, clk_mhz, bps, cpb);
|
||||||
|
#else
|
||||||
memset(data, 0, sizeof(data));
|
memset(data, 0, sizeof(data));
|
||||||
const uintptr_t total = 1024*1024;
|
const uintptr_t total = DATA_TOTAL;
|
||||||
for (uintptr_t off = 0; off < total; off += count_of(data)) {
|
for (uintptr_t off = 0; off < total; off += count_of(data)) {
|
||||||
rorand_get(data, count_of(data)*CHAR_BIT);
|
rorand_get(data, count_of(data)*CHAR_BIT);
|
||||||
hexdump(NULL, off, data, sizeof(data));
|
hexdump(NULL, off, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
iprintf("done\n");
|
iprintf("done\n");
|
||||||
/*uint32_t a = 0;
|
|
||||||
while(1) {
|
|
||||||
iprintf("a%lu ", a);
|
|
||||||
++a;
|
|
||||||
if (a>16)break;
|
|
||||||
}
|
|
||||||
iprintf("\n");*/
|
|
||||||
while(1);
|
while(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
207
src/rorand.c
207
src/rorand.c
|
@ -7,13 +7,38 @@
|
||||||
#include <hardware/structs/psm.h>
|
#include <hardware/structs/psm.h>
|
||||||
#include <hardware/structs/rosc.h>
|
#include <hardware/structs/rosc.h>
|
||||||
#include <hardware/structs/systick.h>
|
#include <hardware/structs/systick.h>
|
||||||
|
#include <hardware/clocks.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
#include <pico/critical_section.h>
|
#include <pico/critical_section.h>
|
||||||
|
|
||||||
#include "rorand.h"
|
#include "rorand.h"
|
||||||
|
|
||||||
|
|
||||||
#define IMPL 2
|
#define TEST_DO_CONTINUOUS 1
|
||||||
|
#define TEST_DO_STARTUP 1
|
||||||
|
|
||||||
|
#define TEST_HIST_SIZE 256
|
||||||
|
// TODO: get good bounds for averages
|
||||||
|
#define TEST_HIST_X_MIN 10
|
||||||
|
#define TEST_HIST_X_MAX 5000
|
||||||
|
#define TEST_HIST_S_MIN 0
|
||||||
|
#define TEST_HIST_S_MAX 300
|
||||||
|
#define TEST_NEUMANN_MAX 0x20
|
||||||
|
#define TEST_STARTUP_NUM 512
|
||||||
|
|
||||||
|
#define ROSC_COUNT_VAL 0x40
|
||||||
|
// TODO: tweak the above parameter.
|
||||||
|
// * 250MHz
|
||||||
|
// * 0x20 seems to result in a few weak test results in dieharder (1 MiB data)
|
||||||
|
// * * 0x80 seems to pass them
|
||||||
|
// -> take something in the middle to speed up things while still being good?
|
||||||
|
// problematic test are diehard_operm5, sts_monobit
|
||||||
|
// * 48 MHz: 0xff too high, 0x20 too low -> no variance
|
||||||
|
// -> 0x40..0xC0 is fine
|
||||||
|
|
||||||
|
|
||||||
|
#define LOG(...) printf(__VA_ARGS__)
|
||||||
|
/*#define LOG(...) do{}while(0)*/
|
||||||
|
|
||||||
|
|
||||||
static inline uint32_t enter_critical_section(void) {
|
static inline uint32_t enter_critical_section(void) {
|
||||||
|
@ -30,14 +55,42 @@ static inline void exit_critical_section(uint32_t dis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void rosc_wait_stab(void) {
|
static enum rorand_error env_check(void) {
|
||||||
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)) ;
|
if (clock_get_hz(clk_sys) < 48*1000*1000) {
|
||||||
|
return rr_sysclk_too_slow;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t tests[256];
|
if ((clocks_hw->clk[clk_sys].ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) ==
|
||||||
|
(CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB)) {
|
||||||
|
return rr_rosc_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((SysTick->CTRL & SysTick_CTRL_TICKINT_Msk)
|
||||||
|
|| ((SysTick->CTRL & SysTick_CTRL_ENABLE_Msk) && SysTick->LOAD != 0xffffffu)) {
|
||||||
|
return rr_systick_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rr_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool do_tests = true;
|
||||||
|
static bool test_has_alarm = false;
|
||||||
|
static rorand_err_cb errcb = NULL;
|
||||||
|
|
||||||
|
static void test_alarm(const char* msg) {
|
||||||
|
LOG("[!!!] TEST ALARM: %s!\n", msg);
|
||||||
|
test_has_alarm = true;
|
||||||
|
if (errcb) errcb(msg);
|
||||||
|
// TODO: ?
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t tests[TEST_HIST_SIZE];
|
||||||
static uint32_t testind;
|
static uint32_t testind;
|
||||||
static critical_section_t cs;
|
static critical_section_t cs;
|
||||||
static void test_monitor(uint32_t v) {
|
static void test_monitor(uint32_t v) {
|
||||||
|
if (!do_tests) return;
|
||||||
|
|
||||||
tests[testind] = v;
|
tests[testind] = v;
|
||||||
++testind;
|
++testind;
|
||||||
|
|
||||||
|
@ -55,32 +108,41 @@ static void test_monitor(uint32_t v) {
|
||||||
}
|
}
|
||||||
var >>= 8;
|
var >>= 8;
|
||||||
float stddev = sqrtf((uint32_t)var);
|
float stddev = sqrtf((uint32_t)var);
|
||||||
printf("[tst] avg=%llu, var=%llu stddev=%f\n", avg, var, stddev);
|
//LOG("[tst] avg=%llu, var=%llu stddev=%f\n", avg, var, stddev);
|
||||||
|
|
||||||
|
// idk really. this really needs to be better
|
||||||
|
if (avg < TEST_HIST_X_MIN) {
|
||||||
|
test_alarm("Runtime test average too low");
|
||||||
|
} else if (avg > TEST_HIST_X_MAX) {
|
||||||
|
test_alarm("Runtime test average too high");
|
||||||
|
} else if (var < TEST_HIST_S_MIN*TEST_HIST_S_MIN) {
|
||||||
|
test_alarm("Runtime test variance too low");
|
||||||
|
} else if (var > TEST_HIST_S_MAX*TEST_HIST_S_MAX) {
|
||||||
|
test_alarm("Runtime test variance too high");
|
||||||
|
}
|
||||||
|
|
||||||
testind = 0;
|
testind = 0;
|
||||||
|
|
||||||
|
switch (env_check()) {
|
||||||
|
case rr_sysclk_too_slow:
|
||||||
|
test_alarm("System clock is below 48 MHz");
|
||||||
|
break;
|
||||||
|
case rr_rosc_used:
|
||||||
|
test_alarm("System is running from ring oscillator");
|
||||||
|
break;
|
||||||
|
case rr_systick_used:
|
||||||
|
test_alarm("SysTick timer used for another purpose");
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint __time_critical_func(get_raw_bit_a)(void) {
|
static uint __time_critical_func(get_raw_bit)(void) {
|
||||||
busy_wait_us_32(1);
|
|
||||||
// 1. power-gate rosc and wait a bit for the value to become indeterminate
|
|
||||||
psm_hw->frce_off = PSM_FRCE_OFF_ROSC_BITS;
|
|
||||||
busy_wait_us_32(1);
|
|
||||||
// 2. bring it back
|
|
||||||
psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
|
|
||||||
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
|
|
||||||
rorand_init();
|
|
||||||
|
|
||||||
uint bit = rosc_hw->randombit & 1;
|
|
||||||
|
|
||||||
// TODO: test monitor?
|
|
||||||
|
|
||||||
return bit;
|
|
||||||
}
|
|
||||||
static uint __time_critical_func(get_raw_bit_b)(void) {
|
|
||||||
volatile uint32_t* tick = &SysTick->VAL;
|
volatile uint32_t* tick = &SysTick->VAL;
|
||||||
volatile uint32_t* count = &rosc_hw->count;
|
volatile uint32_t* count = &rosc_hw->count;
|
||||||
uint32_t a, b;
|
uint32_t a, b, stat, rbit;
|
||||||
|
|
||||||
critical_section_enter_blocking(&cs);
|
critical_section_enter_blocking(&cs);
|
||||||
uint32_t v = enter_critical_section();
|
uint32_t v = enter_critical_section();
|
||||||
|
@ -89,76 +151,105 @@ static uint __time_critical_func(get_raw_bit_b)(void) {
|
||||||
__COMPILER_BARRIER();
|
__COMPILER_BARRIER();
|
||||||
a = *tick;
|
a = *tick;
|
||||||
__COMPILER_BARRIER();
|
__COMPILER_BARRIER();
|
||||||
for (size_t i = 0; i < 0x1/*000*/; ++i) {
|
*count = ROSC_COUNT_VAL;
|
||||||
*count = 0x80;
|
|
||||||
// TODO: tweak the above parameter.
|
|
||||||
// * 0x20 seems to result in a few weak test results in dieharder (1 MiB data)
|
|
||||||
// * 0x80 seems to pass them
|
|
||||||
// -> take something in the middle to speed up things while still being good?
|
|
||||||
// problematic test are diehard_operm5, sts_monobit
|
|
||||||
__COMPILER_BARRIER();
|
__COMPILER_BARRIER();
|
||||||
while (*count) __COMPILER_BARRIER();
|
while (*count) __COMPILER_BARRIER();
|
||||||
}
|
|
||||||
__COMPILER_BARRIER();
|
|
||||||
b = *tick;
|
b = *tick;
|
||||||
|
stat = SysTick->CTRL;
|
||||||
|
rbit = rosc_hw->randombit;
|
||||||
|
__COMPILER_BARRIER();
|
||||||
}
|
}
|
||||||
exit_critical_section(v);
|
exit_critical_section(v);
|
||||||
critical_section_exit(&cs);
|
critical_section_exit(&cs);
|
||||||
|
|
||||||
uint32_t diff = a - b;
|
uint32_t diff = a - b;
|
||||||
//iprintf("[---] diff=%lu a=%lu b=%lu\n", diff, a, b);
|
/*if (stat & SysTick_CTRL_COUNTFLAG_Msk) { // doesn't seem to work, so back to reseting the counter
|
||||||
|
// overflow happened
|
||||||
|
//LOG("[!!!] ovf diff=%lu a=%lu b=%lu\n", diff, a, b);
|
||||||
|
diff += 1<<24;
|
||||||
|
//LOG("[---] diff=%lu a=%lu b=%lu\n", diff, a, b);
|
||||||
|
}*/
|
||||||
|
//LOG("[---] diff=%lu a=%lu b=%lu\n", diff, a, b);
|
||||||
uint bit = diff & 1;
|
uint bit = diff & 1;
|
||||||
uint32_t test = diff >> 1;
|
uint32_t test = diff >> 1;
|
||||||
//test_monitor(test);
|
test_monitor(test);
|
||||||
|
|
||||||
return bit ^ rosc_hw->randombit;
|
return bit ^ rbit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static uint get_raw_bit(void) {
|
|
||||||
/*#if IMPL == 1
|
|
||||||
return get_raw_bit_a();
|
|
||||||
#else*/
|
|
||||||
return get_raw_bit_b();
|
|
||||||
/*#endif*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint neumann_filter(void) {
|
static uint neumann_filter(void) {
|
||||||
uint a, b;
|
uint a, b;
|
||||||
uint32_t counter = 0;
|
uint32_t counter = 0;
|
||||||
const uint32_t limit = 0x40;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
a = get_raw_bit();
|
a = get_raw_bit();
|
||||||
b = get_raw_bit();
|
b = get_raw_bit();
|
||||||
++counter;
|
++counter;
|
||||||
} while (a == b && counter < limit);
|
} while (a == b && counter < TEST_NEUMANN_MAX);
|
||||||
|
|
||||||
if (counter == limit) iprintf("[---] aaaaaaa!\n");
|
if (counter == TEST_NEUMANN_MAX)
|
||||||
//iprintf("[---] emit bit %u%s\n", b, (counter == 0x100) ? "aaaaaa" : "");
|
test_alarm("max. Von Neumann filter iterations reached");
|
||||||
|
|
||||||
|
//iprintf("[---] emit bit %u\n", b);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rorand_init(void) {
|
enum rorand_error rorand_init(rorand_err_cb err_cb) {
|
||||||
|
enum rorand_error e = env_check();
|
||||||
|
if (e != rr_ok) return e;
|
||||||
|
|
||||||
critical_section_init(&cs);
|
critical_section_init(&cs);
|
||||||
|
|
||||||
testind = 0;
|
testind = 0;
|
||||||
memset(tests, 0, sizeof(tests));
|
memset(tests, 0, sizeof(tests));
|
||||||
|
|
||||||
SysTick->LOAD = 0xffffffffu;
|
SysTick->LOAD = 0xffffff;
|
||||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
|
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
|
||||||
|
|
||||||
/*psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
|
if (!(psm_hw->done & PSM_DONE_ROSC_BITS)) {
|
||||||
|
psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
|
||||||
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
|
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
|
||||||
iprintf("[---] rosc power on\n");*/
|
LOG("[---] rosc power on\n");
|
||||||
|
}
|
||||||
|
|
||||||
//rosc_hw->dormant = 1;
|
|
||||||
rosc_hw->ctrl = 0xfabfa7; // enable, high freqrange
|
rosc_hw->ctrl = 0xfabfa7; // enable, high freqrange
|
||||||
rosc_hw->freqa = 0x96967777;
|
rosc_hw->freqa = 0x96967777; // high drive strength
|
||||||
rosc_hw->freqb = 0x96967777;
|
rosc_hw->freqb = 0x96967777; // high drive strength
|
||||||
//rosc_hw->dormant = 0;
|
// wait for stabilization
|
||||||
rosc_wait_stab();
|
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)) ;
|
||||||
iprintf("[---] rosc now stab\n");
|
LOG("[---] rosc now stab\n");
|
||||||
|
|
||||||
|
test_has_alarm = false;
|
||||||
|
do_tests = TEST_DO_STARTUP;
|
||||||
|
if (do_tests) {
|
||||||
|
errcb = NULL;
|
||||||
|
for (size_t i = 0; i < TEST_STARTUP_NUM; ++i) neumann_filter();
|
||||||
|
|
||||||
|
if (test_has_alarm) {
|
||||||
|
SysTick->CTRL = 0;
|
||||||
|
critical_section_deinit(&cs);
|
||||||
|
return rr_fail_init_test;
|
||||||
|
}
|
||||||
|
test_has_alarm = false;
|
||||||
|
LOG("[---] startup tests ok\n");
|
||||||
|
}
|
||||||
|
errcb = err_cb;
|
||||||
|
do_tests = TEST_DO_CONTINUOUS;
|
||||||
|
|
||||||
|
return rr_ok;
|
||||||
|
}
|
||||||
|
bool rorand_had_error(bool clear_if_raised) {
|
||||||
|
bool r;
|
||||||
|
|
||||||
|
uint32_t v = enter_critical_section();
|
||||||
|
{
|
||||||
|
r = test_has_alarm;
|
||||||
|
if (clear_if_raised && r)
|
||||||
|
test_has_alarm = false;
|
||||||
|
}
|
||||||
|
exit_critical_section(v);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rorand_get(void* dst_, size_t nbits) {
|
void rorand_get(void* dst_, size_t nbits) {
|
||||||
|
@ -167,7 +258,6 @@ void rorand_get(void* dst_, size_t nbits) {
|
||||||
for (size_t j = 0; j < nbits; j += 8) {
|
for (size_t j = 0; j < nbits; j += 8) {
|
||||||
size_t bs = nbits - j;
|
size_t bs = nbits - j;
|
||||||
if (bs > 8) bs = 8;
|
if (bs > 8) bs = 8;
|
||||||
//iprintf("[===] byte %u (%u bits)\n", j>>3, bs);
|
|
||||||
|
|
||||||
uint8_t v = 0;
|
uint8_t v = 0;
|
||||||
for (size_t i = 0; i < bs; ++i) {
|
for (size_t i = 0; i < bs; ++i) {
|
||||||
|
@ -176,7 +266,6 @@ void rorand_get(void* dst_, size_t nbits) {
|
||||||
v |= r;
|
v |= r;
|
||||||
}
|
}
|
||||||
|
|
||||||
//iprintf("[===] emit byte %02hhx\n", v);
|
|
||||||
*dst = v;
|
*dst = v;
|
||||||
++dst;
|
++dst;
|
||||||
}
|
}
|
||||||
|
|
15
src/rorand.h
15
src/rorand.h
|
@ -3,8 +3,21 @@
|
||||||
#define RORAND_H_
|
#define RORAND_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
enum rorand_error {
|
||||||
|
rr_ok = 0,
|
||||||
|
rr_rosc_used = -1,
|
||||||
|
rr_systick_used = -2,
|
||||||
|
rr_sysclk_too_slow = -3,
|
||||||
|
rr_fail_init_test = -4,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*rorand_err_cb)(const char* errmsg);
|
||||||
|
|
||||||
|
enum rorand_error rorand_init(rorand_err_cb err_cb);
|
||||||
|
bool rorand_had_error(bool clear_if_raised);
|
||||||
|
|
||||||
void rorand_init(void);
|
|
||||||
void rorand_get(void* dst, size_t nbits);
|
void rorand_get(void* dst, size_t nbits);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue