Fixup divider save_restore for floating point too; improve tests (#405)

- The divider state needs to be saved for __aeabi_ddiv, __aeabi_fdiv, __aeabi_dtan and __aeabi_ftan or they won't work in interrupts *(probably not used much youd hope), or on an RTOS context switch
 - Refactored code out for the integer and floating point cases
 - Improved the floating point 'tests' in passing to check more return values against GCC implementations
 - Added floating point usage to the IRQ nesting test case
This commit is contained in:
Graham Sanderson
2021-05-13 07:38:42 -05:00
committed by GitHub
parent c6c4eeb122
commit 574fdee37b
9 changed files with 501 additions and 158 deletions

View File

@ -12,7 +12,7 @@ if (PICO_ON_DEVICE)
pico_add_extra_outputs(pico_divider_test)
target_compile_definitions(pico_divider_test PRIVATE
PICO_DIVIDER_DISABLE_INTERRUPTS=1
# PICO_DIVIDER_DISABLE_INTERRUPTS=1
# TURBO
)

View File

@ -15,6 +15,9 @@ volatile bool failed;
volatile uint32_t count[3];
volatile bool done;
#define FAILED() ({ failed = true; })
//#define FAILED() ({ failed = true; __breakpoint(); })
bool timer_callback(repeating_timer_t *t) {
count[0]++;
static int z;
@ -23,9 +26,27 @@ bool timer_callback(repeating_timer_t *t) {
int a = z / 7;
int b = z % 7;
if (z != a * 7 + b) {
failed = true;
FAILED();
}
a = z / -7;
b = z % -7;
if (z != a * -7 + b) {
FAILED();
}
}
float fz = z;
float fa = fz / 11.0f;
float fb = fmodf(fz, 11.0f);
if (fabsf(fz - (fa * 11.0 + fb) > 1e-9)) {
FAILED();
}
double dz = z;
double da = dz / 11.0;
double db = fmod(dz, 11.0);
if (fabsf(dz - (da * 11.0 + db) > 1e-9)) {
FAILED();
}
return !done;
}
@ -41,16 +62,20 @@ void do_dma_start(uint ch) {
dma_channel_configure(ch, &c, &word[ch], &word[ch], 513 + ch * 23, true);
}
double d0c, d0s, d0t, dz;
float f0c, f0s, f0t, fz;
void test_irq_handler0() {
count[1]++;
dma_hw->ints0 |= 1u;
static uint z;
static uint dz;
for (int i=0; i<80;i++) {
z += 31;
uint a = z / 11;
uint b = z % 11;
if (z != a * 11 + b) {
failed = true;
FAILED();
}
}
if (done) dma_channel_abort(0);
@ -66,16 +91,17 @@ void test_irq_handler1() {
uint a = z / -13;
uint b = z % -13;
if (z != a * -13 + b) {
failed = true;
FAILED();
}
static uint64_t z64;
z64 -= 47;
uint64_t a64 = z64 / -13;
uint64_t b64 = z64 % -13;
if (z64 != a64 * -13 + b64) {
failed = true;
FAILED();
}
}
if (done) dma_channel_abort(1);
else do_dma_start(1);
}
@ -89,7 +115,7 @@ void test_nesting() {
// They all busily make use of the dividers, to expose any issues with nested use
repeating_timer_t timer;
add_repeating_timer_us(529, timer_callback, NULL, &timer);
add_repeating_timer_us(929, timer_callback, NULL, &timer);
irq_set_exclusive_handler(DMA_IRQ_0, test_irq_handler0);
irq_set_exclusive_handler(DMA_IRQ_1, test_irq_handler1);
@ -101,7 +127,7 @@ void test_nesting() {
irq_set_enabled(DMA_IRQ_1, 1);
do_dma_start(0);
do_dma_start(1);
absolute_time_t end = delayed_by_ms(get_absolute_time(), 2000);
absolute_time_t end = delayed_by_ms(get_absolute_time(), 10000);
int count_local=0;
while (!time_reached(end)) {
for(uint i=0;i<100;i++) {
@ -109,8 +135,39 @@ void test_nesting() {
uint a = z / 11;
uint b = z % 11;
if (z != a * 11 + b) {
failed = true;
FAILED();
}
int zz = (int)z;
int aa = zz / -11;
int bb = zz % -11;
if (zz != aa * -11 + bb) {
FAILED();
}
aa = -zz / -11;
bb = -zz % -11;
if (-zz != aa * -11 + bb) {
FAILED();
}
aa = -zz / 11;
bb = -zz % 11;
if (-zz != aa * 11 + bb) {
FAILED();
}
a = 0xffffffffu / 11;
b = 0xffffffffu % 11;
if (0xffffffffu != a * 11 + b) {
FAILED();
}
}
// these use the divider
for(uint i=0;i<=100;i+=20) {
// both in and out bootrom range (we perform mod in wrapper code if necessarry)
f0t = tanf(i * 50);
f0c = cosf(i * 50);
f0s = sinf(i * 50);
d0t = tan(i * 1000);
d0c = cos(i * 1000);
d0s = sin(i * 1000);
}
count_local++;
}