NoICE uses a small set of commands to query and control a target processor. The minimum set of commands is:
Some targets can provide some or all of these additional commands, which can add capabilities to NoICE:
NoICE uses the available commands to implement more sophisticated behaviors. For example, if a target doesn't have a command to set or clear software breakpoints, NoICE will use memory read and write commands to do the equivalent. If a target doesn't have a command to do single-step, NoICE will insert a breakpoint or breakpoints after the current instruction, and then use the Run Program command to execute the instruction.
Some target processors contain built-in support for some or all of these commands. These include
For information on using NoICE with these, click on the appropriate link.
Other target processors generally use NoICE Classic Monitor.
For processor without built-in debugging support, or when the built-in support cannot be used, NoICE relies on a target-resident monitor which implements a small set of commands. Monitor commands are used to read target configuration, to read and write blocks of memory, to read and write processor registers, to input from and output to I/O ports, to set and clear breakpoints, and to execute. Everything else is done by the PC.
The commands are identical in format for all target processors. Only the format of the register block is unique to the specific target processor.
Note: Traditionally, the connect between NoICE and the serial protocol has been via a serial port connection to a monitor program running on the target. However, NoICE also supports this protocol via TCP/IP connection. In most cases, this will not be a direct connection to a target, but rather a connection to a user-supplied process or device that can translate the NoICE monitor commands into actions appropriate for your target. For more information on this, please contact us.
The resources used by the monitor are similar to those required by hex debug monitors such as BUFFALO for the 68HC11, or Steve Kemplin's MONPLUS for the 8051:
Source code for the monitors may be found in the "monitors" subdirectory of wherever you install NoICE. The default location is C:\Program Files\NoICE\monitors.
Additional information is available about customizing target monitors.
As provided on the distribution disk, the monitors run with interrupts disabled. This is generally the best way to run a monitor, as it essentially "freezes time" while the monitor is running. User code can use interrupts by enabling them as appropriate. Interrupts will be disabled by the monitor upon breakpoint or other entry, and will be restored to their pre-entry states before the user code is resumed.
Since the EPROM containing the monitor will generally reside in the portion of the processor address space where the interrupt vectors and/or interrupt handler entrypoints reside, most of the monitors re-direct the interrupts to an area of the download RAM. The location of this area is determined by equates within each monitor. There are two basic schemes:
"ROM at the bottom" processors such as the Z80 and 8051 begin execution at address zero after reset. Interrupts cause calls to reserved locations in low memory. In order for the NoICE monitor to take control after reset, it must reside in low memory. The monitor contains code to route interrupts other than reset through the lower portion of the download RAM, beginning at an address defined as USER_CODE in the monitor source. The layout of this region of USER_CODE is identical to the "real" reset and interrupt region. Thus, a user program may be debugged by locating or ORGing it to begin at USER_CODE, and may be burned into EPROM by locating or ORGing it at zero. Typically, only this single equate needs to be changed between debug and EPROM versions. Refer to the source file for your target monitor for the exact details of the routing process.
"ROM at the top" processors such as the 68HC11 and 65C02 begin execution by fetching an address from an interrupt vector table at address 0FFFxH after reset. The addresses of interrupt handlers are stored in the same vector table. In order for the NoICE monitor to take control after reset, it (or at least a reset vector to it) must reside in high memory. The monitor contains code to route interrupts other than reset through a user vector table in download RAM, beginning at an address defined as USER_VECTORS in the monitor source. The layout of USER_VECTORS is identical to the "real" reset and interrupt vectors. Thus, a user program may be debugged by locating or ORGing it to begin at USER_CODE, with vectors at USER_VECTORS, and may be burned into EPROM by locating or ORGing the vectors at 0FFFxH. Typically, only this equate, and perhaps the location of the code, needs to be changed between debug and EPROM versions. Refer to the source file for your target monitor for the exact details of the interrupt routing process.
When the monitor is first started, it initializes the interrupt region of download RAM to point to default interrupt handlers within the monitor. Thus, if an interrupt occurs for which the user code has not provided a handler, the default handler will cause entry into the monitor as if a breakpoint had been executed. The identity of the interrupt will be displayed as the processor state in the NoICE title bar.
Some target monitors do not route certain interrupts which are used by the monitors. For example, SWI (software interrupt) on the 68HC11 is used for a breakpoint instruction. Thus, it passes directly to the monitor. The 68HC11 COP Fail interrupt is not normally routed, as its occurrence is generally considered to indicate a "fatal error". This could be changed if desired by modifying the monitor code appropriately.
NoICE is able to perform single-step without the use of special hardware (although such hardware may be optionally used. See FN_STEP below.) This is accomplished by the insertion of breakpoint instructions at the location(s) to be executed after the instruction to be stepped. For most instructions, the next instruction to be executed is the next one in sequential memory. Since the disassembler knows how long each instruction is, the address of the next sequential instruction may be obtained simply by calling the disassembler's instruction processing function for the instruction to be stepped. A breakpoint is inserted at the next sequential address, and the target told to execute until the breakpoint is hit, at which time the breakpoint is removed.
Certain instructions, such as branches, jumps, subroutine calls, and returns may cause the flow of execution to be changed. Code is added to the instruction processing functions of such instructions to derive the alternate execution address. In the case of subroutine returns and computed jumps, this may necessitate reading target registers or memory. Breakpoints are inserted at both the alternate execution address and the next sequential address, and the target told to execute until a breakpoint is hit, at which time both breakpoints are removed.
We had originally planned to determine the single next instruction address, but this caused several difficulties: the first is the larger number of instruction processing functions which would need to be written, to account for different conditional branches and the like. A more serious problem exists for targets such as the 8051 family which can branch based on the states of bits in I/O devices: For such instructions, there is no guarantee that the same value will be seen by the monitor reading ahead, and by the target at execution time. For these reasons, NoICE inserts two breakpoint instructions for all transfer of control instructions.
The NoICE serial protocol can use any serial port known to Windows, at any baud rate supported by your serial driver.
The message format is
Byte 0 | Function code, whose value must be greater than 7F hex or the target will ignore it. This aids in re-synchronization if target and host lose sync. |
Byte 1 | Length of data to follow, 0 to 255. Some target implementations may restrict the length to a smaller value. All targets must allow a data length of at least 19. |
Byte 2 to n | Data (if Byte 1 is non-zero). Interpretation of the data is determined by the function code in Byte 0. See below. |
Byte n+1 | Two's complement of the eight bit sum of Bytes 0 through n, such that the sum of Bytes 0 through n+1 is zero for a correctly received message. Messages received with an incorrect checksum are ignored. |
The communications protocol is half duplex, with the PC acting as master. Messages receive an immediate reply, except for FN_RUN_TARGET, the reply to which will be generated if and when the target executes a breakpoint, an unhandled interrupt, or is reset.
The messages are
Function | hex value | description |
---|---|---|
FN_GET_STATUS | 0FFH | get device info |
FN_READ_MEM | 0FEH | read memory |
FN_WRITE_MEM | 0FDH | write memory |
FN_READ_REGS | 0FCH | read registers |
FN_WRITE_REGS | 0FBH | write registers |
FN_RUN_TARGET | 0FAH | run target |
FN_SET_BYTES | 0F9H | set or clear breakpoint |
FN_IN | 0F8H | input from port |
FN_OUT | 0F7H | output to port |
FN_RESET_TARGET | 0F6H | reset target hardware |
FN_STEP | 0F5H | step one instruction |
FN_STOP_TARGET | 0F4H | stop program execution |
FN_ERROR | 0F0H | error reply |
This function allows the host to identify the target's processor type, and to obtain other useful information about the target. It is sent when NoICE starts up and when communications parameters are changed.
The request contains no data bytes. The reply data is as follows:
Byte 2 | Processor type | ||||||||||||||||
Byte 3 | Size of target communications buffer (19 to 255) | ||||||||||||||||
Byte 4 | Options flags
|
||||||||||||||||
Bytes 5,6 | Low bound of target mapped memory (0 if not mapped). Least significant byte first. | ||||||||||||||||
Bytes 7,8 | High bound of target mapped memory (0 if not mapped) Least significant byte first. | ||||||||||||||||
Byte 9 | Length of target's breakpoint instruction. | ||||||||||||||||
Bytes 10 to n | Target's breakpoint instruction (number of bytes specified by the value of Byte 9) | ||||||||||||||||
Bytes n+1 to m | Zero-terminated ASCII string: target description | ||||||||||||||||
Bytes m+1 to m+3 | Address For Subroutine Breakpoint, present only if Bit 7 of the Option Flags byte is set.
This address is pushed on the stack when the CALL command is executed. If these bytes are all zero, the user will be prompted for an appropriate address the first time the CALL command is used.
|
This function allows the host to read bytes from the target's memory. The request data is always 4 bytes long, and appears as follows:
Byte 2 | Memory page (or zero if paged memory is not supported) |
Bytes 3,4 | Memory address, least significant byte first |
Byte 5 | Number of bytes to return |
The reply data is as follows:
Bytes 2 to n | Requested data bytes |
This function allows the host to write bytes to the target's memory. The request data is always at least 3 bytes long, and appears as follows:
Byte 2 | Memory page (or zero if paged memory is not supported) |
Bytes 3,4 | Memory address, least significant byte first |
Bytes 5 to nn | Data to write. The length of the data to write may be computed from the net data length in Byte 1 as write length = Byte 1 - 3 |
The reply data is as follows:
Byte 2 | Status value for write: 0=success, 1=failed verify after write |
This function allows the host to read the target processor's registers. The request contains no data bytes. The reply data is as follows:
Byte 2 to nn | Register image. The byte order must match the target register definition in the host's target support module. Any multi-byte values must be provided least significant byte first. |
This function allows the host to write the target processor's registers. The request data is as follows:
Byte 2 to nn | Register image. |
Two possible reply formats exist. The first is used by most processors:
Byte 2 | Status value for write: 0=success, 1=failed write |
The second format is used by processors such as the 8051 which have multiple register banks. Since the register bank specifier is considered to be one of the processor registers, this format allows the processor to return a new register set when the bank register is changed (the previous format should be used if the target wishes to indicate a write failure, as due to an illegal register value etc.):
Byte 2 to nn | Register image. |
This function tells the target to begin execution at the address specified in its local register structure. If the host wishes to specify an execution address, it must do so by writing to the target's registers before issuing the execute command. The request contains no data bytes.
The reply data is as follows (returned when and if the target executes a breakpoint or is reset):
Byte 2 to nn | Register image. |
This optional function allows the host to write to target memory, and to obtain the contents before the write. It is used to insert and remove breakpoint instructions.
The length of the request is four times the number of bytes to be set. Request data is as follows:
Byte 2 | Page for first byte (0 if paged memory not supported) |
Bytes 3,4 | Address for first byte (least significant byte first) |
Byte 5 | Data to store at first byte |
... | ... |
Byte 4n-2 | Page for n'th byte (0 if paged memory not supported) |
Bytes 4n-1, 4n | Address for n'th byte (least significant byte first) |
Byte 4n+1 | Data to store at n'th byte |
The reply data is as follows:
Byte 2 | Data from first byte before store |
... | ... |
Byte n+2 | Data from n'th byte before store |
If the target is unable to successfully write a byte (for example, if an attempt is made to write a breakpoint into ROM), no further insertions will made in response to the command, and the returned data will include only the number of bytes actually inserted. Thus, the return length may be used to verify complete insertion of all bytes, or to tell where a failure has occurred.
The first time NoICE sets a breakpoint, it will send this function to the target. If the target does not support FN_SET_BYTES, it will return FN_ERROR, and NoICE will begin using FN_WRITE_MEM and FN_READ_MEM to set and clear breakpoints. This is slightly slower that using FN_SET_BYTES, but saves a few bytes of monitor code.
This function allows the host to read a target input port. If the target processor does not support separate memory and input/output spaces, then this command reads a byte from target memory. The request data is as follows:
Bytes 2,3 | Port address, least significant byte first |
The reply data is as follows:
Byte 2 | Data byte from port |
This function allows the host to write to a target output port. If the target processor does not support separate memory and input/output spaces, then this command writes a byte to target memory. Note that unlike FN_WRITE_MEM, no verification is done, since re-reading an I/O device may cause undesired operation. For this reason, this function is useful even for processors without separate input/output address spaces. The request data is as follows:
Bytes 2,3 | Port address, least significant byte first |
Byte 4 | Data byte to write |
The reply data is as follows:
Byte 2 | Status value: 0 |
This optional function allows the host to reset the target processor and hardware. NoICE will send this command to the target only if Bit 5 of the Option Flags byte is set. This function is not normally implemented in targets using a ROM monitor, since such hardware can seldom reset itself. FN_RESET_TARGET is provided for use by intermediate hardware such as In Circuit Emulators (ICE) and serial BDM converters which may have connections to the target reset line.
The request contains no data bytes.
Upon receiving this command, a target (or intermediate device) that supports the function will immediately send a response containing no data bytes to confirm reception of the command. The target will then wait long enough to ensure that the reply has completely left its UART, and then cause a reset of the target processor and hardware
After sending FN_RESET_TARGET and receiving a reply, NoICE will wait for approximately one second, ignoring any received characters (typically the register dump send during target startup, but often including some garbage bytes sent during UART initialization). After waiting, NoICE will send FN_GET_STATUS and FN_READ_REGS to get target state information.
This optional function allows the host to single-step the target processor. This function is not normally implemented in targets using a ROM monitor. FN_STEP is provided primarily for use by intermediate hardware such as In Circuit Emulators (ICE) and serial BDM converters which may have the ability to step the target. Certain ROM monitor targets may use non-maskable timer interrupts to perform single-step as well.
If Bit 4 of the Option Flags byte is set, then NoICE will use this function for instruction step. If Bit 4 of the Option Flags is not set, then NoICE will always use breakpoints to perform single-step.
The request contains no data bytes. The reply data is as follows:
Byte 2 to nn | Register image after stepping. The byte order must match the target register definition in the host's target support module. Any multi-byte values must be provided least significant byte first. |
This optional function allows the host to stop the execution of user programs by the target processor. This function must be supported if Bit 6 of the Option Flags byte is set.
This function is not normally implemented in targets using a ROM monitor. FN_STOP_TARGET is provided primarily for use by intermediate hardware such as In Circuit Emulators (ICE) and serial BDM converters which may have the ability to stop the target. Interrupt-driven ROM monitors may implement this function as well.
The request contains no data bytes.
The reply contains no data bytes. However, after sending the reply, the target must send an FN_RUN_TARGET response containing the target registers, as if the target had hit a breakpoint.
This function is never sent by the host to the target. It may be returned by the target in response to a message with a valid checksum, but whose function code is unknown to or unsupported by the target.
The reply may contain one data byte to specify the type of error. However, NoICE does not currently examine the contents of any data byte.
Normally, NoICE will not send messages to the target when a user program is running, that is, between the time when NoICE sends FN_RUN_TARGET and the time when the reply is received.
However, if Bit 6 of the Option Flags byte is set, NoICE can send the following messages even if a user program is running.
Note that this will not work correctly with the standard NoICE monitor, which uses polled communications. In order to allow communications while the user program is running, you must modify the montitor to use interrupt-driven communications, and ensure that interrupts are not disabled by your user programs for any appreciable length of time. We recommend that you not attempt this until you have some experience using NoICE with the standard polled monitor.
Messages not sendable during user program execution are