Files
retroSoC/tests/c/test_runtime.c
T

807 lines
31 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <ps2_keyboard.h>
#include <ps2_mouse.h>
#include <retrosoc/core/status.h>
#include <retrosoc/core/wait.h>
#include <retrosoc/hal/gpio.h>
#include <retrosoc/hal/dma.h>
#include <retrosoc/hal/i2c.h>
#include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/i2s.h>
#include <retrosoc/hal/psram.h>
#include <retrosoc/hal/sdram.h>
#include <retrosoc/hal/sdio.h>
#include <retrosoc/hal/spisd.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/hal/uart.h>
#include <retrosoc/hal/user_ip.h>
#include <retrosoc/hal/ws2812.h>
#include <retrosoc/lib/printf.h>
#include <retrosoc/lib/stdlib.h>
#include <retrosoc/lib/string.h>
#include <retrosoc/media/video_player.h>
#include <retrosoc/media/wav_audio.h>
#include "../../crt/src/hal/opipsram_math.c"
#define TEST_STORAGE_ADDRESS ((uintptr_t)0x1000U)
int __clzsi2(unsigned int value);
long long __divdi3(long long dividend, long long divisor);
int __ffssi2(unsigned int value);
unsigned long long __udivdi3(unsigned long long dividend, unsigned long long divisor);
unsigned long long __umoddi3(unsigned long long dividend, unsigned long long divisor);
static uint8_t storage[32];
static uint32_t image_call_count;
void putch(char ch) {
(void)ch;
}
void lcd_fill_image(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end,
uint32_t *data) {
(void)x_start;
(void)y_start;
(void)x_end;
(void)y_end;
(void)data;
++image_call_count;
}
rs_status_t rs_spisd_read_bytes(void *buffer, size_t byte_count, uintptr_t address) {
size_t offset;
if ((buffer == NULL) || (address < TEST_STORAGE_ADDRESS)) {
return RS_EINVAL;
}
offset = (size_t)(address - TEST_STORAGE_ADDRESS);
if (byte_count > (sizeof(storage) - offset)) {
return RS_EIO;
}
for (size_t index = 0U; index < byte_count; ++index) {
((uint8_t *)buffer)[index] = storage[offset + index];
}
return RS_OK;
}
static rs_status_t test_reader_read(void *context, uint32_t offset, void *buffer,
size_t byte_count) {
const uint8_t *bytes = context;
if ((bytes == NULL) || (buffer == NULL)) {
return RS_EINVAL;
}
for (size_t index = 0U; index < byte_count; ++index) {
((uint8_t *)buffer)[index] = bytes[offset + index];
}
return RS_OK;
}
static int test_string_helpers(void) {
char buffer[8] = {'x', '\0'};
int32_t value;
if (strncpy(buffer, "z", 0U) != buffer || buffer[0] != 'x') {
return 1;
}
if (strncmp("left", "right", 0U) != 0) {
return 2;
}
if (rs_strlcpy(buffer, "abcdefghi", sizeof(buffer)) != 9U || strcmp(buffer, "abcdefg") != 0) {
return 3;
}
if (rs_strlcat(buffer, "x", sizeof(buffer)) != 8U || strcmp(buffer, "abcdefg") != 0) {
return 4;
}
if (rs_strtoi32("-2147483648", &value) != RS_OK || value != INT32_MIN ||
rs_strtoi32("2147483648", &value) != RS_EFORMAT ||
rs_strtoi32("12x", &value) != RS_EFORMAT) {
return 5;
}
return 0;
}
static int test_formatter(void) {
char buffer[32];
if (rs_snprintf(buffer, sizeof(buffer), "%#08x:%lld:%zu", 0x2AU, -42LL, (size_t)7U) != 14 ||
strcmp(buffer, "0x00002a:-42:7") != 0) {
return 1;
}
if (rs_snprintf(buffer, 4U, "abcdef") != 6 || strcmp(buffer, "abc") != 0) {
return 2;
}
if (rs_snprintf(NULL, 0U, "value=%llu", UINT64_MAX) != 26) {
return 3;
}
if (rs_snprintf(buffer, sizeof(buffer), "%p", (void *)(uintptr_t)0x1234U) != 6 ||
strcmp(buffer, "0x1234") != 0) {
return 4;
}
return 0;
}
static int test_compiler_helpers(void) {
if ((__clzsi2(0U) != 32) || (__clzsi2(1U) != 31) || (__ffssi2(0U) != 0) ||
(__ffssi2(1U) != 1) || (__ffssi2(0x10U) != 5)) {
return 1;
}
if ((__udivdi3(UINT64_MAX, 3U) != 6148914691236517205ULL) ||
(__umoddi3(UINT64_MAX, 3U) != 0U) || (__udivdi3(UINT64_MAX, UINT64_MAX) != 1U) ||
(__umoddi3(100U, 7U) != 2U) || (__divdi3(-100LL, 7LL) != -14LL)) {
return 2;
}
return 0;
}
static int test_wait_helper(void) {
volatile uint32_t value = 0x30U;
if (rs_wait_mask(&value, 0x30U, 0x30U, 1U) != RS_OK ||
rs_wait_mask(&value, 0x40U, 0x40U, 1U) != RS_ETIMEOUT ||
rs_wait_mask(NULL, 1U, 1U, 1U) != RS_EINVAL || rs_wait_value(&value, 0x30U, 1U) != RS_OK ||
rs_wait_not_value(&value, 0U, 1U) != RS_OK ||
rs_wait_not_value(&value, 0x30U, 1U) != RS_ETIMEOUT) {
return 1;
}
return 0;
}
static int test_ws2812_helpers(void) {
const rs_ws2812_config_t config = {
72000000U,
RS_WS2812_DEFAULT_BIT_PERIOD_NS,
RS_WS2812_DEFAULT_T0H_NS,
RS_WS2812_DEFAULT_T1H_NS,
RS_WS2812_DEFAULT_RESET_NS,
4U,
};
rs_ws2812_config_t invalid = config;
rs_ws2812_timing_t timing;
if ((rs_ws2812_pack_grb(0x12U, 0x34U, 0x56U) != UINT32_C(0x341256)) ||
(rs_ws2812_timing_from_ns(&config, &timing) != RS_OK) || (timing.bit_cycles != 90U) ||
(timing.t0h_cycles != 25U) || (timing.t1h_cycles != 50U) ||
(timing.reset_cycles != 21600U)) {
return 1;
}
invalid.t0h_ns = invalid.t1h_ns;
if ((rs_ws2812_timing_from_ns(&invalid, &timing) != RS_EINVAL) ||
(rs_ws2812_timing_from_ns(NULL, &timing) != RS_EINVAL) ||
(rs_ws2812_timing_from_ns(&config, NULL) != RS_EINVAL)) {
return 2;
}
invalid = config;
invalid.source_clock_hz = 1U;
if (rs_ws2812_timing_from_ns(&invalid, &timing) != RS_EINVAL) {
return 3;
}
return 0;
}
static int test_timer_helpers(void) {
rs_timer_period_t period;
if ((rs_timer_period_from_ms(72000000U, 1U, &period) != RS_OK) || (period.prescale != 0U) ||
(period.load != 71999U)) {
return 1;
}
if ((rs_timer_period_from_ms(72000000U, 1000U, &period) != RS_OK) || (period.prescale != 0U) ||
(period.load != 71999999U)) {
return 2;
}
if ((rs_timer_period_from_ms(0U, 1U, &period) != RS_EINVAL) ||
(rs_timer_period_from_ms(72000000U, 0U, &period) != RS_EINVAL) ||
(rs_timer_period_from_ms(72000000U, 1U, NULL) != RS_EINVAL) ||
(rs_timer_period_from_ms(UINT32_MAX, UINT32_MAX, &period) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_i2s_helpers(void) {
uint8_t sclk_div;
uint8_t lrck_div;
uint16_t first;
uint16_t second;
if (rs_i2s_pack_stereo16(0x1111U, 0x2222U) != UINT32_C(0x22221111))
return 1;
rs_i2s_unpack_stereo16(UINT32_C(0x22221111), &first, &second);
if ((first != 0x1111U) || (second != 0x2222U))
return 2;
if ((rs_i2s_div_from_hz(18432000U, 48000U, 16U, &sclk_div, &lrck_div) != RS_OK) ||
(sclk_div != 5U) || (lrck_div != 15U))
return 3;
if ((rs_i2s_div_from_hz(18432000U, 96000U, 24U, &sclk_div, &lrck_div) != RS_OK) ||
(sclk_div != 1U) || (lrck_div != 23U))
return 4;
if ((rs_i2s_rxdata_address() - rs_i2s_txdata_address()) != (uintptr_t)4U)
return 6;
if ((rs_i2s_div_from_hz(0U, 48000U, 16U, &sclk_div, &lrck_div) != RS_EINVAL) ||
(rs_i2s_div_from_hz(18432000U, 48000U, 20U, &sclk_div, &lrck_div) != RS_EINVAL) ||
(rs_i2s_div_from_hz(18432000U, 48000U, 16U, NULL, &lrck_div) != RS_EINVAL))
return 5;
return 0;
}
static int test_sdram_helpers(void) {
rs_sdram_timing_t timing;
if ((rs_sdram_timing_from_hz(72000000U, 0U, &timing) != RS_OK) || (timing.trp_cycles != 1U) ||
(timing.trcd_cycles != 1U) || (timing.tras_cycles != 2U) || (timing.trc_cycles != 3U) ||
(timing.twr_cycles != 1U) || (timing.trfc_cycles != 3U) || (timing.trrd_cycles != 2U) ||
(timing.twtr_cycles != 2U) || (timing.trtp_cycles != 1U) || (timing.tmrd_cycles != 2U) ||
(timing.txsr_cycles != 3U) || (timing.trefi_cycles != 281U) ||
(timing.powerup_cycles != 3600U) || (timing.actual_sdram_hz != 36000000U)) {
return 1;
}
if ((rs_sdram_timing_from_hz(0U, 0U, &timing) != RS_EINVAL) ||
(rs_sdram_timing_from_hz(72000000U, 4U, &timing) != RS_EINVAL) ||
(rs_sdram_timing_from_hz(72000000U, 0U, NULL) != RS_EINVAL)) {
return 2;
}
return 0;
}
static int test_psram_helpers(void) {
rs_psram_timing_t timing;
if ((rs_psram_timing_from_hz(72000000U, 36000000U, &timing) != RS_OK) ||
(timing.half_period_cycles != 1U) || (timing.cs_setup_cycles != 1U) ||
(timing.cs_high_cycles != 4U) || (timing.cs_hold_cycles != 3U) ||
(timing.powerup_cycles != 10800U) || (timing.cs_max_low_cycles != 576U) ||
(timing.actual_sclk_hz != 36000000U) || timing.above_84mhz) {
return 1;
}
if ((rs_psram_timing_from_hz(192000000U, 133000000U, &timing) != RS_OK) ||
(timing.half_period_cycles != 1U) || (timing.actual_sclk_hz != 96000000U) ||
!timing.above_84mhz) {
return 2;
}
if ((rs_psram_timing_from_hz(0U, 36000000U, &timing) != RS_EINVAL) ||
(rs_psram_timing_from_hz(72000000U, 0U, &timing) != RS_EINVAL) ||
(rs_psram_timing_from_hz(72000000U, 134000000U, &timing) != RS_EINVAL) ||
(rs_psram_timing_from_hz(72000000U, 36000000U, NULL) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_opipsram_helpers(void) {
rs_opipsram_config_t config = {
.profile = RS_OPIPSRAM_PROFILE_OPI,
.device_size = UINT32_C(0x00800000),
.timing =
{
.divider = 1U,
.phy_ratio = 2U,
.source_clock_hz = 72000000U,
.requested_ck_hz = 36000000U,
.actual_phy_hz = 72000000U,
.actual_ck_hz = 36000000U,
.cs_setup_cycles = 1U,
.cs_hold_cycles = 2U,
.cs_high_cycles = 4U,
.powerup_cycles = 10800U,
.timeout_cycles = 720000U,
},
.opi =
{
.read_command = UINT16_C(0xEE11),
.write_command = UINT16_C(0x12ED),
.register_read_command = UINT16_C(0),
.register_write_command = UINT16_C(0),
.command_width = RS_OPIPSRAM_COMMAND_WIDTH_16,
.address_width = RS_OPIPSRAM_ADDRESS_WIDTH_32,
.dummy_cycles = 8U,
.latency_cycles = 6U,
.dqs_policy = RS_OPIPSRAM_DQS_READ_WRITE,
.burst_boundary = 32U,
},
.hyperbus =
{
.initial_latency = 6U,
.additional_latency = 2U,
.read_recovery_cycles = 4U,
.write_recovery_cycles = 4U,
.rwds_additional_latency = true,
},
.enable = true,
.memory_enable = true,
.auto_initialize = false,
.line_buffer = true,
};
rs_opipsram_timing_t timing;
rs_opipsram_training_window_t window;
rs_dma_config_t dma_config;
rs_opipsram_indirect_t indirect = {
.write = false,
.register_space = false,
.length = 8U,
.address = UINT32_C(0x007FFFF8),
.write_data = UINT64_C(0),
};
if ((RS_OPIPSRAM_CMD_WIDTH_SHIFT != UINT32_C(16)) ||
(RS_OPIPSRAM_CMD_WIDTH_MASK != UINT32_C(0x00010000)) ||
(RS_OPIPSRAM_OPI_TIMING_ADDR_BYTES_MASK != UINT32_C(0x00000003)) ||
(RS_OPIPSRAM_OPI_TIMING_DUMMY_SHIFT != UINT32_C(2)) ||
(RS_OPIPSRAM_OPI_TIMING_DUMMY_MASK != UINT32_C(0x000003FC)) ||
(RS_OPIPSRAM_OPI_TIMING_LATENCY_SHIFT != UINT32_C(10)) ||
(RS_OPIPSRAM_OPI_TIMING_LATENCY_MASK != UINT32_C(0x00007C00)) ||
(RS_OPIPSRAM_OPI_TIMING_DQS_READ != UINT32_C(0x00008000)) ||
(RS_OPIPSRAM_OPI_TIMING_DQS_WRITE != UINT32_C(0x00010000)) ||
(RS_OPIPSRAM_HYPER_TIMING_RWDS_LATENCY_ENABLE != UINT32_C(0x80000000)) ||
(RS_OPIPSRAM_CLK_PHY_RATIO_MASK != UINT32_C(0x00010000)) ||
(RS_OPIPSRAM_CLK_PHY_RATIO_2X != UINT32_C(0x00010000)) ||
(RS_OPIPSRAM_PROFILE_STATUS_LOCKED != UINT32_C(0x00000002)) ||
(RS_OPIPSRAM_PROFILE_STATUS_VALID != UINT32_C(0x00000004)) ||
(RS_OPIPSRAM_PROFILE_STATUS_ERROR_MASK != UINT32_C(0x00000008))) {
return 1;
}
if ((rs_opipsram_timing_from_hz(72000000U, 36000000U, &timing) != RS_OK) ||
(timing.divider != 1U) || (timing.phy_ratio != 2U) || (timing.actual_phy_hz != 72000000U) ||
(timing.actual_ck_hz != 36000000U) || (timing.powerup_cycles != 10800U)) {
return 2;
}
if ((rs_opipsram_timing_from_hz(144000000U, 72000000U, &timing) != RS_OK) ||
(timing.actual_ck_hz != 72000000U) ||
(rs_opipsram_timing_from_hz(200000000U, 100000000U, &timing) != RS_OK) ||
(timing.actual_ck_hz != 100000000U)) {
return 3;
}
if ((rs_opipsram_timing_from_hz(192000000U, 48000000U, &timing) != RS_OK) ||
(timing.divider != 2U) || (timing.actual_phy_hz != 96000000U) ||
(timing.actual_ck_hz != 48000000U) ||
(rs_opipsram_timing_from_hz(UINT32_MAX, 36000000U, &timing) != RS_EINVAL)) {
return 4;
}
if ((rs_opipsram_timing_from_hz(0U, 36000000U, &timing) != RS_EINVAL) ||
(rs_opipsram_timing_from_hz(72000000U, 0U, &timing) != RS_EINVAL) ||
(rs_opipsram_timing_from_hz(72000000U, 35999999U, &timing) != RS_EINVAL) ||
(rs_opipsram_timing_from_hz(72000000U, 100000001U, &timing) != RS_EINVAL) ||
(rs_opipsram_timing_from_hz(72000000U, 36000000U, NULL) != RS_EINVAL)) {
return 5;
}
if (rs_opipsram_config_validate(&config) != RS_OK) {
return 6;
}
config.device_size = UINT32_C(0x00600000);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 7;
}
config.device_size = RS_OPIPSRAM_MAX_DEVICE_SIZE + UINT32_C(1);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 8;
}
config.device_size = UINT32_C(0x00800000);
config.opi.address_width = (rs_opipsram_address_width_t)5U;
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 9;
}
config.opi.address_width = RS_OPIPSRAM_ADDRESS_WIDTH_32;
config.opi.dummy_cycles = RS_OPIPSRAM_MAX_DUMMY_CYCLES + UINT8_C(1);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 10;
}
config.opi.dummy_cycles = 8U;
config.opi.latency_cycles = RS_OPIPSRAM_MAX_LATENCY_CYCLES + UINT8_C(1);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 11;
}
config.opi.latency_cycles = 6U;
config.profile = RS_OPIPSRAM_PROFILE_HYPERBUS;
config.hyperbus.initial_latency = RS_OPIPSRAM_MAX_LATENCY_CYCLES + UINT8_C(1);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 12;
}
config.hyperbus.initial_latency = 6U;
config.hyperbus.write_recovery_cycles = UINT8_C(128);
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 13;
}
config.hyperbus.write_recovery_cycles = 4U;
config.profile = RS_OPIPSRAM_PROFILE_OPI;
config.timing.timeout_cycles = config.timing.powerup_cycles;
if (rs_opipsram_config_validate(&config) != RS_EINVAL) {
return 14;
}
if ((rs_opipsram_training_window_from_mask(UINT32_C(0xC3), 8U, &window) != RS_OK) ||
!window.valid || !window.wrapped || (window.first != 6U) || (window.last != 1U) ||
(window.width != 4U) || (window.center != 0U)) {
return 15;
}
if ((rs_opipsram_training_window_from_mask(UINT32_C(0), 8U, &window) != RS_OK) ||
window.valid || (window.width != 0U)) {
return 16;
}
if ((rs_opipsram_training_window_from_mask(UINT32_C(0x0E), 8U, &window) != RS_OK) ||
!window.valid || window.wrapped || (window.first != 1U) || (window.last != 3U) ||
(window.width != 3U) || (window.center != 2U)) {
return 17;
}
if ((rs_opipsram_training_window_from_mask(UINT32_C(0x01), 0U, &window) != RS_EINVAL) ||
(rs_opipsram_training_window_from_mask(UINT32_C(0x01), 33U, &window) != RS_EINVAL)) {
return 18;
}
if ((rs_opipsram_dma_copy_validate(RS_DMA_CHANNEL_BULK, (uintptr_t)0x40001000U,
(uintptr_t)RS_SOC_OPIPSRAM_BASE, 64U, 1U, 8U,
&dma_config) != RS_OK) ||
(dma_config.kind != RS_DMA_KIND_MM_TO_MM) ||
(dma_config.request != RS_DMA_REQUEST_SOFTWARE)) {
return 19;
}
if (rs_opipsram_dma_copy_validate(RS_DMA_CHANNEL_BULK, (uintptr_t)0x40001002U,
(uintptr_t)RS_SOC_OPIPSRAM_BASE, 64U, 1U, 8U,
&dma_config) != RS_EINVAL) {
return 20;
}
if (rs_opipsram_indirect_validate(&indirect, UINT32_C(0x00800000)) != RS_OK) {
return 21;
}
indirect.address = UINT32_C(0x007FFFF9);
if (rs_opipsram_indirect_validate(&indirect, UINT32_C(0x00800000)) != RS_EINVAL) {
return 22;
}
indirect.register_space = true;
indirect.address = UINT32_MAX;
if (rs_opipsram_indirect_validate(&indirect, UINT32_C(0)) != RS_EINVAL) {
return 23;
}
indirect.address = UINT32_C(0x00FFFFFF);
if (rs_opipsram_indirect_validate(&indirect, UINT32_C(0)) != RS_OK) {
return 24;
}
return 0;
}
static int test_uart_helpers(void) {
rs_uart_timing_t timing;
if ((rs_uart_timing_calculate(72000000U, 921600U, &timing) != RS_OK) ||
(timing.baud_integer != 78U) || (timing.baud_fraction != 32U)) {
return 1;
}
if ((rs_uart_timing_calculate(16000000U, 1000000U, &timing) != RS_OK) ||
(timing.baud_integer != 16U) || (timing.baud_fraction != 0U)) {
return 2;
}
if ((rs_uart_timing_calculate(0U, 115200U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(72000000U, 0U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(1000000U, 1000000U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(72000000U, 115200U, NULL) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_i2c_helpers(void) {
rs_i2c_timing_t timing;
if ((rs_i2c_timing_calculate(72000000U, 400000U, &timing) != RS_OK) ||
(timing.scl_low_cycles != 136U) || (timing.scl_high_cycles != 44U) ||
(timing.start_hold_cycles != 44U) || (timing.start_setup_cycles != 44U) ||
(timing.data_setup_cycles != 8U) || (timing.stop_setup_cycles != 44U) ||
(timing.bus_free_cycles != 94U)) {
return 1;
}
if ((rs_i2c_timing_calculate(72000000U, 1000000U, &timing) != RS_OK) ||
(timing.scl_low_cycles != 53U) || (timing.scl_high_cycles != 19U) ||
(timing.data_setup_cycles != 4U)) {
return 2;
}
if ((rs_i2c_timing_calculate(0U, 400000U, &timing) != RS_EINVAL) ||
(rs_i2c_timing_calculate(72000000U, 0U, &timing) != RS_EINVAL) ||
(rs_i2c_timing_calculate(72000000U, 1000001U, &timing) != RS_EINVAL) ||
(rs_i2c_timing_calculate(72000000U, 400000U, NULL) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_sdio_helpers(void) {
rs_sdio_clock_t clock;
rs_sdio_response_t csd = {{0U, 0U, 0U, 0U, 0U}};
rs_sdio_cmd52_t cmd52 = {
.function = 2U,
.address = UINT32_C(0x123),
.write = true,
.raw = false,
.data = UINT8_C(0xA5),
};
rs_sdio_cmd53_t cmd53 = {
.function = 1U,
.address = UINT32_C(0x100),
.count = UINT16_C(512),
.write = true,
.block_mode = true,
.fixed_address = false,
};
rs_sdio_descriptor_t descriptor;
rs_sd_memory_info_t info = {0};
uint32_t value;
if ((rs_sdio_clock_calculate(72000000U, 400000U, &clock) != RS_OK) ||
(clock.half_period != 90U) || (clock.actual_hz != 400000U) ||
(rs_sdio_clock_calculate(100000000U, 50000000U, &clock) != RS_OK) ||
(clock.half_period != 1U) || (clock.actual_hz != 50000000U)) {
return 1;
}
if ((rs_sdio_clock_calculate(0U, 400000U, &clock) != RS_EINVAL) ||
(rs_sdio_clock_calculate(72000000U, 0U, &clock) != RS_EINVAL) ||
(rs_sdio_clock_calculate(72000000U, 40000001U, &clock) != RS_EINVAL) ||
(rs_sdio_clock_calculate(72000000U, 400000U, NULL) != RS_EINVAL)) {
return 2;
}
if ((rs_sd_memory_address(RS_SD_MEMORY_SDSC, 2U, &value) != RS_OK) || (value != 1024U) ||
(rs_sd_memory_address(RS_SD_MEMORY_SDHC, 2U, &value) != RS_OK) || (value != 2U) ||
(rs_sdio_cmd52_argument(&cmd52, &value) != RS_OK) || (value != UINT32_C(0xA00246A5)) ||
(rs_sdio_cmd53_argument(&cmd53, &value) != RS_OK) || (value != UINT32_C(0x9C020000))) {
return 3;
}
if ((rs_sdio_validate_dma_buffer((const void *)(uintptr_t)UINT32_C(0x40000000), 4U) != RS_OK) ||
(rs_sdio_validate_dma_buffer((const void *)(uintptr_t)UINT32_C(0x40000002), 4U) !=
RS_EINVAL) ||
(rs_sdio_descriptor_prepare(&descriptor, (uintptr_t)UINT32_C(0x40000000), 64U,
(uintptr_t)0U, true, true) != RS_OK) ||
(rs_sdio_descriptor_validate(&descriptor) != RS_OK) ||
(rs_sdio_descriptor_publish(&descriptor) != RS_OK) ||
((descriptor.control_status & (UINT32_C(1) << RS_SDIO_DESC_OWN_BIT)) == 0U)) {
return 4;
}
if (rs_sdio_descriptor_prepare(&descriptor, (uintptr_t)UINT32_C(0x40000000), 64U,
(uintptr_t)UINT32_C(0x40000FF0), false, false) != RS_EINVAL) {
return 5;
}
descriptor.buffer_addr = UINT32_C(0x40000000);
descriptor.byte_count = 64U;
descriptor.next_addr = UINT32_C(0x40000FF0);
descriptor.control_status = UINT32_C(0x00000003);
if (rs_sdio_descriptor_validate(&descriptor) != RS_EINVAL) {
return 6;
}
for (uint32_t bit = 48U; bit <= 69U; bit++) {
if (((UINT32_C(0x3FF) >> (bit - 48U)) & 1U) != 0U) {
csd.words[bit / 32U] |= UINT32_C(1) << (bit % 32U);
}
}
csd.words[3] |= UINT32_C(1) << (126U - 96U);
if ((rs_sd_memory_parse_csd(&csd, &info) != RS_OK) || (info.card_type != RS_SD_MEMORY_SDHC) ||
(info.capacity_blocks != UINT32_C(0x100000)) ||
(info.block_length != RS_SD_MEMORY_BLOCK_SIZE)) {
return 5;
}
return 0;
}
static int test_spisd_helpers(void) {
rs_spisd_clock_t clock;
rs_spisd_card_info_t info = {0};
rs_spisd_descriptor_t descriptor;
uint8_t csd_v2[16] = {0};
uint8_t csd_v1[16] = {0};
uint32_t argument;
if ((rs_spisd_clock_calculate(72000000U, 400000U, &clock) != RS_OK) ||
(clock.half_period != 90U) || (clock.actual_hz != 400000U) ||
(rs_spisd_clock_calculate(72000000U, 36000000U, &clock) != RS_OK) ||
(clock.half_period != 1U) || (clock.actual_hz != 36000000U)) {
return 1;
}
if ((rs_spisd_clock_calculate(0U, 400000U, &clock) != RS_EINVAL) ||
(rs_spisd_clock_calculate(72000000U, 36000001U, &clock) != RS_EINVAL) ||
(rs_spisd_clock_calculate(72000000U, 400000U, NULL) != RS_EINVAL)) {
return 2;
}
if ((rs_spisd_card_address(RS_SPISD_CARD_SDSC, 2U, &argument) != RS_OK) ||
(argument != 1024U) ||
(rs_spisd_card_address(RS_SPISD_CARD_SDHC, 2U, &argument) != RS_OK) || (argument != 2U) ||
(rs_spisd_card_address((rs_spisd_card_type_t)2U, 0U, &argument) != RS_EINVAL)) {
return 3;
}
csd_v2[0] = UINT8_C(0x40);
csd_v2[8] = UINT8_C(0x03);
csd_v2[9] = UINT8_C(0xFF);
if ((rs_spisd_parse_csd(csd_v2, &info) != RS_OK) || !info.high_capacity ||
(info.card_type != RS_SPISD_CARD_SDHC) || (info.capacity_blocks != UINT32_C(0x00100000))) {
return 4;
}
csd_v1[5] = UINT8_C(9);
csd_v1[7] = UINT8_C(0xFF);
csd_v1[8] = UINT8_C(0xC0);
csd_v1[9] = UINT8_C(0x03);
csd_v1[10] = UINT8_C(0x80);
if ((rs_spisd_parse_csd(csd_v1, &info) != RS_OK) || info.high_capacity ||
(info.card_type != RS_SPISD_CARD_SDSC) || (info.capacity_blocks != UINT32_C(0x00080000))) {
return 5;
}
if ((rs_spisd_descriptor_prepare(&descriptor, (uintptr_t)UINT32_C(0x40000000), 64U,
(uintptr_t)0U, true, true) != RS_OK) ||
(rs_spisd_descriptor_validate(&descriptor) != RS_OK) ||
(rs_spisd_descriptor_publish(&descriptor) != RS_OK) ||
((descriptor.control_status & RS_SPISD_DESC_OWN) == 0U)) {
return 6;
}
if ((rs_spisd_descriptor_prepare(&descriptor, (uintptr_t)UINT32_C(0x40000002), 64U,
(uintptr_t)0U, true, false) != RS_EINVAL) ||
(rs_spisd_descriptor_prepare(&descriptor, (uintptr_t)UINT32_C(0x40000000), 64U,
(uintptr_t)UINT32_C(0x40000FF0), false, false) != RS_EINVAL)) {
return 7;
}
return 0;
}
static int test_gpio_helpers(void) {
rs_gpio_filter_timing_t timing;
if ((rs_gpio_filter_timing_from_us(72000000U, 2U, 3U, &timing) != RS_OK) ||
(timing.divider != 143U) || (timing.stable_samples != 3U)) {
return 1;
}
if ((rs_gpio_filter_timing_from_us(1U, 1U, 1U, &timing) != RS_OK) || (timing.divider != 0U)) {
return 2;
}
if ((rs_gpio_filter_timing_from_us(0U, 1U, 1U, &timing) != RS_EINVAL) ||
(rs_gpio_filter_timing_from_us(72000000U, 0U, 1U, &timing) != RS_EINVAL) ||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 0U, &timing) != RS_EINVAL) ||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 16U, &timing) != RS_EINVAL) ||
(rs_gpio_filter_timing_from_us(72000000U, 1000U, 3U, &timing) != RS_EINVAL) ||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 3U, NULL) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_dma_config_validation(void) {
rs_dma_config_t config = {
.kind = RS_DMA_KIND_MM_TO_MM,
.request = RS_DMA_REQUEST_SOFTWARE,
.source = (uintptr_t)UINT32_C(0x40000000),
.destination = (uintptr_t)UINT32_C(0x41000000),
.byte_count = 64U,
.width = RS_DMA_WIDTH_32,
.source_increment = true,
.destination_increment = true,
.priority = 1U,
.burst_beats = RS_DMA_MAX_BURST_BEATS,
};
if (rs_dma_config_validate(RS_DMA_CHANNEL_BULK, &config) != RS_OK) {
return 1;
}
config.width = RS_DMA_WIDTH_16;
if (rs_dma_config_validate(RS_DMA_CHANNEL_BULK, &config) != RS_EINVAL) {
return 2;
}
config.width = RS_DMA_WIDTH_32;
config.byte_count = 6U;
if (rs_dma_config_validate(RS_DMA_CHANNEL_BULK, &config) != RS_EINVAL) {
return 3;
}
config.byte_count = 64U;
config.kind = RS_DMA_KIND_MM_TO_STREAM;
config.request = RS_DMA_REQUEST_I2S_TX;
config.destination = (uintptr_t)0U;
if (rs_dma_config_validate(RS_DMA_CHANNEL_BULK, &config) != RS_OK) {
return 4;
}
config.source_increment = false;
if (rs_dma_config_validate(RS_DMA_CHANNEL_BULK, &config) != RS_EINVAL) {
return 5;
}
return 0;
}
static int test_user_ip_validation(void) {
uint32_t value;
if ((rs_user_ip_get_selected(NULL) != RS_EINVAL) ||
(rs_user_ip_select(UINT8_MAX) != RS_EINVAL) ||
(rs_user_ip_probe(UINT8_MAX, &value) != RS_EINVAL) ||
(rs_user_ip_probe(0U, NULL) != RS_EINVAL)) {
return 1;
}
if ((rs_user_ip_read(0U, NULL) != RS_EINVAL) || (rs_user_ip_read(1U, &value) != RS_EINVAL) ||
(rs_user_ip_read(UINT32_C(0x1000), &value) != RS_EINVAL)) {
return 2;
}
if ((rs_user_ip_write(2U, 0U) != RS_EINVAL) ||
(rs_user_ip_write(UINT32_C(0x1000), 0U) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_ps2_decoders(void) {
ps2_keyboard_decoder_t keyboard;
ps2_mouse_decoder_t mouse;
ps2_key_event_t key_event;
ps2_mouse_event_t mouse_event;
ps2_keyboard_decoder_init(&keyboard);
if (!ps2_keyboard_decode_byte(&keyboard, UINT8_C(0x1C), &key_event) || !key_event.pressed ||
key_event.extended || (key_event.scan_code != UINT16_C(0x001C))) {
return 1;
}
if (ps2_keyboard_decode_byte(&keyboard, UINT8_C(0xE0), &key_event) ||
ps2_keyboard_decode_byte(&keyboard, UINT8_C(0xF0), &key_event) ||
!ps2_keyboard_decode_byte(&keyboard, UINT8_C(0x75), &key_event) || key_event.pressed ||
!key_event.extended || (key_event.scan_code != UINT16_C(0xE075))) {
return 2;
}
ps2_mouse_decoder_init(&mouse, UINT8_C(4));
if (ps2_mouse_decode_byte(&mouse, UINT8_C(0x08), &mouse_event) ||
ps2_mouse_decode_byte(&mouse, UINT8_C(0x02), &mouse_event) ||
ps2_mouse_decode_byte(&mouse, UINT8_C(0x01), &mouse_event) ||
!ps2_mouse_decode_byte(&mouse, UINT8_C(0x3F), &mouse_event) || (mouse_event.dx != 2) ||
(mouse_event.dy != 1) || (mouse_event.wheel != -1) ||
((mouse_event.buttons & UINT8_C(0x18)) != UINT8_C(0x18))) {
return 3;
}
return 0;
}
static int test_wav_parser(void) {
static const uint8_t wav[] = {
'R', 'I', 'F', 'F', 40U, 0U, 0U, 0U, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
16U, 0U, 0U, 0U, 1U, 0U, 1U, 0U, 0x40U, 0x1FU, 0U, 0U, 0x80U, 0x3EU, 0U, 0U,
2U, 0U, 16U, 0U, 'd', 'a', 't', 'a', 4U, 0U, 0U, 0U, 0U, 1U, 2U, 3U,
};
rs_wav_info_t info;
const rs_wav_reader_t reader = {test_reader_read, (void *)wav, sizeof(wav)};
if (rs_wav_parse(&reader, &info) != RS_OK || info.sample_rate != 8000U ||
info.block_align != 2U || info.data_offset != 44U || info.data_size != 4U) {
return 1;
}
if (rs_wav_parse(&(rs_wav_reader_t){test_reader_read, (void *)wav, 12U}, &info) != RS_EFORMAT) {
return 2;
}
return 0;
}
static int test_video_parser(void) {
rs_video_info_t info;
(void)memset(storage, 0, sizeof(storage));
storage[0] = 2U;
storage[4] = 2U;
storage[8] = 1U;
if (rs_video_parse(storage, 24U, &info) != RS_OK || info.frame_size != 8U ||
rs_video_parse(storage, 16U, &info) != RS_EFORMAT) {
return 1;
}
image_call_count = 0U;
if (rs_video_show_spisd(TEST_STORAGE_ADDRESS, 24U) != RS_OK || image_call_count != 1U) {
return 2;
}
return 0;
}
int main(void) {
const int results[] = {
test_string_helpers(), test_formatter(), test_compiler_helpers(),
test_wait_helper(), test_ws2812_helpers(), test_timer_helpers(),
test_psram_helpers(), test_sdram_helpers(), test_uart_helpers(),
test_i2s_helpers(), test_i2c_helpers(), test_sdio_helpers(),
test_spisd_helpers(), test_gpio_helpers(), test_dma_config_validation(),
test_opipsram_helpers(), test_user_ip_validation(), test_ps2_decoders(),
test_wav_parser(), test_video_parser(),
};
for (size_t index = 0U; index < (sizeof(results) / sizeof(results[0])); ++index) {
if (results[index] != 0) {
return (int)(index + 1U);
}
}
return 0;
}