---
name: make-mips-interpreter
description: Guidance for building MIPS interpreters or emulators that execute MIPS binaries. This skill applies when implementing CPU emulation, ELF loaders, instruction decoders, or syscall handlers for MIPS architecture. Use when tasks involve creating virtual machines for MIPS executables, interpreting MIPS assembly instructions, or emulating MIPS system calls.
---

# MIPS Interpreter Implementation

## Overview

This skill provides guidance for implementing MIPS interpreters/emulators that can load and execute MIPS ELF binaries. The core challenge involves parsing ELF files, decoding MIPS instructions, managing virtual memory, and handling system calls.

## Critical Approach: Incremental Development

The most important principle for this task is **incremental development over comprehensive analysis**. Avoid spending excessive time analyzing before writing code. Instead:

1. Start with a minimal working skeleton early
2. Expand functionality iteratively
3. Test frequently with partial implementations
4. Debug and refine based on actual execution

## Implementation Phases

### Phase 1: Minimal ELF Loader

Start with the bare minimum to load an executable:

1. Parse ELF header to extract:
   - Magic number verification (0x7f, 'E', 'L', 'F')
   - Architecture (MIPS32)
   - Endianness (typically little-endian)
   - Entry point address
2. Parse program headers to identify loadable segments
3. Load segments into virtual memory at specified addresses
4. Set program counter to entry point

Key data structures needed:
- Memory array/map for virtual address space
- Registers array (32 general-purpose + PC + HI/LO)

### Phase 2: Core Instruction Decoding

Implement instruction decoding for the three MIPS instruction formats:

**R-type format** (register operations):
- Bits 31-26: opcode (0x00 for R-type)
- Bits 25-21: rs (source register 1)
- Bits 20-16: rt (source register 2)
- Bits 15-11: rd (destination register)
- Bits 10-6: shamt (shift amount)
- Bits 5-0: funct (function code)

**I-type format** (immediate operations):
- Bits 31-26: opcode
- Bits 25-21: rs
- Bits 20-16: rt
- Bits 15-0: immediate value

**J-type format** (jump operations):
- Bits 31-26: opcode
- Bits 25-0: target address

### Phase 3: Essential Instructions First

Implement instructions in priority order based on typical program needs:

**High Priority (implement first):**
- Arithmetic: ADD, ADDU, ADDI, ADDIU, SUB, SUBU
- Logical: AND, ANDI, OR, ORI, XOR, NOR
- Shifts: SLL, SRL, SRA, SLLV, SRLV, SRAV
- Comparison: SLT, SLTI, SLTU, SLTIU
- Memory: LW, SW, LB, LBU, SB, LH, LHU, SH
- Branches: BEQ, BNE, BGTZ, BLEZ, BLTZ, BGEZ
- Jumps: J, JAL, JR, JALR
- Load: LUI

**Medium Priority:**
- Multiply/Divide: MULT, MULTU, DIV, DIVU, MFHI, MFLO, MTHI, MTLO

**Lower Priority:**
- Coprocessor instructions (if needed)
- Floating point (if needed)

### Phase 4: Syscall Handler

Implement system call interface based on the target environment:

1. Detect SYSCALL instruction
2. Read syscall number from register (typically $v0 or $2)
3. Read arguments from registers ($a0-$a3 or $4-$7)
4. Execute syscall and set return value in $v0

Common syscalls to implement:
- read (file descriptor, buffer, count)
- write (file descriptor, buffer, count)
- open (path, flags, mode)
- close (file descriptor)
- lseek (file descriptor, offset, whence)
- exit (status code)

### Phase 5: I/O and File System

For programs requiring file access:
- Implement file descriptor table
- Handle standard streams (stdin=0, stdout=1, stderr=2)
- Support opening/reading external files (e.g., data files)
- Handle output file creation (e.g., frame buffers, results)

## Verification Strategies

### Incremental Testing

Test after each implementation phase:

1. **ELF loader test**: Verify entry point and memory layout match expected values
2. **Instruction test**: Create simple test sequences for each instruction group
3. **Syscall test**: Test each syscall with known inputs/outputs
4. **Integration test**: Run actual target binary

### Debugging Techniques

- Add instruction tracing (PC, instruction, register changes)
- Log syscall invocations with arguments
- Verify memory reads/writes at expected addresses
- Compare register state against expected values at checkpoints

### Common Validation Points

- Entry point address matches ELF header
- Stack pointer initialized correctly
- Memory segments loaded at correct addresses
- Register $0 always reads as zero
- Signed vs unsigned operations handled correctly
- Branch delay slots handled (if applicable to target)

## Common Pitfalls

### Analysis Paralysis
**Problem**: Spending too much time understanding every detail before writing code.
**Solution**: Start implementation after understanding ELF basics, entry point, and syscall numbers. Iterate and learn through building.

### Missing Endianness Handling
**Problem**: Incorrect byte ordering when loading instructions or data.
**Solution**: Check ELF header for endianness flag and apply consistently when reading multi-byte values.

### Register Zero Hardwiring
**Problem**: Allowing writes to register $0 to persist.
**Solution**: Always return 0 when reading $0, or ignore writes to $0.

### Sign Extension Errors
**Problem**: Incorrect sign extension for immediate values or load operations.
**Solution**: Carefully distinguish signed vs unsigned operations. LB sign-extends, LBU zero-extends.

### Branch/Jump Address Calculation
**Problem**: Incorrect target address computation.
**Solution**:
- Branches: PC + 4 + (sign-extended offset << 2)
- Jumps: (PC & 0xF0000000) | (target << 2)

### Memory Alignment
**Problem**: Unaligned memory access causing errors.
**Solution**: Either enforce alignment or handle unaligned access appropriately for the target.

### Syscall Return Values
**Problem**: Not setting error codes or return values correctly.
**Solution**: Set $v0 for return value, handle error cases consistently.

### Incomplete Instruction Coverage
**Problem**: Missing instructions causing silent failures.
**Solution**: Log unimplemented instructions with their encodings for debugging.

## Time Management Strategy

For complex interpreter tasks:

1. **First 25% of time**: ELF loading + basic instruction loop skeleton
2. **Next 25% of time**: Core arithmetic/logic/memory instructions
3. **Next 25% of time**: Branches, jumps, and syscalls
4. **Final 25% of time**: Testing, debugging, edge cases

Prioritize a running (even incomplete) interpreter over comprehensive analysis. A partial implementation that executes provides more debugging information than complete analysis without code.
