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 <string.h>
|
||||
|
||||
#include <hardware/structs/bus_ctrl.h>
|
||||
#include <hardware/structs/rosc.h>
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/vreg.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
@ -16,9 +14,29 @@
|
|||
#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() {
|
||||
vreg_set_voltage(VREG_VOLTAGE_1_15);
|
||||
set_sys_clock_khz(250*1000, true);
|
||||
// high freq, high voltage
|
||||
//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");
|
||||
busy_wait_ms(16);
|
||||
|
||||
|
@ -27,28 +45,39 @@ int main() {
|
|||
busy_wait_ms(16);
|
||||
iprintf("hello world!\n");
|
||||
|
||||
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)) {
|
||||
panic("System is running from ring oscillator. This makes it impossible to be used as randomness source.\n");
|
||||
int d = rorand_init(NULL);
|
||||
if (d < 0) {
|
||||
iprintf("rorand_init() returned %d\n", d);
|
||||
panic("can't init rorand");
|
||||
}
|
||||
|
||||
rorand_init();
|
||||
uint8_t data[32];
|
||||
#if DO_TIME_BENCH
|
||||
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));
|
||||
const uintptr_t total = 1024*1024;
|
||||
const uintptr_t total = DATA_TOTAL;
|
||||
for (uintptr_t off = 0; off < total; off += count_of(data)) {
|
||||
rorand_get(data, count_of(data)*CHAR_BIT);
|
||||
hexdump(NULL, off, data, sizeof(data));
|
||||
}
|
||||
#endif
|
||||
|
||||
iprintf("done\n");
|
||||
/*uint32_t a = 0;
|
||||
while(1) {
|
||||
iprintf("a%lu ", a);
|
||||
++a;
|
||||
if (a>16)break;
|
||||
}
|
||||
iprintf("\n");*/
|
||||
while(1);
|
||||
return 0;
|
||||
}
|
||||
|
|
211
src/rorand.c
211
src/rorand.c
|
@ -7,13 +7,38 @@
|
|||
#include <hardware/structs/psm.h>
|
||||
#include <hardware/structs/rosc.h>
|
||||
#include <hardware/structs/systick.h>
|
||||
#include <hardware/clocks.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/critical_section.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) {
|
||||
|
@ -30,14 +55,42 @@ static inline void exit_critical_section(uint32_t dis) {
|
|||
}
|
||||
|
||||
|
||||
static inline void rosc_wait_stab(void) {
|
||||
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)) ;
|
||||
static enum rorand_error env_check(void) {
|
||||
if (clock_get_hz(clk_sys) < 48*1000*1000) {
|
||||
return rr_sysclk_too_slow;
|
||||
}
|
||||
|
||||
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 uint32_t tests[256];
|
||||
|
||||
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 critical_section_t cs;
|
||||
static void test_monitor(uint32_t v) {
|
||||
if (!do_tests) return;
|
||||
|
||||
tests[testind] = v;
|
||||
++testind;
|
||||
|
||||
|
@ -55,32 +108,41 @@ static void test_monitor(uint32_t v) {
|
|||
}
|
||||
var >>= 8;
|
||||
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;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
static uint __time_critical_func(get_raw_bit)(void) {
|
||||
volatile uint32_t* tick = &SysTick->VAL;
|
||||
volatile uint32_t* count = &rosc_hw->count;
|
||||
uint32_t a, b;
|
||||
uint32_t a, b, stat, rbit;
|
||||
|
||||
critical_section_enter_blocking(&cs);
|
||||
uint32_t v = enter_critical_section();
|
||||
|
@ -89,76 +151,105 @@ static uint __time_critical_func(get_raw_bit_b)(void) {
|
|||
__COMPILER_BARRIER();
|
||||
a = *tick;
|
||||
__COMPILER_BARRIER();
|
||||
for (size_t i = 0; i < 0x1/*000*/; ++i) {
|
||||
*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();
|
||||
while (*count) __COMPILER_BARRIER();
|
||||
}
|
||||
*count = ROSC_COUNT_VAL;
|
||||
__COMPILER_BARRIER();
|
||||
while (*count) __COMPILER_BARRIER();
|
||||
b = *tick;
|
||||
stat = SysTick->CTRL;
|
||||
rbit = rosc_hw->randombit;
|
||||
__COMPILER_BARRIER();
|
||||
}
|
||||
exit_critical_section(v);
|
||||
critical_section_exit(&cs);
|
||||
|
||||
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;
|
||||
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) {
|
||||
uint a, b;
|
||||
uint32_t counter = 0;
|
||||
const uint32_t limit = 0x40;
|
||||
|
||||
do {
|
||||
a = get_raw_bit();
|
||||
b = get_raw_bit();
|
||||
++counter;
|
||||
} while (a == b && counter < limit);
|
||||
} while (a == b && counter < TEST_NEUMANN_MAX);
|
||||
|
||||
if (counter == limit) iprintf("[---] aaaaaaa!\n");
|
||||
//iprintf("[---] emit bit %u%s\n", b, (counter == 0x100) ? "aaaaaa" : "");
|
||||
if (counter == TEST_NEUMANN_MAX)
|
||||
test_alarm("max. Von Neumann filter iterations reached");
|
||||
|
||||
//iprintf("[---] emit bit %u\n", 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);
|
||||
|
||||
testind = 0;
|
||||
memset(tests, 0, sizeof(tests));
|
||||
|
||||
SysTick->LOAD = 0xffffffffu;
|
||||
SysTick->LOAD = 0xffffff;
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
|
||||
|
||||
/*psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
|
||||
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
|
||||
iprintf("[---] rosc power on\n");*/
|
||||
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)) ;
|
||||
LOG("[---] rosc power on\n");
|
||||
}
|
||||
|
||||
//rosc_hw->dormant = 1;
|
||||
rosc_hw->ctrl = 0xfabfa7; // enable, high freqrange
|
||||
rosc_hw->freqa = 0x96967777;
|
||||
rosc_hw->freqb = 0x96967777;
|
||||
//rosc_hw->dormant = 0;
|
||||
rosc_wait_stab();
|
||||
iprintf("[---] rosc now stab\n");
|
||||
rosc_hw->freqa = 0x96967777; // high drive strength
|
||||
rosc_hw->freqb = 0x96967777; // high drive strength
|
||||
// wait for stabilization
|
||||
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)) ;
|
||||
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) {
|
||||
|
@ -167,7 +258,6 @@ void rorand_get(void* dst_, size_t nbits) {
|
|||
for (size_t j = 0; j < nbits; j += 8) {
|
||||
size_t bs = nbits - j;
|
||||
if (bs > 8) bs = 8;
|
||||
//iprintf("[===] byte %u (%u bits)\n", j>>3, bs);
|
||||
|
||||
uint8_t v = 0;
|
||||
for (size_t i = 0; i < bs; ++i) {
|
||||
|
@ -176,7 +266,6 @@ void rorand_get(void* dst_, size_t nbits) {
|
|||
v |= r;
|
||||
}
|
||||
|
||||
//iprintf("[===] emit byte %02hhx\n", v);
|
||||
*dst = v;
|
||||
++dst;
|
||||
}
|
||||
|
|
15
src/rorand.h
15
src/rorand.h
|
@ -3,8 +3,21 @@
|
|||
#define RORAND_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);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue