diff --git a/examples/tests/cycle_count/Makefile b/examples/tests/cycle_count/Makefile new file mode 100644 index 000000000..54d6a7969 --- /dev/null +++ b/examples/tests/cycle_count/Makefile @@ -0,0 +1,11 @@ +# Makefile for user application + +# Specify this directory relative to the current application. +TOCK_USERLAND_BASE_DIR = ../../.. + +# Which files to compile. +C_SRCS := $(wildcard *.c) + +# Include userland master makefile. Contains rules and flags for actually +# building the application. +include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk diff --git a/examples/tests/cycle_count/README.md b/examples/tests/cycle_count/README.md new file mode 100644 index 000000000..ae552f58d --- /dev/null +++ b/examples/tests/cycle_count/README.md @@ -0,0 +1,5 @@ +Test `cycle_count` +==================== + +This tests the cycle counter capsule. +It will print the number of cycles required to toggle an LED. diff --git a/examples/tests/cycle_count/main.c b/examples/tests/cycle_count/main.c new file mode 100644 index 000000000..270ff4158 --- /dev/null +++ b/examples/tests/cycle_count/main.c @@ -0,0 +1,36 @@ +#include + +#include +#include +#include + +int main(void) { + uint64_t cycles = 0; + + int rc = cycle_counter_reset(); + if (rc == RETURNCODE_ENOSUPPORT) { + printf("Cycle counter not available\n"); + } else if (rc == RETURNCODE_ERESERVE) { + printf("Cycle counter claimed by another app\n"); + } else if (rc != 0) { + printf("Cycle counter: other error: %d\n", rc); + } + + if (rc != 0) { + return 0; + } + + cycle_counter_start(); + led_toggle(0); + cycle_counter_stop(); + cycle_counter_read(&cycles); + printf("cycles to toggle led first time: %lld\n", cycles); + + cycle_counter_reset(); + cycle_counter_start(); + led_toggle(0); + cycle_counter_stop(); + cycle_counter_read(&cycles); + printf("cycles to toggle led second time: %lld\n", cycles); + return 0; +} diff --git a/libtock/cycle_counter.c b/libtock/cycle_counter.c new file mode 100644 index 000000000..d7887a0aa --- /dev/null +++ b/libtock/cycle_counter.c @@ -0,0 +1,29 @@ +#include "cycle_counter.h" + +bool cycle_counter_exists(void) { + return driver_exists(DRIVER_NUM_CYCLE_COUNTER); +} + +// Start the cycle counter +int cycle_counter_start(void) { + syscall_return_t rval = command(DRIVER_NUM_CYCLE_COUNTER, 1, 0, 0); + return tock_command_return_novalue_to_returncode(rval); +} + +// Get the current cycle count +int cycle_counter_read(uint64_t* count) { + syscall_return_t rval = command(DRIVER_NUM_CYCLE_COUNTER, 2, 0, 0); + return tock_command_return_u64_to_returncode(rval, (uint64_t*) count); +} + +// Reset the cycle counter +int cycle_counter_reset(void) { + syscall_return_t rval = command(DRIVER_NUM_CYCLE_COUNTER, 3, 0, 0); + return tock_command_return_novalue_to_returncode(rval); +} + +// Stop the cycle counter +int cycle_counter_stop(void) { + syscall_return_t rval = command(DRIVER_NUM_CYCLE_COUNTER, 4, 0, 0); + return tock_command_return_novalue_to_returncode(rval); +} diff --git a/libtock/cycle_counter.h b/libtock/cycle_counter.h new file mode 100644 index 000000000..45e9ef3f2 --- /dev/null +++ b/libtock/cycle_counter.h @@ -0,0 +1,19 @@ +#pragma once + +#include "tock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRIVER_NUM_CYCLE_COUNTER 0x00090008 + +bool cycle_counter_exists(void); +int cycle_counter_start(void); +int cycle_counter_stop(void); +int cycle_counter_reset(void); +int cycle_counter_read(uint64_t *count); + +#ifdef __cplusplus +} +#endif diff --git a/libtock/tock.c b/libtock/tock.c index 86a56f58f..aa0fe4ce8 100644 --- a/libtock/tock.c +++ b/libtock/tock.c @@ -66,6 +66,21 @@ int tock_command_return_u32_to_returncode(syscall_return_t command_return, uint3 } } +int tock_command_return_u64_to_returncode(syscall_return_t command_return, uint64_t* val) { + if (command_return.type == TOCK_SYSCALL_SUCCESS_U64) { + uint32_t upper = command_return.data[1]; + uint32_t lower = command_return.data[0]; + *val = ((uint64_t)upper << 32) | lower; + return RETURNCODE_SUCCESS; + } else if (command_return.type == TOCK_SYSCALL_FAILURE) { + return tock_status_to_returncode(command_return.data[0]); + } else { + // The remaining SyscallReturn variants must never happen if using this + // function. We return `EBADRVAL` to signal an unexpected return variant. + return RETURNCODE_EBADRVAL; + } +} + int tock_subscribe_return_to_returncode(subscribe_return_t subscribe_return) { // If the subscribe was successful, easily return SUCCESS. if (subscribe_return.success) { diff --git a/libtock/tock.h b/libtock/tock.h index bb5ce0500..e38cccb00 100644 --- a/libtock/tock.h +++ b/libtock/tock.h @@ -152,6 +152,13 @@ int tock_command_return_novalue_to_returncode(syscall_return_t); // variants. int tock_command_return_u32_to_returncode(syscall_return_t, uint32_t*); +// Convert a `syscall_return_t` with two u32s to a `returncode_t`. +// +// This expects exactly two u32s to be returned (i.e. the only success case is +// `TOCK_SYSCALL_SUCCESS_U64`). Do not use with other expected SyscallReturn +// variants. +int tock_command_return_u64_to_returncode(syscall_return_t, uint64_t*); + // Convert a `subscribe_return_t` to a `returncode_t`. int tock_subscribe_return_to_returncode(subscribe_return_t);