Skip to content

CPE 225 Midterm Study Guide

Created: February 2, 2025 3:23 PM Class: CPE 225

1. RISC-V Architecture Fundamentals

1.1 Register Conventions

  • Argument Registers (a0-a7)
    • Used for passing parameters to subroutines
    • a0 also used for return values
    • Caller-save (not preserved across calls)
    • First 8 arguments go in these registers
    • Additional arguments go on stack
  • Saved Registers (s0-s11)
    • Must preserve values across subroutine calls
    • Used for variables that persist across calls
    • Callee must save and restore if used
    • Often used for loop counters and important variables
  • Temporary Registers (t0-t6)
    • Used for intermediate calculations
    • Caller-save (not preserved across calls)
    • Can be freely used without preservation
    • Good for short-term storage within a single subroutine
  • Special Purpose Registers
    • ra (x1): Return address
    • sp (x2): Stack pointer
    • zero (x0): Always contains 0
    • gp (x3): Global pointer
    • tp (x4): Thread pointer

1.2 Memory Organization

  • Text Segment (0x00400000)
    • Contains program instructions
    • Read-only during execution
    • Instructions aligned on word boundaries
  • Data Segment (0x10010000)
    • Static data (.data directive)
    • Global variables
    • String constants
    • Initialized at program start
  • Stack (0x7fffefff)
    • Grows downward
    • Used for:
      • Local variables
      • Saved registers
      • Return addresses
      • Additional arguments
    • Automatically managed with sp register

2. Subroutines and Calling Convention

2.1 Calling Subroutines

# Basic subroutine call
jal subroutine_label   # Jump and link
# Return happens here

# Returning from subroutine
ret                    # Actually jalr ra

2.2 Parameter Passing

# Passing parameters
mv a0, s0    # First parameter
mv a1, s1    # Second parameter
jal function # Call function

# Inside function
mv t0, a0    # Can use parameters directly
mv t1, a1    # No need to copy unless preserving

2.3 Nested Subroutine Calls

function1:    
    # Must save ra if calling another function    
    addi sp, sp, -4   # Make space on stack    
    sw ra, 0(sp)      # Save return address    

    jal function2     # Call nested function    

    lw ra, 0(sp)      # Restore return address    
    addi sp, sp, 4    # Restore stack    
    ret

3. Number Systems and Binary Operations

3.1 Number Base Conversions

Binary to Decimal

  • Each position represents a power of 2, starting from 2⁰ on the right
  • Multiply each bit by its position value and sum

Examples:

  1. Short conversion:

    1101₂
    = 1×2³ + 1×2² + 0×2¹ + 1×2⁰
    = 1×8  + 1×4  + 0×2  + 1×1
    = 8    + 4    + 0    + 1
    = 13₁₀
    
  2. Longer conversion:

    10110101₂
    = 1×2⁷ + 0×2⁶ + 1×2⁵ + 1×2⁴ + 0×2³ + 1×2² + 0×2¹ + 1×2⁰
    = 128  + 0    + 32   + 16   + 0    + 4    + 0    + 1
    = 181₁₀
    
  3. Quick reference for powers of 2:

    2⁰  = 1
    2¹  = 2
    2²  = 4
    2³  = 8
    2⁴  = 16
    2⁵  = 32
    2⁶  = 64
    2⁷  = 128
    2⁸  = 256
    2⁹  = 512
    2¹⁰ = 1024
    

Decimal to Binary

Two main methods:

Method 1: Division by 2

  • Divide by 2 repeatedly until quotient is 0
  • Read remainders from bottom to top

Example: Convert 181₁₀ to binary

181 ÷ 2 = 90  remainder 1
90  ÷ 2 = 45  remainder 0
45  ÷ 2 = 22  remainder 1
22  ÷ 2 = 11  remainder 0
11  ÷ 2 = 5   remainder 1
5   ÷ 2 = 2   remainder 1
2   ÷ 2 = 1   remainder 0
1   ÷ 2 = 0   remainder 1

Reading bottom-up: 10110101b

Method 2: Subtraction of Powers of 2

  • Find largest power of 2 less than number
  • Subtract and repeat

Example: Convert 181₁₀ to binary

181 - 128 (2⁷) = 53   [1xxxxxxx]
53  - 32  (2⁵) = 21   [101xxxxx]
21  - 16  (2⁴) = 5    [1011xxxx]
5   - 4   (2²) = 1    [10110xxx]
1   - 1   (2⁰) = 0    [10110101]

Result: 10110101b

Hexadecimal Conversions

Binary to Hex Conversion Table:

Binary | Hex    Binary | Hex
0000   | 0     1000   | 8
0001   | 1     1001   | 9
0010   | 2     1010   | A
0011   | 3     1011   | B
0100   | 4     1100   | C
0101   | 5     1101   | D
0110   | 6     1110   | E
0111   | 7     1111   | F

Examples:

  1. Converting Binary to Hex:

    Binary:   1011 0101
    Grouped:  1011 0101
    Hex:        B    5
    Result:   0xB5
    
  2. Converting Hex to Binary:

    Hex:     0x3E1
    Binary:  0011 1110 0001
    

3.2 Two's Complement

Basic Rules

  • Most significant bit (leftmost) indicates sign
    • 0 = positive
    • 1 = negative
  • For n bits:
    • Range: -2^(n-1) to 2^(n-1)-1
    • Example for 8 bits: -128 to 127

Converting Between Positive and Negative

  1. Positive to Negative:

    Original:     00011100  (+28)
    Invert:       11100011
    Add 1:        11100100  (-28)
    
  2. Negative to Positive (same process):

    Original:     11111011  (-5)
    Invert:       00000100
    Add 1:        00000101  (+5)
    

Common Gotchas

  1. Sign Extension When extending to more bits, copy the sign bit

    8-bit:  11111011 (-5)
    16-bit: 1111111111111011 (still -5)
    
  2. Overflow Occurs when result doesn't fit in available bits

    Adding:  01111111 (127)
            +00000001 (1)
            --------
            10000000 (-128) Overflow!
    
  3. Special Cases

    • Negating smallest negative number gives itself
    -128:    10000000
    Invert:  01111111
    Add 1:   10000000 (back to -128!)
    

Practice Problems

  1. Convert +47 to -47 in 8-bit two's complement

    +47:     00101111
    Invert:  11010000
    Add 1:   11010001  Answer: -47
    
  2. Add these 8-bit numbers: 0x3B + 0xC4

    0x3B =   00111011
    0xC4 =   11000100
             --------
             11111111 = -1
    

3.3 Bitwise Operations

# AND - useful for masking
and t0, t1, t2   # t0 = t1 & t2

# OR - useful for combining flags
or t0, t1, t2    # t0 = t1 | t2

# XOR - useful for toggling bits
xor t0, t1, t2   # t0 = t1 ^ t2

# Shifts
slli t0, t1, 2   # Logical left shift (multiply by 4)
srai t0, t1, 1   # Arithmetic right shift (divide by 2)

4. RISC-V Instructions

4.1 Core Instructions

# Arithmetic
add  rd, rs1, rs2    # rd = rs1 + rs2
addi rd, rs1, imm    # rd = rs1 + imm
sub  rd, rs1, rs2    # rd = rs1 - rs2

# Memory
lw   rd, offset(rs1) # rd = Memory[rs1 + offset]
sw   rs2, offset(rs1)# Memory[rs1 + offset] = rs2

# Branches
beq  rs1, rs2, label # Branch if equal
bne  rs1, rs2, label # Branch if not equal
blt  rs1, rs2, label # Branch if less than
bge  rs1, rs2, label # Branch if greater/equal

4.2 Pseudo-Instructions

# Load immediate
li t0, 100      # Load immediate value

# Load address
la t0, label    # Load address of label

# Move register
mv t0, t1       # Copy t1 to t0

# Branch always
b label         # Unconditional branch

5. Control Structures

5.1 If Statement

# if (x > 0) { ... }    
    blez x, endif     # Skip if x <= 0    
    # If body here

endif:

5.2 If-Else Statement

# if (x > y) { ... } else { ... }    
    ble x, y, else    # Branch to else if x <= y    
    # If body here    
    b endif           # Skip else block

else:    # Else body here

endif:

5.3 Loops

# While loop
loop:    
    beq t0, zero, endloop  # Exit condition    
    # Loop body    
    b loop
endloop:

# For loop (counting down)    
    li t0, 10             # Initialize counter

loop:    
    beqz t0, endloop      # Check if done    
    # Loop body    
    addi t0, t0, -1       # Decrement    
    b loop
endloop:

6. Common Programming Patterns

6.1 Array Access

# Array base in t0, index in t1
slli t2, t1, 2      # Multiply index by 4 (word size)
add t2, t0, t2      # Add to base address
lw t3, 0(t2)        # Load array[index]

6.2 String Processing

loop:    
    lb t0, 0(s0)        # Load byte from string    
    beqz t0, done       # Check for null terminator    
    # Process character    
    addi s0, s0, 1      # Move to next char    
    b loop
done:

7. Exam Preparation Tips

  1. Practice Problems
    • Convert C code to assembly
    • Implement basic algorithms
    • Write helper functions
    • Debug existing code
  2. Common Mistakes to Avoid
    • Not saving ra in nested calls
    • Forgetting to preserve s registers
    • Incorrect parameter passing
    • Misaligned memory access
  3. Testing Strategy
    • Read entire question first
    • Plan register usage before coding
    • Test edge cases mentally
    • Double-check register preservation
  4. Time Management
    • Start with problems you’re confident about
    • Don’t spend too long on any one problem
    • Leave time to review all answers
    • Check for basic mistakes