ARM Debug Monitor
=================


Introduction
------------

The ARM debug monitor, <demon>, provides a common low-level programming, C 
library and debugging environment across:

 *  the ARM emulator, linked with <armsd>;

 *  <pisd> driving Advanced RISC Machines's Platform Independent Evaluation 
    (PIE) card for the ARM60;

This document describes the common programming and debugging environment 
supported by implementations of <demon>. For implementation details refer to 
the following:

 *  For the ARMulator model of <demon>, see <armos.h> and <armos.c> in the 
    <armul> directory of this release.

 *  For the implementation used in the PIE, see the <PIE User Manual>.

 *  To see how the functions of the debug monitor are used to implement a 
    <semi-hosted> C library, see the <semi> subdirectory of the <clib> 
    directory in this release.


Target Memory Map
-----------------

An initial memory map is defined as follows:

    Address
    0x00000       CPU Reset Vector
    0x00004       CPU Undefined Instruction Vector
    0x00008       CPU Software Interrupt Vector
    0x0000c       CPU Prefetch Abort Vector
    0x00010       CPU Data Abort Vector
    0x00014       CPU Address Exception Vector
    0x00018       CPU Interrupt Vector
    0x0001c       CPU Fast Interrupt Vector
    0x00020       ~1 KBytes for FIQ routine and FIQ mode stack
    0x00400       256 bytes for IRQ mode stack
    0x00500       256 bytes for Undefined mode stack
    0x00600       256 bytes for Abort mode stack
    0x00700       256 bytes for SVC mode stack
    0x00800       Debug monitor Private Workspace
    0x01000       Free for user supplied Debug Monitor
    0x02000       Floating Point Emulator space
    0x08000       Application space
    Top of memory

<Top of memory> is an implementation-dependent address returned by the debug 
monitor SWI <SWI_Getenv>. For the PIE and ARMulator variant it has the value 
0x80000 (512 KBytes). The C library support uses the top of memory address for 
the base of the user mode stack. All stacks grow towards address zero.


Standard Monitor SWIs
---------------------

Demon implements a number of useful SWIs:


SWI_WriteC (SWI 0)

Write a byte, passed in register 0, to the debug channel. When executed under 
<armsd>, the character will appear on the display device connected to <armsd>.


SWI_Write0 (SWI 2)

Write the null terminated string, pointed to by register 0, to the debug 
channel. When executed under <armsd>, the characters will appear on the display 
device connected to <armsd>.


SWI_ReadC (SWI 4)

Read a byte from the debug channel, returning it in register 0. The read is 
notionally from the keyboard attached to the debugger.


SWI_CLI (SWI 5)

Pass the string, pointed to by register 0, to the host's command line 
interpreter (NOT AVAILABLE IN THE PC/DOS RELEASE).


SWI_GetEnv (SWI 0x10)

Returns in register 0 the address of the command line string used to invoke the 
program, and in register 1 the highest available address in user memory.


SWI_Exit (SWI 0x11)

Halt emulation. This is the way a program exits cleanly, returning control to 
the debugger.


SWI_EnterOS (SWI 0x16)

Put the processor into supervisor mode. If the processor is currently in a 
26-bit mode, then SVC26 is entered; otherwise SVC32 is entered.


SWI_GetErrno (SWI 0x60)

Return, in r0, the value of the C library <errno> variable associated with the 
host support for this debug monitor. <errno> may be set by a number of C 
library support SWIs, including <SWI_Remove>, <SWI_Rename>, <SWI_Open>, 
<SWI_Close>, <SWI_Read>, <SWI_Write>, <SWI_Seek>, etc. Whether or not, and to 
what value <errno> is set is completely host-specific, except where the ANSI C 
standard defines the behaviour.


SWI_Clock (SWI 0x61)

Return, in r0, the number of centi-seconds since the support code began 
execution. In general, only the difference between successive calls to 
<SWI_Clock>, can be meaningful.


SWI_Time (SWI 0x63)

Return, in r0, the number of seconds since the beginning of 1970 (the Unix time 
origin).


SWI_Remove (SWI 0x64)

Delete (remove, un-link, wipe, destroy) the file named by the NUL-terminated 
string addressed by r0. Return (in r0) a <zero> if the removal succeeds, or a 
<non-zero>, host-specific error code if it fails.


SWI_Rename (SWI 0x65)

R0 and r1 address NUL-terminated strings, the <old-name> and <new-name>, 
respectively. If the rename succeeds, zero is returned in r0; otherwise, a 
non-zero, host-specific error code is returned.


SWI_Open (SWI 0x66)

R0 addresses a NUL-terminated string containing a file or device name; r1 is a 
small integer specifying the file opening mode (see table below). If the open 
succeeds, a non-zero <handle> is returned in r0, which can be quoted to 
<SWI_Close>, <SWI_Read>, <SWI_Write>, <SWI_Seek>, <SWI_Flen> and <SWI_IsTTY>. 
Nothing else may be asserted about the value of the <handle>. If the open 
fails, the value 0 is returned in r0.

    r1 value      ANSI C fopen() mode

    0             "r"
    1             "rb"
    2             "r+"
    3             "r+b"

    4             "w"
    5             "wb"
    6             "w+"
    7             "w+b"

    8             "a"
    9             "ab"
    10            "a+"
    11            "a+b"


SWI_Close (SWI 0x68)

On entry, r0 must be a <handle> for an open file, previously returned by 
<SWI_Open>. If the close succeeds, zero is returned in r0; otherwise, a 
non-zero value is returned.


SWI_Write (SWI 0x69)

On entry, r0 must contain a handle for a previously opened file; r1 points to a 
buffer in the callee; and r2 contains the number of bytes to be written from 
the buffer to the file. SWI_Write returns, in r0, the number of bytes <not> 
written (and so indicates success with a 0 return value).


SWI_Read (SWI 0x6a)

On entry, r0 must contain a handle for a previously opened file or device; r1 
points to a buffer in the callee; and r2 contains the number of bytes to be 
read from the file into the buffer. <SWI_Read> returns, in r0, the number of 
bytes <not> read, and so indicates the success of a read from a file with a 
zero return value. If the handle is for an interactive device (<SWI_IsTTY> 
returns non-zero for this handle), then a non-zero return from <SWI_Read> 
indicates that the line read did not fill the buffer.


SWI_Seek (SWI 0x6b)

On entry, r0 must contain a handle for a seekable file object, and r1 the 
absolute byte position to be sought to. If the request can be honoured then 
<SWI_Seek> returns 0 in r0; otherwise it returns a host-specific non-zero 
value. Note that the effect of seeking outside of the current extent of the 
file object is undefined.


SWI_Flen (SWI 0x6c)

On entry, r0 contains a handle for a previously opened, seekable file object. 
<SWI_Flen> returns, in r0, the current length of the file object, otherwise it 
returns -1.


SWI_IsTTY (SWI 0x6e)

On entry, r0 must contain a handle for a previously opened file or device 
object. On exit, r0 contains 1 if the handle identifies an interactive device; 
otherwise r0 contains 0.


SWI_TmpNam (SWI 0x6f)

On entry, r0 points to a buffer and r1 contains the length of the buffer (r1 
should be at least the value of L_tmpnam on the host system). On successful 
return, r0 points to the buffer which contains a host temporary file name. If 
the request cannot be satisfied (e.g. because the buffer is too small) then 0 
is returned in r0.


SWI_InstallHandler (SWI 0x70)

<SWI_InstallHandler> installs a handler for a hardware exception. On entry, r0 
contains the exception number (see the table below); r1 contains a value to 
pass to the handler when it is eventually invoked; and r2 contains the address 
of the handler. On return, r2 contains the address of the previous handler and 
r1 contains its argument.

On occurrence of the exception, the handler is entered in the appropriate 
non-user mode, with r10 holding a value dependent on the exception type, and 
r11 holding the handler argument (as passed to InstallHandler in r1). r10, r11, 
r12 and r14 (for the processor mode in which the handler is entered) are saved 
on the stack of the mode in which the handler is entered; all other registers 
are as at the time of the exception. (Any effects of the instruction causing 
the exception have been unwound, and the saved r14 points at the instruction 
that failed, rather than one or two words ahead.) If the handler returns, the 
exception will be passed to the debugger (regardless of the value of the 
debugger variable $vector_catch).

   no   exception               mode      r10 value

    0   branch through zero     swi32     -
    1   undefined instruction   undef32   -
    2   swi                     swi32     swi number
    3   prefetch abort          abort32   -
    4   data abort              abort32   -
    5   address exception       swi32     -
    6   IRQ                     irq32     -
    7   FIQ                     fiq32     -
    8   Error                   swi32     error pointer


SWI_GenerateError (SWI 0x71)

On entry, r0 points to an error block (containing a 32-bit error number, 
followed by a zero-terminated error string); r1 points to a 17-word block 
containing the values of the ARM CPU registers at the instant the error 
occurred (the 17th word contains the PSR).

<SWI_GenerateError> causes the (software) error vector to be called: if bit 8 
of $vector_catch is set this causes the debugger to be entered directly; 
otherwise, the installed error handler is called (see <SWI_InstallHandler>).


The implementation of Demon for the PIE 
----------------------------------------

The debug monitor is split into two parts, called Level 0 and Level 1. The code 
in Level 1 is replaceable, allowing new targets to be debugged using the same 
standard interface. The Remote Debug Protocol (RDP) is implemented between the 
debugger and the debuggee. See "<ARM Remote Debug Protocol>" 
for a complete description. Quite simply, the RDP defines a protocol that can 
communicate with a debugger and a debug monitor. Level 0 is responsible for 
recognising incoming RDP messages from the debug channel, and dispatching them 
to Level 1 of the debug monitor. Level 0 also drives the debug channel, at the 
request of Level 1.

Level 1 handles RDP messages from the debugger, and generates RDP messages to 
support the actions of the application using it. The Level 1 code implements a 
number of SWI instructions to allow an application access to high level 
functions. See "<Standard Monitor SWIs>"

The interface between Level 0 and Level 1 is via a number of entry addresses 
situated at the beginning the Level 0 code. Their layout is as follows:

    Offset

    0x00000       Reset Instruction

    0x00004       Address of Reset routine

    0x00008       Address of InstallRDP routine

    0x0000c       Address of ResetChannel routine

    0x00010       Address of ChannelSpeed routine

    0x00014       Address of GetByte routine

    0x00018       Address of PutByte routine

    0x0001c       Address of ReadTimer routine

    0x00020       Address of SetLED routine

The first two words are mapped into address 0 and 4 when the CPU is reset to 
provide the initial code entry.

The <InstallRDP> routine is used by the Level 1 code to register a handler of 
all RDP messages. The address of the handler should be passed in register 0, 
and the address of the previous handler will be returned in register 0. Level 1 
code that does not wish to handle all RDP messages may pass unhandled messages 
to the previous handler. The RDP handler is entered in FIQ mode, with 
interrupts disabled and the RDP message number in register 0. Exit from the 
handler by loading the program counter from the stack with an instruction such 
as LDMFD sp!, {pc}. All register values have been saved before entry to the 
handler, and will be restored after exit. Once the Level 1 RDP handler has been 
entered, it may read successive bytes from the debug channel using the <GetByte> 
routine, and send replies using the <PutByte> routine. The Level 1 handler may 
also formulate RDP messages to support application code that it has been called 
by, and these too are sent using <PutByte>.

The <ResetChannel> routine can be used to reset the debug channel driver, 
should error be detected by the Level 1 Code.

The <ChannelSpeed> routine is used to change the speed of the debug channel in 
an implementation designed fashion. Currently the PIE board supports baud rates 
of 9600, 19200 and 38400 bits per second over its serial channel. These speeds 
can be selected by sending the values 1, 2 or 3 respectively to the 
<ChannelSpeed> routine. A value of 0 selects the default (power on reset) 
value, which for the PIE is 9600 bps. The meaning of all other values is 
undefined.

The <GetByte> and <PutByte> routine get and put bytes to and from the debug 
channel, as described above.

The <ReadTimer> routine returns in register 0 a centi-second count from an on 
board timer. If an on board timer is not available, this routine will always 
return 0xFFFFFFFF (-1).

The <SetLED> routine allows the setting and clearing of an on board Light 
Emitting Diode (LED). Register 0 dictates the action required: 0 turns the LED 
off; any other values turn it on.

 

 

