| /* |
| * Copyright 2021, Google LLC |
| * |
| * Demo to show that concurrent applications can be running. |
| * |
| * This program prints the first LOG_FIBONACCI_LIMIT Fibonacci numbers |
| * to the console, waiting for INTERRUPTS_PER_WAIT interrupts between each |
| * number. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <cantrip.h> |
| #include <stdint.h> |
| |
| // How many Fibonacci numbers to write to the log. |
| #define LOG_FIBONACCI_LIMIT 80 |
| |
| #define CONFIG_TIMER_TICK_MS 5 |
| #define INTERRUPTS_PER_VIRT_SEC (1000 / CONFIG_TIMER_TICK_MS) |
| #define INTERRUPTS_PER_WAIT (1 * INTERRUPTS_PER_VIRT_SEC) |
| |
| typedef uint64_t interrupt_count_t; |
| |
| typedef struct { |
| uint64_t f1; |
| uint64_t f2; |
| uint64_t n; |
| } fibonacci_state_t; |
| |
| void fibonacci_init(fibonacci_state_t *state) { |
| state->f1 = 0; |
| state->f2 = 1; |
| state->n = 0; |
| } |
| |
| void fibonacci_increment(fibonacci_state_t *state) { |
| uint64_t swap = state->f2; |
| state->f2 = state->f1 + state->f2; |
| state->f1 = swap; |
| ++state->n; |
| } |
| |
| void wait(interrupt_count_t interrupt_count_to_wait, |
| interrupt_count_t *counter) { |
| for (interrupt_count_t i = 0; i < interrupt_count_to_wait; ++i) { |
| asm volatile("wfi"); |
| ++*counter; |
| } |
| } |
| |
| float virtual_seconds(interrupt_count_t interrupt_count) { |
| return interrupt_count / INTERRUPTS_PER_VIRT_SEC; |
| } |
| |
| uint64_t rdtime(void) { |
| uint32_t upper, lower, upper_reread; |
| while (1) { |
| asm volatile( |
| "rdtimeh %0\n" |
| "rdtime %1\n" |
| "rdtimeh %2\n" |
| : "=r"(upper), "=r"(lower), "=r"(upper_reread)); |
| if (upper_reread == upper) { |
| return ((uint64_t)upper << 32) | lower; |
| } |
| } |
| } |
| |
| void fibonacci_log(const fibonacci_state_t *fibonacci_state, |
| interrupt_count_t interrupt_count) { |
| // TODO(sleffler): bring in snprintf |
| #if 0 |
| char log_buf[128]; |
| snprintf(log_buf, sizeof(log_buf) / sizeof(char), |
| "\nfibonacci: n == %llu; f == %llu; interrupt_count == " |
| "%llu; rdtime == %llu; virt_sec ~= %.2f\n", |
| fibonacci_state->n, fibonacci_state->f1, interrupt_count, rdtime(), |
| virtual_seconds(interrupt_count)); |
| debug_printf(log_buf); |
| #else |
| debug_printf( |
| "n == %d; " |
| "f == %x; " |
| "interrupt_count == %d; " |
| "rdtime == %d; " |
| "virt_sec ~= %d\n", |
| (uint32_t)fibonacci_state->n, (uint32_t)fibonacci_state->f1, |
| (uint32_t)interrupt_count, (uint32_t)rdtime(), |
| (uint32_t)virtual_seconds(interrupt_count)); |
| #endif |
| } |
| |
| int main() { |
| interrupt_count_t interrupt_count = 0; |
| fibonacci_state_t fibonacci_state; |
| fibonacci_init(&fibonacci_state); |
| debug_printf("\nFibonacci:\n"); |
| while (1) { |
| wait(INTERRUPTS_PER_WAIT, &interrupt_count); |
| if (fibonacci_state.n >= LOG_FIBONACCI_LIMIT) { |
| fibonacci_init(&fibonacci_state); |
| } |
| fibonacci_log(&fibonacci_state, interrupt_count); |
| fibonacci_increment(&fibonacci_state); |
| } |
| } |