[sw] Collect various "runtime-ey" functions into lib/runtime.
This directory is made distinct from libbase mostly for semantic
reasons:
- It needs to know timing-ey things about Ibex, which are isolated in
ibex.h.
- It's more "system-aware" than what we tend to put in libbase.
hart.h contains "execution control" functions that may be
RISC-V-flavored, but independent of ibex.h.
Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/boot_rom/meson.build b/sw/device/boot_rom/meson.build
index 180e591..7f26417 100644
--- a/sw/device/boot_rom/meson.build
+++ b/sw/device/boot_rom/meson.build
@@ -34,6 +34,7 @@
link_depends: rom_link_deps,
dependencies: [
chip_info_h,
+ sw_lib_runtime_hart,
sw_lib_flash_ctrl,
sw_lib_pinmux,
sw_lib_gpio,
diff --git a/sw/device/examples/hello_usbdev/hello_usbdev.c b/sw/device/examples/hello_usbdev/hello_usbdev.c
index 2152ef1..65509aa 100644
--- a/sw/device/examples/hello_usbdev/hello_usbdev.c
+++ b/sw/device/examples/hello_usbdev/hello_usbdev.c
@@ -5,6 +5,7 @@
#include "sw/device/lib/base/stdasm.h"
#include "sw/device/lib/common.h"
#include "sw/device/lib/gpio.h"
+#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/uart.h"
#include "sw/device/lib/usb_controlep.h"
#include "sw/device/lib/usb_simpleserial.h"
@@ -32,38 +33,12 @@
static usb_controlep_ctx_t control_ctx;
static usb_ss_ctx_t ss_ctx[2];
-/**
- * Delay loop executing within 8 cycles on ibex
- */
-static void delay_loop_ibex(unsigned long loops) {
- int out; /* only to notify compiler of modifications to |loops| */
- asm volatile(
- "1: nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " addi %1, %1, -1 \n" // 1 cycle
- " bnez %1, 1b \n" // 3 cycles
- : "=&r"(out)
- : "0"(loops));
-}
-
-static int usleep_ibex(unsigned long usec) {
- unsigned long usec_cycles;
- usec_cycles = CLK_FIXED_FREQ_HZ * usec / 1000 / 1000 / 8;
-
- delay_loop_ibex(usec_cycles);
- return 0;
-}
-
-static int usleep(unsigned long usec) { return usleep_ibex(usec); }
-
static void test_error(void) {
while (1) {
gpio_write_all(0xAA00); // pattern
- usleep(200 * 1000);
+ busy_sleep_micros(200 * 1000);
gpio_write_all(0x5500); // pattern
- usleep(100 * 1000);
+ busy_sleep_micros(100 * 1000);
}
}
@@ -104,7 +79,7 @@
// Give a LED pattern as startup indicator for 5 seconds
gpio_write_all(0xAA00); // pattern
- usleep(1000);
+ busy_sleep_micros(1000);
gpio_write_all(0x5500); // pattern
// usbdev_init here so dpi code will not start until simulation
// got through all the printing (which takes a while if --trace)
diff --git a/sw/device/examples/hello_usbdev/meson.build b/sw/device/examples/hello_usbdev/meson.build
index 9b50288..dc89956 100644
--- a/sw/device/examples/hello_usbdev/meson.build
+++ b/sw/device/examples/hello_usbdev/meson.build
@@ -7,6 +7,7 @@
sources: ['hello_usbdev.c'],
name_suffix: 'elf',
dependencies: [
+ sw_lib_runtime_hart,
sw_lib_gpio,
sw_lib_irq,
sw_lib_uart,
diff --git a/sw/device/examples/hello_world/hello_world.c b/sw/device/examples/hello_world/hello_world.c
index b1338ca..0e55c53 100644
--- a/sw/device/examples/hello_world/hello_world.c
+++ b/sw/device/examples/hello_world/hello_world.c
@@ -6,37 +6,12 @@
#include "sw/device/lib/common.h"
#include "sw/device/lib/gpio.h"
#include "sw/device/lib/pinmux.h"
+#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/spi_device.h"
#include "sw/device/lib/uart.h"
#define SPI_MAX 32
-/**
- * Delay loop executing within 8 cycles on ibex
- */
-static void delay_loop_ibex(unsigned long loops) {
- int out; /* only to notify compiler of modifications to |loops| */
- asm volatile(
- "1: nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " addi %1, %1, -1 \n" // 1 cycle
- " bnez %1, 1b \n" // 3 cycles
- : "=&r"(out)
- : "0"(loops));
-}
-
-static int usleep_ibex(unsigned long usec) {
- unsigned long usec_cycles;
- usec_cycles = CLK_FIXED_FREQ_HZ * usec / 1000 / 1000 / 8;
-
- delay_loop_ibex(usec_cycles);
- return 0;
-}
-
-static int usleep(unsigned long usec) { return usleep_ibex(usec); }
-
// called from ctr0 when something bad happens
// char I=illegal instruction, A=lsu error (address), E=ecall
void trap_handler(uint32_t mepc, char c) {
@@ -44,9 +19,9 @@
uart_send_uint(mepc, 32);
while (1) {
gpio_write_all(0xAA00); // pattern
- usleep(200 * 1000);
+ busy_sleep_micros(200 * 1000);
gpio_write_all(0x5500); // pattern
- usleep(100 * 1000);
+ busy_sleep_micros(100 * 1000);
}
}
@@ -70,7 +45,7 @@
// Give a LED pattern as startup indicator for 5 seconds
gpio_write_all(0xFF00); // all LEDs on
for (int i = 0; i < 32; i++) {
- usleep(100 * 1000); // 100 ms
+ busy_sleep_micros(100 * 1000); // 100 ms
gpio_write_bit(8 + (i % 8), (i / 8));
}
@@ -91,7 +66,7 @@
spid_send("SPI!", 4);
while (1) {
- usleep(10 * 1000); // 10 ms
+ busy_sleep_micros(10 * 1000); // 10 ms
// report changed switches over UART
gpio_in = gpio_read() & 0x100FF; // 0-7 is switch input, 16 is FTDI
diff --git a/sw/device/examples/hello_world/meson.build b/sw/device/examples/hello_world/meson.build
index 6caee00..11c3099 100644
--- a/sw/device/examples/hello_world/meson.build
+++ b/sw/device/examples/hello_world/meson.build
@@ -7,6 +7,7 @@
sources: ['hello_world.c'],
name_suffix: 'elf',
dependencies: [
+ sw_lib_runtime_hart,
sw_lib_pinmux,
sw_lib_gpio,
sw_lib_irq,
diff --git a/sw/device/lib/base/memory.c b/sw/device/lib/base/memory.c
index d403989..177cbfa 100644
--- a/sw/device/lib/base/memory.c
+++ b/sw/device/lib/base/memory.c
@@ -25,8 +25,3 @@
return dest;
}
-noreturn void abort(void) {
- while (true) {
- asm volatile("wfi");
- }
-}
diff --git a/sw/device/lib/base/memory.h b/sw/device/lib/base/memory.h
index bf1d280..060523c 100644
--- a/sw/device/lib/base/memory.h
+++ b/sw/device/lib/base/memory.h
@@ -94,14 +94,4 @@
*/
void *memset(void *dest, int value, size_t len);
-// TODO: Find a better header for this function to live. See #1207.
-/**
- * Immediately halt program execution.
- *
- * This function conforms to the semantics defined in ISO C11 S7.22.4.1, except
- * that it cannot be pre-empted by signal handlers (which do not exist in this
- * environment).
- */
-noreturn void abort(void);
-
#endif // SW_DEVICE_LIB_BASE_MEMORY_H_
diff --git a/sw/device/lib/common.h b/sw/device/lib/common.h
index 3aea0dc..41d3b67 100644
--- a/sw/device/lib/common.h
+++ b/sw/device/lib/common.h
@@ -6,10 +6,8 @@
#define _COMMON_H_
#ifdef SIMULATION
-#define CLK_FIXED_FREQ_HZ (500 * 1000)
static const unsigned long UART_BAUD_RATE = 9600;
#else
-#define CLK_FIXED_FREQ_HZ (50ULL * 1000 * 1000)
static const unsigned long UART_BAUD_RATE = 230400;
#endif
diff --git a/sw/device/lib/gpio.c b/sw/device/lib/gpio.c
index d8a6f05..8c1d737 100644
--- a/sw/device/lib/gpio.c
+++ b/sw/device/lib/gpio.c
@@ -6,6 +6,7 @@
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/common.h"
+#include "sw/device/lib/runtime/hart.h"
void gpio_init(uint32_t oe) { REG32(GPIO_DIRECT_OE(0)) = oe; }
diff --git a/sw/device/lib/meson.build b/sw/device/lib/meson.build
index dae41b9..6b139c5 100644
--- a/sw/device/lib/meson.build
+++ b/sw/device/lib/meson.build
@@ -3,6 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
subdir('base')
+subdir('runtime')
# UART library (sw_lib_uart)
sw_lib_uart = declare_dependency(
@@ -12,7 +13,8 @@
sources: [
hw_ip_uart_reg_h,
'uart.c',
- ]
+ ],
+ dependencies: [sw_lib_runtime_ibex],
)
)
@@ -36,7 +38,8 @@
sources: [
hw_ip_gpio_reg_h,
'gpio.c',
- ]
+ ],
+ dependencies: [sw_lib_runtime_hart],
)
)
@@ -110,6 +113,7 @@
],
dependencies: [
sw_lib_irq,
+ sw_lib_runtime_ibex,
sw_lib_uart,
],
)
@@ -123,7 +127,8 @@
sources: [
hw_ip_rv_timer_reg_h,
'rv_timer.c',
- ]
+ ],
+ dependencies: [sw_lib_runtime_ibex],
)
)
diff --git a/sw/device/lib/runtime/README.md b/sw/device/lib/runtime/README.md
new file mode 100644
index 0000000..ee9d84a
--- /dev/null
+++ b/sw/device/lib/runtime/README.md
@@ -0,0 +1,5 @@
+# `libruntime`, the OpenTitan Runtime Library
+
+This directory contains machine-aware base libraries for OpenTitan, being more
+aware and able to control the execution environment than the "pure algorithm"
+functions in `libbase`.
diff --git a/sw/device/lib/runtime/hart.c b/sw/device/lib/runtime/hart.c
new file mode 100644
index 0000000..1f02ac9
--- /dev/null
+++ b/sw/device/lib/runtime/hart.c
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/runtime/hart.h"
+
+#include <stdbool.h>
+
+#include "sw/device/lib/runtime/ibex.h"
+
+extern void wait_for_interrupt(void);
+
+void busy_sleep_micros(size_t microseconds) {
+ size_t cycles = kIbexClockFreqHz * microseconds / 10000000;
+ ibex_busy_loop(cycles);
+}
+
+noreturn void abort(void) {
+ while (true) {
+ wait_for_interrupt();
+ }
+}
diff --git a/sw/device/lib/runtime/hart.h b/sw/device/lib/runtime/hart.h
new file mode 100644
index 0000000..2290076
--- /dev/null
+++ b/sw/device/lib/runtime/hart.h
@@ -0,0 +1,40 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef SW_DEVICE_LIB_RUNTIME_HART_H_
+#define SW_DEVICE_LIB_RUNTIME_HART_H_
+
+#include <stddef.h>
+#include <stdnoreturn.h>
+
+#include "sw/device/lib/base/stdasm.h"
+
+/**
+ * This header provides functions for controlling the excution of a hart, such
+ * as halt-like functionality.
+ */
+
+/**
+ * Hints to the processor that we don't have anything better to be doing, and to
+ * go into low-power mode until an interrupt is serviced.
+ *
+ * This function may behave as if it is a no-op.
+ */
+inline void wait_for_interrupt(void) { asm volatile("wfi"); }
+
+/**
+ * Spin for roughly the given number of microseconds.
+ *
+ * @param microseconds the duration for which to spin.
+ */
+void busy_sleep_micros(size_t microseconds);
+
+/**
+ * Immediately halt program execution.
+ *
+ * This function conforms to the semantics defined in ISO C11 S7.22.4.1.
+ */
+noreturn void abort(void);
+
+#endif // SW_DEVICE_LIB_RUNTIME_HART_H_
diff --git a/sw/device/lib/runtime/ibex.c b/sw/device/lib/runtime/ibex.c
new file mode 100644
index 0000000..854d33d
--- /dev/null
+++ b/sw/device/lib/runtime/ibex.c
@@ -0,0 +1,13 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/runtime/ibex.h"
+
+#ifdef SIMULATION
+const size_t kIbexClockFreqHz = 500 * 1000; // 500 kHz
+#else
+const size_t kIbexClockFreqHz = 50 * 1000 * 1000; // 50 MHz
+#endif
+
+extern void ibex_busy_loop(size_t);
diff --git a/sw/device/lib/runtime/ibex.h b/sw/device/lib/runtime/ibex.h
new file mode 100644
index 0000000..a31d609
--- /dev/null
+++ b/sw/device/lib/runtime/ibex.h
@@ -0,0 +1,41 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef SW_DEVICE_LIB_RUNTIME_IBEX_H_
+#define SW_DEVICE_LIB_RUNTIME_IBEX_H_
+
+#include <stddef.h>
+
+#include "sw/device/lib/base/stdasm.h"
+
+/**
+ * This header provides Ibex-specific functions, such as the clock frequency and
+ * cycle-accurate busy loops.
+ */
+
+/**
+ * The clock frequency of the Ibex core, in hertz.
+ */
+extern const size_t kIbexClockFreqHz;
+
+/**
+ * Spins for roughly the number of |cycles| given. For best results, |cycles|
+ * should be a multiple of eight.
+ *
+ * This function should not be used for time-keeping.
+ *
+ * @param cycles the number of cycles to burn.
+ */
+inline void ibex_busy_loop(size_t cycles) {
+ size_t out; // Used to create an inout parameter below.
+ asm volatile(
+ "busy_loop%=:"
+ " nop; nop; nop; nop;" // 4 cycles.
+ " addi %1, %1, -8;" // 1 cycle.
+ " blez %1, busy_loop%=;" // 3 cycles.
+ : "=&r"(out)
+ : "0"(cycles));
+}
+
+#endif // SW_DEVICE_LIB_RUNTIME_IBEX_H_
diff --git a/sw/device/lib/runtime/meson.build b/sw/device/lib/runtime/meson.build
new file mode 100644
index 0000000..6e7e5ab
--- /dev/null
+++ b/sw/device/lib/runtime/meson.build
@@ -0,0 +1,18 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+sw_lib_runtime_ibex = declare_dependency(
+ link_with: static_library(
+ 'runtime_ibex_ot',
+ sources: ['ibex.c'],
+ )
+)
+
+sw_lib_runtime_hart = declare_dependency(
+ link_with: static_library(
+ 'runtime_hart_ot',
+ sources: ['hart.c'],
+ dependencies: [sw_lib_runtime_ibex],
+ )
+)
diff --git a/sw/device/lib/rv_timer.c b/sw/device/lib/rv_timer.c
index caa8f24..f6f1b4a 100644
--- a/sw/device/lib/rv_timer.c
+++ b/sw/device/lib/rv_timer.c
@@ -5,8 +5,8 @@
#include "sw/device/lib/rv_timer.h"
#include "rv_timer_regs.h" // Generated.
-
#include "sw/device/lib/common.h"
+#include "sw/device/lib/runtime/ibex.h"
#define RV_TIMER0_BASE_ADDR 0x40080000
#define HART_CFG_ADDR_GAP 0x100
@@ -14,7 +14,7 @@
static const uint32_t NS_IN_S = 1000 * 1000 * 1000;
void rv_timer_set_us_tick(uint32_t hart) {
- uint32_t ticks_per_us = (uint32_t)((1000 * CLK_FIXED_FREQ_HZ) / NS_IN_S) - 1;
+ uint32_t ticks_per_us = (uint32_t)((1000 * kIbexClockFreqHz) / NS_IN_S) - 1;
REG32(RV_TIMER_CFG0(0) + hart * 4) =
(ticks_per_us & RV_TIMER_CFG0_PRESCALE_MASK) |
diff --git a/sw/device/lib/uart.c b/sw/device/lib/uart.c
index 5fba477..ffa936c 100644
--- a/sw/device/lib/uart.c
+++ b/sw/device/lib/uart.c
@@ -5,10 +5,11 @@
#include "sw/device/lib/uart.h"
#include "sw/device/lib/common.h"
+#include "sw/device/lib/runtime/ibex.h"
inline void uart_init(unsigned int baud) {
// nco = 2^20 * baud / fclk
- uint64_t uart_ctrl_nco = ((uint64_t)baud << 20) / CLK_FIXED_FREQ_HZ;
+ uint64_t uart_ctrl_nco = ((uint64_t)baud << 20) / kIbexClockFreqHz;
REG32(UART_CTRL(0)) =
((uart_ctrl_nco & UART_CTRL_NCO_MASK) << UART_CTRL_NCO_OFFSET) |
(1 << UART_CTRL_TX) | (1 << UART_CTRL_RX);
diff --git a/sw/device/tests/flash_ctrl/flash_test.c b/sw/device/tests/flash_ctrl/flash_test.c
index 478c16e..6df32dc 100644
--- a/sw/device/tests/flash_ctrl/flash_test.c
+++ b/sw/device/tests/flash_ctrl/flash_test.c
@@ -6,40 +6,15 @@
#include "sw/device/lib/common.h"
#include "sw/device/lib/flash_ctrl.h"
#include "sw/device/lib/gpio.h"
+#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/uart.h"
-/**
- * Delay loop executing within 8 cycles on ibex
- */
-static void delay_loop_ibex(unsigned long loops) {
- int out; /* only to notify compiler of modifications to |loops| */
- asm volatile(
- "1: nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " nop \n" // 1 cycle
- " addi %1, %1, -1 \n" // 1 cycle
- " bnez %1, 1b \n" // 3 cycles
- : "=&r"(out)
- : "0"(loops));
-}
-
-static int usleep_ibex(unsigned long usec) {
- unsigned long usec_cycles;
- usec_cycles = CLK_FIXED_FREQ_HZ * usec / 1000 / 1000 / 8;
-
- delay_loop_ibex(usec_cycles);
- return 0;
-}
-
-static int usleep(unsigned long usec) { return usleep_ibex(usec); }
-
static void break_on_error(uint32_t error) {
if (error) {
// inifinitely fetch instructions, will flag an assertion error
uart_send_str("FAIL!\r\n");
while (1) {
- usleep(100);
+ busy_sleep_micros(100);
}
}
}
diff --git a/sw/device/tests/flash_ctrl/meson.build b/sw/device/tests/flash_ctrl/meson.build
index d1c60f8..4be3f42 100644
--- a/sw/device/tests/flash_ctrl/meson.build
+++ b/sw/device/tests/flash_ctrl/meson.build
@@ -7,6 +7,7 @@
sources: ['flash_test.c'],
name_suffix: 'elf',
dependencies: [
+ sw_lib_runtime_hart,
sw_lib_flash_ctrl,
sw_lib_gpio,
sw_lib_irq,