NoICE Debugger

Target Requirements

Impact on User Programs

Interrupts and Startup Code

Breakpoints, Execution, and Single-Step

Protocol Details

Customizing the NoICE monitor

68HC11 Details

8051 Details

6502/65C02 Details

Z80/Z180 Details

6801/6301 Details

6809/6309 Details

8080/8085 Details

8096/80196 Details

 
Home Download Purchase Tutorials FAQ NoICE Help

 

NoICE for 68HC11, 8051, 6502/65C02, Z80/Z180, 6801/6301, 6809/6309, 8080/8085 and 8096/80196 using a target monitor and the NoICE Serial Protocol

Many newer microprocessors contain on-chip debugging resources that allow NoICE to burn and debug programs in Flash. NoICE supports this mode of operation for the 68HC12 using BDM or AN2548; the 68HC08 using BDM, AN2140 or MON08; and MSP430 using JTAG.

On other processors, NoICE requires the presence of a small monitor program in the target, and the program to be debugged must reside in RAM.

The monitor protocol includes messages 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.

The resources used by the monitor are similar to those required by classic hex debug monitors such as BUFFALO for the 68HC11, or Steve Kemplin's MONPLUS for the 8051. You need:

  • Enough EPROM or Flash to hold the monitor (about 1024 bytes; smaller than most stand-alone monitors).
  • Enough RAM to hold the monitor's data (32 to 256 bytes, depending on the number of processor registers and the desired communications buffer size)
  • A UART to communicate with the PC host (or an input bit, an output bit, and the appropriate user-provided bit-banging serial code)
  • Enough RAM to hold the program to be downloaded and debugged. If the processor distinguishes between code and data space (e.g., the 8051), then hardware external to the processor is required to allow the program space to be read and written by the processor. On the 8051, this usually means circuitry to OR together PSEN and RD, and to connect WR.
  • A "bash button" connected to a non-maskable interrupt is useful, but is not required.
  • Special hardware to support single step operation is not required.

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.


Impact on User Programs

In order for the monitor to take control at reset, it must generally be located in the portion of the processor address space where the interrupt vectors and/or interrupt handler entrypoints reside.

This means that the user program will generally not be able to be located in this region when you are debugging. In most cases, you will need to modify your build or make file, or your IDE's project settings to change the address of your program and/or its interrupt vectors. Details depend on your processor and your development tools.

Impact of this on interrupt handling are discussed in the following section.


Interrupts and Startup Code

Since the monitor program usually contains the interrupt vectors and/or interrupt handler entrypoints, 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.

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.


Breakpoints, Execution, and Single-Step

NoICE is able to perform single-step operations without the use of special hardware. 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.

More about the NoICE serial protocol

More about customizing the NoICE monitor

 
   
NoICE Debugger • Copyright © 2022 by John Hartman • Revised 28 February 2022