程序代写代做代考 assembly assembler Guide to Using the Windows version of the LC-2 Simulator

Guide to Using the Windows version of the LC-2 Simulator

Guide to Using the Windows version of the LC-3 Simulator
and LC3Edit

by

Kathy Buchheit
The University of Texas at Austin


2001, 2003

1

Guide to Using the Windows version of the LC-3 Simulator
and LC3Edit

The LC-3 is a piece of hardware, so you might be wondering why we need a simulator.
The reason is that the LC-3 doesn’t actually exist (though it might one day). Right now
it’s just a plan – an ISA and a microarchitecture which would implement that ISA. The
simulator lets us watch what would happen in the registers and memory of a “real” LC-3
during the execution of a program.

How this guide is arranged
For those of you who like to dive in and try things out right away, the first section walks
you through entering your first program, in machine language, into the text editor (known
as LC3Edit). You’ll also find information about writing assembly language programs,
but you’ll probably skip that part until you’ve learned the LC-3 assembly language later
in the semester.

The second section gives you a quick introduction to the simulator’s interface, and the
third shows you how to use the simulator to watch the effects of the program you just
wrote.

The fourth section takes you through a couple of examples of debugging in the simulator.

The last two sections are meant as reference material, for LC3Edit, and for the simulator
itself.

In other words,
page
Chapter 1 Creating a program for the simulator 2

Chapter 2 The simulator: what you see on the screen 7

Chapter 3 Running a program in the simulator 10

Chapter 4 Debugging programs in the simulator 15

Chapter 5 LC3Edit reference 24

Chapter 6 LC-3 Simulator reference, Windows version 28

Chapter 7 LC-3 Assembler Quick Reference 37

2

Chapter 1

Creating a program for the simulator

This example is also in the textbook, Introduction to Computing Systems: From Bits and
Gates to C and Beyond! You’ll find it in Chapter 6, beginning on page 166. The main
difference here is that we’re going to examine the program with the error of line x3003
corrected. We’ll get to a debugging example once we’ve seen the “right way” to do
things.

The Problem Statement
Our goal is to take the ten numbers which are stored in memory locations x3100 through
x3109, and add them together, leaving the result in register 1.

Using LC3Edit
If you’re using Windows, there’s another program in the same folder as the simulator,
called LC3Edit.exe. Start that program by double-clicking on its icon, and you’ll see a
simple text editor with a few special additions.

Entering your program in machine language
You have the option to type your program into LC3Edit in one of three ways: binary,
hex, or the LC-3 assembly language. Here’s what our little program looks like in binary:

0011000000000000
0101001001100000
0101100100100000
0001100100101010
1110010011111100
0110011010000000
0001010010100001
0001001001000011
0001100100111111
0000001111111011
1111000000100101

When you type this into LC3Edit, you’ll probably be looking at a chart which tells you
the format of each instruction, such as the one inside the back cover of the textbook. So
it may be easier for you to read your own code if you leave spaces between the different
sections of each instruction. Also, you may put a semicolon followed by a comment after
any line of code, which will make it simpler for you to remember what you were trying to
do. In that case your binary would look like this:

0011 0000 0000 0000 ;start the program at location x3000
0101 001 001 1 00000 ;clear R1, to be used for the running sum
0101 100 100 1 00000 ;clear R4, to be used as a counter
0001 100 100 1 01010 ;load R4 with #10, the number of times to add

3

1110 010 011111100 ;load the starting address of the data
0110 011 010 000000 ;load the next number to be added
0001 010 010 1 00001 ;increment the pointer
0001 001 001 0 00 011 ;add the next number to the running sum
0001 100 100 1 11111 ;decrement the counter
0000 001 111111011 ;do it again if the counter is not yet zero
1111 0000 00100101 ;halt

Either way is fine with LC3Edit. It ignores spaces anyway. The second way will just be
easier for you to read. Your program could also look like this, if you choose to type it in
hex (comments after a semicolon are still an option):

3000
5260
5920
192A
E4FC
6680
14A1
1243
193F
03FB
F025

Saving your program
Click on this button or choose “Save” under the File menu. You probably want to make a
new folder to save into, because you’ll be creating more files in the same place when you
turn your program into an object file. Call your program addnums.bin if you typed it in
1s and 0s. Call it addnums.hex if you typed it in hex.

Creating the .obj file for your program
Before the simulator can run your program, you need to convert the program to a
language that the LC-3 simulator can understand. The simulator doesn’t understand the
ASCII representations of hex or binary that you just typed into LC3Edit. It only
understands true binary, so you need to convert your program to actual binary, and save it
in a file called addnums.obj. If you’re using LC3Edit, one and only one of these buttons
will make this happen:

How will you know which one? It depends whether you entered your program in 1s and
0s (B and an arrow), in hex (X and an arrow), or in assembly language (asm and an
arrow).

When you press the appropriate button, a new file will be created in the same folder
where you saved your original addnums program. It will automatically have the same

4

name, except that its file extension (the part of its name which comes after the “.”) will be
.obj.

If you typed your program in 1s and 0s, or in hex, only one new file will appear:
addnums.obj.

If you don’t know the LC-3 assembly language yet, now you’re ready to skip ahead to
Chapter 2, and learn about the simulator. Once you do learn the assembly language, a
little bit later in the semester, you can finish Chapter 1 and learn about the details of
entering your program in a much more readable way.

Entering your program in the LC-3 assembly language
So you’re partway through the semester, and you’ve been introduced to assembly
language. Now entering your program is going to be quite a bit easier. This is what the
program to add ten numbers could look like, making use of pseudo-ops, labels, and
comments.

.ORIG x3000
AND R1,R1,x0 ;clear R1, to be used for the running sum
AND R4,R4,x0 ;clear R4, to be used as a counter
ADD R4,R4,xA ;load R4 with #10, the number of times to add
LEA R2,x0FC ;load the starting address of the data
LOOP LDR R3,R2,x0 ;load the next number to be added
ADD R2,R2,x1 ;increment the pointer
ADD R1,R1,R3 ;add the next number to the running sum
ADD R4,R4,x-1 ;decrement the counter
BRp LOOP ;do it again if the counter is not yet zero
HALT
.END

You still need to change your program to a .obj file, which is now called “assembling”

your program. To do this, click on the button .

Since you used the fancier assembly language approach, you’ve been rewarded with not
just one, but a handful of files:
addnums.obj, as you expected
addnums.bin, your program in ASCII 1s and 0s
addnums.hex, your program in ASCII hex format
addnums.sym, the symbol table created on the assembler’s first pass
addnums.lst, the list file for your program

The .bin and .hex files look the same as the ones shown earlier in the chapter (with any
comments removed). The last two files are worth looking at.

addnums.sym
Here’s what this file looks like if you open it in a text editor:

5

//Symbol Name Page Address
//—————- ————
// LOOP 3004

You only had one label in your program: LOOP. So that’s the only entry in the symbol
table. 3004 is the address, or memory location, of the label LOOP. In other words, when
the assembler was looking at each line one by one during the first pass, it got to the line

LOOP LDR R3,R2,x0 ;load the next number to be added

and saw the label “LOOP,” and noticed that the Location Counter held the value x3004
right then, and put that single entry into the symbol table.

So on the second pass, whenever the assembler saw that label referred to, as in the
statement

BRp LOOP

it replaced LOOP with the hex value 3004. If you’d had more labels in your program,
they would have been listed under Symbol Name, and their locations would have been
listed under Page Address.

addnums.lst
If you open the list file using any text editor, you’ll see this:

(0000) 3000 0011000000000000 ( 1) .ORIG x3000
(3000) 5260 0101001001100000 ( 2) AND R1 R1 #0
(3001) 5920 0101100100100000 ( 3) AND R4 R4 #0
(3002) 192A 0001100100101010 ( 4) ADD R4 R4 #10
(3003) E4FC 1110010011111100 ( 5) LEA R2 x3100
(3004) 6680 0110011010000000 ( 6) LOOP LDR R3 R2 #0
(3005) 14A1 0001010010100001 ( 7) ADD R2 R2 #1
(3006) 1243 0001001001000011 ( 8) ADD R1 R1 R3
(3007) 193F 0001100100111111 ( 9) ADD R4 R4 #-1
(3008) 03FB 0000001111111011 ( 10) BRP LOOP
(3009) F025 1111000000100101 ( 11) TRAP x25

Let’s pick one line and take it apart. Since the sixth line has a label, that’s the most
interesting one. So let’s look at the pieces.

(3004) 6680 0110011010000000 ( 6) LOOP LDR R3 R2 #0

(3004)
This is the address where the instruction will be located in memory when your program is
loaded into the simulator.

6

6680
This is the hex value of the instruction itself.

0110011010000000
This is the instruction in binary.

( 6)
The instruction is the sixth line of the assembly language program. It will actually be the
fifth line of the program once it gets loaded into memory in the simulator, since the line
marked ( 1) just specifies the starting location. But we’re counting assembly language
lines now, not memory locations, so this is the sixth line.

LOOP
This is the label associated with the line.

LDR R3 R2 #0
And last, this is the assembly language version of the instruction. Notice that the
comments after the instruction are gone now. Those were only for your own (or other
programmers’) information. The simulator doesn’t care about them.

7

Chapter 2
The simulator: what you see on the screen

When you launch the Windows version of the LC-3 Simulator, you see this:

Chapter 6 of this guide is a more complete reference to all the parts of this interface. If
you want all the details, look there. If you want just enough details to be able to continue
the step-by-step example, keep reading.

The registers
Below the menu items and toolbar buttons, notice the list of registers.

Starting at the left, you see R0 through R3, and then skipping over to the fourth column,
you see R4 through R7. Those are the eight registers that LC-3 instructions use as
sources of data and destinations of results. The columns of x0000s and 0s are the
contents of those registers, first in hex (that x at the front of the number always means
“treat what follows as a hex number”), and then in decimal. When you launch the
simulator, the temporary registers always contain zero.

8

If, during the execution of a program, R2 contained the decimal value 129, you would see
this:

The last three columns at the top of the simulator show the names and contents of five
important registers in the LC-3 control unit. Those registers are the PC, the IR, and the
N, Z, and P condition code registers.

The PC, or program counter, points to the next instruction to be run. When you load your
program, it will contain the address of your first instruction. The default value is x3000.

The IR, or instruction register, contains the value of the current instruction. It holds a
zero when you launch the simulator, since no instruction is “current” yet.

The PSR, or processor status register, contains the state of the processor, which is either
user mode or privileged mode and the value of the condition codes.

The CC, or condition codes, are set by certain instructions (ADD, AND, OR, LEA, LD,
LDI, and LDR). They consist of three registers: N, Z, and P. Since only one of the three
can have the value 1 at any time, the simulator just shows us the name of the register
which currently has the value 1. (So when you start the simulator, N=0, Z=1, and P=0 by
default.)

The memory
Below the registers, you see a long, dense list of numbers which begins like this:

Use the scrollbar at the right to scroll up and down through the memory of the LC-3.
Remember that the LC-3 has an address space of 216, or 65536 memory locations in all.
That’s a very long list to scroll through. You’re likely to get lost. If you do, go to the
“Jump to” box near the top of the interface, and enter the address (remember the little “x”
before an address in hex) where you’d like to go.

9

The first column in the long list of memory locations tells you the address of the location.
The second column tells you the contents of a location, in binary. The third column also
represents the contents, but in hex instead of binary, because that’s sometimes easier to
interpret. The fourth column is the assembly language interpretation of the contents of a
location. If a location contains an instruction, this assembly interpretation will be useful.
If a location contains data, just ignore the fourth column entirely.

The Console Window
A second window also appears when you run the simulator. It is rather inconspicuous,
and has the vague title “LC3 Console.” This window will give you messages such as
“Halting the processor.” If you use input and output routines in your program, you’ll see
your output and do your input in this window.

10

Chapter 3
Running a program in the simulator

Now you’re ready to run your program in the simulator. Open the simulator, and then

click the Load Program button . Browse and choose addnums.obj. Notice that you
only get the option to open one type of file in the simulator: the .obj file. This is what
you’ll see when your program is loaded:

Notice that the first line of your program, no matter what format you originally used, is
gone. That line specified where the program should be loaded in memory: x3000. As
you can see if you scroll up a line or so, the locations before x3000 are still all 0s. Since
nothing has happened yet (you haven’t started running or stepping through your
program), the temporary registers (R0 through R7) still contain all 0s, the PC is pointing
to the first line of your program (as is the blue arrow), and the IR is empty.

Loading the data (ten numbers) into memory
There are several ways to get the ten numbers that you’re planning to add into the
memory of the LC-3 simulator. You want them to begin at location x3100.

First way: click in the “Jump to” box to the right of the buttons on the toolbar, and type
the hex number x3100. When you press return, you’ll jump x100 locations ahead in the
memory display, so that location x3100 is the first one shown.

Now double-click anywhere on line x3100. You’ll get this popup window:

11

In the “Value” box, type the hex number x3107, and choose OK. Now your first data
location will look like this:

Notice that you get to see the binary representation, the hex representation, and some
silly, useless assembly language representation (ST R0, x3107). Of course, this is data,
not an instruction, but the LC-3 simulator doesn’t know that. In fact, the contents of all
memory locations are equal in the eyes of the LC-3, until they get run as instructions or
loaded as data. Since you have a halt instruction far before the place where you’re
putting this data, it will never be treated as an instruction. So ignore that assembly
language interpretation.

You can double-click on each line in turn and enter the data. If you only want to open the
popup window once, keep changing the value of the Location field, enter the next number
in the Value field, and click the Apply button. When you’re done, click OK.

Second way: go back to the LC3Edit program, and enter this code in hex.

3100 ;data starts at memory location x3100
3107 ;the ten numbers we want to add begin here
2819
0110
0310
0110
1110
11B1
0019
0007
0004

Save this code as data.hex by clicking on .

12

As usual, the first line is the address where we want the data to begin. The other lines are

the actual data we want to load into memory. Click on , since you typed your
program in hex. Now, a file called data.obj will exist wherever you saved .hex file.

Now go back to the simulator, choose Load Program once again, and select data.obj.
Note that you can load multiple .obj files so they exist concurrently in the LC-3
simulator’s memory. The memory locations starting with x3100 will look like this:

Now your data is in place, and you’re ready to run your program.

Running your program
Click on the “Jump to” field, and choose x3000 as the location where you want to go.

This next step is VERY important: double-click on the little grey square in front of the
line at address x3009.

That sets a breakpoint on that line. If you don’t follow this suggestion, you’ll never see
your result in R1, because we’ll do the trap routine for HALT, which changes R1 before
it halts the simulator. (I’ll explain breakpoints in more detail in the next chapter.) After
you double-click, the line will look like this:

That red blob is a stop sign. So we’ll stop when we get to line x3009, before we run the
instruction there.

Now you’re ready to run your program. Make sure the PC has the value x3000, because
that’s where the first instruction is. If it doesn’t, double-click on the PC value near the
top of the interface, and change it to x3000.

Now for the big moment: click on , the Run Program button!

13

If you’ve already added up the ten numbers you put into the data section of your
program, you know that x8135 is the answer to expect. That’s what you should see in R1
when the program stops at the breakpoint. (In decimal, the result is –32,459. It’s
negative because the first bit in x8135 is a 1, which is a negative 2’s complement
number.) You’ll get a popup window telling you that you’ve reached a breakpoint, which
in this case is the event when the PC gets the value x3009.

Stepping through your program
So now that you’ve seen your program run, you know it works. But that doesn’t give you
a good sense for what’s actually going on in the LC-3 during the execution of each
instruction. It’s much more interesting to step through the program line by line, and see
what happens. You’ll need to do this quite a bit to debug less perfect code, so let’s try it.

First, you need to reset the very important program counter to the first location of your
program. So set the PC back to x3000. You can either double-click on it, and enter a

new value, or use this quicker method: click on line x3000, and then click on , which
sets the PC to that location. Now you’re ready to step through your program.

Click , Step Over, one time. A few interesting things just happened:
• R1 got cleared. (If you “cleaned up” by clearing R1 before you started, this won’t

be an exciting event.)
• The blue arrow, and the PC, both point to location x3001 now, which is the next

instruction to run.
• The IR has the value x5260. Look at the hex value of location x3000. That is

also x5260. The IR holds the value of the “current” instruction. Since we
finished the first instruction, and have not yet run the second, the first instruction
is still the current one.

Click , Step Over, for a second time. Again, notice the new values for the PC and IR.
The second instruction clears R4.

Click , Step Over, a third time. The PC and IR update once again, and now R4 holds
the value x0A, which is decimal 10, the number of times we need to repeat our loop to
add ten numbers. This is because the instruction which just executed added x000A to
x0000, and put the result in R4.

Continue to step through your program, watching the results of each instruction, and
making sure they are what you expect them to be.

At any point, if you “get the idea” and want your program to finish executing in a hurry,

click on the Run Program button, , and that will cause your program to execute until it
reaches the breakpoint you set on the Halt line.

14

So now you know how it feels to write a program perfectly the very first time, and see it
run successfully. Savor this moment, because usually it’s not so easy to attain. But
maybe programming wouldn’t be as fun if you always got it right immediately. So let’s
pretend we didn’t. The next chapter will walk you through debugging some programs in
the simulator.

15

Chapter 4
Debugging programs in the simulator

Now that you’ve experienced the ideal situation of seeing a program work perfectly the
first time, you’re ready for a more realistic challenge – realizing that a program has a
problem, and trying to track down that problem and fix it.

Example 1:
Debugging the program to multiply without a multiply instruction

This example is taken from the textbook, and is discussed on pages 129 and 130. The
program is supposed to multiply two positive numbers, and leave the result in R2.

Typing in the program
First you’ll need to enter the program in LC3Edit. It should look like this:

0011 0010 0000 0000 ;the address where the program begins: x3200
0101 010 010 1 00000 ;clear R2
0001 010 010 0 00 100 ;add R4 to R2, put result in R2
0001 101 101 1 11111 ;subtract 1 from R5, put result in R5
0000 011 111111101 ;branch to location x3201 if the result is zero or positive
1111 0000 00100101 ;halt

As you can tell by studying this program, the contents of R4 and R5 will be “multiplied”
by adding the value in R4 to itself some number of times, specified by the contents of R5.
For instance, if R4 contains the value 7, and R5 contains the value 6, we want to add 0+7
the first time through, then 7+7 the second time through, then 14+7 the third time
through, then …, then 35+7 the sixth time through, ending up with the value 42 in R2
when the program finishes.

Converting the program to .obj format
Once you’ve typed your program into LC3Edit, save it as multiply.bin and then click on

to convert it to an .obj file.

Loading the program into the simulator
Start the simulator, and then click to load your program: multiply.obj. Now the
memory portion of the simulator will look like this:

16

Also notice that the PC contains the value x3200, which corresponds to the blue arrow
pointing to that line – the next instruction to be run, which happens to be the first
instruction of your program, since you haven’t started yet.

Setting a breakpoint at the halt instruction
Breakpoints are extremely useful in many ways, and we’ll get to a few of those soon.
You should make it a habit to set a breakpoint on your “halt” line, because if you run
your program without that, you’ll end up in the halt subroutine, which will change some
of your registers before halting the machine. So first, set a breakpoint on line x3204 by
double-clicking on the little gray square at the beginning of that line.

Now line x3204 should look like this:

That red stop sign tells you that a breakpoint is set on that line, so if the program is
running, and the PC gets the value x3204, the simulator will pause and wait for you to do
something.

Running the buggy multiply program
Before you run your program for the first time, you need to put some values in R4 and R5
so that they’ll be multiplied (or not, in this case!). How should you choose values to test?
Common sense will help you here. 0 and 1 are probably bad choices to start with, since
they’ll be rather boring. (It would be good to test those later though.) If you choose a
large number for R5, you’ll have to watch the loop repeat that large number of times. So
let’s start with two reasonably small, but different numbers, like 5 and 3.

Click on , Set Value, and you’ll get the popup window. In the Location field, choose
R4, and for Value, type “x5.” So you should see this:

17

Click Apply (which means “set the location I just picked to the value I just entered, but
leave this popup window open so I can do more stuff”), and now choose R5 in the
Location field, and type “x3” in the Value field. Click OK to close the popup window.
Now your registers are set, and you’re ready to try running your program.

To run your program until the breakpoint, click on , Run Program. In a fraction of a
second, you’ll get a popup window that looks like this:

That happened because you set a breakpoint at your halt line. Click OK to close the
popup, and then take a look at R2, which is supposed to contain your result now that
you’ve run all but the last line of the program. As you realize, 3 * 5 = 15 in decimal, but
R2 now contains 20 in decimal (which is x14 in hex). Something went wrong. Now you
need to figure out what that something was.

Stepping through the multiply program
One option for debugging your program is to step through the entire multiply program
from beginning to end. Since you have a loop, let’s approach debugging a different way.
First, let’s try stepping through one iteration of the loop to make sure that each instruction
does what you think it should.

Double-click on the R5, near the top of the interface. That will bring up a “Set Value”
popup window. Set the value of R5 to x3, and click OK to close the window.

Now click (once!) on memory location x3200, and click . That will set the PC to
whatever memory location is selected.

The blue arrow is now pointing to the first line, and the two registers you’ll need are
initialized to the values you want. So you’re ready to step through the program, in your
first attempt to figure out what’s going wrong.

Click , Step Over. Notice that several things changed. The PC now points to the next
instruction, x3201. The IR contains the value of the first instruction, x54A0. R2, which
moments ago contained our incorrect result (decimal 20), is clear. This is exactly what
you should have expected the first instruction to do, so let’s keep going.

18

Click again. Once more, the PC and IR have changed as expected. Now R2 contains
the value 5 (the same in hex and decimal, by the way). Again, this is what you want. So
keep going.

The next time you click , the value of R5 changes from x3 to x2. (I’m not going to
keep mentioning the PC and IR, but you’ll notice those changing after each instruction as
well.) R5 has a double purpose in this program. It is one of the numbers to multiply, but
it is also your “counter” – it tells you how many more repetitions of the loop are left to
go. So each time through the loop, R5 gets decremented. That seemed to happen just
fine, so keep going.

Clicking once more causes the branch instruction to execute. When a branch
instruction executes, one of two things can happen. Either the branch gets taken, or it
doesn’t get taken. In this case, the branch got taken. Why? Because the branch tested
the condition codes which were set by the add instruction right before it. The result of
the add was x2, a positive number, so the P register was set to 1. Your branch is taken if
the Z register or the P register contains a 1. So the branch was executed, and the branch
was taken, and the PC now points to x3201, ready for another iteration of the loop.

Stepping through the program for one repetition of the loop has shown that there’s
nothing wrong with any of the individual instructions in the loop. Maybe the problem
lies in the way the loop is set up instead, so let’s try another approach.

Debugging the loop with a breakpoint
One good technique for discovering whether a loop is being executed too many times, is
to put a breakpoint at the branch instruction. That way, you can pause once at the end of
each iteration, and check out the state of various registers (and memory locations, in more
complicated programs).

Let’s set this breakpoint in a different way from last time, so that you’ll get to see the

Breakpoints dialog box. Click on . You’ll see this:

19

If you click on the drop-down arrow next to the Location field, you’ll see that you have
all sorts of choices:

PC
X
PSR
IR
CC
R0
R1
R2
R3
R4
R5
R6
R7

Basically, you can have the simulator pause when it notices that any one of those
registers or memory locations has the value that you specify. So if you want, you could
set a breakpoint so that the simulator would pause when R0 contains x00FF (choose R0
for Location, and choose x00FF for Value), or when the condition codes have Z = 0
(choose CC for Location, and choose Z for Value), or when memory location x4000
contains x1234 (choose x4000 for Location, and choose x1234 for Value).

In this case, you want to choose PC for your Location, and type x3203 for your Value.
Click Add. N