EE476 Final Project

Real-time Debugger

By

Emre Tezel & Cagdas Ozgenc

 

Objective

Parts Required

Features

Implementation Details

Conclusion

Objective: To design a debugger that is capable of tracing AT90S1200 user programs while the micro-controller is attached to external peripherals. The debugger will be able to display I/O activities, and dump the values of the registers.

Parts Required: Atmel STK-200 starter kit (kit includes a single AT90S8515 micro-controller), Inter x86 compatible PC (required for debugger software), serial cable (required for UART communication), 32k 24 pin 70ns SRAM (HY62256A), latch (CD74HC573E).

Features: Currently Atmel AT90S1200 micro-controllers do not have any tracing functionality, therefore there is no procedure to gather information about the MCU state although it is possible to suspend the program execution by putting the MCU into idle, or sleep mode.

For this reason, the only way to control the program execution is to implement a Virtual Machine inside the MCU, that is, there has to be a program responsible for execution of other programs. This program will be listening to external commands and suspend the program execution and report about the MCU state when necessary.

PC software and the Virtual Machine will be communicating through the UART, and Virtual Machine suspends, resumes execution, and dumps registers, program counter, stack and I/O register values according to the commands sent from the PC software.

The user programs are loaded to external RAM instead of being programmed into FLASH. Accordingly, a loader is implemented. Atmel assembler generates an object file that contains the opcodes. This file is read from any PC secondary storage, such as a hard-drive or a floppy, and opcodes are extracted and transferred through serial connection to the SRAM of the MCU.

The available RAM size on the AT90S8518 is 512 bytes. This is not enough for emulating an AT90S1200 since AT90S1200 has 1K of FLASH, 32 bytes of register space, 15 I/O lines, and an additional 64 bytes of EEPROM. Therefore, it is required to use the external RAM addressing capability of AT90S8515. However, according to the limitations of Atmel’s design, the I/O ports A and C of AT90S8515 are not able to be used for emulating AT90S1200 I/O functionality, since these ports are used for external memory access. Fortunately, in AT90S1200 ports A and C are not implemented. In contrast, pins 6, and 7 of I/O port D are also used to access external SRAM and are forfeited. Moreover pins 0, and 1 of the same port are allocated to UART communication. Unfortunately, it is not possible to emulate these missing I/O pins through any other pin of the AT90S8515 since they all serve a specific purpose.

To emulate AT90S1200 on an AT90S8515, it is required to imitate all processing functionality of the AT90S1200. The I/O functionality is through the AT90S8515 capabilities since AT90S8515 supports all the I/O functionality of AT90S1200. Since the user program is loaded into SRAM, there is no direct way to execute the instructions. Therefore, each opcode (all 16-bit wide in AT90S1200, total of 89 different instructions) is decoded and executed by the virtual machine.

The PC software brings the users a friendly environment to debug their programs, while all the peripherals are attached to the MCU. This is the advantage of this system over software simulators. Software simulators are not capable of detecting input signals coming from the peripherals.

The features of the PC software are running the program, step by step execution, adding break-points, displaying the values of the program counter, registers, contents of the stack, and resetting the Virtual Machine. Note that the time spent to program an MCU repeatedly for each small change in the user program does not exist anymore. The corrected code is uploaded to the external RAM instantly. Moreover, MCU will not be worn out because of nonexistence of write/erase cycles.

The implementation of the PC software benefits the object file generated by the Atmel’s assembler. The object file lists the position of the instructions within the source files. This is helpful to highlight the instruction where the execution stopped on the display window.

Implementation Details:

PART A AT90S1200 EMULATION

Instruction-set emulation

I/O emulation

Interrupts

Instruction-set emulation

The machine code written for the AT90S1200 that is to be emulated on the AT90S8515 is transferred through UART. This code is then copied from a communication buffer to a location reserved on the external RAM. The emulation is necessary since the instructions cannot be fetched and executed from the RAM, because, on this series of micro-controllers, the program memory and the data memory are separate memory spaces. The alternative solution is to write both the Real-time Debugger code and the code to be debugged to the reprogrammable FLASH, and control program execution by time-switching between the debugger code and the code to be debugged using timer interrupts. However, this solution requires precise timing if a step by step execution is desired, and more importantly the FLASH has to be rewritten each time a change to the code to be debugged has been made.

The emulation is achieved by a virtual machine that can fetch decode and execute AT90S1200 instructions from the external RAM. All memory requirements of the AT90S1200 is mapped to the RAM of AT90S8515, that is reprogrammable FLASH, registers, I/O space, hardware stack, program counter and EEPROM are all physically located on the external RAM of the AT90S8515.

The virtual program counter holds the location of the instruction to be executed, which is located on the RAM. A careful design is required here, since originally the flash is organized as words, however the RAM is organized as bytes, so a 16-bit instruction takes up 2 bytes of RAM. This becomes problematic, especially in relative branches, and jumps.

The hardware stack is designed so that boundary checking is possible. When the stack overflows, micro-controller immediately sends the appropriate error message to the PC software signaling that the stack has overflowed. This is very crucial because most of the programming errors occur by either calling subroutines extensively, or forgetting to return from these subroutines by a "ret" instruction.

I/O emulation

The purpose of the Real-time Debugger is to be able to test AT90S1200 programs when all I/O peripherals are attached to the development board. This requires full I/O emulation. To make life easier the I/O functionality of AT90S8515 is directly used. I/O emulation requires synchronizing the values in I/O registers of the AT90S8515 and the corresponding virtual I/O space reserved on the external RAM. For this reason, after execution of a single instruction the contents of the real I/O space is copied to the virtual I/O space. However, not all the I/O registers are required to be synched, in fact some should not be synched at all. For example, the status register of the AT90S8515 and the status register of the virtual machine should work independent to each other; same applies to the micro-controller control register. Let’s say we would like to put the AT90S1200 into idle mode, this does not imply that the AT90S8515 should go into idle mode, in fact we want it fully operational at all times, and just want it to behave as if it is in the idle mode. To unify the process, mask values, which are a single byte long, are associated with each I/O register to specify which bits are to be copied from real registers to virtual registers or vice versa. For example the mask value for the status register is binary 00000000, which means none of the bits in the status register will be copied from the real status register to the virtual. If there are 1s in any of the bits in a mask value, only those bits are copied. This is crucial in the synchronization of most I/O registers.

Interrupts

The interrupts are not enabled on the AT90S8515; that is interrupt service routines are not executed. Instead, after executing an instruction in the virtual machine, the interrupt flag registers of the AT90S8515 are checked to see whether there is a pending interrupt or not, and the virtual program counter is set to the address of the appropriate interrupt service routine in the virtual memory space. This approach correlate with the emulation of I/O, that is the interrupts of the AT90S8515 are used, but never serviced. They are just propagated to the virtual machine. The interrupts are propagated under the condition that the "interrupt enable flag" in the virtual status register is set, and the corresponding interrupt is enabled in the virtual I/O space. This is another reason why some of the I/O registers in the virtual I/O space should work independent of the corresponding registers of the AT90S8515. It is important to note that the interrupt service routines are delayed more than an original AT90S1200, because it takes time to do the necessary checks and propagate the interrupts to the virtual machine. The exact clock cycles are not known.

PART B THE USER INTERFACE

The Goal of the User Interface

The Design of the User Interface

· Requirements

· User Interface Controls

· Parser Class

· Communicator Class

· Demultiplexer Class

· Communication Protocol

The Goal of the User Interface

The main task of the User Interface (UI) is to establish a communication between the user and the microcontroller (MCU) through the serial port. This communication is based on a protocol. The UI sends to the MCU data packets that hold basic debugging commands such as go, break, trace, insert breakpoint, remove breakpoint and reset, and MCU sends to the UI in return data packets that hold the memory location of where the MCU stopped the execution, or error information.

The Design of the User Interface

The design of the UI can be categorized in five parts: UI Controls, Parser Class, Communicator Class, Demultiplexer Class and the Communication Protocol. Before going into detail with each part, it makes sense to mention first what is required to run the UI, since it is a Java application.

Requirements

The UI makes use of the Microsoft’s Windows Foundation Classes to implement UI Controls such as RichEdit, Menu, ProgressBar, ListView, OpenFileDialog and Multi Document Interface (MDI). It also uses the wrapper classes of the Win32 API in order to read and write to a communication port (serial port). Therefore the latest version of Microsoft Java Virtual Machine is required. Microsoft Virtual Machine can be downloaded from http://www.microsoft.com/java. You should also make sure that there are no conflicts with the communication ports.

User Interface Controls

The UI is a MDI application. Each source file (asm file) is opened in a different window. Each window includes a RichEdit control to which the source file is loaded initially. When the execution stops at a line in that source file, the line gets selected and the color of the line is changed to red. The user can also insert a breakpoint at a line whose color is again changed to red.

On the right side of the application, there is a ListView control, which has three columns and ninety-six rows. It displays the names, addresses and the values of the I/O space. The first thirty-two entries refer to the registers.

Figure 1 The User Interface Controls. On the right you can see the ListView control that displays the addresses, names and values of the I/O space. Currently "INTTEST.ASM" file is opened and maximized in a MDI window, and the program came to a stopped at the breakpoint at line 38.

Additional controls are Menu, ProgressBar and OpenFileDialog.

Parser Class

The task of the Parser Class is to parse the object file. It stores the names of the asm files, and for each instruction the opcode, memory address, line number in the source file and source file number. This information is later used by the UI to display the asm files and to find the location of a particular instruction in an asm file.

Communicator Class

The task of the Communicator Class is to open a connection to the serial port, and read and write an array of bytes to/from it. In order to that it uses wrapper classes of the Win32 API. Communicator Class opens an overlapped connection to the serial port, which enables multiple threads, read and write to port concurrently.

Demultiplexer Class

Demultiplexer Class is a thread, which tries to read bytes from the serial port all the time. As soon as an array of bytes is read, the Demultiplexer parses the byte array and fires the necessary events, such as the stop event or error event.

Communication Protocol

The Communication Protocol is the most important aspect for the communication between the UI and MCU. The protocol itself is very simple. First you send two bytes indicating the number of bytes you are going to send next, and then you send a packet of that many bytes. The first byte of the data packet is the "Tag", which tells the Demultiplexer the format of the rest of the data. Figure 2 shows the various tags and their formats.

Figure 2 Tags.

Figure 3 Running cycles of the UI and MCU.

Conclusion: The debugger kit that we have designed solves most of the debugging problems that the users are exposed to. The kit behaves like an AT90S1200. This gives the users a friendly environment to design and test their programs.