Department of Electrical and Computer Engineering
University
of Wisconsin-Madison

ECE 353: INTRODUCTION TO MICROPROCESSOR SYSTEMS
Spring 2007

Assembler/Debugger Tutorial

TABLE OF CONTENTS

·  1 Introduction

·  2 Example Source Code

·  3 Setup on CAE machine

·  4 Open the Project

·  5 Build the Project

·  6 Debug

·  7 Project File Tree

 

 


1 Introduction

This semester we will use the Keil uVision3 Development tool, including  Assembler, Linker, and Debugger, available at CAE on the Novell (NT) PC network. You can also download and install the tool on your own PC. (See the course web page for a link.) This tutorial is designed to help you learn how to use this tool for creating, compiling,  simulating and debugging assembly-level software for this course. Several features of the tools that will be useful for these purposes will be introduced. These skills will be needed for completing the homework assignments in this course.

An example project folder is available on the course web page and will be used to demonstrate the tools. You are to download the programs from the course web page, assemble them, then debug and fix any errors which may cause the program not to work, and get it to run. In the process of doing so, you will gain experience with using the toolset.

2 Example Source Code

The following source code is provided for this tutorial as text files main.s and strchr.s contained in the tutorial.zip file linked on the course web page. Download it and save it in an appropriate directory, then unzip it.  The source code has three errors, one on each of the three lines indicated in bold type.  Do not fix the errors until after you try to assemble the program and see the reported errors.  This will help to give you some idea of the type and extent of information that the assembler will give you when it detects an error.

; Filename:    main.s
; Author:      ECE 353 Staff
; Description: main program file for tutorial

    ARM                    ;use ARM instruction set

    EXTERN  strchr
    EXTERN  strchr2
    EXPORT  __main

    AREA    FLASH, CODE, READONLY

__main

    ADR     R0, string1
    MOV     R1, #'a'
    BL      strchr

    ADR     R0, string2
    MOVE    R1, #'a'
    BL      strchr1

    B       __main

string1     DCB     "This is a test 1-2-3", 0
string2     DCB     "Not in here!", 0

    END

----------------------------------------------------------------

; Filename:    strchr.s
; Author:      ECE 353 Staff
; Description: Implementation of C strchr function

    ARM                 ;use ARM instruction set

    EXPORT  strchr
    EXPORT  strchr1

    AREA    FLASH, CODE, READONLY


; Name: strchr
; Description: Implements C strchr function
;              using register parameter passing
; Assumes:     R0 - string address
;              R1 - character to find
; Returns:     R0 - address of first instance of character
;                   or 0 if not found
; Modifies:    None
strchr
    STR     R2, [R13, #-4]!       ;context save
strchr_loop
    LDRB    R2, [R0], #+1         ;get character from string
    CMP     R2, R1                ;found the character?
    BEQ     strchr_end            ;if so, return current R0
    CMP     R2, #0                ;hit end of string?
    BNE     strchr_loop           ;if not, keep looking
strchr_not_found
    MOV     R0, #0                ;set 0 return value
strchr_end
    LDR     R2, [R13], #+4        ;context restore
    MOV     PC, LR                ;return

; Name: strchr1
; Description: Implements C strchr function
;              using register parameter passing
; Assumes:     R0 - string address
;              R1 - character to find
; Returns:     R0 - address of first instance of character
;                   or 0 if not found
; Modifies:    None
strchr1
    STMFD   R13!, {R2, LR}        ;context save
strchr1_loop
    LDRB    R2, [R0], #+1         ;get character from string
    CMP     R2, R1                ;found character?
    LDMEQFD R13!, {R2, PC}        ;if so, return
    CMP     R2, #0                ;hit end of string?
    BNE     strchr_loop
    MOV     R0, #0                ;if so, return 0
    LDMFD   R13!, {R2, PC}        ;context restore/return

    END

The three errors in the program are; the "EXTERN strchr2" line should read "EXTERN strchr1", the instruction "move" on the second bold line should be "mov", and the label "strchr_loop" on the third bold line should be "strchr1_loop".

3 Setup on CAE machine

Before you can use the Keil tool on your CAE account, you must add it to the CAE Applications menu. Click on 'Start' in the bottom left corner of the screen, then on 'CAE Applications-->Add_Application'. Select Microvision 3.01 from the alphabetical listing by checking the box to the left. Select 'apply', then quit. Now the Keil uVision3 tool should be available as an option from the menu 'CAE Applications-->Engineering. Start the tool and wait for it to initialize.

4 Open the project

To open the tutorial project, click  'Project-->Open'  from the top menu and select "tutorial.Uv2" from the directory where you placed it, then click 'open'. You should now see several source files listed in the Project Workspace window (main.s, ADuC702x.s). You need to add the file strchr.s to the project. In the 'Project Workspace' window, right click over the 'Source Group 1' item and select the menu option 'Add Files to Group 'Source Group 1' '. Note that you must select the file type of Asm Source File (.s, etc.) for this file to show up in the list.

Now, double click on each of these file names in the Project Workspace window to open each of them in the source window. Observe the header information and overall layout of these source files. Be sure to read and follow the Source Code Documentation Standards available on the course web page when you write your own code.

5 Build the project

At this point, you only have 'source' files, written in assembly language. This is great for you as a programmer to look at and understand, but the processor needs to have the code translated into 'machine code' so it can understand and execute it. Converting the source code to machine code is a several step process including steps like compiling, assembling and linking. This tool combines these steps into one menu selection, called build. So, in order to test the functionality of the source code, it must first be built. To build it, select the menu item 'Project-->Build target(F7)'. The tool will give status information about the build process in the output-->Build window at the bottom of the screen. If there are errors that the tool can  discern, it will give an error message in this window. When it is done, it will report the total number of errors and warnings. Generally, errors prevent successful building of the project, warnings allow it to produce an executable, but make sure it isn't something significant. You should see an error message 'main.s(20): error: A1163E: Unknown opcode MOVe , expecting opcode or Macro'. Correct this error, save the file and try building again.You should get an error 'main.s(21): error: A1516E: Bad symbol 'strchr1', not defined or external'. Correct the typo in the EXTERN statement and try building again. Your build should have been successful.

The executable file in this project is called test2.afx. In the project directory, you will also see some other files created by the build process. The object files (*.o) are the result of the assembly step and are used by the Linker to create the final executable. The list files (*.lst) show the source code and the machine code it gets translated into, as well as the symbols used. The map file (test2.map) shows the memory usage and where the different source files get mapped into memory.

 

6 Debug

Next, start a debug session by selecting 'Debug-->Start/Stop Debug Session'. This will open a Disassembly window, which shows the assembly code instructions and the corresponding machine code. The next instruction to be executed is indicated by the location of the cursor. Note that there is no debug information in the disassembly window (the original assembly code with comments is missing). This is due to the double mapping of the Flash memory to 0x00000000 and 0x00080000. The debug information is only available at the 0x00080000 address region since that is where our source code maps it. To execute one instruction and then stop, select 'Debug-->Step (F11)'. Notice that we now have debug information and the code address has changed to the 0x00080000range. The code that is executing at the start is from ADuC702x.s. We won't be looking at this file here, so select the main.s window and put the cursor at line 15 and then select 'Debug-->Run to Cursor line'. The cursor should now be at that line in main.s. Do another step. Look at the left side of the tool and find the register window. Register R0 should have a value of 0x000800c4, which is the starting location of string1. R1 should be zero. Do another step. Register R1 should now have a value of 0x00000061, which is the ascii value 'a'. Also, notice that this register is highlighted, as is R15(PC). The tool highlights any registers that changed value during the execution of the last instruction, making it easier to know what changes actually occurred.

Do another step. The cursor is now in a different source file - strchr.s. This is due to the branch taken during execution of the BL instruction. It moved the execution to a different location - a subroutine, or function. This routine will save the value in the Program Counter (PC) at the branch so it can be restored at the end, allowing program execution to resume at the next instruction in the calling program.

Some other useful commands include:  'Debug-->Step Over (F10)', which will not "dive into" a subroutine call,  'Debug-->Run to Cursor line (Ctrl+F10)', which allows you to set the cursor to some line further in the execution stream and execute all instructions up to that one then stop. If something gets messed up, or you just want to start over, the 'Peripherals-->Reset CPU' command will put the microprocessor in its reset state and will set the cursor to the first instruction.

If you want to let the program run, but want it to stop at one particular spot, or at one of several locations, this can be accomplished using breakpoints. A breakpoint can be set at a line of source code in one of several ways. You can use the menu item 'Debug-->Insert/Remove Breakpoint (F9)' with the cursor at the line where you want the breakpoint. Another way is to place the mouse cursor to the left of the line where you want the breakpoint and double-click the left button. Another double-click will remove it.

Another useful feature for debugging is the memory window. Open one by selecting 'View-->Memory Window'. It should be at the bottom of the screen. To see how it can be used, look at line 15 of main.s. Set the cursor there, run to cursor, then do a step. The cursor should be at line 16 and the address of string1 should be in R0. R0 has a value of 0x000800c4, which is the address in memory where string1 starts. Enter this value in the address box of the memory window and hit enter. The values in memory starting at 0x000800c4 should now be displayed. A right mouse click on the shaded area to the right of the address box will show a menu for selecting how you want the values to be displayed. Select 'unsigned char' if you want to see the hexadecimal numbers for this string, 'ascii' if you want to see the letters.

The values of variables or registers can also be monitored using a 'watch'. Open the watch window by selecting 'View-->Watch & Call Stack Window'. Select the 'Watch#1' tab on the bottom of the window. Now, add R0, R1 and R2 to the watch window. To add a register, put the mouse cursor over the register name in a source window and right click. Select 'Add Rx to watch window...' and specify #1. Once all three registers are added, step through the code and watch the values change.

For larger projects, the 'Edit-->Find in files' command can be useful to see where a variable or function call is used in the project. This tutorial is small enough that it would not likely be needed.

7 Project file tree

In the 'Project Workspace' window, click on the 'files' icon in the lower left corner. You should now see the list of files in this project. If a source file is not already open in the source window, double-clicking on its name in the 'Project Workspace' window will open it.

To add a new source file to the project, select 'File-->New' to open a new source file window. Add the needed code to the file and save as a .s file type. Now, in the 'Project Workspace' window, right click over the 'Source Group 1' item and select the menu option 'Add Files to Group 'Source Group 1' ' with file type asm selected. Select the file you want and click 'add'. The new file should now be in the file list in the 'Project Workspace' window.