Skip to content
Memory Layout
step 1/5

Reading — step 1 of 5

Read

~1 min readArchitecture Basics

Memory Layout

The simulator's memory is a byte array, 4 GiB conceptually but typically a few MiB allocated.

Standard layout for our toy:

0x00000000 - 0x0000FFFF: Reserved / null guard
0x00010000 - 0x000FFFFF: Code (.text)
0x00100000 - 0x001FFFFF: Read-only data (.rodata)
0x00200000 - 0x002FFFFF: Initialized data (.data)
0x00300000 - 0x003FFFFF: Uninit data (.bss)
0x80000000 - 0x80FFFFFF: Stack (grows down from top)

Loads/stores are size-typed:

  • LB/LBU: load byte (signed/unsigned).
  • LH/LHU: load halfword (16-bit).
  • LW: load word (32-bit).
  • SB: store byte.
  • SH: store halfword.
  • SW: store word.
python

Alignment: RISC-V requires loads/stores aligned to their size. Misaligned access raises an exception. Some implementations handle in software.

Address translation: real CPUs use MMU (paging). Toy: skip translation, use physical address directly.

Memory-mapped I/O:

  • Special addresses correspond to devices (UART, timer, etc.).
  • Write to 0x10000000 → byte appears on serial console.
  • Read from 0x10000004 → status flag.
  • Our toy: simulate one UART for output.

Bootstrap:

  1. Load program binary at 0x10000.
  2. Set pc = 0x10000.
  3. Set sp = 0x80FFFFF0 (top of stack, aligned).
  4. Set x10 (a0) = argc, x11 (a1) = argv pointer.
  5. Run until ECALL with system_exit.

ECALL convention (Linux-like):

  • a7 = syscall number.
  • a0-a6 = args.
  • 64 = sys_write, 93 = sys_exit.
  • After ECALL, simulator dispatches to host action.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…