Skip to content

Meeting Summary: CS 631-02 Systems Foundations

  • Date: Mar 26, 2026
  • Time: 02:49 PM Pacific
  • Meeting ID: 882 2309 0019

Quick Recap

The session introduced the RISC-V emulator project. Greg: - Compared major CPU architectures, noting similarities among RISC-V, MIPS, and ARM, and key differences with x86 (e.g., variable-length instructions). - Presented the structure of a RISC-V emulator in Rust, including register state, the program counter (PC), memory layout, and stack emulation. - Explained decoding for instruction types (R-type, I-type, memory, branches, jumps). - Demonstrated unsafe pointer handling in Rust where needed. - Walked through the emulator’s core execution loop and how to extend the starter code to support more instructions. - Previewed an upcoming cache memory component to be implemented.

Next Steps

  • Students: Read the cache memory guide before Tuesday’s class to prepare for the cache simulator extension.
  • Students: Implement the required code changes for the cache memory simulator as specified in the project assignment.
  • Students: Extend the emulator by adding support for additional RISC-V instructions used in the provided assembly programs.
  • Students: Bring their own fibrec file to the Project 3 repository.
  • Students: Complete as much of the emulator as possible before Tuesday, leaving primarily the cache and analysis components.

Summary

Assembly Language Architecture Comparison

  • RISC-V, MIPS, and ARM share similar, regular instruction formats; x86 differs notably due to variable-length instructions.
  • Modern x86 implementations often translate complex instructions into simpler, RISC-like micro-operations internally.
  • RISC-V is considered particularly approachable for emulation because of its regularity.
  • Greg briefly mentioned industry interest (e.g., a new chip company) in RISC-V.
  • Reminder: a project was due that night.

RISC-V Course Updates and Resources

  • Project 3 introduces a cache memory simulator extension.
  • New resources were posted on Campus Wire:
  • A RISC-V cheat sheet
  • The full specification document
  • The cache memory guide
  • The Docker image now includes GDB support.
  • Suggested workflows include local development with deployment to the Beagle board as needed.

RISC-V Emulator Architecture Overview

  • The emulator models a 64-bit RISC-V processor state:
  • General-purpose registers (with x0 hard-wired to zero)
  • Program counter (PC)
  • Emulated memory
  • Machine instructions are fetched from memory; stack space is allocated for emulated functions (the heap is ignored).
  • Clarification on threading: in a multi-core system, each kernel thread has its own stack, while code and address space are shared across threads.

RISC-V Emulator Implementation in Rust

  • The emulator is implemented in Rust to:
  • Represent the machine state (registers, PC, memory)
  • Read and decode real RISC-V machine instructions
  • The approach is contrasted with virtual machines (e.g., Java, Python), highlighting the project’s goal of understanding real instruction formats.
  • Topics covered:
  • Data types for representing registers, immediates, and memory
  • Use of unsafe Rust for low-level memory access where required
  • Interaction with assembly code where helpful

ROP Grant Implementation in Rust

  • Focus on immutability and clear separation of read-only vs. mutable data.
  • Emulation flow for function calls:
  • Initialize the state struct
  • Set up function arguments
  • Configure the stack to match RISC-V calling conventions
  • The return address (RA) is used to track control flow and returns.
  • The stack is initialized to reflect the expected memory layout for RISC-V functions.

Emulator Execution Loop

  • The main loop runs until the PC becomes zero.
  • Register x0 is enforced to remain zero after each instruction step.
  • Single-instruction execution:
  • Fetch instruction word from the PC
  • Decode using Rust’s match on opcode (with specialization by format)
  • Note: Some I-type opcodes (e.g., JALR vs. arithmetic immediate) share a format but are dispatched to different handlers.

Rust Bit Manipulation and Memory Access

  • Helper functions:
  • get_bits: masks and shifts values for field extraction.
  • Unsafe Rust is used for memory access beyond normal Rust references.
  • Pointer arithmetic supports both positive and negative offsets (e.g., for branches).
  • Safe unaligned access patterns are discussed for load/store emulation, allowing the compiler to handle potential alignment issues.

Implementation Approach and Code Organization

  • Recommended workflow:
  • Start with simpler assembly programs from the starter repository.
  • Incrementally implement instruction handlers, guided by the spec and cheat sheet.
  • Memory allocation:
  • Use Box to avoid large stack allocations for emulator state or memory buffers.
  • Instruction dispatch:
  • Pattern-match on opcode, then on funct3 and funct7 for R-type and I-type decoding.
  • Arithmetic:
  • Use wrapping_add (and related wrapping operations) on u64 to match RISC-V’s wraparound semantics.

R-Type and I-Type Details

  • R-type:
  • Implement arithmetic and logical operations using rs1 and rs2, with writes to rd.
  • Ensure PC updates correctly after each instruction.
  • I-type:
  • Separate handlers for arithmetic immediates, loads, and JALR.
  • JALR updates the PC using RA for returns and writes the link to rd as appropriate.

Instruction Encoding and Semantics

  • Immediate handling:
  • Correct sign extension for immediates and branch offsets.
  • Proper masking for shift amounts.
  • Branches:
  • Construct 13-bit branch offsets and update PC accordingly.
  • Use correct signed comparisons (cast between u64 and i64 as needed).
  • Loads/Stores:
  • Support unaligned reads/writes where necessary.
  • Apply the correct width and sign-extension rules per instruction.
  • Jumps/Calls:
  • Implement JAL by computing offsets, writing the link register, and updating PC.
  • Closing guidance:
  • Review the cache guide before Tuesday.
  • Prioritize finishing emulator functionality so only cache and analysis remain.