NoICE for 68HC11, 8051, 6502/65C02, Z80/Z180, 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
- 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
- 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
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