LAB 03: Introduction to the LC-3
Due 11:59pm Wednesday, Sept 24
The program handin33 will only submit files in the
cs33/lab/03 directory. (You should run update33 first to set
up the directory and create the lab03.txt file.)
You are encouraged to work with a partner; however, you may
work alone if you choose to do so.
When we begin to write programs on the LC-3, we will talk about
the instruction set of the machine. The instruction set
describes the complete set of supported operations. As we have
seen, Appendix A (section A.3, p.523) in the text book contains
a complete description of the LC-3 instruction set.
- How many instructions are in the LC-3 instruction
set? Contrast this with the Intel x86 instruction set which is (a
subset of) the instruction set of nearly every Intel desktop
processor you have probably ever used, including all the
Pentium, Xeon, Core Solo, and Core Duo models. The x86
instruction set contains well over 150 instructions.
- The LC-3 and x86 instruction sets both contain the
operations AND, ADD, and NOT. One
important instruction from the x86 instruction set that is
excluded from the LC-3 is SAL. The SAL
instruction performs a left shift on a register. The
result of a left shift is that each of the bits in the
register are moved over one position to the left. The
leftmost bit is discarded and then rightmost bit is replaced
with a zero.
- Recalling that the LC-3 has a word size of 16-bits, the
LC-3 would store the 2s complement integer 23 in memory as
0000 0000 0001 0111. If we performed
a shift left on this value, what would the result be in both
binary and decimal?
- What is the 2s complement notation for -50? What is the
result (in binary and decimal) of performing a left shift on
this value?
- Your answers to part a. and b. should give you insight
into what left shift does to 2s complement integers. Given a
more common description of this operation.
- How would you compute R2 = SAL(R1) on
the LC-3? Your answer should not be LC-3 instructions
written in binary, but rather something like
R2 = R0 ADD R1, or R3 = NOT R4. You may
only use the ALU (arithmetic logic unit) operations
AND, ADD, and NOT
- The LC-3 implements two versions of the ADD instruction.
The first adds two 16-bit registers (the first row in Figure A.2
on page 525) and the second adds one 16-bit register to an
immediate 5-bit value (the second row).
- What is the largest value that can be stored in the
5-bit immediate position? (Remember that this is a
2s complement integer.)
- If the 2s complement representation of the number 727 is
stored in register R0 and you wish to compute
R2 = R1 ADD 727, it is easy to
do since we can use the first version of ADD:
R2 = R1 ADD R0. But, what if
727 is not stored in a register (or in memory)? Provide a
sequence of instructions that compute
R2 = R1 ADD 727. You may use
other registers as temporary storage, but R1 must
not be modified. You may only use ALU operations and your
answer should be in the same format as question 2.
HINT: It may help you if you assume that R3
contains the value 0, or you can go ahead and answer
question 5 first, then come back to complete your answer
without that assumption. CHALLENGE: Without making
the assumption that R3 is 0, can you complete this
in 11 operations or less?
- Another instruction supported by the x86 instruction set
but not supported by the LC-3 instruction set is SUB,
which performs subtraction. Assuming that the registers
R0 and R1 each contain 2s complement
integers, how would you compute
R2 = R0 SUB R1? (Again, same
format as question 2 using only the ALU operations.)
- A common operation performed in programming is setting a
value to zero. Show two ways to perform the assignment
R0 = 0. Both ways should take 3 or less
instructions. You may use other registers as temporary
storage if necessary. Your answer should work regardless
of the initial value of R0. (Again, same format
as question 2 using only the ALU operations.)
- Assume that R0 contains a positive 2s
complement integer. Write a sequence of LC-3 statements (same
format/only ALU operations) that sets
R1 = 1 if R0 is odd, otherwise it
sets R1 = 0. You may only use ALU
operations.
- Another x86 instruction excluded from the LC-3 is the
ROL instruction which performs a left rotate.
Left rotating is similar to left shifting (SAL), except
that instead of throwing away the leftmost bit and forcing the
rightmost bit to 0 (which we do in shifting), we make the
rightmost bit equal to the previous leftmost bit. For example,
if R0 = 1001 0100 0010 0000,
then the after executing R1 = ROL(R0),
R1 would store the value
0010 1000 0100 0001.
- Using the 2s complement values from questions 2a. and
2b., what is the result of performing a left rotate?
- Assume that the LC-3 supported a fictional instruction called
SIGN(DR, SR) which did the following:
if SR >= 0 then
DR = 0
else
DR = 1
Write a sequence of LC-3 instructions (using the ALU
instructions + the SIGN instruction) which
performs R1 = ROL(R0).
- Write a sequence of statements which stores in
R1 the number of 1's in the 4 leftmost bits of
R0 (using the ALU instructions + the SIGN
instruction).
- Sometimes data only requires 8 bits of storage space.
Generally, characters (such as the letter 'A') are stored using
only 8 bits (1 byte). However, the LC-3 has a word size of
16-bits (2 bytes), which means that if we store a character in a
memory location, we end up wasting 1 byte of the memory space
per character. On a modern 64-bit processor, we would be
wasting 56 bits (7 bytes) for each 1 byte character. That's a
lot of waste! To get around this problem, multiple characters
can be stored in a single memory location using what is known as
packing. The idea is simple: we use the first 8 bits
(bits [15:8]) of the 16-bit word to store one character, and we
use the second 8 bits (bits [7:0]) to store the next character.
- Assuming that R0 contains the ASCII encoding of
the letter 'A' and R1 contains the ASCII encoding
of the letter 'B', write a sequence of LC-3 statements
(using the ALU operations + the SIGN instruction)
that packs the contents of R0 and R1 into
R2 (with R0 occupying [15:8]).
- Assuming that R2 contains two packed bytes
(such as the result of performing part a. above), write a
sequence of LC-3 statements (using the ALU operations + the
SIGN instruction) that unpacks the contents of
R2 into R0 (bits [15:8]) and R1.
- The LC-3 has three methods for loading data from memory into
a register.
- One method is LD which performs the operation
DR = LD(PCoffset9). If you picture memory as being
a giant list (or array) of 16-bit words, then the effect of
this statement is
DR = mem[PC + PCoffset9], where
PC is the current value of the Program Counter. Using the
LD instruction, what range of memory addresses do
you have access to (relative to the PC)?
- Recall that the Program Counter is incremented at the
same time as the current instruction is loaded into the
Instruction Register (IR). If the instruction
R2 = LD(x14A) is located in memory
location x3004, what memory address is loaded into
R2 when this instruction is executed?
- Another method for loading values from memory is
LDR whose format is
DR = LDR(BaseR + offset6). Similar to
LD, this statement has the effect of
DR = mem[BaseR + offset6], with
the value stored in the register BaseR replacing
the PC from the LD instruction. This
allows you to specify memory addresses relative to the value
stored in a register, rather than the Program Counter. Using the
LDR instruction, what range of memory addresses do
you have access to (relative to the BaseR)?
- The final way of loading values into memory is using the
LDI instruction whose format is the same as
LD: DR = LDI(PCoffset9). The
LDI statement has the effect of
DR = mem[mem[PC + PCoffset9]].
Be sure to compare this to the LD statement to see
how they are different. Write a series of statements
(again, in a similar format to those shown so far) that
perform R2 = LDI(x00F) without using the
LDI instruction. For this question, you can use
the LD and LDR instructions.