small refactor, adds baisc functionality
This commit is contained in:
parent
075e04249a
commit
3ff59ba45d
|
@ -1,621 +1,108 @@
|
|||
#include "semihosting.h"
|
||||
#include <cstdint>
|
||||
#include <iss/vm_types.h>
|
||||
#include <stdexcept>
|
||||
|
||||
// explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h
|
||||
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.
|
||||
*/
|
||||
switch(static_cast<semihosting_syscalls>(call_number)) {
|
||||
case semihosting_syscalls::SYS_CLOCK: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_CLOSE: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ELAPSED: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ERRNO: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_EXIT: {
|
||||
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT");
|
||||
break;
|
||||
}
|
||||
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_syscalls::SYS_EXIT_EXTENDED: {
|
||||
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT_EXTENDED");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_FLEN: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_GET_CMDLINE: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_HEAPINFO: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_ISERROR: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_ISTTY: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_OPEN: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_READ: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_READC: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_REMOVE: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_RENAME: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_SEEK: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_SYSTEM: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_TICKFREQ: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_TIME: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_TMPNAM: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::SYS_WRITE: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
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_syscalls::SYS_WRITEC: {
|
||||
uint8_t 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;
|
||||
putchar(character);
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
case semihosting_syscalls::SYS_WRITE0: {
|
||||
uint8_t character;
|
||||
while(1) {
|
||||
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, parameter, 1, &character);
|
||||
|
@ -626,54 +113,19 @@ template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T cal
|
|||
putchar(character);
|
||||
parameter++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
case semihosting_syscalls::USER_CMD_0x100: {
|
||||
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.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::USER_CMD_0x1FF: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
} /* Last user cmd op code */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
}
|
||||
template void semihosting_callback<uint32_t>(iss::arch_if* arch_if_ptr, uint32_t call_number, uint32_t parameter);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* https://static.docs.arm.com/100863/0200/semihosting.pdf
|
||||
* from ARM Ltd.
|
||||
*
|
||||
* The available semihosting operation numbers passed in R0 are allocated
|
||||
* The available semihosting operation numbers passed in A0 are allocated
|
||||
* as follows:
|
||||
* - 0x00-0x31 Used by ARM.
|
||||
* - 0x32-0xFF Reserved for future use by ARM.
|
||||
|
@ -18,38 +18,34 @@
|
|||
* - 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 */
|
||||
enum class semihosting_syscalls {
|
||||
|
||||
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 */
|
||||
SYS_OPEN = 0x01,
|
||||
SYS_CLOSE = 0x02,
|
||||
SYS_WRITEC = 0x03,
|
||||
SYS_WRITE0 = 0x04,
|
||||
SYS_WRITE = 0x05,
|
||||
SYS_READ = 0x06,
|
||||
SYS_READC = 0x07,
|
||||
SYS_ISERROR = 0x08,
|
||||
SYS_ISTTY = 0x09,
|
||||
SYS_SEEK = 0x0A,
|
||||
SYS_FLEN = 0x0C,
|
||||
SYS_TMPNAM = 0x0D,
|
||||
SYS_REMOVE = 0x0E,
|
||||
SYS_RENAME = 0x0F,
|
||||
SYS_CLOCK = 0x10,
|
||||
SYS_TIME = 0x11,
|
||||
SYS_SYSTEM = 0x12,
|
||||
SYS_ERRNO = 0x13,
|
||||
SYS_GET_CMDLINE = 0x15,
|
||||
SYS_HEAPINFO = 0x16,
|
||||
SYS_EXIT = 0x18,
|
||||
SYS_EXIT_EXTENDED = 0x20,
|
||||
SYS_ELAPSED = 0x30,
|
||||
SYS_TICKFREQ = 0x31,
|
||||
USER_CMD_0x100 = 0x100,
|
||||
USER_CMD_0x1FF = 0x1FF,
|
||||
};
|
||||
|
||||
template <typename T> void semihosting_callback(iss::arch_if* arch_if_ptr, T call_number, T parameter);
|
||||
|
|
Loading…
Reference in New Issue