diff --git a/src/iss/semihosting/semihosting.cpp b/src/iss/semihosting/semihosting.cpp index 183ae03..02f8d65 100644 --- a/src/iss/semihosting/semihosting.cpp +++ b/src/iss/semihosting/semihosting.cpp @@ -1,22 +1,680 @@ #include "semihosting.h" -#include #include #include -template void semihosting_callback(iss::arch_if* arch_if_ptr, T a0, T a1) { - if(a0 == 0x04 /*WRITE0*/) { + +template void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter) { + switch(call_number) { + case SEMIHOSTING_ENTER_SVC: { + throw std::runtime_error("Semihosting Call not Implemented"); + } /* DEPRECATED */ + case SEMIHOSTING_SYS_CLOCK: { + /* + * Returns the number of centiseconds (hundredths of a second) + * since the execution started. + * + * Values returned can be of limited use for some benchmarking + * purposes because of communication overhead or other + * agent-specific factors. For example, with a debug hardware + * unit the request is passed back to the host for execution. + * This can lead to unpredictable delays in transmission and + * process scheduling. + * + * Use this function to calculate time intervals, by calculating + * differences between intervals with and without the code + * sequence to be timed. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The number of centiseconds since some arbitrary start + * point, if the call is successful. + * - –1 if the call is not successful. For example, because + * of a communications error. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_CLOSE: { + /* + * Closes a file on the host system. The handle must reference + * a file that was opened with SYS_OPEN. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 Contains a handle for an open file. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful + * - –1 if the call is not successful. + */ + + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_ELAPSED: { + /* + * Returns the number of elapsed target ticks since execution + * started. + * Use SYS_TICKFREQ to determine the tick frequency. + * + * Entry (32-bit) + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The least significant field and is at the low address. + * - field 2 The most significant field and is at the high address. + * + * Entry (64-bit) + * On entry the PARAMETER REGISTER points to a one-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The number of elapsed ticks as a 64-bit value. + * + * Return + * On exit: + * - On success, the RETURN REGISTER contains 0, the PARAMETER + * REGISTER is unchanged, and the data block pointed to by the + * PARAMETER REGISTER is filled in with the number of elapsed + * ticks. + * - On failure, the RETURN REGISTER contains -1, and the + * PARAMETER REGISTER contains -1. + * + * Note: Some semihosting implementations might not support this + * semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_ERRNO: { + /* + * Returns the value of the C library errno variable that is + * associated with the semihosting implementation. The errno + * variable can be set by a number of C library semihosted + * functions, including: + * - SYS_REMOVE + * - SYS_OPEN + * - SYS_CLOSE + * - SYS_READ + * - SYS_WRITE + * - SYS_SEEK. + * + * Whether errno is set or not, and to what value, is entirely + * host-specific, except where the ISO C standard defines the + * behavior. + * + * Entry + * There are no parameters. The PARAMETER REGISTER must be 0. + * + * Return + * On exit, the RETURN REGISTER contains the value of the C + * library errno variable. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_EXIT: { + /* + * Note: SYS_EXIT was called angel_SWIreason_ReportException in + * previous versions of the documentation. + * + * An application calls this operation to report an exception + * to the debugger directly. The most common use is to report + * that execution has completed, using ADP_Stopped_ApplicationExit. + * + * Note: This semihosting operation provides no means for 32-bit + * callers to indicate an application exit with a specified exit + * code. Semihosting callers may prefer to check for the presence + * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use + * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it + * is available. + * + * Entry (32-bit) + * On entry, the PARAMETER register is set to a reason code + * describing the cause of the trap. Not all semihosting client + * implementations will necessarily trap every corresponding + * event. Important reason codes are: + * + * - ADP_Stopped_ApplicationExit 0x20026 + * - ADP_Stopped_RunTimeErrorUnknown 0x20023 + * + * Entry (64-bit) + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which is one of the set of + * reason codes in the above tables. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. + * In particular, if field 1 is ADP_Stopped_ApplicationExit + * then field 2 is an exit status code, as passed to the C + * standard library exit() function. A simulator receiving + * this request must notify a connected debugger, if present, + * and then exit with the specified status. + * + * Return + * No return is expected from these calls. However, it is + * possible for the debugger to request that the application + * continues by performing an RDI_Execute request or equivalent. + * In this case, execution continues with the registers as they + * were on entry to the operation, or as subsequently modified + * by the debugger. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_EXIT_EXTENDED: { + /* + * This operation is only supported if the semihosting extension + * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is + * reported using feature byte 0, bit 0. If this extension is + * supported, then the implementation provides a means to + * report a normal exit with a nonzero exit status in both 32-bit + * and 64-bit semihosting APIs. + * + * The implementation must provide the semihosting call + * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. + * + * SYS_EXIT_EXTENDED is used by an application to report an + * exception or exit to the debugger directly. The most common + * use is to report that execution has completed, using + * ADP_Stopped_ApplicationExit. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which should be one of the set + * of reason codes that are documented for the SYS_EXIT + * (0x18) call. For example, ADP_Stopped_ApplicationExit. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. In particular, if field 1 is + * ADP_Stopped_ApplicationExit then field 2 is an exit status + * code, as passed to the C standard library exit() function. + * A simulator receiving this request must notify a connected + * debugger, if present, and then exit with the specified status. + * + * Return + * No return is expected from these calls. + * + * For the A64 API, this call is identical to the behavior of + * the mandatory SYS_EXIT (0x18) call. If this extension is + * supported, then both calls must be implemented. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_FLEN: { + /* + * Returns the length of a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 A handle for a previously opened, seekable file + * object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The current length of the file object, if the call is + * successful. + * - –1 if an error occurs. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_GET_CMDLINE: { + /* + * Returns the command line that is used for the call to the + * executable, that is, argc and argv. + * + * Entry + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the command string and its length: + * - field 1 A pointer to a buffer of at least the size that is + * specified in field 2. + * - field 2 The length of the buffer in bytes. + * + * Return + * On exit: + * If the call is successful, then the RETURN REGISTER contains 0, + * the PARAMETER REGISTER is unchanged, and the data block is + * updated as follows: + * - field 1 A pointer to a null-terminated string of the command + * line. + * - field 2 The length of the string in bytes. + * If the call is not successful, then the RETURN REGISTER + * contains -1. + * + * Note: The semihosting implementation might impose limits on + * the maximum length of the string that can be transferred. + * However, the implementation must be able to support a + * command-line length of at least 80 bytes. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_HEAPINFO: { + /* + * Returns the system stack and heap parameters. + * + * Entry + * On entry, the PARAMETER REGISTER contains the address of a + * pointer to a four-field data block. The contents of the data + * block are filled by the function. The following C-like + * pseudocode describes the layout of the block: + * struct block { + * void* heap_base; + * void* heap_limit; + * void* stack_base; + * void* stack_limit; + * }; + * + * Return + * On exit, the PARAMETER REGISTER is unchanged and the data + * block has been updated. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_ISERROR: { + /* + * Determines whether the return code from another semihosting + * call is an error status or not. + * + * This call is passed a parameter block containing the error + * code to examine. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field data block: + * - field 1 The required status word to check. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the status field is not an error indication + * - A nonzero value if the status field is an error indication. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_ISTTY: { + /* + * Checks whether a file is connected to an interactive device. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * field 1 A handle for a previously opened file object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 1 if the handle identifies an interactive device. + * - 0 if the handle identifies a file. + * - A value other than 1 or 0 if an error occurs. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_OPEN: { + /* + * Opens a file on the host system. + * + * The file path is specified either as relative to the current + * directory of the host process, or absolute, using the path + * conventions of the host operating system. + * + * Semihosting implementations must support opening the special + * path name :semihosting-features as part of the semihosting + * extensions reporting mechanism. + * + * ARM targets interpret the special path name :tt as meaning + * the console input stream, for an open-read or the console + * output stream, for an open-write. Opening these streams is + * performed as part of the standard startup code for those + * applications that reference the C stdio streams. The + * semihosting extension SH_EXT_STDOUT_STDERR allows the + * semihosting caller to open separate output streams + * corresponding to stdout and stderr. This extension is + * reported using feature byte 0, bit 1. Use SYS_OPEN with + * the special path name :semihosting-features to access the + * feature bits. + * + * If this extension is supported, the implementation must + * support the following additional semantics to SYS_OPEN: + * - If the special path name :tt is opened with an fopen + * mode requesting write access (w, wb, w+, or w+b), then + * this is a request to open stdout. + * - If the special path name :tt is opened with a mode + * requesting append access (a, ab, a+, or a+b), then this is + * a request to open stderr. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field argument block: + * - field 1 A pointer to a null-terminated string containing + * a file or device name. + * - field 2 An integer that specifies the file opening mode. + * - field 3 An integer that gives the length of the string + * pointed to by field 1. + * + * The length does not include the terminating null character + * that must be present. + * + * Return + * On exit, the RETURN REGISTER contains: + * - A nonzero handle if the call is successful. + * - –1 if the call is not successful. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_READ: { + /* + * Reads the contents of a file into a buffer. The file position + * is specified either: + * - Explicitly by a SYS_SEEK. + * - Implicitly one byte beyond the previous SYS_READ or + * SYS_WRITE request. + * + * The file position is at the start of the file when it is + * opened, and is lost when the file is closed. Perform the + * file operation as a single action whenever possible. For + * example, do not split a read of 16KB into four 4KB chunks + * unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to a buffer. + * - field 3 Contains the number of bytes to read to the buffer + * from the file. + * + * Return + * On exit, the RETURN REGISTER contains the number of bytes not + * filled in the buffer (buffer_length - bytes_read) as follows: + * - If the RETURN REGISTER is 0, the entire buffer was + * successfully filled. + * - If the RETURN REGISTER is the same as field 3, no bytes + * were read (EOF can be assumed). + * - If the RETURN REGISTER contains a value smaller than + * field 3, the read succeeded but the buffer was only partly + * filled. For interactive devices, this is the most common + * return value. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_READC: { + /* + * Reads a byte from the console. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters or values possible. + * + * Return + * On exit, the RETURN REGISTER contains the byte read from + * the console. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_REMOVE: { + /* + * Deletes a specified file on the host filing system. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a null-terminated string that gives the + * path name of the file to be deleted. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the delete is successful + * - A nonzero, host-specific error code if the delete fails. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_RENAME: { + /* + * Renames a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * four-field data block: + * - field 1 A pointer to the name of the old file. + * - field 2 The length of the old filename. + * - field 3 A pointer to the new filename. + * - field 4 The length of the new filename. Both strings are + * null-terminated. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the rename is successful. + * - A nonzero, host-specific error code if the rename fails. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_SEEK: { + /* + * Seeks to a specified position in a file using an offset + * specified from the start of the file. The file is assumed + * to be a byte array and the offset is given in bytes. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 A handle for a seekable file object. + * - field 2 The absolute byte position to seek to. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the request is successful. + * - A negative value if the request is not successful. + * Use SYS_ERRNO to read the value of the host errno variable + * describing the error. + * + * Note: The effect of seeking outside the current extent of + * the file object is undefined. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_SYSTEM: { + /* + * Passes a command to the host command-line interpreter. + * This enables you to execute a system command such as dir, + * ls, or pwd. The terminal I/O is on the host, and is not + * visible to the target. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a string to be passed to the host + * command-line interpreter. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + + /* Provide SYS_SYSTEM functionality. Uses the + * libc system command, there may be a reason *NOT* + * to use this, but as I can't think of one, I + * implemented it this way. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_TICKFREQ: { + /* + * Returns the tick frequency. + * + * Entry + * The PARAMETER REGISTER must contain 0 on entry to this routine. + * + * Return + * On exit, the RETURN REGISTER contains either: + * - The number of ticks per second. + * - –1 if the target does not know the value of one tick. + * + * Note: Some semihosting implementations might not support + * this semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_TIME: { + /* + * Returns the number of seconds since 00:00 January 1, 1970. + * This value is real-world time, regardless of any debug agent + * configuration. + * + * Entry + * There are no parameters. + * + * Return + * On exit, the RETURN REGISTER contains the number of seconds. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_TMPNAM: { + /* + * Returns a temporary name for a file identified by a system + * file identifier. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-word argument block: + * - field 1 A pointer to a buffer. + * - field 2 A target identifier for this filename. Its value + * must be an integer in the range 0-255. + * - field 3 Contains the length of the buffer. The length must + * be at least the value of L_tmpnam on the host system. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - –1 if an error occurs. + * + * The buffer pointed to by the PARAMETER REGISTER contains + * the filename, prefixed with a suitable directory name. + * If you use the same target identifier again, the same + * filename is returned. + * + * Note: The returned string must be null-terminated. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_WRITE: { + /* + * Writes the contents of a buffer to a specified file at the + * current file position. The file position is specified either: + * - Explicitly, by a SYS_SEEK. + * - Implicitly as one byte beyond the previous SYS_READ or + * SYS_WRITE request. + * + * The file position is at the start of the file when the file + * is opened, and is lost when the file is closed. + * + * Perform the file operation as a single action whenever + * possible. For example, do not split a write of 16KB into + * four 4KB chunks unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to the memory containing the data to be written. + * - field 3 Contains the number of bytes to be written from + * the buffer to the file. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - The number of bytes that are not written, if there is an error. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_WRITEC: { + /* + * Writes a character byte, pointed to by the PARAMETER REGISTER, + * to the debug channel. When executed under a semihosting + * debugger, the character appears on the host debugger console. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to the + * character. + * + * Return + * None. The RETURN REGISTER is corrupted. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } + case SEMIHOSTING_SYS_WRITE0: { + /* + * Writes a null-terminated string to the debug channel. + * When executed under a semihosting debugger, the characters + * appear on the host debugger console. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to the + * first byte of the string. + * + * Return + * None. The RETURN REGISTER is corrupted. + */ + uint8_t character; while(1) { - auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, a1, 1, &character); + auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character); if(res != iss::Ok) return; if(character == 0) break; putchar(character); - a1++; + parameter++; } - } else { - throw std::runtime_error("Not Implemented Error"); + } + case SEMIHOSTING_USER_CMD_0x100: { + /** + * + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, none are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } /* First user cmd op code */ + + case SEMIHOSTING_USER_CMD_0x1FF: { + /** + * + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, none are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + throw std::runtime_error("Semihosting Call not Implemented"); + } /* Last user cmd op code */ + default: + throw std::runtime_error("Semihosting Call not Implemented"); } } -template void semihosting_callback(iss::arch_if* arch_if_ptr, uint32_t a0, uint32_t a1); -template void semihosting_callback(iss::arch_if* arch_if_ptr, uint64_t a0, uint64_t a1); +template void semihosting_callback(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter); +template void semihosting_callback(iss::arch_if* arch_if_ptr, uint64_t call_number, uint64_t parameter); diff --git a/src/iss/semihosting/semihosting.h b/src/iss/semihosting/semihosting.h index cf396e4..ea6a5c6 100644 --- a/src/iss/semihosting/semihosting.h +++ b/src/iss/semihosting/semihosting.h @@ -1,6 +1,57 @@ #ifndef _SEMIHOSTING_H_ #define _SEMIHOSTING_H_ #include -template void semihosting_callback(iss::arch_if* arch_if_ptr, T a0, T a1); +/* + * According to: + * "Semihosting for AArch32 and AArch64, Release 2.0" + * https://static.docs.arm.com/100863/0200/semihosting.pdf + * from ARM Ltd. + * + * The available semihosting operation numbers passed in R0 are allocated + * as follows: + * - 0x00-0x31 Used by ARM. + * - 0x32-0xFF Reserved for future use by ARM. + * - 0x100-0x1FF Reserved for user applications. These are not used by ARM. + * However, if you are writing your own SVC operations, you are advised + * to use a different SVC number rather than using the semihosted + * SVC number and these operation type numbers. + * - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended + * that you do not use these. + */ +enum semihosting_operation_numbers { + /* + * ARM semihosting operations, in lexicographic order. + */ + SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */ + + SEMIHOSTING_SYS_CLOCK = 0x10, + SEMIHOSTING_SYS_CLOSE = 0x02, + SEMIHOSTING_SYS_ELAPSED = 0x30, + SEMIHOSTING_SYS_ERRNO = 0x13, + SEMIHOSTING_SYS_EXIT = 0x18, + SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20, + SEMIHOSTING_SYS_FLEN = 0x0C, + SEMIHOSTING_SYS_GET_CMDLINE = 0x15, + SEMIHOSTING_SYS_HEAPINFO = 0x16, + SEMIHOSTING_SYS_ISERROR = 0x08, + SEMIHOSTING_SYS_ISTTY = 0x09, + SEMIHOSTING_SYS_OPEN = 0x01, + SEMIHOSTING_SYS_READ = 0x06, + SEMIHOSTING_SYS_READC = 0x07, + SEMIHOSTING_SYS_REMOVE = 0x0E, + SEMIHOSTING_SYS_RENAME = 0x0F, + SEMIHOSTING_SYS_SEEK = 0x0A, + SEMIHOSTING_SYS_SYSTEM = 0x12, + SEMIHOSTING_SYS_TICKFREQ = 0x31, + SEMIHOSTING_SYS_TIME = 0x11, + SEMIHOSTING_SYS_TMPNAM = 0x0D, + SEMIHOSTING_SYS_WRITE = 0x05, + SEMIHOSTING_SYS_WRITEC = 0x03, + SEMIHOSTING_SYS_WRITE0 = 0x04, + SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */ + SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */ +}; + +template void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter); #endif \ No newline at end of file