Assembler and Debugger

Purpose

The purpose of this assignment is to familiarize you with the assembly language of the machine we are using, and give you more practice with:

Due dates

You must hand in the answers to the questions about common programming language constructs and addressing modes at the beginning of your laboratory session on Thursday, September 4. This part of the assignment is worth 16 points.

You must also be prepared to discuss your work at the beginning of your laboratory session on Tuesday, September 9, and to demonstrate your use of the simulator to your TA during that period. This part of the assignment is worth 10 points.

Background

One important reason for writing in assembly code is to access low-level features of the machine. We might want to do this in order to communicate with some device, or to implement some critical operation more efficiently than a compiler can. In either case, the assembly language code will form only a small portion of the complete program, and will consist of routines called from code written in a higher-level programming language.

Assembly language programming is difficult because of the amount of code that must be written to accomplish even simple tasks. When writing in assembly language, it is easy to lose sight of the structure in the welter of detail. In order to control this complexity, we should approach an assembly language programming problem by thinking in terms of the constructs we are familiar with, expressing the solution using those constructs, and then coding them individually with assembly language instructions. This approach allows us to think locally when writing assembly language, because the global aspects have been expressed in the higher-level constructs.

In order to carry out this strategy, it is important to understand how high-level constructs can be implemented by sequences of assembly language instructions. Also, reading such implementations helps us to understand the assembly language instructions themselves and see how they are used. The best way to gain this understanding is to ask the compiler to show us the assembly code that it has produced.

Assembly code programs produced by the compiler are not only useful for helping us to understand the use of machine instructions; they also serve as starting points for code development. For example, if you need to implement some critical operation more efficiently than the compiler can, then you should start from the assembly code produced by the compiler for that operation. The code produced by the compiler gives you the basic algorithmic structure and the interface to the invoker, thus leaving you with only the local task of improving the code. Similarly, if you want to communicate with some device, write a dummy routine in a high-level language that obeys the interface you desire. The compiler's translation of that program then provides a skeleton into which the assembly code communicating with the device can be inserted.

A simulator allows us to monitor a program's execution, stopping it at critical points to examine the content of registers and memory. We can advance the program one instruction at a time, or let it run until it reaches an interesting area. This assignment is designed to familiarize you with such a simulator, which runs on the HP.

In order to successfully use the simulator to examine a program, you must know what that program is supposed to do and how it goes about doing that. This knowledge includes the purpose of each variable and register, and the relationships among those variables and registers.

A particular variable or register may have different purposes at different points in the program. The contents of all variables and registers at a particular point in the execution of a program constitute the state of the program at that point. When we examine the contents of variables or memory, what we are trying to do is to determine whether those contents are consistent with the desired state of the program according to our understanding of how it is supposed to operate.

The ability to read and understand a program written in C or in assembly language is a vital skill that you must practice. When you are not fluent in a specific programming language, you must be prepared to look up the meaning of unfamiliar language constructs, just as you must look up the meanings of unfamiliar words when reading text in a natural language. As your fluency increases, your need to look up the meanings of constructs will decrease. There is no need for you to devote special efforts to memorizing language constructs; familiarity will come with repetition.

All of the MC68000 development system documentation is available on the HP itself. It can be obtained via the Windows Start menu, but it's useful to have a shortcut for it on the desktop: Click the Start menu on the Windows toolbar at the bottom of the screen, and go to Programs->MGC embedded->Online documents->Microtec Toolkit (Simulator) for 68K Docs. (Don't select the version with ``[CD]'' at the end of the line, because Windows will then look for the documents on a CD.) Right-click on this, and select Create Shortcut. Left-click, and a line Microtec Toolkit (Simulator) for 68K Docs (2) will appear. Drag this line to the desktop to get the shortcut icon.

The simulator documentation is actually a set of documents covering the compiler, assembler, and simulator. When you select it, you will get an Adobe Acrobat window that will allow you to read and bookmark any of the manuals.

Task

The greatest common divisor (GCD) of two non-negative integers can be computed by a simple iterative process coded as a C routine.

Your task is to obtain a copy of the program containing this routine, compile that program, and use the HP's MC68000 simulator to explore its behavior.

Note any problems you have as they occur, and be prepared to discuss them at your next laboratory session. Also be prepared to demonstrate and explain your use of the development system to your TA during the lab session.

The individual steps are expanded below.

Log onto an HP

When you press Ctrl+Alt+Delete on one of the HP, a Windows Log On window will appear. Fill in your user name and password, and select METAVERSE in the Log on to pane before clicking OK.

Set up your environment

All of your compilations on the HP will use a command-line interface. There are two possibilities: Cygwin (which provides a Unix interface) and the Windows command line interface. Icons for both of these programs are on the HP desktop, and it is your choice which you use. In either case, when you open the window the shell will be in your home directory on the ECE server (the Z: drive of the HP). For the remainder of the course, we will refer to this directory simply as ``your home directory''. We strongly recommend that you do all of your work in this directory and directories descended from it, rather than moving to another drive.

If you use the Cygwin interface, you will get an error message when the window first opens:


CMD.EXE was started with '\\blacksun\arp\Windows Folders\Desktop' as
the current
directory path.  UNC paths
are not supported.  Defaulting to Windows directory.
Your group is currently "mkpasswd".  This indicates that
the /etc/passwd (and possibly /etc/group) files should be rebuilt.
See the man pages for mkpasswd and mkgroup then, for example, run
mkpasswd -l [-d] > /etc/passwd
mkgroup  -l [-d] > /etc/group
Note that the -d switch is necessary for domain users.

You are a ``domain user'', because you are working in your home directory on the ECE server rather than being logged on to the particular HP you're sitting at. Simply ignore this message.

If you use the Cygwin interface, you will need to add the MC68000 development system binary directory to your path. Edit file .bashrc in your home directory adding the following line to the end of the file:

PATH=$PATH:/cygdrive/c/MGC/embedded/bin
We recommend the vim editor for use in this course. It is a capable editor that is available on a variety of platforms. You can run it as a Cygwin command, or you can double-click the gVim 6.3 icon on your desktop. There is also a vimtutor icon on the desktop; double-clicking it will put you into an excellent tutorial.

Understand the source program

Start Internet Explorer on one of the HPs in the laboratory, and point it to this assignment.

First click here to study the gcd subroutine. That subroutine is provided with an interface specification describing its purpose and result. The interface specification constitutes the framework for understanding the code that implements the subroutine; given the interface specification, you don't have to consider the behavior of the calling program.

You should concentrate your attention on the if statement that follows the while (not the if that is the body of the while): How does this code guarantee that Biggest[In] satisfies the exit condition?

Click here to see the main program that calls the subroutine. It can be understood without knowing the details of the subroutine implementation; the subroutine's interface specification provides all of the necessary information.

Obtain the program and compile it

Click here to get a zip file containing the source code and an appropriate Makefile. The browser will pop up a ``File Download'' window asking you what to do with the file; click Open: to invoke WinZip. Click the middle button in the bottom row (I Agree) of the license window, and when the WinZip control window appears click the Extract icon. An ``Extract'' window will pop up.

Select a directory on your Z: drive, either by using the browse area of the ``Extract'' window or by typing the full path name into the Extract to: area in the upper left. Click the Extract button in the upper right after you have selected the directory. WinZip will create a hw1 subdirectory of the selected directory, and this subdirectory will contain all of the source files and the Makefile needed to create the decryption program. After this operation is complete, you can dismiss the WinZip window. Obtain a command-line window by double-clicking on either the Cygwin icon or the Command Prompt icon. In your command-line window, cd to the hw2 directory unpacked from the zip file, and execute make. This will cause the computer to carry out a sequence of compilations, translating the source files into machine code, followed by a linking step that combines them.

The linking step may produce a warning message:

(W) #A0347-D Command Ignored: Output is S
Ignore this warning.

The linker has produced a file called driver.abs, which contains the MC68000 program in a form (``Motorola S-Records'') that can be downloaded to the MB5.

Your hw2 directory should now contain some files with a .src extension. These are assembly source files produced by the compiler. They were assembled by the assembler to produce the corresponding .lst and .o files. The .lst files are assembly listing files, which provide information on how the assembler generated code from the source files.

The Makefile directed the linker to produce the mcc68k.map file, which provides information on where code and variables will be placed in the simulator's memory.

Examine the assembly code

Look at either the .src files produced by the compiler or the .lst files produced by the assembler, and answer the questions given below.

The purpose of looking at assembly code in this assignment is not to understand every line, but to try to see how familiar C constructs like while statements and if statements can be implemented using the instructions of the MC68000. Here are some hints to help you orient yourself:

Program execution

Use the simulator to execute the program, control that execution, and inspect the internal state.

The simulator can be started via the Windows Start menu, but it's useful to have a shortcut for it on the desktop: Click the Start menu on the Windows toolbar at the bottom of the screen, and go to Programs->MGC Embedded->68K XRAY Simulator. Right-click on this, and select Create Shortcut. Left-click, and a line 68K XRAY Simulator (2) will appear. Drag this line to the desktop to get the shortcut icon.

When you start the simulator, three windows should pop up: a Managers window, a Code window, and an Output Logging window.

Select the Managers window and then click on the Connect tab (it may already be selected by default). Within this window, you will see two main areas labeled Active Connections and Available Connections There are also a number of buttons.

Under Available Connections, select the localhost associated with the Server named SIM68K_MEM_CONNEC.... You must click on the Name localhost and only it will be highlighted. Next click on the Connect button below. In a few seconds, some messages will come up on the Output Logging window. You may ignore these.

Next select the Code window. Click on File and select the Change Directory menu item. Change the current directory to the hw2 directory in which you compiled your C code.

Once you have changed your directory for the code window, go back to the Managers window and select the Files tab. Click on the Load button at the bottom of the window and select the Load File to Target menu item. Another window will pop up. Change directories in this window to hw2 directory, select driver.abs, and click Open. The simulator will load the 68K executable file, and is then ready to begin execution. At the same time, you will notice that the Code window has changed to show the driver.c source text. If you click on the Asm tab the window shows the assembly code that was generated by the assembler and linked by the linker.

With the Code window selected, click on File and select the Open... menu item. Select the gcd.c file and click Open. The code window will now show the content of gcd.c. You can switch between gcd.c and driver.c by clicking on the appropriate tab below the window pane containing the source text.

Now run the program run by clicking on the left-most button in the Code window's toolbar. (The toolbar is just below the line of pull-down menu names.) The program will run for about 15 seconds and a stdio window will pop up to display the output from its printf statements.

Post mortem inspection

Sometimes it is useful to inspect the state of a program after it has completed execution, usually by terminating in some messy fashion. In our case, even though the program should have run to completion without any problems, we may still want to look a some variables that were not output with a print statement. For example, the GCD modules contains two global variables that are not output. Let's verify that the states of these two variables are consistent at the end of the program execution.

Click the Windows pull-down menu of the Code window, and select Inspect. Another window, which allows you to inspect program variables, will pop up. Type the name of the variable of interest (In, perhaps) into the small pane, and click Inspect Symbol or Expression. Information about that variable will then be displayed in the lower pane of the Inspector window. Inspect the values of In and the elements of Biggest to convince yourself that they are in a consistent state, and be prepared to explain to your TA why you think that the state is consistent.

Note that local variables are only ``alive'' and ``known'' in the context of the scope in which they are defined. So, after the program has run, it makes no sense to inspect the value of the local variable i in main. If you type i as the variable to inspect, the value will not be found because the symbol i is not defined in the context outside of main. You can get rid of the bogus information by clicking the ``scissors'' button while the name i is in the variable name window.

You can use a ``fully qualified'' name to specify a local variable. For example, ask to inspect DRIVER\main\i. The simulator will now tell you that the local variable is ``not alive'', rather than saying that it does not exist.

Inspection during execution

In addition to inspecting variables after program execution, it is also useful to view variables during program execution. The actual inspection of the variables is done in the same way whether it is done during or after execution. All that is necessary is to halt the program at an appropriate point so the inspection can take place. For example, we might want to inspect the program's state after computing the greatest common divisors of 20 pairs of random integers.

First reset the state of the machine by selecting the Managers window and clicking on the Files tab. Next select Load and click on Load or Reload All Files to Target. Now select the Code window again and select the driver.c tab. This should show the driver.c code. Double-click on the line number associated with the line where the gcd subroutine is called. A little red icon should pop up indicated that a breakpoint has been set a this line. You can now run the program again.

The program will run until it encounters the selected line of code. It will then stop, allowing you to inspect variable and register values. If you still have an inspection window open, it shows the current values of the specified variables.

Since the breakpoint had the program stop in the context of main, you can see a valid value for i. Moreover, you can describe that variable by either i or DRIVER\main\i.

To see the state of the machine after 20 pairs of random integers have been processed, we could simply keep pressing the go button 19 more times. A different approach is set a break on a condition. For example, we want to stop the program after i has reached a value of 20. First, cancel the current breakpoint by double-clicking on the selected line. Next, use the mouse to place the cursor in the bottom line of the Code window, where you see ``Stop>''. Left-click, and a block cursor will appear after the >. This is the cursor for a command-line interface to the simulator. Here you can type any command that the simulator recognizes.

Type gostep until (i == 20), followed by Enter. The simulator will run the program, checking the value of i against 20 after each instruction. Clearly this is a very time-consuming process! While the program is running, it will display ``Run'' on the bottom line of the code window. After several minutes, the stopping condition will be reached and ``Stop>'' will re-appear on the bottom line.

Once the program stops, you may inspect the variables as before to convince yourself that the state is consistent with respect to Biggest and In.

Shutting down the simulator

When you are finished with your work it is important to terminate the simulator properly. If you do not do so, tasks will remaining running in the background and annoying windows will pop up telling you that the system cannot connect to a target.

To terminate the system, go to the Output Logging Window, select File and click on Exit Program. When asked: ``Do you wish to disconnect from all targets before exiting?'', click on Yes.

Questions

Answer the following questions in writing, and hand in a single copy (signed by each member of your group) at the beginning of your laboratory session on the due date. Each question is worth 2 points.
  1. A while statement in C consists of a condition and a body. The body is executed repeatedly as long as the condition remains true. Identify the body of the while statement in gcd.src.

  2. Point out a use of the immediate addressing mode in the gcd.src code.

  3. Explain the effect of the lea instruction three lines after label L7.

  4. In driver.src, what addressing mode is being used in the addq instruction above the label L15? (Refer to Table 5.8 on page 159 of text.) Identify each of the components of the instruction.

  5. Looking above the label L16 there is a jsr instruction. Just above the jsr is a move.l. Describe the purpose of this instruction.

  6. Going back to the gcd.src code, look at the four-instruction sequence after the label L7. Find another place in the code where this sequence is used.

  7. In this four-instruction sequence, what is the purpose of the lsl.l instruction?

  8. Explain how this four-instruction sequence might be written with fewer instructions. Explain what adjustments you have to make in other parts of the code to reduce the sequence of instructions. (Remember you may use more registers than those used by the compiler. Also you may assume that a simulator will not be used when the code executes.)

Demonstration

You must demonstrate your use of the simulator to your TA on one of the machines in the Microlab.
Instructor Revision 1.43 (2007/08/27 00:15:43)