LC-3 ISA: memory, registers, operate and data movement instructions
The LC-3's memory layout, registers and condition codes; the ADD/AND/NOT and LD/LDI/LDR/LEA/ST/STI/STR instructions, addressing modes and encoding and decoding 16-bit machine code by hand.
Weeks 7 and 8 are the center of the course: the instruction set (ISA) of the LC-3. Everything you have learned so far comes together here: 2’s complement (offsets), sign extension (imm5), the decoder (opcode), mux and register (data path), the instruction cycle (phases). On this page you see the structure of the LC-3, the operate instructions that do calculations, and the data movement instructions that carry data between memory and registers. Branches and loops are in week 8.
Question types on the exam: translate an instruction into 16-bit machine code (encode), translate a hex value into an instruction (decode), compute the effective address, trace a short program and write the register values and condition codes.
The structure of the LC-3
| Item | In the LC-3 |
|---|---|
| Memory | = 65536 locations, each 16 bits (word-addressable) |
| General-purpose registers | R0-R7, each 16 bits |
| Instruction length | Every instruction is exactly 16 bits |
| Opcode | IR[15:12], 4 bits → 16 values (15 instructions + 1 reserved) |
| Condition codes | N, Z, P (exactly one is 1 at any moment) |
| Data type | 16-bit 2’s complement integer |
| Special registers | PC, IR, MAR, MDR, PSR |
User programs usually start at x3000. x0000-x00FF is the trap vector table, xFE00 and above are the device registers (week 6).
Condition codes
Every instruction that writes a value into a register (ADD, AND, NOT, LD, LDI, LDR) sets one of three bits to 1 according to the value written:
| Value written | N | Z | P |
|---|---|---|---|
| negative (bit 15 = 1) | 1 | 0 | 0 |
| zero | 0 | 1 | 0 |
| positive | 0 | 0 | 1 |
Instructions that write to memory (ST, STI, STR) and branch instructions do not change the condition codes. In week 8 the BR instruction will decide by looking at exactly these bits.
PITFALL · LEA and the condition codes. In the 2nd edition of the textbook (the book of this course) LEA also sets the condition codes; in the 3rd edition it does not. If you see a BR right after an LEA in the exam, pay attention to which rule the instructor uses; the safest thing is to put the instruction that actually writes the value before the BR.
Opcode table
| Opcode | Instruction | Type |
|---|---|---|
| 0001 | ADD | operate |
| 0101 | AND | operate |
| 1001 | NOT | operate |
| 0010 | LD | data movement (PC-relative) |
| 1010 | LDI | data movement (indirect) |
| 0110 | LDR | data movement (base+offset) |
| 1110 | LEA | address computation |
| 0011 | ST | data movement (PC-relative) |
| 1011 | STI | data movement (indirect) |
| 0111 | STR | data movement (base+offset) |
| 0000 | BR | control |
| 1100 | JMP / RET | control |
| 0100 | JSR / JSRR | control (subroutine) |
| 1111 | TRAP | control (operating system) |
| 1000 | RTI | control (return from interrupt) |
| 1101 | reserved |
Operate instructions: ADD, AND, NOT
ADD and AND have two forms. Bit 5 tells which one it is.
register mode: op | DR | SR1 | 0 | 00 | SR2
15-12 11-9 8-6 5 4-3 2-0
immediate mode: op | DR | SR1 | 1 | imm5
15-12 11-9 8-6 5 4-0
NOT: 1001| DR | SR | 111111
ADD R5, R1, R3: R5 ← R1 + R3.ADD R3, R1, #-4: R3 ← R1 + SEXT(imm5). imm5 = -4 = 11100, extended to 16 bits as 1111 1111 1111 1100.NOT R1, R1: flips every bit of R1.
The range of imm5 is -16..+15. If you need a larger constant, you have to put it in memory with .FILL and load it with LD.
Encoding example
AND R4, R3, #15:
0101 | 100 | 011 | 1 | 01111
AND R4 R3 imm +15
0101 1000 1110 1111 = x58EF
Ready-made patterns
| Job | Instruction | Why |
|---|---|---|
| R1 = 0 | AND R1, R1, #0 | Anything AND 0 = 0 |
| R2 = R1 | ADD R2, R1, #0 | +0 copies |
| R2 = 2·R2 | ADD R2, R2, R2 | Adding to itself = shift left |
| R3 = -R2 | NOT R3, R2 + ADD R3, R3, #1 | 2’s complement |
| R3 = R1 OR R2 | NOT R1, NOT R2, AND, NOT | DeMorgan |
The result of NOT alone is : NOT 7 = -8. Do not forget to add +1.
Addressing modes
Where can an operand be? In the LC-3 there are five answers:
| Mode | Where is the operand? | Instructions |
|---|---|---|
| Register | in a register | ADD R1, R2, R3 |
| Immediate | inside the instruction | ADD R1, R1, #5 |
| PC-relative | M[PC + offset9] | LD, ST |
| Indirect | M[M[PC + offset9]] | LDI, STI |
| Base+offset | M[BaseR + offset6] | LDR, STR |
LEA also computes PC + offset9 but does not read memory; it puts the address itself in the register.
PC-relative: LD and ST
LD/ST: op | DR/SR | PCoffset9
address = (incremented PC) + SEXT(PCoffset9)
The PC is used in its incremented form. If the instruction is at x3010, when FETCH finishes PC = x3011. The offset is added to this. The offset is 9 bits, range -256..+255: an instruction can access about 256 locations near itself.
LD R2, #-5 at x3010: address = x3011 - 5 = x300C.
0010 | 010 | 1 1111 1011 = x25FB
LD R2 -5
PITFALL · adding the offset to the instruction’s own address. Whoever writes x3010 + (-5) = x300B loses points. The PC had already been incremented by one in FETCH: x3011 + (-5) = x300C.
Indirect: LDI and STI
An address is stored in memory. First that address is read, then the data at that address.
LDI R3, #2 (at x3000)
1) x3001 + 2 = x3003 M[x3003] = x4000 (this is a pointer)
2) M[x4000] = x0042 → R3 = x0042
This is the way to reach far addresses (for example the device registers at xFE00).
Base+offset: LDR and STR
LDR/STR: op | DR/SR | BaseR | offset6
address = BaseR + SEXT(offset6) range -32..+31
Because the base register is 16 bits, any place in memory can be reached. Arrays, the stack and pointers work with this mode (you will see them in the C weeks).
With STR R2, R5, #-1 and R5 = x4001, R2 = x00AA → M[x4000] = x00AA.
LEA: load the address
LEA R1, ARR → R1 ← the address of ARR. Memory is not read. To get the starting address of an array, use LEA, then access the elements with LDR:
LEA R1, ARR ; R1 = x3005 (the address of ARR)
LDR R2, R1, #2 ; R2 = ARR[2] = 10
LDR R3, R1, #0 ; R3 = ARR[0] = 7
ADD R4, R2, R3 ; R4 = 17
HALT
ARR .FILL #7
.FILL #-2
.FILL #10
Decode recipe
- Expand the hex to 16 bits.
- The first 4 bits are the opcode, look at the table.
- According to the format of the opcode, split the remaining 12 bits into fields.
- If there is an offset, sign-extend it, and if an address is needed, add it to the incremented PC.
Example: x2A10, at address x3100.
0010 101 0 0001 0000
LD R5 PCoffset9 = 0 0001 0000 = +16
address = x3101 + 16 = x3101 + x10 = x3111
→ LD R5, x3111 (R5 ← M[x3111])
Example: x7F3F.
0111 111 100 111111
STR R7 R4 offset6 = 111111 = -1
→ STR R7, R4, #-1 (M[R4 - 1] ← R7)
Worked trace
.ORIG x3000
LD R1, A ; R1 = 13
LD R2, B ; R2 = -6
ADD R3, R1, R2 ; R3 = 7
AND R4, R3, #7 ; R4 = 7
NOT R5, R4 ; R5 = -8
ST R3, C ; M[C] = 7
HALT
A .FILL #13
B .FILL #-6
C .BLKW 1
.END
The machine code the assembler produced:
x3000 x2206 LD R1, A (x3001 + 6 = x3007 = A)
x3001 x2406 LD R2, B (x3002 + 6 = x3008 = B)
x3002 x1642 ADD R3, R1, R2
x3003 x58E7 AND R4, R3, #7
x3004 x9B3F NOT R5, R4
x3005 x3603 ST R3, C (x3006 + 3 = x3009 = C)
x3006 xF025 HALT
x3007 x000D A = 13
x3008 xFFFA B = -6
x3009 x0000 C
Result: R3 = 7, R4 = 7, R5 = xFFF8 (-8), M[x3009] = 7. The last instruction that set the CC is NOT (R5 is negative) → N. ST did not change the CC.
Common mistakes
| Wrong idea | The truth |
|---|---|
| The offset is added to the instruction’s own address | To the incremented PC (address + 1) |
| The imm5 range is 0..31 | -16..+15, sign-extended |
| LEA reads from memory | It only computes the address |
| LDI = LD | LDI reads twice: first the address, then the data |
| The LDR offset is 9 bits | 6 bits, -32..+31 |
| ST sets the condition codes | Instructions that write to memory do not touch the CC |
| NOT x = -x | NOT x = -x - 1; add +1 for -x |
| Bit 5 = 0 → immediate | Bit 5 = 1 is immediate, 0 is register |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
Encode ADD R3, R1, #-4 as a 16-bit LC-3 machine instruction in hex.
Show answer
Format: 0001 | DR | SR1 | 1 | imm5. DR = R3 = 011, SR1 = R1 = 001, bit 5 = 1 (immediate), imm5 = -4 = 11100.
0001 011 001 1 11100 → 0001 0110 0111 1100 = x167C.
Decode the LC-3 instruction x1A43.
Show answer
x1A43 = 0001 1010 0100 0011. Opcode 0001 = ADD. DR = bits 11:9 = 101 = R5. SR1 = bits 8:6 = 001 = R1. Bit 5 = 0 → register mode, SR2 = bits 2:0 = 011 = R3.
Decode x927F.
Show answer
1001 0010 0111 1111. Opcode 1001 = NOT. DR = 001, SR = 001, bits 5:0 = 111111 (all 1s in NOT). R1 ← NOT R1.
What is the range of the immediate value in ADD DR, SR1, #imm5?
Show answer
imm5 is a 5-bit 2's complement value: . At run time it is sign-extended to 16 bits. If you write #16 or #-17 the assembler gives an error.
The instruction LD R2, LABEL is at address x3010 and its PCoffset9 is -5. Which address is read, and what is the machine code?
Show answer
Address = incremented PC + SEXT(offset) = x3011 + (-5) = x300C. The PC was incremented in FETCH, the offset is added to x3011, not x3010.
Code: 0010 | 010 | 1 1111 1011 → 0010 0101 1111 1011 = x25FB.
LEA R0, #10 is at address x3005. What value is placed in R0? Does LEA access memory?
Show answer
LEA computes the address and puts the address itself in R0: x3006 + 10 = x3006 + xA = x3010. It does not read memory. The name 'Load Effective Address' comes from this.
Before execution, M[x3003] = x4000 and M[x4000] = x0042. What does LDI R3, #2 at address x3000 load into R3?
Show answer
LDI reads in two steps. 1) x3001 + 2 = x3003; M[x3003] = x4000, this is an address. 2) M[x4000] = x0042 → R3. The condition code becomes P.
R6 = x5000 and M[x5004] = xFFFE. After LDR R1, R6, #4, what are R1 and the condition codes?
Show answer
Address = R6 + SEXT(offset6) = x5000 + 4 = x5004. R1 ← M[x5004] = xFFFE = -2. Because it is negative, N = 1.
Write three LC-3 instructions that compute R3 = R1 - R2 (R1 and R2 must not change).
Show answer
There is no SUB in the LC-3. 2's complement: . First R3 ← NOT R2, then R3 ← R3 + 1 (now -R2), finally R3 ← R1 + R3. Example: R1 = 20, R2 = 27 → R3 = -7 = xFFF9, CC = N.
What are R3, R4, R5 and the memory location C after this program runs?
.ORIG x3000
LD R1, A
LD R2, B
ADD R3, R1, R2
AND R4, R3, #7
NOT R5, R4
ST R3, C
HALT
A .FILL #13
B .FILL #-6
C .BLKW 1
.ENDShow answer
R1 = 13, R2 = -6. R3 = 13 + (-6) = 7 = 0000 0000 0000 0111.
R4 = 7 AND 7 = 7 (low 3 bits). R5 = NOT 7 = 1111 1111 1111 1000 = xFFF8 = -8 (NOT x = -x - 1).
ST R3, C → M[C] = 7. ST does not change the condition codes.
Which of these instructions set the condition codes: ADD, ST, LDR, STR, NOT, AND?
Show answer
The condition codes are set by instructions that WRITE a value into a register: ADD, AND, NOT, LD, LDI, LDR (and LEA in the 2nd edition of the textbook). ST, STI, STR, which write to memory, and branch instructions do not change the CC.
Decode xE1FD located at address x3050. What does it put in R0?
Show answer
1110 0001 1111 1101: opcode 1110 = LEA, DR = 000 = R0, PCoffset9 = 1 1111 1101 = -3.
R0 = x3051 + (-3) = x304E.
Verification: Every encoding, decoding and trace was produced on the LC-3 assembler + simulator we wrote ourselves (verify/SEN2201/lc3.mjs); the register values, condition codes and memory contents were taken from there (verify/SEN2201/07.mjs). The condition code behavior of LEA follows the 2nd edition of the textbook.