Skip to content

Sontran0118/mips-game-solver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MIPS Assembly Game Engine

A high-performance MIPS assembly language implementation of core game logic functions. This project demonstrates low-level systems programming, register optimization, and assembly language mastery for the MIPS architecture.

Overview

This project implements critical game engine functions in pure MIPS assembly, achieving production-grade performance with minimal instruction overhead. The implementation showcases advanced assembly optimization techniques and demonstrates deep understanding of the MIPS instruction set architecture (ISA).

Technical Scope

Three core functions implemented in MIPS assembly:

  1. printBoard: Efficient board rendering to output
  2. zeroOut: Optimized memory initialization
  3. place_tile: Validated tile placement with boundary checking

These functions form the foundation of a high-performance game system running on MIPS processors.

Project Structure

├── hw5.asm                # Main assembly implementation
├── skeleton.asm           # Reference template
├── tests/                 # Comprehensive test suite
│   ├── test_*.asm        # Individual test cases
│   └── outputs/          # Expected output validation
├── MarsFall2020.jar       # MARS MIPS simulator
└── README.md             # This file

Architecture

MIPS Processor Overview

MIPS (Microprocessor without Interlocked Pipeline Stages) is a RISC architecture featuring:

  • 32-bit word size (classic MIPS32)
  • Simple instruction set (~50 core instructions)
  • Register-based operation (32 registers, $0-$31)
  • Load/Store architecture (memory accessed via specific instructions)
  • Efficient pipelining (predictable performance)

Register Convention

Register Name Purpose Convention
$zero Zero Always 0 N/A
$v0-$v1 Values Return values Caller-saved
$a0-$a3 Arguments Function arguments Caller-saved
$t0-$t9 Temp Temporary work Caller-saved
$s0-$s7 Saved Preserved values Callee-saved
$sp Stack Ptr Stack pointer Callee-saved
$ra Return Addr Return address Callee-saved
$gp Global Ptr Global pointer Callee-saved

Key Rules:

  • Caller-Saved: Function may modify; caller must preserve if needed
  • Callee-Saved: Function must preserve; use sw/lw if modified
  • Function arguments in $a0-$a3
  • Return values in $v0-$v1
  • Return via jr $ra

Core Functions

1. printBoard()

Renders the game board to standard output with optimal performance.

# Function: printBoard
# Arguments: None (uses global variables)
# Returns: void
# Uses: board (char[]), board_width (int), board_height (int)

Functionality:

  • Iterates through board array in row-major order
  • Prints ASCII representation of each cell (0-9)
  • Preserves all caller-saved registers
  • Zero return value

Performance Target: <300 instructions for 5×5 board

Implementation Strategy:

1. Calculate total cells = width × height
2. Initialize loop counter and base address
3. Load byte from memory
4. Convert to ASCII ('0' for 0, '1' for 1, etc.)
5. Print via syscall
6. Increment address and counter
7. Branch if more cells remain

2. zeroOut()

Clears board memory with optimized write performance.

# Function: zeroOut
# Arguments: None (uses global variables)
# Returns: void
# Uses: board (char[]), board_width (int), board_height (int)

Functionality:

  • Iterates through entire board array
  • Sets each byte to 0 (memory initialization)
  • Direct memory write operation
  • Preserves caller-saved registers

Performance Target: <200 instructions for 5×5 board

Implementation Strategy:

1. Load board base address from global
2. Load dimension globals (width, height)
3. Calculate total bytes = width × height
4. Initialize loop counter
5. Store zero byte (sb $zero, 0($t0))
6. Increment address pointer
7. Decrement counter
8. Loop until all bytes cleared

3. place_tile()

Places game tiles with comprehensive validation.

# Function: place_tile
# Arguments:
#   $a0 - row (0 to height-1)
#   $a1 - col (0 to width-1)
#   $a2 - value (0-9)
#
# Returns:
#   $v0 - Status code
#        0 = Success
#        1 = Cell occupied
#        2 = Out of bounds
#
# Uses: board (char[]), board_width (int), board_height (int)

Functionality:

  • Validate row coordinate: 0 ≤ row < height
  • Validate column coordinate: 0 ≤ col < width
  • Check cell occupancy (non-zero = occupied)
  • Place tile if all validations pass
  • Return appropriate status code

Performance Target: <50 instructions for success case

Implementation Strategy:

1. Check row boundary: if row >= height, return 2
2. Check col boundary: if col >= width, return 2
3. Calculate offset = row × width + col
4. Load byte at offset
5. Check if occupied: if non-zero, return 1
6. Write value to address
7. Return 0 (success)

Key Assembly Techniques

Memory Access Patterns

# Load globals
la $t0, board         # Load address of board array
lw $t1, board_width   # Load width value
lw $t2, board_height  # Load height value

# Array indexing (row-major)
# offset = row * width + col
mul $t3, $a0, $t1     # row * width
add $t3, $t3, $a1     # + col
add $t4, $t0, $t3     # base + offset

# Byte access
lb $t5, 0($t4)        # Load byte
sb $t5, 0($t4)        # Store byte

Efficient Looping

# Count-up loop pattern
li $t0, 0              # counter = 0
loop_start:
    # ... loop body ...
    addi $t0, $t0, 1   # counter++
    blt $t0, $t1, loop_start  # if counter < limit, continue

# Count-down loop pattern (slightly more efficient)
li $t0, 100            # counter = size
loop:
    # ... loop body ...
    addi $t0, $t0, -1  # counter--
    bne $t0, $zero, loop  # if counter != 0, continue

Conditional Branching

# Check bounds
bge $a0, $t1, out_of_bounds  # if row >= height
blt $a0, $zero, out_of_bounds # if row < 0

# Check occupancy
bne $t0, $zero, occupied      # if cell != 0
beq $t0, $zero, empty         # if cell == 0

MIPS Syscalls

# Print character (ASCII value in $a0)
li $v0, 11
int 10

# Print integer (value in $a0)
li $v0, 1
int 10

# Print string (address in $a0, null-terminated)
li $v0, 4
int 10

# Exit program (code in $a0)
li $v0, 10
int 10

Building & Testing

GUI Environment (Windows/macOS)

# Launch MARS simulator
java -jar MarsFall2020.jar

# Load assembly file and run with debugger

Command-Line Environment (Linux/Codespaces)

# Test individual file
java -jar MarsFall2020.jar tests/test_print_01.asm --noGui

# Run with output capture
java -jar MarsFall2020.jar test.asm --noGui > output.txt 2>&1

Performance Analysis

  1. Load test file in MARS GUI
  2. Navigate to: Tools → Instruction Statistics
  3. Click "Connect to MIPS"
  4. Run your code
  5. Review instruction count (target: ≤500,000)

Example Implementation

printBoard Pattern

printBoard:
    # Calculate total cells
    lw $t0, board_width
    lw $t1, board_height
    mul $t0, $t0, $t1      # total = width * height
    
    # Load board address
    la $t1, board
    li $t2, 0              # counter = 0
    
print_loop:
    # Load byte
    add $t3, $t1, $t2
    lb $a0, 0($t3)
    
    # Convert to ASCII
    addi $a0, $a0, 48      # Add 48 to convert 0-9 to ASCII
    
    # Print
    li $v0, 11
    int 10
    
    # Continue
    addi $t2, $t2, 1
    blt $t2, $t0, print_loop
    
    jr $ra

Memory Address Calculation

For row-major board (width=W, height=H):

Cell at (row, col) → offset = row × W + col
Memory address = board_base + offset

Testing Strategy

Unit Tests

Each function tested independently:

  1. Boundary Tests: Min/max values
  2. Edge Cases: Empty boards, full boards
  3. Functionality: Normal operations
  4. Stress Tests: Large boards, repeated operations

Test Coverage

  • ✅ Variable board dimensions
  • ✅ All 10 tile values (0-9)
  • ✅ Boundary conditions
  • ✅ Multiple sequential operations
  • ✅ Error conditions

Performance Benchmarks

Target instruction counts on MARS simulator:

  • printBoard(5×5): ~300 instructions
  • zeroOut(5×5): ~200 instructions
  • place_tile(success): ~50 instructions
  • place_tile(out_of_bounds): ~20 instructions
  • place_tile(occupied): ~40 instructions

Debugging Techniques

MARS Debugger

  1. Set Breakpoints: Click line number in editor
  2. Single-Step: Execute one instruction at a time
  3. Register Watch: Monitor $t0-$t9, $a0-$a3
  4. Memory Inspector: View board array contents
  5. Stack Trace: Follow function calls

Debug Output

# Add syscalls for debugging
li $v0, 1          # Print integer
move $a0, $t0
int 10

Optimization Strategies

Instruction Minimization

  • Use addi for small constants (faster than add)
  • Eliminate unnecessary move instructions
  • Combine related operations
  • Use register variables for frequently accessed values

Pipeline Optimization

  • Avoid register dependencies on consecutive instructions
  • Structure code for branch prediction success
  • Minimize branch instructions
  • Use delayed branch slots effectively

Memory Efficiency

  • Load globals once, reuse values
  • Cache frequently accessed values in registers
  • Use sb/lb only when necessary (slower than word operations)

Common Pitfalls & Solutions

Problem: Not preserving $ra for nested calls
Solution: Push $ra to stack before calling other functions

Problem: Off-by-one errors in loops
Solution: Double-check loop termination: blt vs ble

Problem: Incorrect address calculation
Solution: Verify: offset = row * width + col (row-major)

Problem: Forgetting return instruction
Solution: Always end with jr $ra

Problem: Register conflicts
Solution: Track which registers are in use

Real-World Applications

MIPS assembly skills demonstrated here are used in:

  • Embedded Systems: MIPS processors in IoT devices
  • Network Equipment: Cisco routers (IOS runs on MIPS)
  • Game Consoles: PlayStation, Nintendo systems
  • Mobile: MIPS processors in some phones
  • Education: Teaching low-level programming concepts

Learning Outcomes

This project demonstrates mastery of:

  • Low-level memory manipulation
  • Assembly language programming
  • Register allocation and optimization
  • Function calling conventions
  • Control flow in limited instruction sets
  • Performance analysis and optimization
  • Debugging at the instruction level

Advanced Topics

Register Allocation

Efficient use of limited registers:

  • Identify hot variables (used frequently)
  • Allocate callee-saved registers for hot variables
  • Use caller-saved registers for temporary values
  • Minimize register spills to memory

Branch Prediction

Modern MIPS processors use branch prediction:

  • Loops typically branch back (high prediction accuracy)
  • Conditional branches may miss prediction
  • Structure code to minimize mispredictions

Instruction Scheduling

Maximize pipeline efficiency:

  • Avoid dependent instructions on consecutive lines
  • Fill delay slots when possible
  • Consider cache locality for memory access

Resources

  • MARS Help: Built-in documentation
  • MIPS ISA Reference: Course materials
  • MIPS Programming Guides: Classic computer architecture texts
  • Online MIPS Tutorials: Various educational sites

Code Quality Standards

  • Clear Comments: Explain non-obvious logic
  • Consistent Formatting: Proper indentation
  • Meaningful Labels: Self-documenting code
  • Register Tracking: Document register usage
  • Performance Notes: Mark optimization opportunities

License

MIT License - Open source, educational and professional use

Author

Portfolio project demonstrating assembly language expertise, low-level optimization, and MIPS architecture mastery.

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors