Initial Release
This commit is contained in:
10
test/CMakeLists.txt
Normal file
10
test/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
add_subdirectory(pico_test)
|
||||
|
||||
add_subdirectory(pico_stdlib_test)
|
||||
add_subdirectory(pico_time_test)
|
||||
add_subdirectory(pico_divider_test)
|
||||
if (PICO_ON_DEVICE)
|
||||
add_subdirectory(pico_float_test)
|
||||
add_subdirectory(kitchen_sink)
|
||||
add_subdirectory(hardware_pwm_test)
|
||||
endif()
|
4
test/hardware_pwm_test/CMakeLists.txt
Normal file
4
test/hardware_pwm_test/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
add_executable(hardware_pwm_test hardware_pwm_test.c)
|
||||
|
||||
target_link_libraries(hardware_pwm_test PRIVATE pico_test hardware_pwm)
|
||||
pico_add_extra_outputs(hardware_pwm_test)
|
168
test/hardware_pwm_test/hardware_pwm_test.c
Normal file
168
test/hardware_pwm_test/hardware_pwm_test.c
Normal file
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/test.h"
|
||||
#include "pico/time.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/resets.h"
|
||||
#include "hardware/pwm.h"
|
||||
|
||||
PICOTEST_MODULE_NAME("PWM", "PWM SDK Test harness");
|
||||
|
||||
/* In a struct for future expansion of the interrupt testv */
|
||||
struct interrupt_state {
|
||||
int count;
|
||||
} interrupt_states[NUM_PWM_SLICES] = {0};
|
||||
|
||||
void on_pwm_wrap() {
|
||||
for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
|
||||
// See if this pwm, is the one that fired.
|
||||
if (pwm_get_irq_status_mask() & (1 << pwm)) {
|
||||
// Clear the interrupt flag that brought us here
|
||||
pwm_clear_irq(pwm);
|
||||
|
||||
interrupt_states[pwm].count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
reset_block(RESETS_RESET_PWM_BITS);
|
||||
unreset_block_wait(RESETS_RESET_PWM_BITS);
|
||||
|
||||
setup_default_uart();
|
||||
|
||||
PICOTEST_START();
|
||||
|
||||
pwm_config config = pwm_get_default_config();
|
||||
|
||||
|
||||
// Test that config sets works on all PWMs by comparing what we pass in
|
||||
// via the API with what the registers contains afterwards
|
||||
|
||||
pwm_config_set_phase_correct(&config, true);
|
||||
pwm_config_set_clkdiv(&config, 42.5);
|
||||
pwm_config_set_clkdiv_mode(&config, PWM_DIV_B_HIGH);
|
||||
pwm_config_set_output_polarity(&config, false, true);
|
||||
pwm_config_set_wrap(&config, 0x1234);
|
||||
|
||||
PICOTEST_START_SECTION("PWM config init tests");
|
||||
for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
|
||||
pwm_slice_hw_t *slice = &pwm_hw->slice[pwm];
|
||||
|
||||
pwm_init(pwm, &config, false);
|
||||
|
||||
uint div = (uint)(42.5f * (float)(1 << PWM_CH0_DIV_INT_LSB));
|
||||
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->top == config.top, "HW top does not match requested config");
|
||||
//PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == 0x1234, "HW counter does not match config");
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->cc == PWM_CH0_CC_RESET, "HW compares does not match config");
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->div == div, "HW divider does not match config");
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->csr ==
|
||||
(1 << PWM_CH0_CSR_PH_CORRECT_LSB | 0 << PWM_CH0_CSR_A_INV_LSB | 1 << PWM_CH0_CSR_B_INV_LSB |
|
||||
PWM_CH0_CSR_DIVMODE_VALUE_LEVEL << PWM_CH0_CSR_DIVMODE_LSB), "HW CSR does not match config");
|
||||
}
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
|
||||
// Need to test the SDK APIs do the right thing
|
||||
|
||||
PICOTEST_START_SECTION("PWM SDK API tests");
|
||||
for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
|
||||
pwm_slice_hw_t *slice = &pwm_hw->slice[pwm];
|
||||
int v = 100 + pwm * 10;
|
||||
|
||||
pwm_set_wrap(pwm, v);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->top == v, "pwm_set_wrap() failed to set register");
|
||||
|
||||
pwm_set_both_levels(pwm, v + 1, v);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->cc == (((v) << PWM_CH0_CC_B_LSB) | ((v + 1) << PWM_CH0_CC_A_LSB)),
|
||||
"pwm_set_compare() failed to set register");
|
||||
|
||||
float divider = 100.5;
|
||||
int i = (int16_t) divider;
|
||||
int f = (int8_t) ((divider - i) * 16);
|
||||
pwm_set_clkdiv(pwm, divider);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->div == (i << 4 | f), "pwm_set_divider_fract() failed to set register");
|
||||
|
||||
i++;
|
||||
pwm_set_clkdiv_int_frac(pwm, i, f);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->div == (i << 4 | f),
|
||||
"pwm_set_divider_int_fract() failed to set register");
|
||||
|
||||
int c = 1234;
|
||||
pwm_set_counter(pwm, c);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == c, "pwm_set_count() failed to set register");
|
||||
|
||||
int cc = pwm_get_counter(pwm);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, slice->ctr == cc && cc == c, "pwm_get_count() failed to get register");
|
||||
|
||||
pwm_set_output_polarity(pwm, false, false);
|
||||
PICOTEST_CHECK_CHANNEL(pwm,
|
||||
!(slice->csr & PWM_CH0_CSR_A_INV_BITS) && !(slice->csr & PWM_CH0_CSR_B_INV_BITS),
|
||||
"pwm_set_output_polarity() (F/F)");
|
||||
|
||||
pwm_set_output_polarity(pwm, true, false);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_A_INV_BITS) && !(slice->csr & PWM_CH0_CSR_B_INV_BITS),
|
||||
"pwm_set_output_polarity() (T/F)");
|
||||
|
||||
pwm_set_output_polarity(pwm, false, true);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, !(slice->csr & PWM_CH0_CSR_A_INV_BITS) && (slice->csr & PWM_CH0_CSR_B_INV_BITS),
|
||||
"pwm_set_output_polarity() (F/T)");
|
||||
|
||||
pwm_set_output_polarity(pwm, true, true);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_A_INV_BITS) && (slice->csr & PWM_CH0_CSR_B_INV_BITS),
|
||||
"pwm_set_output_polarity() (T/T)");
|
||||
|
||||
pwm_set_phase_correct(pwm, true);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, (slice->csr & PWM_CH0_CSR_PH_CORRECT_BITS), "pwm_set_phase_correction(T)");
|
||||
|
||||
pwm_set_phase_correct(pwm, false);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, !(slice->csr & PWM_CH0_CSR_PH_CORRECT_BITS), "pwm_set_phase_correction(F)");
|
||||
|
||||
for (int m = PWM_DIV_FREE_RUNNING; m <= PWM_DIV_B_FALLING; m++) {
|
||||
pwm_set_clkdiv_mode(pwm, m);
|
||||
PICOTEST_CHECK_CHANNEL(pwm, ((slice->csr & PWM_CH0_CSR_DIVMODE_BITS) >> PWM_CH0_CSR_DIVMODE_LSB) == m,
|
||||
"pwm_set_divider_mode");
|
||||
}
|
||||
}
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("PWM IRQ tests");
|
||||
|
||||
irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);
|
||||
irq_set_enabled(PWM_IRQ_WRAP, true);
|
||||
|
||||
config = pwm_get_default_config();
|
||||
|
||||
// Slow down the interrupt rate a load, don't need it high.
|
||||
// This give about 40 per second on Picoboard
|
||||
pwm_config_set_clkdiv(&config, 50);
|
||||
|
||||
for (int pwm = 0; pwm < NUM_PWM_SLICES; pwm++) {
|
||||
pwm_init(pwm, &config, false);
|
||||
pwm_clear_irq(pwm);
|
||||
pwm_set_irq_enabled(pwm, true);
|
||||
}
|
||||
|
||||
// Now enable all the PWM at the same time.
|
||||
pwm_set_mask_enabled(0xff);
|
||||
|
||||
sleep_ms(1000);
|
||||
|
||||
int err = 0;
|
||||
|
||||
for (int p = 0; p < NUM_PWM_SLICES; p++) {
|
||||
PICOTEST_CHECK_CHANNEL(p, interrupt_states[p].count != 0, "No interrupts detected from PWM %d\n");
|
||||
}
|
||||
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_END_TEST();
|
||||
}
|
||||
|
101
test/kitchen_sink/CMakeLists.txt
Normal file
101
test/kitchen_sink/CMakeLists.txt
Normal file
@ -0,0 +1,101 @@
|
||||
add_library(kitchen_sink_libs INTERFACE)
|
||||
target_sources(kitchen_sink_libs INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c
|
||||
)
|
||||
target_link_libraries(kitchen_sink_libs INTERFACE
|
||||
hardware_adc
|
||||
hardware_clocks
|
||||
hardware_divider
|
||||
hardware_dma
|
||||
hardware_flash
|
||||
hardware_gpio
|
||||
hardware_i2c
|
||||
hardware_interp
|
||||
hardware_irq
|
||||
hardware_pio
|
||||
hardware_pll
|
||||
hardware_pwm
|
||||
hardware_resets
|
||||
hardware_rtc
|
||||
hardware_uart
|
||||
hardware_spi
|
||||
hardware_sync
|
||||
hardware_timer
|
||||
hardware_uart
|
||||
hardware_vreg
|
||||
hardware_watchdog
|
||||
hardware_xosc
|
||||
pico_bit_ops
|
||||
pico_bootrom
|
||||
pico_divider
|
||||
pico_double
|
||||
pico_fix_rp2040_usb_device_enumeration
|
||||
pico_float
|
||||
pico_int64_ops
|
||||
pico_malloc
|
||||
pico_mem_ops
|
||||
pico_multicore
|
||||
pico_platform
|
||||
pico_stdlib
|
||||
pico_sync
|
||||
pico_time
|
||||
pico_util
|
||||
)
|
||||
|
||||
add_library(kitchen_sink_options INTERFACE)
|
||||
|
||||
target_compile_options(kitchen_sink_options INTERFACE
|
||||
-Werror
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
-Wno-inline
|
||||
-Wnull-dereference
|
||||
# -pedantic
|
||||
-Wall
|
||||
-Wcast-qual
|
||||
-Wno-deprecated-declarations
|
||||
-Wfloat-equal
|
||||
-Wmissing-format-attribute
|
||||
-Wno-long-long
|
||||
|
||||
# todo not sure these are true, but investigate
|
||||
#-Wpacked
|
||||
|
||||
# todo we have some of these in usb_device_tiny to try to make it more readable.. perhaps doxygen would help here instead
|
||||
#-Wredundant-decls
|
||||
-Wno-shadow
|
||||
-Wno-missing-field-initializers
|
||||
-Wno-missing-braces
|
||||
-Wno-sign-compare
|
||||
-Wno-multichar
|
||||
|
||||
# todo useful but fix later
|
||||
#-Wundef
|
||||
)
|
||||
|
||||
target_compile_definitions(kitchen_sink_libs INTERFACE
|
||||
NDEBUG
|
||||
PICO_AUDIO_DMA_IRQ=1
|
||||
)
|
||||
|
||||
add_executable(kitchen_sink)
|
||||
target_link_libraries(kitchen_sink kitchen_sink_libs kitchen_sink_options)
|
||||
pico_set_program_name(kitchen_sink "Wombat tenticles")
|
||||
pico_add_extra_outputs(kitchen_sink)
|
||||
|
||||
add_executable(kitchen_sink_extra_stdio)
|
||||
target_link_libraries(kitchen_sink_extra_stdio kitchen_sink_libs) # no kitchen_sink_options as TinyUSB has warnings
|
||||
pico_add_extra_outputs(kitchen_sink_extra_stdio)
|
||||
pico_enable_stdio_usb(kitchen_sink_extra_stdio 1)
|
||||
pico_enable_stdio_semihosting(kitchen_sink_extra_stdio 1)
|
||||
|
||||
add_executable(kitchen_sink_copy_to_ram)
|
||||
pico_set_binary_type(kitchen_sink_copy_to_ram copy_to_ram)
|
||||
target_link_libraries(kitchen_sink_copy_to_ram kitchen_sink_libs kitchen_sink_options)
|
||||
pico_add_extra_outputs(kitchen_sink_copy_to_ram)
|
||||
|
||||
add_executable(kitchen_sink_no_flash)
|
||||
pico_set_binary_type(kitchen_sink_no_flash no_flash)
|
||||
target_link_libraries(kitchen_sink_no_flash kitchen_sink_libs kitchen_sink_options)
|
||||
pico_add_extra_outputs(kitchen_sink_no_flash)
|
102
test/kitchen_sink/kitchen_sink.c
Normal file
102
test/kitchen_sink/kitchen_sink.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/time.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "pico/bit_ops.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/pwm.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/timer.h"
|
||||
#include "pico/divider.h"
|
||||
#include "pico/critical_section.h"
|
||||
#include "pico/binary_info.h"
|
||||
|
||||
bi_decl(bi_block_device(
|
||||
BINARY_INFO_MAKE_TAG('K', 'S'),
|
||||
"foo",
|
||||
0x80000,
|
||||
0x40000,
|
||||
NULL,
|
||||
BINARY_INFO_BLOCK_DEV_FLAG_READ | BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
|
||||
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
|
||||
|
||||
void my_timer(uint i) {
|
||||
puts("XXXX timer");
|
||||
}
|
||||
|
||||
//#pragma GCC push_options
|
||||
//#pragma GCC optimize ("O3")
|
||||
|
||||
uint32_t *foo = (uint32_t *) 200;
|
||||
|
||||
uint32_t dma_to = 0;
|
||||
uint32_t dma_from = 0xaaaa5555;
|
||||
|
||||
void spiggle() {
|
||||
dma_channel_config c = dma_channel_get_default_config(1);
|
||||
channel_config_set_bswap(&c, true);
|
||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_16);
|
||||
channel_config_set_ring(&c, true, 13);
|
||||
dma_channel_set_config(1, &c, false);
|
||||
dma_channel_transfer_from_buffer_now(1, foo, 23);
|
||||
}
|
||||
|
||||
void __isr dma_handler_a() {
|
||||
printf("HELLO A\n");
|
||||
if (dma_hw->ints1 & 1) {
|
||||
dma_hw->ints1 = 1;
|
||||
printf("A WINS DMA_TO %08x\n", (uint) dma_to);
|
||||
irq_remove_handler(DMA_IRQ_1, dma_handler_a);
|
||||
}
|
||||
}
|
||||
|
||||
void __isr dma_handler_b() {
|
||||
printf("HELLO B\n");
|
||||
if (dma_hw->ints1 & 1) {
|
||||
dma_hw->ints1 = 1;
|
||||
printf("B WINS DNA_TO %08x\n", (uint) dma_to);
|
||||
// irq_remove_handler(DMA_IRQ_1, dma_handler_b);
|
||||
}
|
||||
}
|
||||
|
||||
//#pragma GCC pop_options
|
||||
|
||||
int main() {
|
||||
spiggle();
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
printf("HI %d\n", (int)time_us_32());
|
||||
puts("Hello Everything!");
|
||||
puts("Hello Everything2!");
|
||||
|
||||
irq_add_shared_handler(DMA_IRQ_1, dma_handler_a, 0x80);
|
||||
irq_add_shared_handler(DMA_IRQ_1, dma_handler_b, 0xC0);
|
||||
|
||||
dma_channel_config config = dma_channel_get_default_config(0);
|
||||
// set_exclusive_irq_handler(DMA_IRQ_1, dma_handler_a);
|
||||
dma_channel_set_irq1_enabled(0, true);
|
||||
irq_set_enabled(DMA_IRQ_1, true);
|
||||
dma_channel_configure(0, &config, &dma_to, &dma_from, 1, true);
|
||||
dma_channel_set_config(0, &config, false);
|
||||
|
||||
// timer_start_ms(2, 2000, my_timer);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
puts("sleepy");
|
||||
sleep_ms(1000);
|
||||
dma_channel_configure(0, &config, &dma_to, &dma_from, 1, true);
|
||||
if (i==3) {
|
||||
irq_remove_handler(DMA_IRQ_1, dma_handler_a);
|
||||
}
|
||||
if (i==2) {
|
||||
irq_remove_handler(DMA_IRQ_1, dma_handler_b);
|
||||
}
|
||||
}
|
||||
}
|
17
test/pico_divider_test/CMakeLists.txt
Normal file
17
test/pico_divider_test/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
PROJECT(pico_divider_test)
|
||||
|
||||
if (PICO_ON_DEVICE)
|
||||
add_executable(pico_divider_test
|
||||
pico_divider_test.c
|
||||
)
|
||||
|
||||
target_link_libraries(pico_divider_test pico_stdlib)
|
||||
|
||||
pico_set_divider_implementation(pico_divider_test hardware_explicit) # want to compare against compiler impl
|
||||
|
||||
pico_add_extra_outputs(pico_divider_test)
|
||||
|
||||
target_compile_definitions(pico_divider_test PRIVATE
|
||||
# TURBO
|
||||
)
|
||||
endif()
|
376
test/pico_divider_test/pico_divider_test.c
Normal file
376
test/pico_divider_test/pico_divider_test.c
Normal file
@ -0,0 +1,376 @@
|
||||
// make test-div64_64.bin && qemu-system-arm -M lm3s6965evb -cpu cortex-m3 -nographic -serial null -monitor null -semihosting -kernel test-div64_64.bin
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "pico/divider.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#ifdef TURBO
|
||||
#include "hardware/vreg.h"
|
||||
#endif
|
||||
|
||||
typedef uint64_t ui64;
|
||||
typedef int64_t i64;
|
||||
typedef uint32_t ui32;
|
||||
typedef int32_t i32;
|
||||
|
||||
void test_mulib_divu64u64(ui64*y,ui64*x,ui64*q,ui64*r) {
|
||||
*q = divmod_u64u64_rem(*y, *x, r);
|
||||
}
|
||||
void test_mulib_divs64s64( i64*y, i64*x, i64*q, i64*r) {
|
||||
*q = divmod_s64s64_rem(*y, *x, r);
|
||||
}
|
||||
|
||||
ui32 hwdiv_data[4];
|
||||
|
||||
void hwdiv_sim() {
|
||||
hwdiv_data[2]=hwdiv_data[0]/hwdiv_data[1];
|
||||
hwdiv_data[3]=hwdiv_data[0]%hwdiv_data[1];
|
||||
// ostr("HWS: ");
|
||||
// o8hex(hwdiv_data[0]); osp();
|
||||
// o8hex(hwdiv_data[1]); osp();
|
||||
// o8hex(hwdiv_data[2]); osp();
|
||||
// o8hex(hwdiv_data[3]); onl();
|
||||
}
|
||||
|
||||
ui64 ntests=0;
|
||||
|
||||
|
||||
void o1ch(int c) {
|
||||
uart_putc(uart_default, c);
|
||||
}
|
||||
|
||||
void ostr(char*p) { while(*p) o1ch(*p++); }
|
||||
void onl() {ostr("\r\n");}
|
||||
void osp() {o1ch(' ');}
|
||||
void ostrnl(char*p) { ostr(p); onl();}
|
||||
void o1hex(int u) {u&=0x0f; if(u>=10) o1ch(u-10+'A'); else o1ch(u+'0');}
|
||||
void o2hex(int u) {o1hex(u>> 4); o1hex(u);}
|
||||
void o4hex(int u) {o2hex(u>> 8); o2hex(u);}
|
||||
void o8hex(int u) {o4hex(u>>16); o4hex(u);}
|
||||
void o16hex(ui64 u) {o8hex(u>>32); o8hex(u);}
|
||||
unsigned int odig(unsigned int*pv,unsigned int d,int zf) {
|
||||
char c='0';
|
||||
unsigned int v=*pv;
|
||||
while(v>=d) v-=d,c++;
|
||||
if(zf==1&&c=='0') osp();
|
||||
else o1ch(c),zf=0;
|
||||
*pv=v;
|
||||
return zf;
|
||||
}
|
||||
|
||||
void odec(int u) {
|
||||
unsigned int v=u;
|
||||
int zf=1;
|
||||
if(u<0) o1ch('-'),v=-v;
|
||||
zf=odig(&v,1000000000,zf);
|
||||
zf=odig(&v,100000000,zf);
|
||||
zf=odig(&v,10000000,zf);
|
||||
zf=odig(&v,1000000,zf);
|
||||
zf=odig(&v,100000,zf);
|
||||
zf=odig(&v,10000,zf);
|
||||
zf=odig(&v,1000,zf);
|
||||
zf=odig(&v,100,zf);
|
||||
zf=odig(&v,10,zf);
|
||||
zf=odig(&v,1,0);
|
||||
}
|
||||
|
||||
|
||||
int xdigval(int c) {
|
||||
if(c>='0'&&c<='9') return c-'0';
|
||||
if(c>='A'&&c<='F') return c-'A'+10;
|
||||
if(c>='a'&&c<='f') return c-'a'+10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ui64 seed;
|
||||
|
||||
ui64 rnd64() {
|
||||
if(seed&1) seed=(seed>>1)^0x800000000000000dULL;
|
||||
else seed= seed>>1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
unsigned int rnd32() {
|
||||
return rnd64();
|
||||
}
|
||||
|
||||
//#define RANDOMISE
|
||||
//#define rfn "/dev/random"
|
||||
|
||||
void test_divu64u64(ui64 y,ui64 x) {
|
||||
ui64 q,r;
|
||||
test_mulib_divu64u64(&y,&x,&q,&r);
|
||||
#if !PICO_ON_DEVICE
|
||||
if (!x) return;
|
||||
#endif
|
||||
if(q==y/x&&r==y%x) ;
|
||||
else {
|
||||
ostr("U ");
|
||||
o16hex(y); osp();
|
||||
o16hex(x); osp();
|
||||
o16hex(q); osp();
|
||||
o16hex(r);
|
||||
ostr(" : ");
|
||||
o16hex(y/x); osp();
|
||||
o16hex(y%x); onl();
|
||||
}
|
||||
ntests++;
|
||||
}
|
||||
|
||||
void test_divs64s64(i64 y,i64 x) {
|
||||
i64 q,r;
|
||||
#if !PICO_ON_DEVICE
|
||||
if (y == INT64_MIN) return;
|
||||
#endif
|
||||
test_mulib_divs64s64(&y,&x,&q,&r);
|
||||
#if !PICO_ON_DEVICE
|
||||
if (!x) return;
|
||||
#endif
|
||||
if(q==y/x&&r==y%x) ;
|
||||
else {
|
||||
ostr("S ");
|
||||
o16hex(y); osp();
|
||||
o16hex(x); osp();
|
||||
o16hex(q); osp();
|
||||
o16hex(r);
|
||||
ostr(" : ");
|
||||
o16hex(y/x); osp();
|
||||
o16hex(y%x); onl();
|
||||
}
|
||||
ntests++;
|
||||
}
|
||||
|
||||
|
||||
// for all x and y consisting of a single run of 1:s, test a region around (x,y)
|
||||
void test_special() {
|
||||
int i0,j0,i1,j1,dy,dx;
|
||||
ui64 y,x;
|
||||
for(i0=0;i0<64;i0++) {
|
||||
y=0;
|
||||
for(i1=i0;i1<65;i1++) {
|
||||
for(j0=0;j0<64;j0++) {
|
||||
x=0;
|
||||
for(j1=j0;j1<65;j1++) {
|
||||
#define A 2
|
||||
for(dy=-A;dy<=A;dy++) {
|
||||
for(dx=-A;dx<=A;dx++) {
|
||||
test_divu64u64( y+dy, x+dx);
|
||||
test_divs64s64( y+dy, x+dx);
|
||||
test_divs64s64( y+dy,-x-dx);
|
||||
test_divs64s64(-y-dy, x+dx);
|
||||
test_divs64s64(-y-dy,-x-dx);
|
||||
}
|
||||
}
|
||||
x|=1ULL<<j1;
|
||||
}
|
||||
}
|
||||
y|=1ULL<<i1;
|
||||
}
|
||||
odec(i0+1); ostr(" "); odec(i1+1); ostr(" specials\n");
|
||||
}
|
||||
}
|
||||
|
||||
void test_random() {
|
||||
int i,j;
|
||||
ui64 y,x,m;
|
||||
for(i=0;;i++) {
|
||||
for(j=0;j<200000;j++) {
|
||||
m=1ULL<<(rnd32()%48+15); m+=m-1; y=rnd64()&m;
|
||||
m=1ULL<<(rnd32()%48+15); m+=m-1; x=rnd64()&m;
|
||||
test_divu64u64( y, x);
|
||||
test_divs64s64( y, x);
|
||||
test_divs64s64( y,-x);
|
||||
test_divs64s64(-y, x);
|
||||
test_divs64s64(-y,-x);
|
||||
}
|
||||
odec(i+1); ostr("M\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t __attribute__((naked)) time_32(uint32_t a, uint32_t b, uint32_t (*func)(uint32_t a, uint32_t b)) {
|
||||
asm(
|
||||
".syntax unified\n"
|
||||
"push {r4, r5, lr}\n"
|
||||
"ldr r4, =#0xe000e018\n"
|
||||
"ldr r5, [r4]\n"
|
||||
"blx r2\n"
|
||||
"ldr r0, [r4]\n"
|
||||
"subs r5, r0\n"
|
||||
"lsls r0, r5, #8\n"
|
||||
"asrs r0, #8\n"
|
||||
"pop {r4, r5, pc}\n"
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t __attribute__((naked)) time_64(uint64_t a, uint64_t b, uint64_t (*func64)(uint64_t a, uint64_t b)) {
|
||||
asm(
|
||||
".syntax unified\n"
|
||||
"push {r4-r6, lr}\n"
|
||||
"ldr r6, [sp, #16]\n"
|
||||
"ldr r4, =#0xe000e018\n"
|
||||
"ldr r5, [r4]\n"
|
||||
"blx r6\n"
|
||||
"ldr r0, [r4]\n"
|
||||
"subs r5, r0\n"
|
||||
"lsls r0, r5, #8\n"
|
||||
"asrs r0, #8\n"
|
||||
"pop {r4-r6, pc}\n"
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t compiler_div_s32(uint32_t a, uint32_t b) {
|
||||
return ((int32_t)a) / (int32_t)b;
|
||||
}
|
||||
|
||||
uint32_t pico_div_s32(uint32_t a, uint32_t b) {
|
||||
return div_s32s32(a, b);
|
||||
}
|
||||
|
||||
uint32_t compiler_div_u32(uint32_t a, uint32_t b) {
|
||||
return a/b;
|
||||
}
|
||||
|
||||
uint32_t pico_div_u32(uint32_t a, uint32_t b) {
|
||||
return div_u32u32(a, b);
|
||||
}
|
||||
|
||||
uint64_t compiler_div_s64(uint64_t a, uint64_t b) {
|
||||
return ((int64_t)a) / (int64_t)b;
|
||||
}
|
||||
|
||||
uint64_t pico_div_s64(uint64_t a, uint64_t b) {
|
||||
return div_s64s64(a, b);
|
||||
}
|
||||
|
||||
uint64_t compiler_div_u64(uint64_t a, uint64_t b) {
|
||||
return a/b;
|
||||
}
|
||||
|
||||
uint64_t pico_div_u64(uint64_t a, uint64_t b) {
|
||||
return div_u64u64(a, b);
|
||||
}
|
||||
|
||||
|
||||
void perf_test() {
|
||||
*(volatile unsigned int *)0xe000e010=5; // enable SYSTICK at core clock
|
||||
|
||||
for(int bit = 30; bit>=0; bit--) {
|
||||
int div = 1u << (31-bit);
|
||||
const int N = 1000;
|
||||
int tc = 0, tp = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
int a = rnd32();
|
||||
int b;
|
||||
do {
|
||||
b = rnd32() / div;
|
||||
} while (b == 0);
|
||||
tc += time_32(a, b, compiler_div_s32);
|
||||
tp += time_32(a, b, pico_div_s32);
|
||||
}
|
||||
printf(" S32 %d %f\t%f\n", bit, tc / 1000.0, tp / 1000.0);
|
||||
}
|
||||
|
||||
for(int bit = 30; bit>=0; bit--) {
|
||||
int div = 1u << (31-bit);
|
||||
const int N = 1000;
|
||||
int tc = 0, tp = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
int a = rnd32();
|
||||
int b;
|
||||
do {
|
||||
b = rnd32() / div;
|
||||
} while (b == 0);
|
||||
tc += time_32(a, b, compiler_div_u32);
|
||||
tp += time_32(a, b, pico_div_u32);
|
||||
}
|
||||
printf(" U32 %d %f\t%f\n", bit, tc / 1000.0, tp / 1000.0);
|
||||
}
|
||||
|
||||
for(int extra = 0; extra <= 48; extra+=16)
|
||||
{
|
||||
for(int bit = 62; bit>=0; bit--) {
|
||||
int64_t div = 1ull << (62-bit);
|
||||
const int N = 1000;
|
||||
int tc = 0, tp = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
int64_t a = rnd64() / (1u << extra);
|
||||
int64_t b;
|
||||
do {
|
||||
b = ((int64_t)rnd64()) / div;
|
||||
} while (b == 0);
|
||||
tc += time_64(a, b, compiler_div_s64);
|
||||
tp += time_64(a, b, pico_div_s64);
|
||||
}
|
||||
printf(" S64 %d %d %f\t%f\n", extra, bit, tc / 1000.0, tp / 1000.0);
|
||||
}
|
||||
|
||||
for(int bit = 62; bit>=0; bit--) {
|
||||
int64_t div = 1ull << (62-bit);
|
||||
const int N = 1000;
|
||||
int tc = 0, tp = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
uint64_t a = rnd64();
|
||||
uint64_t b;
|
||||
do {
|
||||
b = rnd64() / div;
|
||||
} while (b == 0);
|
||||
tc += time_64(a, b, compiler_div_u64);
|
||||
tp += time_64(a, b, pico_div_u64);
|
||||
}
|
||||
printf(" U64 %d %d %f\t%f\n", extra, bit, tc / 1000.0, tp / 1000.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
#ifdef TURBO
|
||||
vreg_set_voltage(VREG_VOLTAGE_MAX);
|
||||
set_sys_clock_khz(48000*8, true);
|
||||
#endif
|
||||
setup_default_uart();
|
||||
#ifdef RANDOMISE
|
||||
int u;
|
||||
ifh=sys_host(SYS_OPEN,(int)rfn,0,strlen(rfn));
|
||||
u=sys_host(SYS_READ,ifh,(int)&seed,sizeof(seed));
|
||||
if(u) {ostrnl("Error reading random stream"); return 16;}
|
||||
sys_host(SYS_CLOSE,ifh,0,0);
|
||||
#else
|
||||
seed=12233524287791987605ULL;
|
||||
#endif
|
||||
perf_test();
|
||||
ostr("begin\n");
|
||||
test_divu64u64( 38, 6);
|
||||
test_divs64s64( 38, 6);
|
||||
test_divs64s64( 38,-6);
|
||||
test_divs64s64(-38, 6);
|
||||
test_divs64s64(-38,-6);
|
||||
test_divu64u64(1234567890123ULL,6);
|
||||
test_divu64u64(0x0000000100000000ULL,6);
|
||||
test_divu64u64(0xffffffffffffffffULL,6);
|
||||
test_special();
|
||||
o16hex(ntests);
|
||||
ostr(" special tests done; starting random tests\n");
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000000100000000ULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00000001ffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00000003ffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00000007ffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000000fffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000001fffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000003fffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000007fffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x000000ffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x000001ffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x000003ffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x000007ffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00000fffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00001fffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00003fffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x00007fffffffffffULL);
|
||||
test_divu64u64(0xf123456789abcdefULL,0x0000ffffffffffffULL);
|
||||
|
||||
test_random();
|
||||
|
||||
ostr("END\n");
|
||||
return 0;
|
||||
}
|
||||
|
38
test/pico_float_test/CMakeLists.txt
Normal file
38
test/pico_float_test/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
PROJECT(pico_float_test)
|
||||
|
||||
add_executable(pico_float_test
|
||||
pico_float_test.c
|
||||
llvm/call_apsr.S
|
||||
)
|
||||
|
||||
add_executable(pico_double_test
|
||||
pico_double_test.c
|
||||
llvm/call_apsr.S
|
||||
)
|
||||
|
||||
|
||||
target_compile_definitions(pico_float_test PRIVATE
|
||||
PICO_USE_CRT_PRINTF=1 # want full precision output
|
||||
# PICO_FLOAT_PROPAGATE_NANS=1
|
||||
)
|
||||
|
||||
target_compile_definitions(pico_double_test PRIVATE
|
||||
PICO_USE_CRT_PRINTF=1 # want full precision output
|
||||
PICO_FLOAT_PROPAGATE_NANS=1
|
||||
PICO_DOUBLE_PROPAGATE_NANS=1
|
||||
)
|
||||
|
||||
# handy for testing we aren't pulling in extra stuff
|
||||
#target_link_options(pico_float_test PRIVATE -nodefaultlibs)
|
||||
|
||||
target_include_directories(pico_float_test PRIVATE ${CMAKE_CURRENT_LIST_DIR}/llvm)
|
||||
target_link_libraries(pico_float_test pico_float pico_stdlib)
|
||||
pico_add_extra_outputs(pico_float_test)
|
||||
#pico_set_float_implementation(pico_float_test compiler)
|
||||
#pico_set_double_implementation(pico_float_test compiler)
|
||||
|
||||
target_include_directories(pico_double_test PRIVATE ${CMAKE_CURRENT_LIST_DIR}/llvm)
|
||||
target_link_libraries(pico_double_test pico_double pico_stdlib)
|
||||
pico_add_extra_outputs(pico_double_test)
|
||||
#pico_set_float_implementation(pico_double_test compiler)
|
||||
#pico_set_double_implementation(pico_double_test compiler)
|
68
test/pico_float_test/llvm/LICENSE.TXT
Normal file
68
test/pico_float_test/llvm/LICENSE.TXT
Normal file
@ -0,0 +1,68 @@
|
||||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
Copyrights and Licenses for Third Party Software Distributed with LLVM:
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
Google Test llvm/utils/unittest/googletest
|
||||
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
|
||||
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
|
||||
ARM contributions llvm/lib/Target/ARM/LICENSE.TXT
|
||||
md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
|
38
test/pico_float_test/llvm/call_apsr.S
Normal file
38
test/pico_float_test/llvm/call_apsr.S
Normal file
@ -0,0 +1,38 @@
|
||||
//===-- call_apsr.S - Helpers for ARM EABI floating point tests -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements helpers for ARM EABI floating point tests for the
|
||||
// compiler_rt library.
|
||||
//
|
||||
//===-
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.align 2
|
||||
|
||||
.global call_apsr_f
|
||||
.type call_apsr_f,%function
|
||||
.thumb_func
|
||||
call_apsr_f:
|
||||
push {lr}
|
||||
blx r2
|
||||
mrs r0, apsr
|
||||
pop {pc}
|
||||
|
||||
.global call_apsr_d
|
||||
.type call_apsr_d,%function
|
||||
.thumb_func
|
||||
call_apsr_d:
|
||||
push {r4, lr}
|
||||
ldr r4, [sp, #8]
|
||||
blx r4
|
||||
mrs r0, apsr
|
||||
pop {r4, pc}
|
40
test/pico_float_test/llvm/call_apsr.h
Normal file
40
test/pico_float_test/llvm/call_apsr.h
Normal file
@ -0,0 +1,40 @@
|
||||
//todo check license
|
||||
//===-- call_apsr.h - Helpers for ARM EABI floating point tests -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares helpers for ARM EABI floating point tests for the
|
||||
// compiler_rt library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CALL_APSR_H
|
||||
#define CALL_APSR_H
|
||||
|
||||
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
||||
#error big endian support not implemented
|
||||
#endif
|
||||
|
||||
union cpsr {
|
||||
struct {
|
||||
uint32_t filler: 28;
|
||||
uint32_t v: 1;
|
||||
uint32_t c: 1;
|
||||
uint32_t z: 1;
|
||||
uint32_t n: 1;
|
||||
} flags;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
extern __attribute__((pcs("aapcs")))
|
||||
uint32_t call_apsr_f(float a, float b, __attribute__((pcs("aapcs"))) void (*fn)(float, float));
|
||||
|
||||
extern __attribute__((pcs("aapcs")))
|
||||
uint32_t call_apsr_d(double a, double b, __attribute__((pcs("aapcs"))) void (*fn)(double, double));
|
||||
|
||||
#endif // CALL_APSR_H
|
434
test/pico_float_test/pico_double_test.c
Normal file
434
test/pico_float_test/pico_double_test.c
Normal file
@ -0,0 +1,434 @@
|
||||
//===-- aeabi_cdcmpeq.c - Test __aeabi_cdcmpeq ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file tests __aeabi_cdcmpeq for the compiler_rt library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <pico/double.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "inttypes.h"
|
||||
|
||||
extern int __aeabi_dcmpun(double a, double b);
|
||||
|
||||
#if __arm__
|
||||
|
||||
#include "call_apsr.h"
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cdcmpeq(double a, double b);
|
||||
|
||||
int test__aeabi_cdcmpeq(double a, double b, int expected) {
|
||||
uint32_t cpsr_value = call_apsr_d(a, b, __aeabi_cdcmpeq);
|
||||
union cpsr cpsr = {.value = cpsr_value};
|
||||
if (expected != cpsr.flags.z) {
|
||||
printf("error in __aeabi_cdcmpeq(%f, %f) => Z = %08x, expected %08x\n",
|
||||
a, b, cpsr.flags.z, expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int test_cdcmpeq() {
|
||||
#if __arm__
|
||||
if (test__aeabi_cdcmpeq(1.0, 1.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(0.0, -1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-0.0, -1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-1.0, 0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-1.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(NAN, NAN, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(INFINITY, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(0.0, INFINITY, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-INFINITY, 0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(0.0, -INFINITY, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(INFINITY, INFINITY, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmpeq(-INFINITY, -INFINITY, 1))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __arm__
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cdcmple(double a, double b);
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cdrcmple(double a, double b);
|
||||
|
||||
int test_dcmple_gt(double a, double b, int expected) {
|
||||
if ((a <= b) != expected) {
|
||||
printf("error in dcmple(%f, %f) => %d, expected %d\n",
|
||||
a, b, a <= b, expected);
|
||||
return 1;
|
||||
}
|
||||
if ((a > b) == expected && !isnan(a) && !isnan(b)) {
|
||||
printf("error in dcmpgt(%f, %f) => %d, expected %d\n",
|
||||
a, b, a > b, !expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dcmplt_ge(double a, double b, int expected) {
|
||||
if ((a < b) != expected) {
|
||||
printf("error in dcmplt(%f, %f) => %d, expected %d\n",
|
||||
a, b, a < b, expected);
|
||||
return 1;
|
||||
}
|
||||
if ((a >= b) == expected && !isnan(a) && !isnan(b)) {
|
||||
printf("error in dcmpge(%f, %f) => %d, expected %d\n",
|
||||
a, b, a >= b, !expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test__aeabi_cdcmple(double a, double b, int expected) {
|
||||
int32_t cpsr_value = call_apsr_d(a, b, __aeabi_cdcmple);
|
||||
int32_t r_cpsr_value = call_apsr_d(b, a, __aeabi_cdrcmple);
|
||||
int32_t cpsr_value2 = call_apsr_d(b, a, __aeabi_cdcmple);
|
||||
int32_t r_cpsr_value2 = call_apsr_d(a, b, __aeabi_cdrcmple);
|
||||
|
||||
if (cpsr_value != r_cpsr_value) {
|
||||
printf("error: __aeabi_cdcmple(%f, %f) != __aeabi_cdrcmple(%f, %f)\n", a, b, b, a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int expected_z, expected_c;
|
||||
if (expected == -1) {
|
||||
expected_z = 0;
|
||||
expected_c = 0;
|
||||
} else if (expected == 0) {
|
||||
expected_z = 1;
|
||||
expected_c = 1;
|
||||
} else {
|
||||
// a or b is NaN, or a > b
|
||||
expected_z = 0;
|
||||
expected_c = 1;
|
||||
}
|
||||
#if PICO_DOUBLE_COMPILER
|
||||
// gcc has this backwards it seems - not a good thing, but I guess it doesn't ever call them
|
||||
expected_c ^= 1;
|
||||
#endif
|
||||
|
||||
union cpsr cpsr = {.value = cpsr_value};
|
||||
if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
|
||||
printf("error in __aeabi_cdcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
|
||||
a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpsr.value = r_cpsr_value;
|
||||
if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
|
||||
printf("error in __aeabi_cfrcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
|
||||
a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int test_cdcmple() {
|
||||
#if __arm__
|
||||
if (test__aeabi_cdcmple(1.0, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(1234.567, 765.4321, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(765.4321, 1234.567, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(-123.0, -678.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(-678.0, -123.0, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(-123.0, 678.0, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(0.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(1.0, NAN, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(NAN, 1.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cdcmple(NAN, NAN, 1))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_cmple_gt() {
|
||||
if (test_dcmple_gt(1.0, 1.0, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test_dcmple_gt(765.4321, 1234.567, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test_dcmple_gt(-678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(-123.0, 678.0, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(678.0, -123.0, 0))
|
||||
return 1;
|
||||
if (test_dcmple_gt(0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(-0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test_dcmple_gt(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test_dcmple_gt(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test_dcmple_gt(NAN, NAN, 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_cmplt_ge() {
|
||||
if (test_dcmplt_ge(1.0, 1.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(765.4321, 1234.567, 1))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(-678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(-123.0, 678.0, 1))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(678.0, -123.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(0.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(-0.0, 0.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test_dcmplt_ge(NAN, NAN, 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_dcmpun(double a, double b, bool expected, bool expect_equal) {
|
||||
if (__aeabi_dcmpun(a, b) != expected) {
|
||||
printf("Failed dcmpun(%f, %f)\n", a, b);
|
||||
return 1;
|
||||
}
|
||||
if ((a == b) != expect_equal) {
|
||||
printf("Failed equality check %f %f\n", a, b);
|
||||
__breakpoint();
|
||||
if (b == a) {
|
||||
printf("SAS\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dcmpun() {
|
||||
if (check_dcmpun(0, 0, false, true) ||
|
||||
check_dcmpun(-INFINITY, INFINITY, false, false) ||
|
||||
check_dcmpun(NAN, 0, true, false) ||
|
||||
check_dcmpun(0, NAN, true, false) ||
|
||||
check_dcmpun(NAN, NAN, true, false) ||
|
||||
check_dcmpun(-NAN, NAN, true, false)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double aa = 0.5;
|
||||
double bb = 1;
|
||||
|
||||
int main() {
|
||||
setup_default_uart();
|
||||
|
||||
printf("%d\n", aa < bb);
|
||||
for(double a = -1; a <= 1; a++) {
|
||||
for(double b = -1; b <= 1; b++) {
|
||||
printf("%f < %f ? %d\n", a, b, a < b);
|
||||
}
|
||||
}
|
||||
for(double a = -1; a <=1; a++) {
|
||||
for(double b = -1; b <= 1; b++) {
|
||||
printf("%f > %f ? %d\n", a, b, a > b);
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
for (double x = 0; x < 3; x++) {
|
||||
printf("\n ----- %g\n", x);
|
||||
printf("SQRT %10.18g\n", sqrt(x));
|
||||
printf("COS %10.18g\n", cos(x));
|
||||
printf("SIN %10.18g\n", sin(x));
|
||||
printf("TAN %10.18g\n", tan(x));
|
||||
printf("ATAN2 %10.18g\n", atan2(x, 10));
|
||||
printf("ATAN2 %10.18g\n", atan2(10, x));
|
||||
printf("EXP %10.18g\n", exp(x));
|
||||
printf("LN %10.18g\n", log(x));
|
||||
double s, c;
|
||||
sincos(x, &s, &c);
|
||||
printf("SINCOS %10.18f %10.18f\n", s, c);
|
||||
}
|
||||
|
||||
#if PICO_DOUBLE_PROPAGATE_NANS
|
||||
{
|
||||
float x = NAN;
|
||||
printf("NANO %10.18f\n", x);
|
||||
printf("SQRT %10.18f\n", sqrt(x));
|
||||
printf("COS %10.18f\n", cos(x));
|
||||
printf("SIN %10.18f\n", sin(x));
|
||||
printf("TAN %10.18f\n", tan(x));
|
||||
printf("ATAN2 %10.18f\n", atan2(x, 10));
|
||||
printf("ATAN2 %10.18f\n", atan2(10, x));
|
||||
printf("EXP %10.18f\n", exp(x));
|
||||
printf("LN %10.18f\n", log(x));
|
||||
printf("POW %10.18f\n", pow(x, x));
|
||||
printf("TRUNC %10.18f\n", trunc(x));
|
||||
printf("LDEXP %10.18f\n", ldexp(x, x));
|
||||
printf("FMOD %10.18f\n", fmod(x, 3.0f));
|
||||
double s, c;
|
||||
sincos(x, &s, &c);
|
||||
printf("SINCOS %10.18f %10.18f\n", s, c);
|
||||
|
||||
for(int j=0;j<2;j++) {
|
||||
for (int i = 1; i < 4; i++) {
|
||||
char buf[4];
|
||||
sprintf(buf, "%d", i);
|
||||
float f0 = -nanf(buf);
|
||||
double d0 = -nan(buf);
|
||||
// hmm nanf/nan seem to ignore payload
|
||||
*(uint64_t *) &d0 |= i;
|
||||
*(uint32_t *) &f0 |= i;
|
||||
if (j) {
|
||||
// try without top bit set
|
||||
*(uint64_t *) &d0 &= ~0x0008000000000000ull;
|
||||
*(uint32_t *) &f0 &= ~0x00400000u;
|
||||
}
|
||||
float f = (float) d0;
|
||||
double d = (double) f0;
|
||||
printf("f2d %f %08"PRIx32" -> %g %016"PRIx64"\n", f0, *(uint32_t *) &f0, d, *(uint64_t *) &d);
|
||||
printf("d2f %f %016"PRIx64" -> %f %08"PRIx32"\n", d0, *(uint64_t *) &d0, f, *(uint32_t *) &f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int32_t y;
|
||||
// for (int32_t x = 0; x>-512; x--) {
|
||||
// printf("i %d->%f\n", (int)x, (float) x);
|
||||
// }
|
||||
for (int32_t x = -1; x; x <<= 1) {
|
||||
printf("i %d->%f\n", x, (double) x);
|
||||
}
|
||||
for (int32_t x = 1; x; x <<= 1) {
|
||||
printf("i %d->%f\n", x, (double) x);
|
||||
y = x << 1;
|
||||
}
|
||||
for (int64_t x = 1; x; x <<= 1) {
|
||||
printf("i %lld->%f\n", x, (double) x);
|
||||
y = x << 1;
|
||||
}
|
||||
for (int64_t x = -1; x; x <<= 1) {
|
||||
printf("i %lld->%f\n", x, (double) x);
|
||||
y = x << 1;
|
||||
}
|
||||
printf("d %d->%f\n", y, (float) y);
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t y;
|
||||
for(uint32_t x = 1; x; x <<= 1) {
|
||||
printf("u %u->%f\n", x, (double)x);
|
||||
y = x << 1;
|
||||
}
|
||||
printf("u %u->%f\n", y, (double)y);
|
||||
}
|
||||
for(int64_t x = 1; x !=0; x <<= 1u) {
|
||||
printf("%lld->%f\n", x, (double)x);
|
||||
}
|
||||
for(double x = -4294967296.f * 4294967296.f; x<=-0.5f; x/=2.f) {
|
||||
printf("d2i64 %f->%lld\n", x, (int64_t)x);
|
||||
}
|
||||
for(double x = 4294967296.f * 4294967296.f; x>=0.5f; x/=2.f) {
|
||||
printf("d2i64 %f->%lld\n", x, (int64_t)x);
|
||||
}
|
||||
for(double x = -4294967296.f * 4294967296.f; x<=-0.5f; x/=2.f) {
|
||||
printf("d2i32 %f->%d\n", x, (int32_t)x);
|
||||
}
|
||||
for(double x = 4294967296.f * 4294967296.f; x>=0.5f; x/=2.f) {
|
||||
printf("d2i32 %f->%d\n", x, (int32_t)x);
|
||||
}
|
||||
|
||||
for (double x = 1; x < 11; x += 2) {
|
||||
double f = x * x;
|
||||
double g = 1.0 / x;
|
||||
printf("%g %10.18g %10.18g, %10.18g, %10.18g %10.18g\n", x, f, x + 0.37777777777777777777777777777,
|
||||
x - 0.377777777777777777777777777777, g, 123456789.0 / x);
|
||||
}
|
||||
if (test_cdcmpeq() || test_cdcmple() ||
|
||||
test_dcmpun() || test_cmple_gt() || test_cmplt_ge()) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASSED\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_cdcmpeq() || test_cdcmple() ||
|
||||
test_dcmpun() || test_cmple_gt() || test_cmplt_ge()) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASSED\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
538
test/pico_float_test/pico_float_test.c
Normal file
538
test/pico_float_test/pico_float_test.c
Normal file
@ -0,0 +1,538 @@
|
||||
//===-- aeabi_cfcmpeq.c - Test __aeabi_cfcmpeq ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file tests __aeabi_cfcmpeq for the compiler_rt library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <pico/float.h>
|
||||
//#include <pico/float.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "inttypes.h"
|
||||
|
||||
extern int __aeabi_fcmpun(float a, float b);
|
||||
|
||||
#if __arm__
|
||||
|
||||
#include "call_apsr.h"
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cfcmpeq(float a, float b);
|
||||
|
||||
int test__aeabi_cfcmpeq(float a, float b, int expected) {
|
||||
uint32_t cpsr_value = call_apsr_f(a, b, __aeabi_cfcmpeq);
|
||||
union cpsr cpsr = {.value = cpsr_value};
|
||||
if (expected != cpsr.flags.z) {
|
||||
printf("error in __aeabi_cfcmpeq(%f, %f) => Z = %08x, expected %08x\n",
|
||||
a, b, cpsr.flags.z, expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int test_cfcmpeq() {
|
||||
#if __arm__
|
||||
if (test__aeabi_cfcmpeq(1.0, 1.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(0.0, -1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-0.0, -1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-1.0, 0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-1.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(NAN, NAN, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(INFINITY, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(0.0, INFINITY, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-INFINITY, 0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(0.0, -INFINITY, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(INFINITY, INFINITY, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmpeq(-INFINITY, -INFINITY, 1))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __arm__
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cfcmple(float a, float b);
|
||||
|
||||
extern __attribute__((pcs("aapcs"))) void __aeabi_cfrcmple(float a, float b);
|
||||
|
||||
int test_fcmple_gt(float a, float b, int expected) {
|
||||
if ((a <= b) != expected) {
|
||||
printf("error in fcmple(%f, %f) => %d, expected %d\n",
|
||||
a, b, a <= b, expected);
|
||||
return 1;
|
||||
}
|
||||
if ((a > b) == expected && !isnanf(a) && !isnanf(b)) {
|
||||
printf("error in fcmpgt(%f, %f) => %d, expected %d\n",
|
||||
a, b, a > b, !expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_fcmplt_ge(float a, float b, int expected) {
|
||||
if ((a < b) != expected) {
|
||||
printf("error in fcmplt(%f, %f) => %d, expected %d\n",
|
||||
a, b, a < b, expected);
|
||||
return 1;
|
||||
}
|
||||
if ((a >= b) == expected && !isnanf(a) && !isnanf(b)) {
|
||||
printf("error in fcmpge(%f, %f) => %d, expected %d\n",
|
||||
a, b, a >= b, !expected);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test__aeabi_cfcmple(float a, float b, int expected) {
|
||||
int32_t cpsr_value = call_apsr_f(a, b, __aeabi_cfcmple);
|
||||
int32_t r_cpsr_value = call_apsr_f(b, a, __aeabi_cfrcmple);
|
||||
int32_t cpsr_value2 = call_apsr_f(b, a, __aeabi_cfcmple);
|
||||
int32_t r_cpsr_value2 = call_apsr_f(a, b, __aeabi_cfrcmple);
|
||||
|
||||
if (cpsr_value != r_cpsr_value) {
|
||||
printf("error: __aeabi_cfcmple(%f, %f) != __aeabi_cfrcmple(%f, %f)\n", a, b, b, a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int expected_z, expected_c;
|
||||
if (expected == -1) {
|
||||
expected_z = 0;
|
||||
expected_c = 0;
|
||||
} else if (expected == 0) {
|
||||
expected_z = 1;
|
||||
expected_c = 1;
|
||||
} else {
|
||||
// a or b is NaN, or a > b
|
||||
expected_z = 0;
|
||||
expected_c = 1;
|
||||
}
|
||||
#if PICO_FLOAT_COMPILER
|
||||
// gcc has this backwards it seems - not a good thing, but I guess it doesn't ever call them
|
||||
expected_c ^= 1;
|
||||
#endif
|
||||
|
||||
union cpsr cpsr = {.value = cpsr_value};
|
||||
if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
|
||||
printf("error in __aeabi_cfcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
|
||||
a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpsr.value = r_cpsr_value;
|
||||
if (expected_z != cpsr.flags.z || expected_c != cpsr.flags.c) {
|
||||
printf("error in __aeabi_cfrcmple(%f, %f) => (Z = %d, C = %d), expected (Z = %d, C = %d)\n",
|
||||
a, b, cpsr.flags.z, cpsr.flags.c, expected_z, expected_c);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int test_cfcmple() {
|
||||
#if __arm__
|
||||
if (test__aeabi_cfcmple(1.0, 1.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(1234.567, 765.4321, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(765.4321, 1234.567, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(-123.0, -678.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(-678.0, -123.0, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(-123.0, 678.0, -1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(0.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(1.0, NAN, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(NAN, 1.0, 1))
|
||||
return 1;
|
||||
if (test__aeabi_cfcmple(NAN, NAN, 1))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_cmple_gt() {
|
||||
if (test_fcmple_gt(1.0, 1.0, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test_fcmple_gt(765.4321, 1234.567, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test_fcmple_gt(-678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(-123.0, 678.0, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(678.0, -123.0, 0))
|
||||
return 1;
|
||||
if (test_fcmple_gt(0.0, -0.0, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(-0.0, 0.0, 1))
|
||||
return 1;
|
||||
if (test_fcmple_gt(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test_fcmple_gt(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test_fcmple_gt(NAN, NAN, 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_cmplt_ge() {
|
||||
if (test_fcmplt_ge(1.0, 1.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(1234.567, 765.4321, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(765.4321, 1234.567, 1))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(-123.0, -678.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(-678.0, -123.0, 1))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(-123.0, 678.0, 1))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(678.0, -123.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(0.0, -0.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(-0.0, 0.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(1.0, NAN, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(NAN, 1.0, 0))
|
||||
return 1;
|
||||
if (test_fcmplt_ge(NAN, NAN, 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_fcmpun(float a, float b, bool expected, bool expect_equal) {
|
||||
if (__aeabi_fcmpun(a, b) != expected) {
|
||||
printf("Failed fcmpun(%f, %f)\n", a, b);
|
||||
return 1;
|
||||
}
|
||||
if ((a == b) != expect_equal) {
|
||||
printf("Failed equality check %f %f\n", a, b);
|
||||
__breakpoint();
|
||||
if (b == a) {
|
||||
printf("SAS\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_fcmpun() {
|
||||
if (check_fcmpun(0, 0, false, true) ||
|
||||
check_fcmpun(-INFINITY, INFINITY, false, false) ||
|
||||
check_fcmpun(NAN, 0, true, false) ||
|
||||
check_fcmpun(0, NAN, true, false) ||
|
||||
check_fcmpun(NAN, NAN, true, false) ||
|
||||
check_fcmpun(-NAN, NAN, true, false)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double aa = 0.5;
|
||||
double bb = 1;
|
||||
|
||||
int main() {
|
||||
setup_default_uart();
|
||||
|
||||
printf("%d\n", aa < bb);
|
||||
for(float a = -1; a <= 1; a++) {
|
||||
for(float b = -1; b <= 1; b++) {
|
||||
printf("%f < %f ? %d\n", a, b, a < b);
|
||||
}
|
||||
}
|
||||
for(float a = -1; a <=1; a++) {
|
||||
for(float b = -1; b <= 1; b++) {
|
||||
printf("%f > %f ? %d\n", a, b, a > b);
|
||||
}
|
||||
}
|
||||
printf("F\n");
|
||||
for(float f = -1.0; f<=1.f; f+=0.25f) {
|
||||
printf("%d\n", (int)f);
|
||||
}
|
||||
printf("D\n");
|
||||
for(double d = -1.0; d<=1.0; d+=0.25) {
|
||||
printf("%d\n", (int)d);
|
||||
}
|
||||
printf("LD\n");
|
||||
for(double d = -1.0; d<=1.0; d+=0.25) {
|
||||
printf("%lld\n", (int64_t)d);
|
||||
}
|
||||
|
||||
for(float d = -0.125; d>=-65536.0*65536.0*65536.0*65536.0*2; d*=2) {
|
||||
printf("%g %d, %lld, %u, %llu\n", d, (int32_t)d, (int64_t)d, (uint32_t)d, (uint64_t)d);
|
||||
}
|
||||
for(float d = 0.125; d<=65536.0*65536.0*65536.0*65536.0*2; d*=2) {
|
||||
printf("%g %d, %lld, %u, %llu\n", d, (int32_t)d, (int64_t)d, (uint32_t)d, (uint64_t)d);
|
||||
}
|
||||
|
||||
for(double d = -0.125; d>=-65536.0*65536.0*65536.0*65536.0*2; d*=2) {
|
||||
printf("%g %d, %lld, %u, %llu\n", d, (int32_t)d, (int64_t)d, (uint32_t)d, (uint64_t)d);
|
||||
}
|
||||
for(double d = 0.125; d<=65536.0*65536.0*65536.0*65536.0*2; d*=2) {
|
||||
printf("%g %d, %lld, %u, %llu\n", d, (int32_t)d, (int64_t)d, (uint32_t)d, (uint64_t)d);
|
||||
}
|
||||
|
||||
for(int i = (int32_t)0x80000000; i <0; i /= 2) {
|
||||
printf("%d %f\n", i, (double)i);
|
||||
}
|
||||
for(int i = (1<<30); i >0; i /= 2) {
|
||||
printf("%d %f\n", i, (double)i);
|
||||
}
|
||||
|
||||
printf("%f\n", 0.5);
|
||||
printf("SQRT %10.18g\n", 0.5);
|
||||
printf("SQRT %10.18g\n", 0.333333333333333333333333);
|
||||
|
||||
#if 1
|
||||
for (float x = 0; x < 3; x++) {
|
||||
printf("\n ----- %f\n", x);
|
||||
printf("FSQRT %10.18f\n", sqrtf(x));
|
||||
printf("FCOS %10.18f\n", cosf(x));
|
||||
printf("FSIN %10.18f\n", sinf(x));
|
||||
float s, c;
|
||||
sincosf(x, &s, &c);
|
||||
printf("FSINCOS %10.18f %10.18f\n", s, c);
|
||||
printf("FTAN %10.18f\n", tanf(x));
|
||||
printf("FATAN2 %10.18f\n", atan2f(x, 10));
|
||||
printf("FATAN2 %10.18f\n", atan2f(10, x));
|
||||
printf("FEXP %10.18f\n", expf(x));
|
||||
printf("FLN %10.18f\n", logf(x));
|
||||
printf("POWF %10.18f\n", powf(x, x));
|
||||
printf("TRUNCF %10.18f\n", truncf(x));
|
||||
printf("LDEXPF %10.18f\n", ldexpf(x, x));
|
||||
printf("FMODF %10.18f\n", fmodf(x, 3.0f));
|
||||
}
|
||||
|
||||
for (double x = 0; x < 3; x++) {
|
||||
printf("\n ----- %g\n", x);
|
||||
printf("SQRT %10.18g\n", sqrt(x));
|
||||
printf("COS %10.18g\n", cos(x));
|
||||
printf("SIN %10.18g\n", sin(x));
|
||||
printf("TAN %10.18g\n", tan(x));
|
||||
printf("ATAN2 %10.18g\n", atan2(x, 10));
|
||||
printf("ATAN2 %10.18g\n", atan2(10, x));
|
||||
printf("EXP %10.18g\n", exp(x));
|
||||
printf("LN %10.18g\n", log(x));
|
||||
}
|
||||
|
||||
#if PICO_FLOAT_PROPAGATE_NANS
|
||||
{
|
||||
float x = NAN;
|
||||
printf("NANO %10.18f\n", x);
|
||||
printf("FSQRT %10.18f\n", sqrtf(x));
|
||||
printf("FCOS %10.18f\n", cosf(x));
|
||||
printf("FSIN %10.18f\n", sinf(x));
|
||||
printf("FTAN %10.18f\n", tanf(x));
|
||||
printf("FATAN2 %10.18f\n", atan2f(x, 10));
|
||||
printf("FATAN2 %10.18f\n", atan2f(10, x));
|
||||
printf("FEXP %10.18f\n", expf(x));
|
||||
printf("FLN %10.18f\n", logf(x));
|
||||
printf("POWF %10.18f\n", powf(x, x));
|
||||
printf("TRUNCF %10.18f\n", truncf(x));
|
||||
printf("LDEXPF %10.18f\n", ldexpf(x, x));
|
||||
printf("FMODF %10.18f\n", fmodf(x, 3.0f));
|
||||
float s, c;
|
||||
// sincosf(x, &s, &c);
|
||||
printf("FSINCOS %10.18f %10.18f\n", s, c);
|
||||
|
||||
for(int i=1; i<4; i++) {
|
||||
char buf[4];
|
||||
sprintf(buf, "%d", i);
|
||||
float f0 = -nanf(buf);
|
||||
double d0 = -nan(buf);
|
||||
// hmm
|
||||
*(uint64_t *)&d0 |= i;
|
||||
*(uint32_t *)&f0 |= i;
|
||||
float f = (float)d0;
|
||||
double d = (double)f0;
|
||||
printf("f2d %08"PRIx32" -> %g %016"PRIx64"\n", *(uint32_t*)&f0, d, *(uint64_t*)&d);
|
||||
printf("d2f %016"PRIx64" -> %f %08"PRIx32"\n", *(uint64_t*)&d0, f, *(uint32_t*)&f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int32_t y;
|
||||
// for (int32_t x = 0; x>-512; x--) {
|
||||
// printf("i %d->%f\n", (int)x, (float) x);
|
||||
// }
|
||||
for (int32_t x = -1; x; x <<= 1) {
|
||||
printf("i %d->%f\n", x, (float) x);
|
||||
}
|
||||
for (int32_t x = 1; x; x <<= 1) {
|
||||
printf("i %d->%f\n", x, (float) x);
|
||||
y = x << 1;
|
||||
}
|
||||
for (int64_t x = 1; x; x <<= 1) {
|
||||
printf("i %lld->%f\n", x, (float) x);
|
||||
y = x << 1;
|
||||
}
|
||||
for (int64_t x = -1; x; x <<= 1) {
|
||||
printf("i %lld->%f\n", x, (float) x);
|
||||
y = x << 1;
|
||||
}
|
||||
printf("d %d->%f\n", y, (float) y);
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t y;
|
||||
for(uint32_t x = 1; x; x <<= 1) {
|
||||
printf("u %u->%f\n", x, (float)x);
|
||||
y = x << 1;
|
||||
}
|
||||
printf("u %u->%f\n", y, (float)y);
|
||||
}
|
||||
for(int64_t x = 1; x !=0; x <<= 1u) {
|
||||
printf("%lld->%f\n", x, (float)x);
|
||||
}
|
||||
for(float x = 4294967296.f * 4294967296.f; x>=0.5f; x/=2.f) {
|
||||
printf("f %f->%lld\n", x, (int64_t)x);
|
||||
}
|
||||
for (double x = 1; x < 11; x += 2) {
|
||||
double f = x * x;
|
||||
double g = 1.0 / x;
|
||||
printf("%g %10.18g %10.18g, %10.18g, %10.18g %10.18g\n", x, f, x + 0.37777777777777777777777777777,
|
||||
x - 0.377777777777777777777777777777, g, 123456789.0 / x);
|
||||
}
|
||||
if (test_cfcmpeq() || test_cfcmple() ||
|
||||
test_fcmpun() || test_cmple_gt() || test_cmplt_ge()) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASSED\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_cfcmpeq() || test_cfcmple() ||
|
||||
test_fcmpun() || test_cmple_gt() || test_cmplt_ge()) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASSED\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
// todo need to add tests like these
|
||||
|
||||
bool __noinline check(float x, float y) {
|
||||
return x > y;
|
||||
}
|
||||
|
||||
bool __noinline checkd(double x, double y) {
|
||||
return x >= y;
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
#if 0
|
||||
printf("0 op nan %d\n", check(0, nanf("sd")));
|
||||
printf("nan op 0 %d\n", check(nanf("sd"), 0));
|
||||
printf("0 op -nan %d\n", check(0, -nanf("sd")));
|
||||
printf("-nan op 0 %d\n", check(-nanf("sd"), 0));
|
||||
printf("-nan op nan %d\n", check(-nanf("xx"), nanf("xx")));
|
||||
printf("-nan op -nan %d\n", check(-nanf("xx"), -nanf("xx")));
|
||||
printf("nan op -nan %d\n", check(nanf("xx"), -nanf("xx")));
|
||||
printf("nan op nan %d\n", check(nanf("xx"), nanf("xx")));
|
||||
printf("0 op inf %d\n", check(0, infinityf()));
|
||||
printf("inf op 0 %d\n", check(infinityf(), 0));
|
||||
printf("0 op -inf %d\n", check(0, -infinityf()));
|
||||
printf("-inf op 0 %d\n", check(-infinityf(), 0));
|
||||
printf("-inf op inf %d\n", check(-infinityf(), infinityf()));
|
||||
printf("-inf op -inf %d\n", check(-infinityf(), -infinityf()));
|
||||
printf("inf op -inf %d\n", check(infinityf(), -infinityf()));
|
||||
printf("inf op inf %d\n", check(infinityf(), infinityf()));
|
||||
printf("1 op 1 %d\n", check(1, 1));
|
||||
printf("-1 op 1 %d\n", check(-1, 1));
|
||||
printf("1 op -1 %d\n", check(1, -1));
|
||||
printf("-1 op -1 %d\n", check(-1, -1));
|
||||
printf("1 op 2 %d\n", check(1, 2));
|
||||
printf("2 op 1 %d\n", check(2, 1));
|
||||
printf("-1 op -2 %d\n", check(-1, -2));
|
||||
printf("-2 op -1 %d\n", check(-2, -1));
|
||||
#else
|
||||
printf("0 op nan %d\n", checkd(0, nan("sd")));
|
||||
printf("nan op 0 %d\n", checkd(nan("sd"), 0));
|
||||
printf("0 op -nan %d\n", checkd(0, -nan("sd")));
|
||||
printf("-nan op 0 %d\n", checkd(-nan("sd"), 0));
|
||||
printf("-nan op nan %d\n", checkd(-nan("xx"), nan("xx")));
|
||||
printf("-nan op -nan %d\n", checkd(-nan("xx"), -nan("xx")));
|
||||
printf("nan op -nan %d\n", checkd(nan("xx"), -nan("xx")));
|
||||
printf("nan op nan %d\n", checkd(nan("xx"), nan("xx")));
|
||||
printf("0 op inf %d\n", checkd(0, infinity()));
|
||||
printf("inf op 0 %d\n", checkd(infinity(), 0));
|
||||
printf("0 op -inf %d\n", checkd(0, -infinity()));
|
||||
printf("-inf op 0 %d\n", checkd(-infinity(), 0));
|
||||
printf("-inf op inf %d\n", checkd(-infinity(), infinity()));
|
||||
printf("-inf op -inf %d\n", checkd(-infinity(), -infinity()));
|
||||
printf("inf op -inf %d\n", checkd(infinity(), -infinity()));
|
||||
printf("inf op inf %d\n", checkd(infinity(), infinity()));
|
||||
printf("1 op 1 %d\n", checkd(1, 1));
|
||||
printf("-1 op 1 %d\n", checkd(-1, 1));
|
||||
printf("1 op -1 %d\n", checkd(1, -1));
|
||||
printf("-1 op -1 %d\n", checkd(-1, -1));
|
||||
printf("1 op 2 %d\n", checkd(1, 2));
|
||||
printf("2 op 1 %d\n", checkd(2, 1));
|
||||
printf("-1 op -2 %d\n", checkd(-1, -2));
|
||||
printf("-2 op -1 %d\n", checkd(-2, -1));
|
||||
#endif
|
||||
}
|
||||
#endif
|
8
test/pico_stdlib_test/CMakeLists.txt
Normal file
8
test/pico_stdlib_test/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
add_executable(pico_stdlib_test pico_stdlib_test.c)
|
||||
|
||||
target_compile_definitions(pico_stdlib_test PRIVATE
|
||||
#PICO_ENTER_USB_BOOT_ON_EXIT=1
|
||||
)
|
||||
|
||||
target_link_libraries(pico_stdlib_test PRIVATE pico_stdlib)
|
||||
pico_add_extra_outputs(pico_stdlib_test)
|
179
test/pico_stdlib_test/pico_stdlib_test.c
Normal file
179
test/pico_stdlib_test/pico_stdlib_test.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/bit_ops.h"
|
||||
|
||||
int main() {
|
||||
setup_default_uart();
|
||||
|
||||
puts("Hellox, worlxxcd!");
|
||||
printf("Hello world %d\n", 2);
|
||||
#if PICO_NO_HARDWARE
|
||||
puts("This is native");
|
||||
#endif
|
||||
#if PICO_NO_FLASH
|
||||
puts("This is no flash");
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
uint32_t x = 1 << i;
|
||||
uint64_t xl = 1ull << i;
|
||||
// printf("%d %u %u %u %u \n", i, (uint)(x%10u), (uint)(x%16u), (uint)(xl %10u), (uint)(xl%16u));
|
||||
printf("%08x %08x %016llx %016llx\n", (uint) x, (uint) __rev(x), (unsigned long long) xl,
|
||||
(unsigned long long) __revll(xl));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sleep_ms(500);
|
||||
printf( "%" PRIu64 "\n", to_us_since_boot(get_absolute_time()));
|
||||
}
|
||||
absolute_time_t until = delayed_by_us(get_absolute_time(), 500000);
|
||||
printf("\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sleep_until(until);
|
||||
printf("%" PRIu64 "\n", to_us_since_boot(get_absolute_time()));
|
||||
until = delayed_by_us(until, 500000);
|
||||
}
|
||||
puts("DONE");
|
||||
}
|
||||
|
||||
void test1() {
|
||||
uint32_t x = 0;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
x += __builtin_popcount(i);
|
||||
x += __builtin_popcountl(i);
|
||||
x += __builtin_popcountll(i * 1234567ll);
|
||||
x += __builtin_clz(i);
|
||||
x += __builtin_clzl(i);
|
||||
x += __builtin_clzll(i * 1234567ll);
|
||||
x += __builtin_ctz(i);
|
||||
x += __builtin_ctzl(i);
|
||||
x += __builtin_ctzll(i * 1234567ll);
|
||||
}
|
||||
if (x > 12345677) {
|
||||
puts("ok");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct event {
|
||||
|
||||
};
|
||||
|
||||
// something might be asyncrhonous.. it communicates the result via the event
|
||||
void do_something(struct event *e, int a, unsigned int b, char *c) {
|
||||
if (a == b) puts(c);
|
||||
}
|
||||
|
||||
int32_t event_result_timeout_ms(struct event *e, int32_t timeout_ms);
|
||||
int32_t event_result_timeout_us(struct event *e, int32_t timeout_us);
|
||||
bool is_event_done(struct event *e);
|
||||
// asserts if not done
|
||||
int32_t event_result(struct event *e);
|
||||
void event_set_callback(struct event *e, void (*callback)(struct event *e));
|
||||
void init_multi_event(struct event *target, struct event **events, uint event_count);
|
||||
|
||||
#define timeout_ms_result(f, timeout) ({ \
|
||||
struct event __event; \
|
||||
struct event *event = &__event; \
|
||||
(f); \
|
||||
event_result_timeout_ms(event, timeout); \
|
||||
})
|
||||
|
||||
#define blocking_result(f) timeout_ms_result(f, -1)
|
||||
#define on_complete(f, cb) ({ \
|
||||
static struct event __event; \
|
||||
struct event *event = &__event; \
|
||||
(f); \
|
||||
event_set_callback(event, my_callback); \
|
||||
})
|
||||
|
||||
void test2() {
|
||||
// just playing with blocking syntax
|
||||
struct event e;
|
||||
do_something(&e, 1, 1, "Hello");
|
||||
uint32_t result = event_result_timeout_ms(&e, -1);
|
||||
}
|
||||
|
||||
void test3() {
|
||||
uint32_t result = blocking_result(do_something(event, 1, 1, "Hello"));
|
||||
}
|
||||
|
||||
void test4() {
|
||||
struct event e;
|
||||
do_something(&e, 1, 1, "Hello");
|
||||
// this would poll (down to hardware if there is no asynchronous mechanism)
|
||||
while (!is_event_done(&e)) {
|
||||
puts("waiting");
|
||||
}
|
||||
int32_t result = event_result(&e);
|
||||
}
|
||||
|
||||
void my_callback(struct event *event) {
|
||||
puts("Its done");
|
||||
int32_t result = event_result(event);
|
||||
}
|
||||
|
||||
void test5() {
|
||||
static struct event e;
|
||||
do_something(&e, 1, 1, "Hello");
|
||||
event_set_callback(&e, my_callback);
|
||||
}
|
||||
|
||||
void test6() {
|
||||
on_complete(do_something(event, 1, 1, "Hello"), my_callback);
|
||||
}
|
||||
|
||||
static struct event e1;
|
||||
static struct event e2;
|
||||
static struct event *events[2] = {&e1, &e2};
|
||||
static struct event multi;
|
||||
|
||||
void test7() {
|
||||
init_multi_event(&multi,events, count_of(events));
|
||||
do_something(&e1, 1, 1, "Hello");
|
||||
do_something(&e2, 1, 3, "Hello");
|
||||
// something like this
|
||||
}
|
||||
|
||||
struct dimpl {
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
struct doodad {
|
||||
struct dimpl *type;
|
||||
uint32_t param;
|
||||
};
|
||||
|
||||
struct dimpl indefinite_waiter = {
|
||||
.type = 1
|
||||
};
|
||||
|
||||
extern struct dimpl INDEFINITE_WAIT;
|
||||
|
||||
struct dimpl ms_waiter = {
|
||||
.type = 1
|
||||
};
|
||||
|
||||
struct doodad blocking_with_timeout_ms(uint32_t ms) {
|
||||
struct doodad rc = {
|
||||
.type = &ms_waiter,
|
||||
.param = ms
|
||||
};
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct result {
|
||||
|
||||
};
|
||||
|
||||
struct result my_api_call(int arg, float x, struct doodad behavior) {
|
||||
|
||||
}
|
||||
#endif
|
4
test/pico_test/CMakeLists.txt
Normal file
4
test/pico_test/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
add_library(pico_test INTERFACE)
|
||||
|
||||
target_include_directories(pico_test INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_link_libraries(pico_test INTERFACE pico_stdlib)
|
61
test/pico_test/include/pico/test.h
Normal file
61
test/pico_test/include/pico/test.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_TEST_H
|
||||
#define _PICO_TEST_H
|
||||
|
||||
#include "pico.h"
|
||||
|
||||
/* Various macros to help with test harnesses
|
||||
|
||||
Note: really need to change the returns to exit()
|
||||
but not sure that is implemented yet.
|
||||
*/
|
||||
|
||||
#define PICOTEST_MODULE_NAME(n,d) const char *picotest_module=n; const char *picotest_description=d; int picotest_error_code;
|
||||
|
||||
#define PICOTEST_START() printf("Starting Picotest for %s\n", picotest_description);
|
||||
|
||||
#define PICOTEST_START_SECTION(NAME) if (1) {const char *picotest_section_name=NAME; picotest_error_code = 0;
|
||||
|
||||
#define PICOTEST_END_SECTION() if (picotest_error_code != 0) { \
|
||||
printf("Module %s: Section %s : Failed test\n", picotest_module, picotest_section_name);\
|
||||
return -1; \
|
||||
} else \
|
||||
printf("Module %s: Section %s : Passed\n", picotest_module, picotest_section_name); \
|
||||
}
|
||||
|
||||
#define PICOTEST_CHECK(COND, MESSAGE) if (!(COND)) { \
|
||||
printf("Module %s: %s\n", picotest_module, MESSAGE); \
|
||||
picotest_error_code = -1; \
|
||||
}
|
||||
#define PICOTEST_CHECK_CHANNEL(CHANNEL, COND, MESSAGE) if (!(COND)) { \
|
||||
printf("Module %s, channel %d: %s\n", picotest_module, CHANNEL, MESSAGE); \
|
||||
picotest_error_code = -1; \
|
||||
}
|
||||
|
||||
#define PICOTEST_CHECK_AND_ABORT(COND, MESSAGE) if (!(COND)) { \
|
||||
printf("Module %s: %s\n", picotest_module, MESSAGE); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define PICOTEST_CHECK_CHANNEL_AND_ABORT(CHANNEL, COND, MESSAGE) if (!(COND)) { \
|
||||
printf("Module %s, channel %d: %s\n", picotest_module, CHANNEL, MESSAGE); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define PICOTEST_ABORT_IF_FAILED() if (picotest_error_code != 0) { \
|
||||
printf("Module %s: Aborting\n", picotest_module); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define PICOTEST_END_TEST() if (picotest_error_code != 0) \
|
||||
{printf("%s: Failed\n", picotest_description); return -1;} \
|
||||
else \
|
||||
{printf("%s: Success\n", picotest_description); return 0;}
|
||||
|
||||
|
||||
#endif
|
8
test/pico_time_test/CMakeLists.txt
Normal file
8
test/pico_time_test/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
if (NOT PICO_TIME_NO_ALARM_SUPPORT)
|
||||
add_executable(pico_time_test pico_time_test.c)
|
||||
target_compile_definitions(pico_time_test PRIVATE
|
||||
PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS=250
|
||||
)
|
||||
target_link_libraries(pico_time_test PRIVATE pico_test)
|
||||
pico_add_extra_outputs(pico_time_test)
|
||||
endif()
|
211
test/pico_time_test/pico_time_test.c
Normal file
211
test/pico_time_test/pico_time_test.c
Normal file
@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hardware/sync.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/test.h"
|
||||
#include <inttypes.h>
|
||||
PICOTEST_MODULE_NAME("pico_time_test", "pico_time test harness");
|
||||
|
||||
#define NUM_TIMEOUTS 500
|
||||
#define MAX_TIMERS_PER_POOL 250
|
||||
static_assert(PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS >= MAX_TIMERS_PER_POOL, "");
|
||||
#define TEST_LENGTH_US 2000000
|
||||
|
||||
#define NUM_REPEATING_TIMERS 50
|
||||
static struct repeating_timer repeating_timers[NUM_REPEATING_TIMERS];
|
||||
static uint repeating_timer_callback_count[NUM_REPEATING_TIMERS];
|
||||
|
||||
static struct timeout {
|
||||
alarm_id_t alarm_id;
|
||||
absolute_time_t target;
|
||||
absolute_time_t fired_at;
|
||||
uint pool;
|
||||
uint fired_count;
|
||||
bool cancelled;
|
||||
bool not_cancelled; // tried to cancel but it was done
|
||||
} timeouts[NUM_TIMEOUTS];
|
||||
|
||||
int64_t timer_callback1(alarm_id_t id, void *user_data) {
|
||||
struct timeout *timeout = (struct timeout *)user_data;
|
||||
assert(timeout >= timeouts && timeout < (timeouts + NUM_TIMEOUTS));
|
||||
timeout->fired_at = get_absolute_time();
|
||||
timeout->fired_count++;
|
||||
// printf("%d %d %ld\n", timeout->pool, id, to_us_since_boot(timeout->target));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sort_by_target(const void *a, const void *b) {
|
||||
const struct timeout *ta = (const struct timeout *)a;
|
||||
const struct timeout *tb = (const struct timeout *)b;
|
||||
int64_t delta = absolute_time_diff_us(tb->target, ta->target);
|
||||
if (delta < 0) return -1;
|
||||
else if (delta > 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool repeating_timer_callback(struct repeating_timer *t) {
|
||||
// check we get the right timer structure
|
||||
uint i = (uintptr_t)t->user_data;
|
||||
hard_assert(i == (t - repeating_timers));
|
||||
repeating_timer_callback_count[i]++;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef PICO_HARDWARE_TIMER_RESOLUTION_US
|
||||
#define RESOLUTION_ALLOWANCE 0
|
||||
#else
|
||||
#define RESOLUTION_ALLOWANCE PICO_HARDWARE_TIMER_RESOLUTION_US
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
setup_default_uart();
|
||||
alarm_pool_init_default();
|
||||
|
||||
PICOTEST_START();
|
||||
|
||||
struct alarm_pool *pools[NUM_TIMERS];
|
||||
for(uint i=0; i<NUM_TIMERS; i++) {
|
||||
if (i == alarm_pool_hardware_alarm_num(alarm_pool_get_default())) {
|
||||
pools[i] = alarm_pool_get_default();
|
||||
} else {
|
||||
pools[i] = alarm_pool_create(i, MAX_TIMERS_PER_POOL);
|
||||
}
|
||||
PICOTEST_CHECK_AND_ABORT(pools[i], "failed to create timer pool");
|
||||
}
|
||||
|
||||
// Check default config has valid data in it
|
||||
PICOTEST_START_SECTION("Alarm ordering test");
|
||||
|
||||
absolute_time_t time_base = get_absolute_time();
|
||||
uint32_t init_ms = 1000;
|
||||
for(uint i = 0; i < NUM_TIMEOUTS; i++) {
|
||||
// printf("%d %p\n", i);
|
||||
absolute_time_t target;
|
||||
uint pool;
|
||||
if (1 == (i&127u)) {
|
||||
// want occasional duplicate time
|
||||
target = timeouts[i-1].target;
|
||||
pool = timeouts[i-1].pool;
|
||||
} else {
|
||||
target = delayed_by_us(time_base, init_ms + (rand() % TEST_LENGTH_US));
|
||||
pool = rand() % 4;
|
||||
}
|
||||
timeouts[i].target = target;
|
||||
timeouts[i].pool = pool;
|
||||
alarm_id_t id = alarm_pool_add_alarm_at(pools[pool], target, timer_callback1, timeouts + i, true);
|
||||
PICOTEST_CHECK_AND_ABORT(id >=0, "Failed to add timer");
|
||||
}
|
||||
PICOTEST_CHECK(absolute_time_diff_us(time_base, get_absolute_time()) < init_ms * 1000, "This is a flaky test :-(");
|
||||
|
||||
uint64_t last_fired_at[NUM_TIMERS];
|
||||
uint64_t last_target[NUM_TIMERS];
|
||||
memset(&last_fired_at, 0, sizeof(last_fired_at));
|
||||
printf("Sleeping...\n");
|
||||
sleep_us(TEST_LENGTH_US + 250000);
|
||||
printf(" ...done\n");
|
||||
|
||||
qsort(timeouts, NUM_TIMEOUTS, sizeof(struct timeout), sort_by_target);
|
||||
|
||||
uint64_t max_jitter = 0;
|
||||
for(uint i = 0; i < NUM_TIMEOUTS; i++) {
|
||||
printf("%d %d %"PRIi64" : %"PRIi64"\n", timeouts[i].pool, timeouts[i].fired_count, to_us_since_boot(timeouts[i].fired_at), to_us_since_boot(timeouts[i].target));
|
||||
PICOTEST_CHECK(timeouts[i].fired_count, "Timer should have fired");
|
||||
PICOTEST_CHECK(timeouts[i].fired_count < 2, "Timer should only have fired once");
|
||||
uint64_t fired_at = to_us_since_boot(timeouts[i].fired_at);
|
||||
PICOTEST_CHECK(timeouts[i].fired_count != 1 || fired_at >= MAX(RESOLUTION_ALLOWANCE,
|
||||
to_us_since_boot(timeouts[i].target)) - RESOLUTION_ALLOWANCE, "Timer fired early");
|
||||
// we need to be in order unless the targets are the same in which case order is arbitrary
|
||||
PICOTEST_CHECK(timeouts[i].fired_count != 1 || fired_at > MAX(RESOLUTION_ALLOWANCE, last_fired_at[timeouts[i].pool]) - RESOLUTION_ALLOWANCE ||
|
||||
to_us_since_boot(timeouts[i].target) == last_target[timeouts[i].pool], "Timer fired out of order");
|
||||
last_fired_at[timeouts[i].pool] = fired_at;
|
||||
last_target[timeouts[i].pool] = to_us_since_boot(timeouts[i].target);
|
||||
if (timeouts[i].fired_count == 1) {
|
||||
uint64_t jitter = absolute_time_diff_us(timeouts[i].target, timeouts[i].fired_at);
|
||||
if (jitter > max_jitter) {
|
||||
max_jitter = jitter;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("MAX JITTER: %dus\n", (uint)max_jitter);
|
||||
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("Alarm completion or canceled");
|
||||
memset(timeouts, 0, sizeof(timeouts));
|
||||
|
||||
absolute_time_t time_base = get_absolute_time();
|
||||
// this runs concurrently with the firing, so some are in the past
|
||||
uint approx_past_timeouts = 0;
|
||||
// uint32_t save = save_and_disable_interrupts();
|
||||
for(uint i = 0; i < NUM_TIMEOUTS; i++) {
|
||||
// printf("%d %p\n", i);
|
||||
absolute_time_t target = delayed_by_us(time_base, (rand() % TEST_LENGTH_US));
|
||||
if (absolute_time_diff_us(target, get_absolute_time()) >= 0) {
|
||||
approx_past_timeouts++;
|
||||
}
|
||||
uint pool = rand() % 4;
|
||||
timeouts[i].target = target;
|
||||
timeouts[i].pool = pool;
|
||||
alarm_id_t id = alarm_pool_add_alarm_at(pools[pool], target, timer_callback1, timeouts + i, true);
|
||||
timeouts[i].alarm_id = id;
|
||||
PICOTEST_CHECK_AND_ABORT(id >=0, "Failed to add timer");
|
||||
if (id && !(rand() & 6)) {
|
||||
uint j = rand() % (i + 1);
|
||||
if (timeouts[j].alarm_id && !timeouts[j].cancelled && !timeouts[j].not_cancelled) {
|
||||
// alarm_pool_dump(pools[pool]);
|
||||
// printf("removing %d\n", timeouts[j].alarm_id);
|
||||
if (alarm_pool_cancel_alarm(pools[timeouts[j].pool], timeouts[j].alarm_id)) {
|
||||
timeouts[j].cancelled = true;
|
||||
} else {
|
||||
timeouts[j].not_cancelled = true;
|
||||
}
|
||||
// printf("removed %d\n", timeouts[j].alarm_id);
|
||||
// alarm_pool_dump(pools[pool]);
|
||||
}
|
||||
}
|
||||
busy_wait_us_32(2000); // we want to overlap with the firing
|
||||
}
|
||||
printf("approx past timeouts %d/%d\n", approx_past_timeouts, NUM_TIMEOUTS);
|
||||
sleep_us(TEST_LENGTH_US - 2000 * NUM_TIMEOUTS / 4 + 250000);
|
||||
for(uint i = 0; i < NUM_TIMEOUTS/4; i++) {
|
||||
printf("%d %d %d/%d/%d %"PRIi64" : %"PRIi64"\n", timeouts[i].pool, (int)timeouts[i].alarm_id, timeouts[i].fired_count, timeouts[i].cancelled,
|
||||
timeouts[i].not_cancelled, to_us_since_boot(timeouts[i].fired_at), to_us_since_boot(timeouts[i].target));
|
||||
uint total = timeouts[i].fired_count + timeouts[i].cancelled;
|
||||
PICOTEST_CHECK( timeouts[i].not_cancelled ? timeouts[i].fired_count : true, "Timer that failed to cancel should have fired");
|
||||
PICOTEST_CHECK(total == 1, "Timer should have fired or been cancelled");
|
||||
}
|
||||
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("Repeating timertest");
|
||||
for(uint i=0;i<NUM_REPEATING_TIMERS;i++) {
|
||||
|
||||
add_repeating_timer_us(500+ (rand() & 1023), repeating_timer_callback, (void *)(uintptr_t)i, repeating_timers + i);
|
||||
}
|
||||
|
||||
sleep_ms(3000);
|
||||
uint callbacks = 0;
|
||||
for(uint i=0;i<NUM_REPEATING_TIMERS;i++) {
|
||||
PICOTEST_CHECK(cancel_repeating_timer(repeating_timers + i), "Cancelling repeating timer should succeed");
|
||||
PICOTEST_CHECK(repeating_timer_callback_count[i] > 1, "Each repeating timer should have been called back multiple times");
|
||||
callbacks += repeating_timer_callback_count[i];
|
||||
}
|
||||
uint callbacks2 = 0;
|
||||
for(uint i=0;i<NUM_REPEATING_TIMERS;i++) {
|
||||
PICOTEST_CHECK(!cancel_repeating_timer(repeating_timers + i), "Re-cancelling repeating timer should fail");
|
||||
callbacks2 += repeating_timer_callback_count[i];
|
||||
}
|
||||
PICOTEST_CHECK(callbacks == callbacks2, "No repeating timers should have been called back after being cancelled")
|
||||
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_END_TEST();
|
||||
}
|
||||
|
Reference in New Issue
Block a user