Raw File
test.c
#include <hal.h>
#include <randombytes.h>
#include <sendfn.h>
#include <stdint.h>

#if defined(SRAM_TIMING_TEST)
#define TEST_BLOCK_SIZE 4096

/* Don't use opencm3 here, since not all platforms might use opencm3, but all
   have these DWT registers */
#define DWT_CTRL           (*(volatile uint32_t*)(0xE0001000u + 0x00))
#define DWT_CYCCNT         (*(volatile uint32_t*)(0xE0001000u + 0x04))
#define DWT_CTRL_CYCCNTENA (1 << 0)
#define SCS_DEMCR          (*(volatile uint32_t*)(0xE000E000u + 0xDFC))
#define SCS_DEMCR_TRCENA   (1 << 24)
/* Need a really precise cycle counter. */
static void cyccnt_enable()
{
	SCS_DEMCR |= SCS_DEMCR_TRCENA;
	DWT_CYCCNT = 0;
	DWT_CTRL |= DWT_CTRL_CYCCNTENA;
}
static inline void cyccnt_start()
{
	DWT_CYCCNT = 0;
}
static inline uint32_t cyccnt_get()
{
  return DWT_CYCCNT;
}

__attribute__((noinline))
static uint32_t test_load(volatile unsigned* ram_block)
{
  asm volatile("cpsid if");
  cyccnt_start();
#define NL "\n\t"
  asm volatile("_MEMLOOP%=:" NL
               "ldr r12, [%0], #4" NL
               "cmp %0, %1" NL
               "bne _MEMLOOP%=" NL
               :"+r" (ram_block): "r" (ram_block + (TEST_BLOCK_SIZE / sizeof(unsigned))): "r12", "cc");
  uint32_t result = cyccnt_get();
  asm volatile("cpsie if");
  return result;
}

__attribute__((noinline))
static uint32_t test_unalignedload(volatile void* ram_block)
{
  volatile unsigned char* ram_block8 = ram_block;
  ram_block8 += 2;
  asm volatile("cpsid if");
  cyccnt_start();
#define NL "\n\t"
  asm volatile("_MEMLOOP%=:" NL
               "ldr r12, [%0], #4" NL
               "cmp %0, %1" NL
               "blt _MEMLOOP%=" NL
               :"+r" (ram_block8): "r" (ram_block8 + TEST_BLOCK_SIZE): "r12", "cc");
  uint32_t result = cyccnt_get();
  asm volatile("cpsie if");
  return result;
}

__attribute__((noinline))
static uint32_t test_store(volatile unsigned* ram_block)
{
  cyccnt_start();
#define NL "\n\t"
  asm volatile("_MEMLOOP%=:" NL
               "str r12, [%0], #4" NL
               "cmp %0, %1" NL
               "bne _MEMLOOP%=" NL
               :"+r" (ram_block): "r" (ram_block + (TEST_BLOCK_SIZE / sizeof(unsigned))): "r12", "cc");
  return cyccnt_get();
}

__attribute__((noinline))
static uint32_t test_loadstore(volatile unsigned* ram_block)
{
  cyccnt_start();
#define NL "\n\t"
  asm volatile("_MEMLOOP%=:" NL
               "str r12, [%0]" NL
               "add r12, r12, #1" NL
               "ldr r12, [%0], #4" NL
               "cmp %0, %1" NL
               "bne _MEMLOOP%=" NL
               :"+r" (ram_block): "r" (ram_block + (TEST_BLOCK_SIZE / sizeof(unsigned))): "r12", "cc");
  return cyccnt_get();
}

static void memory_timing_test(void)
{
  cyccnt_enable();
#define RAMBLK(BLK)                                                       \
  static volatile unsigned ram ## BLK ## _block[TEST_BLOCK_SIZE / sizeof(unsigned) + 1] __attribute__((section(".ram" #BLK)))

#define TEST(BLK) \
  test_load(ram ## BLK ## _block); \
  test_unalignedload(ram ## BLK ## _block);  \
  test_store(ram ## BLK ## _block); \
  test_loadstore(ram ## BLK ## _block); \
  send_unsigned("ram" #BLK " load", test_load(ram ## BLK ## _block)); \
  send_unsigned("ram" #BLK " unalignedload", test_unalignedload(ram ## BLK ## _block));   \
  send_unsigned("ram" #BLK " store", test_store(ram ## BLK ## _block)); \
  send_unsigned("ram" #BLK " loadstore", test_loadstore(ram ## BLK ## _block));

  static volatile unsigned ram1_block[TEST_BLOCK_SIZE / sizeof(unsigned) + 1];
  TEST(1);
#if defined(HAS_SRAM2)
  RAMBLK(2);
  TEST(2);
#endif
#if defined(HAS_SRAM3)
  RAMBLK(3);
  TEST(3);
#endif
#if defined(HAS_CCM)
  static volatile unsigned ramccm_block[TEST_BLOCK_SIZE / sizeof(unsigned) + 1] __attribute__((section(".ccmram")));
  TEST(ccm);
#endif
}
#endif

int main(void)
{
  hal_setup(CLOCK_FAST);
  hal_send_str("Hello world");
  send_unsigned("Stack Size", hal_get_stack_size());
  unsigned rnd;
  randombytes((unsigned char*) &rnd, sizeof(unsigned));
  send_unsigned("Random number", rnd);
#if defined(SRAM_TIMING_TEST)
  memory_timing_test();
#endif
  return 0;
}
back to top