#include #include #include #include "semihosting.h" #define SEMIHOSTING_SYS_OPEN 0x01 #define SEMIHOSTING_SYS_CLOSE 0x02 #define SEMIHOSTING_SYS_WRITEC 0x03 #define SEMIHOSTING_SYS_WRITE0 0x04 #define SEMIHOSTING_SYS_WRITE 0x05 #define SEMIHOSTING_SYS_READ 0x06 #define SEMIHOSTING_SYS_READC 0x07 #define SEMIHOSTING_SYS_ISERROR 0x08 #define SEMIHOSTING_SYS_ISTTY 0x09 #define SEMIHOSTING_SYS_SEEK 0x0A #define SEMIHOSTING_SYS_FLEN 0x0C #define SEMIHOSTING_SYS_TMPNAM 0x0D #define SEMIHOSTING_SYS_REMOVE 0x0E #define SEMIHOSTING_SYS_RENAME 0x0F #define SEMIHOSTING_SYS_CLOCK 0x10 #define SEMIHOSTING_SYS_TIME 0x11 #define SEMIHOSTING_SYS_SYSTEM 0x12 #define SEMIHOSTING_SYS_ERRNO 0x13 #define SEMIHOSTING_SYS_GET_CMDLINE 0x15 #define SEMIHOSTING_SYS_HEAPINFO 0x16 #define SEMIHOSTING_EnterSVC 0x17 #define SEMIHOSTING_ReportException 0x18 #define SEMIHOSTING_SYS_ELAPSED 0x30 #define SEMIHOSTING_SYS_TICKFREQ 0x31 #define RISCV_SEMIHOSTING_CALL_NUMBER 7 static inline int __attribute__ ((always_inline)) call_host(int reason, void* arg) { #if 1 // This must always be set back to 0 to cover the case where a host wasn't // initially present, but only connected while the program was already up and // running. In that case, trap() suddenly won't be called anymore, so we have to // clear this variable *before* EBREAK is called. sh_missing_host = 0; register int value asm ("a0") = reason; register void* ptr asm ("a1") = arg; asm volatile ( // Workaround for RISC-V lack of multiple EBREAKs. " .option push \n" " .option norvc \n" // Force 16-byte alignment to make sure that the 3 instruction fall // within the same virtual page. If you the instruction straddle a page boundary // the debugger fetching the instructions could lead to a page fault. // Note: align 4 means, align by 2 to the power of 4! " .align 4 \n" " slli x0, x0, 0x1f \n" " ebreak \n" " srai x0, x0, 0x07 \n" " .option pop \n" : "=r" (value) /* Outputs */ : "0" (value), "r" (ptr), [swi] "i" (RISCV_SEMIHOSTING_CALL_NUMBER) /* Inputs */ : "memory" /* Clobbers */ ); return value; #else return 0; #endif } void sh_write0(const char* buf) { // Print zero-terminated string call_host(SEMIHOSTING_SYS_WRITE0, (void*) buf); } void sh_writec(char c) { // Print single character call_host(SEMIHOSTING_SYS_WRITEC, (void*)&c); } char sh_readc(void) { // Read character from keyboard. (Blocking operation!) char c = call_host(SEMIHOSTING_SYS_READC, (void*)NULL); if (sh_missing_host) return 0; else return c; }