code cleanup and benchmark and stuff

This commit is contained in:
Triss 2023-08-23 19:11:43 +02:00
parent 42e59d38c5
commit 572883b269
3 changed files with 210 additions and 79 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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