[test] Add example program for executing code from SRAM
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/examples/sram_program/BUILD b/sw/device/examples/sram_program/BUILD
new file mode 100644
index 0000000..33817bd
--- /dev/null
+++ b/sw/device/examples/sram_program/BUILD
@@ -0,0 +1,36 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+load("//rules:opentitan.bzl", "opentitan_ram_binary")
+load("//rules:linker.bzl", "ld_library")
+
+package(default_visibility = ["//visibility:public"])
+
+ld_library(
+ name = "sram_program_linker_script",
+ script = "sram_program.ld",
+ deps = [
+ "//hw/top_earlgrey/sw/autogen:top_earlgrey_memory",
+ "//sw/device:info_sections",
+ ],
+)
+
+opentitan_ram_binary(
+ name = "sram_program",
+ srcs = [
+ "sram_program.c",
+ ],
+ hdrs = [
+ "sram_program.h",
+ ],
+ archive_symbol_prefix = "sram_program",
+ deps = [
+ ":sram_program_linker_script",
+ "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+ "//sw/device/lib/base:macros",
+ "//sw/device/lib/dif:sram_ctrl",
+ "//sw/device/lib/runtime:log",
+ "//sw/device/lib/testing/test_framework:check",
+ ],
+)
diff --git a/sw/device/examples/sram_program/sram_program.c b/sw/device/examples/sram_program/sram_program.c
new file mode 100644
index 0000000..248682c
--- /dev/null
+++ b/sw/device/examples/sram_program/sram_program.c
@@ -0,0 +1,42 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include <stdint.h>
+
+#include "sw/device/lib/base/macros.h"
+#include "sw/device/lib/base/memory.h"
+#include "sw/device/lib/dif/dif_uart.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/runtime/print.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+static dif_uart_t uart0;
+
+enum {
+ kSramStart = TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR,
+ kSramEnd = TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR +
+ TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_SIZE_BYTES,
+};
+
+void sram_main() {
+ // Initialize UART.
+ CHECK_DIF_OK(dif_uart_init(
+ mmio_region_from_addr(TOP_EARLGREY_UART0_BASE_ADDR), &uart0));
+ CHECK_DIF_OK(
+ dif_uart_configure(&uart0, (dif_uart_config_t){
+ .baudrate = kUartBaudrate,
+ .clk_freq_hz = kClockFreqPeripheralHz,
+ .parity_enable = kDifToggleDisabled,
+ .parity = kDifUartParityEven,
+ }));
+ base_uart_stdout(&uart0);
+
+ // Read the program counter and check that we are executing from SRAM.
+ uint32_t pc = 0;
+ asm("auipc %[pc], 0;" : [pc] "=r"(pc));
+ LOG_INFO("PC: %p, SRAM: [%p, %p)", pc, kSramStart, kSramEnd);
+ CHECK(pc >= kSramStart && pc < kSramEnd, "PC is outside the main SRAM");
+}
diff --git a/sw/device/examples/sram_program/sram_program.ld b/sw/device/examples/sram_program/sram_program.ld
new file mode 100644
index 0000000..04abbff
--- /dev/null
+++ b/sw/device/examples/sram_program/sram_program.ld
@@ -0,0 +1,83 @@
+/* Copyright lowRISC contributors. */
+/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/**
+ * Linker script for an OpenTitan SRAM program.
+ *
+ * Portions of this file are Ibex-specific.
+ */
+
+OUTPUT_ARCH(riscv);
+
+/**
+ * Indicate that there are no dynamic libraries, whatsoever.
+ */
+__DYNAMIC = 0;
+
+INCLUDE hw/top_earlgrey/sw/autogen/top_earlgrey_memory.ld
+
+_stack_end = ORIGIN(ram_main) + LENGTH(ram_main);
+
+/**
+ * DV Log offset.
+ *
+ * Note: This definition is required by the `sw/device/info_sections.ld` script.
+ */
+_dv_log_offset = 0x10000;
+
+ENTRY(sram_main);
+
+SECTIONS {
+ /**
+ * SRAM programs consist only of a `.data` section that contains all input
+ * `.rodata`, `.data`, `.text`, and `.bss` sections.
+ */
+ .data : ALIGN(4){
+ /* This will get loaded into `gp`, and the linker will use that register for
+ * accessing data within [-2048,2047] of `__global_pointer$`.
+ *
+ * This is much cheaper (for small data) than materializing the
+ * address and loading from that (which will take one extra instruction).
+ *
+ * This must match the value used for functional tests to be able to call
+ * SRAM programs from functional tests. */
+ __global_pointer$ = . + 2048;
+
+ /* Place the entry point of the SRAM program to the start of the main SRAM
+ * so that we don't have to maintain a separate offset from the start of
+ * the RAM to the entry point. */
+ ASSERT(DEFINED(sram_main), "SRAM programs must define `sram_main()`");
+ KEEP(*(.text.sram_main))
+ . = ALIGN(4);
+
+ /* Place all input `.rodata`, `.data`, `.text`, and `.bss` sections in the
+ * main SRAM.
+ *
+ * Small data should come before larger data. This helps to ensure small
+ * globals are within 2048 bytes of the value of `gp`, making their accesses
+ * hopefully only take one instruction. Other data will likely need
+ * multiple instructions to load, so we're less concerned about address
+ * materialisation taking more than one instruction. */
+ KEEP(*(.srodata))
+ KEEP(*(.srodata.*))
+ KEEP(*(.rodata))
+ KEEP(*(.rodata.*))
+ . = ALIGN(4);
+ KEEP(*(.sdata))
+ KEEP(*(.sdata.*))
+ KEEP(*(.data))
+ KEEP(*(.data.*))
+ . = ALIGN(4);
+ KEEP(*(.text))
+ KEEP(*(.text.*))
+ . = ALIGN(4);
+ KEEP(*(.sbss))
+ KEEP(*(.sbss.*))
+ KEEP(*(.bss))
+ KEEP(*(.bss.*))
+ . = ALIGN(4);
+ } > ram_main
+
+ INCLUDE sw/device/info_sections.ld
+}