COA Notes
Hands-on assembly language programming labs with exercises and solutions.
Introduction
Assembly language becomes real only when you write it, run it, and debug it yourself. Reading about registers and instructions is not enough — you need to see the bits change, watch the program counter advance, and understand why your loop iterated one too many times. These labs are designed to take you from zero to confident in assembly programming. Each lab builds on the previous one, and every exercise has a clear purpose tied to computer architecture concepts.
Lab Setup and Tools
Recommended Simulators
| Tool | Architecture | Platform | Best For |
|---|---|---|---|
| MARS | MIPS | Windows/Mac/Linux | University courses, clean RISC |
| emu8086 | x86 (8086) | Windows | 16-bit x86, legacy understanding |
| NASM + GDB | x86-64 | Linux | Real-world x86-64 programming |
| CPUlator | ARM, MIPS, Nios II | Browser | No install, quick experiments |
| RARS | RISC-V | Cross-platform | Modern ISA, growing popularity |
For these labs, we will use MIPS assembly (MARS simulator) because MIPS is clean, orthogonal, and widely taught. The concepts transfer directly to any architecture.
MIPS Register Convention
Lab 1: Basic Data Movement and Arithmetic
Objective
Understand register operations, immediate values, and basic ALU instructions.
Exercise 1.1: Load and Add
# Program: Add two numbers and store result
.data
result: .word 0
.text
.globl main
main:
li $t0, 25 # Load immediate: $t0 = 25
li $t1, 37 # Load immediate: $t1 = 37
add $t2, $t0, $t1 # $t2 = $t0 + $t1 = 62
sw $t2, result # Store result to memory
# Print result using syscall
move $a0, $t2 # Argument = result
li $v0, 1 # Syscall 1 = print integer
syscall
li $v0, 10 # Syscall 10 = exit
syscallExercise 1.2: Temperature Conversion (F to C)
# Convert Fahrenheit to Celsius: C = (F - 32) * 5 / 9
.data
fahrenheit: .word 212
.text
.globl main
main:
lw $t0, fahrenheit # Load F value
addi $t0, $t0, -32 # F - 32
li $t1, 5
mul $t0, $t0, $t1 # × 5
li $t1, 9
div $t0, $t1 # ÷ 9
mflo $t2 # Quotient (integer result)
move $a0, $t2
li $v0, 1
syscall # Print: should output 100
li $v0, 10
syscallArchitecture Concepts Demonstrated
- Immediate addressing (li)
- Register addressing (add, move)
- Memory addressing (lw, sw)
- ALU operations (add, mul, div)
Lab 2: Conditional Branching and Comparison
Objective
Understand how the CPU makes decisions using comparison and branch instructions.
Exercise 2.1: Find Maximum of Two Numbers
.data
msg_a: .asciiz "A is larger\n"
msg_b: .asciiz "B is larger\n"
.text
.globl main
main:
li $t0, 42 # A = 42
li $t1, 67 # B = 67
bgt $t0, $t1, a_larger # Branch if A > B
# B is larger (fall through)
la $a0, msg_b
li $v0, 4 # Print string syscall
syscall
j done
a_larger:
la $a0, msg_a
li $v0, 4
syscall
done:
li $v0, 10
syscallExercise 2.2: Grade Calculator
# Input a score, output letter grade
.data
prompt: .asciiz "Enter score (0-100): "
grade_a: .asciiz "Grade: A\n"
grade_b: .asciiz "Grade: B\n"
grade_c: .asciiz "Grade: C\n"
grade_f: .asciiz "Grade: F\n"
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5 # Read integer
syscall
move $t0, $v0 # Score in $t0
bge $t0, 90, is_a
bge $t0, 75, is_b
bge $t0, 60, is_c
la $a0, grade_f
j print_grade
is_a:
la $a0, grade_a
j print_grade
is_b:
la $a0, grade_b
j print_grade
is_c:
la $a0, grade_c
print_grade:
li $v0, 4
syscall
li $v0, 10
syscallArchitecture Concepts Demonstrated
- Branch instructions (bgt, bge, beq, bne)
- How conditional execution maps to hardware comparison + PC modification
- Why branch prediction matters (each branch could go either way)
Lab 3: Loops and Arrays
Objective
Understand loop constructs and array access patterns — directly related to cache behavior.
Exercise 3.1: Sum of Array Elements
Exercise 3.2: Find Maximum Element
Architecture Insights
- Array access pattern demonstrates spatial locality (sequential elements)
- The
sll $t4, $t3, 2(shift left logical by 2) multiplies index by 4 — this is how pointer arithmetic works in hardware - Each loop iteration has a branch — this is where branch prediction saves cycles
Lab 4: Function Calls and Stack
Objective
Understand the call stack, stack frames, and how the hardware supports function calls.
Exercise 4.1: Factorial (Recursive)
.text
.globl main
main:
li $a0, 6 # Calculate 6!
jal factorial # Call factorial
move $a0, $v0 # Print result
li $v0, 1
syscall # Should print 720
li $v0, 10
syscall
factorial:
# Prologue: save $ra and $a0 on stack
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
# Base case: if n <= 1, return 1
ble $a0, 1, base_case
# Recursive case: return n * factorial(n-1)
addi $a0, $a0, -1 # n-1
jal factorial # Recursive call
# After return: $v0 = factorial(n-1)
lw $a0, 0($sp) # Restore original n
mul $v0, $a0, $v0 # n * factorial(n-1)
j epilogue
base_case:
li $v0, 1 # Return 1
epilogue:
lw $ra, 4($sp) # Restore return address
addi $sp, $sp, 8 # Deallocate stack frame
jr $ra # Return to callerStack Frame Visualization
For factorial(4):
Stack grows downward ↓
| ...higher addresses... |
| main's frame |
| $ra (return to main) | ← factorial(4) saves here
| $a0 = 4 |
| $ra (return to fact4) | ← factorial(3) saves here
| $a0 = 3 |
| $ra (return to fact3) | ← factorial(2) saves here
| $a0 = 2 |
| $ra (return to fact2) | ← factorial(1) saves here
| $a0 = 1 | ← SP points here at deepest recursionArchitecture Concepts
- Stack pointer management (SP moves up/down)
- Return address saving ($ra must be preserved across calls)
- Callee-saved vs caller-saved register conventions
- How recursion maps to hardware stack operations
Lab 5: Bit Manipulation
Exercise 5.1: Count Set Bits
# Count number of 1-bits in a word (population count)
.text
.globl main
main:
li $t0, 0xABCD1234 # Number to count bits of
li $t1, 0 # Bit count
li $t2, 32 # Loop 32 times
count_loop:
beq $t2, $zero, done
andi $t3, $t0, 1 # Check LSB
add $t1, $t1, $t3 # Add to count if 1
srl $t0, $t0, 1 # Shift right (next bit becomes LSB)
addi $t2, $t2, -1
j count_loop
done:
move $a0, $t1
li $v0, 1
syscall # Print bit count
li $v0, 10
syscallLab Challenges (Self-Assessment)
- Bubble Sort: Implement bubble sort on an array — demonstrates nested loops and memory access patterns
- String Reverse: Reverse a string in place — demonstrates pointer manipulation
- Fibonacci: Calculate nth Fibonacci number iteratively and recursively — compare stack usage
- Binary Search: Implement binary search — demonstrates the power of O(log n) at the instruction level
- Matrix Multiply: 2×2 matrix multiplication — demonstrates spatial locality and nested array access
Key Takeaways
- Assembly makes explicit what high-level languages hide — every memory access, every branch, every register allocation is visible
- Array indexing (base + index × element_size) maps directly to address calculation hardware
- Function calls require explicit stack management — the hardware does not magically save your registers
- Loops generate branches — understanding this connection explains why branch prediction affects performance
- Bit manipulation instructions (AND, OR, SHIFT) are how the ALU operates at its most fundamental level
- Writing assembly gives you intuition for compiler optimization — you see exactly what the machine does
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Assembly Language Labs.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Computer Organization & Architecture topic.
Search Terms
computer-organization, computer organization & architecture, computer, organization, practicals, and, simulations, assembly
Related Computer Organization & Architecture Topics