aboutsummaryrefslogtreecommitdiff
path: root/debug/programs
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2020-05-26 12:37:09 -0700
committerGitHub <noreply@github.com>2020-05-26 12:37:09 -0700
commitfbe74f48e16be28a2b360e8a9e845b01d9e4b167 (patch)
tree869b79d740a4c5f405f35eb0cab9275ea7da47e0 /debug/programs
parentbc4c1d2866b896f6234d19111993fae4a9f47d74 (diff)
downloadriscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.zip
riscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.tar.gz
riscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.tar.bz2
Test semihosting calls (#280)
* Add a basic semihosting test. * Need to configure semihosting on each target. * WIP * Parse "cannot insert breakpoint" message. Also use sys.exit instead of exit, per new pylint's suggestion.
Diffstat (limited to 'debug/programs')
-rw-r--r--debug/programs/semihosting.c73
-rw-r--r--debug/programs/semihosting.h82
2 files changed, 155 insertions, 0 deletions
diff --git a/debug/programs/semihosting.c b/debug/programs/semihosting.c
new file mode 100644
index 0000000..2ceea8c
--- /dev/null
+++ b/debug/programs/semihosting.c
@@ -0,0 +1,73 @@
+#include <stdint.h>
+
+#include "semihosting.h"
+
+size_t strlen(const char *buf)
+{
+ int len = 0;
+ while (buf[len])
+ len++;
+ return len;
+}
+
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#define O_RDWR 2
+#define O_TRUNC 0x0800
+
+int errno;
+
+/* These semihosting functions came from the Freedom Metal source. */
+static int open(const char *name, int flags, int mode) {
+ int semiflags = 0;
+
+ switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
+ case O_RDONLY:
+ semiflags = 0; /* 'r' */
+ break;
+ case O_WRONLY:
+ if (flags & O_TRUNC)
+ semiflags = 4; /* 'w' */
+ else
+ semiflags = 8; /* 'a' */
+ break;
+ default:
+ if (flags & O_TRUNC)
+ semiflags = 6; /* 'w+' */
+ else
+ semiflags = 10; /* 'a+' */
+ break;
+ }
+
+ volatile semihostparam_t arg = {.param1 = (uintptr_t)name,
+ .param2 = (uintptr_t)semiflags,
+ .param3 = (uintptr_t)strlen(name)};
+
+ int ret = (int)semihost_call_host(SEMIHOST_SYS_OPEN, (uintptr_t)&arg);
+ if (ret == -1)
+ errno = semihost_call_host(SEMIHOST_SYS_ERRNO, 0);
+ return ret;
+}
+
+static ssize_t write(int file, const void *ptr, size_t len)
+{
+ volatile semihostparam_t arg = {.param1 = (uintptr_t)file,
+ .param2 = (uintptr_t)ptr,
+ .param3 = (uintptr_t)len};
+ ssize_t ret =
+ (ssize_t)semihost_call_host(SEMIHOST_SYS_WRITE, (uintptr_t)&arg);
+
+ return (len - ret);
+}
+
+int main()
+{
+ char *filename = NULL;
+ const char *message = "Hello, world!\n";
+ int fd;
+
+begin:
+ fd = open(filename, O_WRONLY, 0644);
+ write(fd, message, strlen(message));
+} \ No newline at end of file
diff --git a/debug/programs/semihosting.h b/debug/programs/semihosting.h
new file mode 100644
index 0000000..201e414
--- /dev/null
+++ b/debug/programs/semihosting.h
@@ -0,0 +1,82 @@
+#include <sys/types.h>
+
+#ifndef _SEMIHOSTING_H_
+#define _SEMIHOSTING_H_
+
+// ----------------------------------------------------------------------------
+
+// Semihosting operations.
+enum Semihost_Sys_Op {
+ // Regular operations
+ SEMIHOST_SYS_CLOCK = 0x10,
+ SEMIHOST_SYS_CLOSE = 0x02,
+ SEMIHOST_SYS_ELAPSED = 0x30,
+ SEMIHOST_SYS_ERRNO = 0x13,
+ SEMIHOST_SYS_EXIT = 0x18,
+ SEMIHOST_SYS_EXIT_EXTENDED = 0x20,
+ SEMIHOST_SYS_FLEN = 0x0C,
+ SEMIHOST_SYS_GET_CMDLINE = 0x15,
+ SEMIHOST_SYS_HEAPINFO = 0x16,
+ SEMIHOST_SYS_ISERROR = 0x08,
+ SEMIHOST_SYS_ISTTY = 0x09,
+ SEMIHOST_SYS_OPEN = 0x01,
+ SEMIHOST_SYS_READ = 0x06,
+ SEMIHOST_SYS_READC = 0x07,
+ SEMIHOST_SYS_REMOVE = 0x0E,
+ SEMIHOST_SYS_RENAME = 0x0F,
+ SEMIHOST_SYS_SEEK = 0x0A,
+ SEMIHOST_SYS_SYSTEM = 0x12,
+ SEMIHOST_SYS_TICKFREQ = 0x31,
+ SEMIHOST_SYS_TIME = 0x11,
+ SEMIHOST_SYS_TMPNAM = 0x0D,
+ SEMIHOST_SYS_WRITE = 0x05,
+ SEMIHOST_SYS_WRITEC = 0x03,
+ SEMIHOST_SYS_WRITE0 = 0x04,
+};
+
+enum ADP_Code {
+ ADP_Stopped_BranchThroughZero = 0x20000,
+ ADP_Stopped_UndefinedInstr = 0x20001,
+ ADP_Stopped_SoftwareInterrupt = 0x20002,
+ ADP_Stopped_PrefetchAbort = 0x20003,
+ ADP_Stopped_DataAbort = 0x20004,
+ ADP_Stopped_AddressException = 0x20005,
+ ADP_Stopped_IRQ = 0x20006,
+ ADP_Stopped_FIQ = 0x20007,
+ ADP_Stopped_BreakPoint = 0x20020,
+ ADP_Stopped_WatchPoint = 0x20021,
+ ADP_Stopped_StepComplete = 0x20022,
+ ADP_Stopped_RunTimeErrorUnknown = 0x20023,
+ ADP_Stopped_InternalError = 0x20024,
+ ADP_Stopped_UserInterruption = 0x20025,
+ ADP_Stopped_ApplicationExit = 0x20026,
+ ADP_Stopped_StackOverflow = 0x20027,
+ ADP_Stopped_DivisionByZero = 0x20028,
+ ADP_Stopped_OSSpecific = 0x20029,
+};
+
+typedef struct {
+ uintptr_t param1;
+ uintptr_t param2;
+ uintptr_t param3;
+} semihostparam_t;
+
+static inline uintptr_t __attribute__((always_inline))
+semihost_call_host(uintptr_t op, uintptr_t arg) {
+ register uintptr_t r0 asm("a0") = op;
+ register uintptr_t r1 asm("a1") = arg;
+
+ asm volatile(".option push \n"
+ ".option norvc \n"
+ " slli zero,zero,0x1f \n"
+ " ebreak \n"
+ " srai zero,zero,0x7 \n"
+ ".option pop \n"
+
+ : "=r"(r0) /* Outputs */
+ : "r"(r0), "r"(r1) /* Inputs */
+ : "memory");
+ return r0;
+}
+
+#endif \ No newline at end of file