681 lines
27 KiB
C++
681 lines
27 KiB
C++
#include "semihosting.h"
|
||
#include <iss/vm_types.h>
|
||
#include <stdexcept>
|
||
|
||
template <typename T> 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, parameter, 1, &character);
|
||
if(res != iss::Ok)
|
||
return;
|
||
if(character == 0)
|
||
break;
|
||
putchar(character);
|
||
parameter++;
|
||
}
|
||
}
|
||
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<uint32_t>(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter);
|
||
template void semihosting_callback<uint64_t>(iss::arch_if* arch_if_ptr, uint64_t call_number, uint64_t parameter);
|