MAVILERA RISC-V Laboratory

MAVILERA RISC-V Laboratory: documentation

Interactive Microprocessor Architecture Laboratory: Visualize. Execute. Understand.

About RISC-V

RISC-V is an open instruction set architecture (ISA): the instructions, registers and memory model that software sees, which anyone may implement without paying a royalty. This laboratory runs RV32I, the 32-bit base integer instruction set, with the M extension for multiplication and division.

Krste Asanović and the graduate students Yunsup Lee and Andrew Waterman started RISC-V in May 2010 in the Parallel Computing Laboratory (Par Lab) of the University of California, Berkeley, which David Patterson directed; the first manual (2011) is by Waterman, Lee, Patterson and Asanović. The RISC-V Foundation was founded in 2015 with 36 founding members, and in March 2020 the RISC-V International Association was incorporated in Switzerland. RISC-V International maintains and ratifies the specifications.

Why it matters: an open, royalty-free ISA lets companies, universities and individuals design processors for it and share cores and tools, instead of licensing an instruction set from one company. Its base is small and regular, with standard extensions added as needed, which makes it practical for teaching processor design, as in this laboratory.

Where it is used, for example: Espressif's ESP32-C3 and ESP32-C6 microcontrollers have RISC-V processors; Raspberry Pi's RP2350 has two Hazard3 RISC-V cores beside two Arm Cortex-M33 cores; Western Digital announced its open-source SweRV RISC-V core in 2018, with the goal of moving one billion of its processor cores to RISC-V; NVIDIA presented in 2016 its plan to replace its Falcon controller with its own RISC-V core.

The architecture is specified in RISC-V International's manuals. They have no DOI; the links are the publishers' own pages.

Sources of the history and the examples:

Overview

The RISC-V Laboratory, the first module of MAVILERA, is an assembler, simulator and teaching compiler for the RISC-V base integer instruction set (RV32I) with the multiply and divide extension (M), together with three processors that you can watch execute a program clock cycle by clock cycle: a single-cycle, a multicycle and a five-stage pipelined processor.

It is a static web page. Every computation runs in your browser; there is no account, no server-side processing, no telemetry, and nothing you write is uploaded.

Getting started

  1. Open the application. The editor holds a short example program; Templates in the toolbar offers others, each showing one idea, with a note at the top on what to try.
  2. Press Assemble (Ctrl+Enter). The listing shows each instruction with its address and machine word; errors are underlined in the editor and explained in the console with a hint.
  3. Press Step (F10) a few times. The current instruction is marked in the editor and the listing; the register it wrote is marked ◆.
  4. Press Step back (Shift+F10) to undo a step, or Run (F5) to run to the end or to a breakpoint.
  5. Choose Pipelined at the top. The same program now runs on the pipelined processor: each step is one clock cycle, and the drawing shows which paths each instruction uses.

A program that should end cleanly finishes with the exit system call or with halt:

        .data
nums:   .word 3, -1, 4, 1
        .text
main:   la    t0, nums        # address of the array
        lw    a0, 0(t0)
        lw    t1, 4(t0)
        add   a0, a0, t1      # a0 = 3 + (-1)
        li    a7, 93          # exit, with the code in a0
        ecall

The workspace

The page is a workspace of panes, as in a code editor.

Layout

Every boundary between panes is a divider: drag it, or focus it with Tab and use the arrow keys (Shift for larger steps); Enter or a double click restores it. Panes fold with the chevron in their heading. Sizes are kept in the browser for each view; View ▸ Reset layout forgets them. Below 900 px the panes stack and the page scrolls.

Projector mode uses larger type and lines and keeps the editor, the main view and the registers open, with the other panes folded but reachable.

Assembly language

Profiles and memory

The profile decides which instructions are accepted and how memory is laid out.

ProfileInstructionsMemory
ISA (RV32I + M)RV32I and M, ecall, ebreak, fence One byte-addressed memory: code from 0x00000000, data from 0x00010000; sp starts at 0x00100000
Single-cycle processorThe processor subset: add sub sll slt sltu xor srl sra or and, addi slti sltiu xori ori andi slli srli srai, lw sw, beq bne blt bge bltu bgeu, jal jalr lui auipc Separate instruction and data memories of 256 words each
Multicycle processorOne memory of 256 words: code from 0, data from 0x200
Pipelined processorSeparate instruction and data memories of 256 words each

The single-cycle view also offers a smaller instruction set and an extension with lbu, chosen beside the profile.

Registers

RegisterABI nameUse
x0zeroalways 0
x1rareturn address
x2spstack pointer
x3, x4gp, tpglobal and thread pointer
x5–x7, x28–x31t0–t6temporaries (caller-saved)
x8, x9, x18–x27s0–s11 (s0 = fp)saved (callee-saved)
x10–x17a0–a7arguments and results

Directives

.text .data .rodata .bss choose the section; .word .half .byte place values; .ascii .asciz .string place text; .space reserves bytes; .align .balign align; .equ .set name a constant. Expressions may use numbers (decimal, 0x…, 0b…), labels, +, -, parentheses, %hi() and %lo().

Pseudo-instructions

WriteMeansAssembled as
nopno operationaddi x0, x0, 0
li rd, valueload a constantaddi, or lui and addi outside ±2048
la rd, labelload an addresslui and addi
mv rd, rs · not · negcopy, invert, negateaddi rd, rs, 0 · xori rd, rs, -1 · sub rd, x0, rs
seqz snez sltz sgtzset if zero, non-zero, negative, positivesltiu, sltu, slt
beqz bnez bltz bgez blez bgtzcompare with zero and brancha branch against x0
bgt ble bgtu bleubranch on > or ≤blt, bge, bltu, bgeu with the operands swapped
j label · jr rs · retjump, jump to a register, returnjal x0, label · jalr x0, 0(rs) · jalr x0, 0(ra)
call label · tail labelcall, and a call that does not return herejal ra, label · jal x0, label
haltstop the programjal x0, 0, a jump to itself

System calls (ISA profile)

a7CallArguments
93exita0 = exit code
64writea0 = 1 (output) or 2 (errors), a1 = address of the bytes, a2 = their number

Several source files can be assembled together; labels are shared between them. GCC output made with gcc -S -march=rv32im -mabi=ilp32 (or rv32i) can be opened directly: it is adapted for the simulator, start-up code is added, and every change is listed in the console.

The C subset

Choose C under Language in the editor heading; Compile replaces Assemble. The compiler translates one statement at a time so that each line of C can be followed into its assembly: point at a line on either side to mark its counterpart.

Translation: Plain keeps every variable in the stack frame, as an unoptimised compiler does; Register keeps scalar locals and parameters in s1–s11. ISA: on RV32I, which has no multiply or divide instructions, the program calls software routines for them. A real compiler such as GCC produces different code.

Running and debugging

ControlWhat it does
Run / PauseRuns until the program halts, an error, a breakpoint or a watchpoint. Speed chooses full speed or an animated run.
Step / Step backOne instruction (one clock cycle in a processor view), forwards or backwards. Step back reaches the start of the run; in a very long run the oldest steps are dropped, with a message.
Step overRuns a call to its return.
Step outRuns to the return of the current procedure.
Run to cursorRuns to the instruction of the editor's line.
ResetRegisters, memory and counters back to their initial values.

Processor views

The three processor views share one layout: the datapath drawing, a row of details tabs below it, and the editor and registers beside it. One step is one clock cycle.

Single-cycle processor

Every instruction completes in one clock cycle. The tabs are:

Multicycle processor

Each instruction takes several shorter clock cycles, steered by a state machine (a Moore machine: every output depends on the state alone).

Code and data share one memory, with data from 0x200. The multicycle processor of this edition has no state for jalr: a program that uses it stops at the jalr with a message.

Pipelined processor

A five-stage pipeline (IF, ID, EX, MEM, WB) with pipeline registers IF/ID, ID/EX, EX/MEM and MEM/WB. The drawing shows the instruction in each stage; forwarding multiplexers are part of the datapath.

Settings above the drawing

Details tabs

This is a five-stage teaching pipeline. Production cores divide the work differently: the Hazard3 cores of the RP2350, for example, have three stages.

Comparison

The Compare view runs the program of the editor to its halt on the three processors and tabulates the instructions N, the clock cycles, CPI, the clock period Tc, the time per instruction, the execution time N × CPI × T_c and the speed-up over the single-cycle processor, and whether the registers and data at the halt agree with the single-cycle run. The pipelined count includes four cycles of pipeline fill. The delays are illustrative, not hardware timing.

Memory and caches

The Memory button chooses the memory model: ideal memory (one cycle per access), main memory without a cache (every access waits), or main memory with an instruction cache (L1I) and a data cache (L1D), each with a size, block size, number of ways, replacement and write policy of your choice. The designs are illustrative, not those of any real processor. Any change restarts the program. The instruction-level view has no clock: its caches show what the program's accesses have done so far, with no timing.

The Cache tab of the Memory and cache panel shows the last access of each cache, how the address finds its line, the lines as sets and ways, and the counters. Under the last access an animation shows the access step by step: the address split into tag, index and offset, the set read and its tags compared, then a hit, or a miss followed by the eviction of a line, the write-back of a dirty block and the fill from main memory, and last the word itself. Replay, Next step and Show all steps control it; with reduced motion switched on in the system, all the steps are shown at once.

The templates of the group Caches and memory each set the memory model they need: spatial locality, stride, conflict misses, write-back, replacement, the pipeline waiting for memory, and the comparison of the processors under the three memory models.

Devices and traps

The profile ISA with traps and devices (Profile list, instruction-level view) adds the platform of the laboratory: a GPIO at 0x4000_0000 with eight LEDs, four switches and a push button, a machine timer at 0x4000_1000, and a UART at 0x4000_2000. The Zicsr instructions, mret and wfi are instructions; ecall, ebreak, a misaligned or protected access and an illegal instruction raise exceptions; the timer, the button and the UART can interrupt. The rules of the traps, the timer and the GPIO follow rvsim.py --priv, the reference model this laboratory is checked against; the UART, a simple model of this laboratory, is not in it. Compiled C programs and the exit and write calls of the plain ISA profile are not available here, because ecall is a trap.

The Peripherals tab of the Memory and cache panel draws the board: the LEDs glow with the GPIO output, the switches and the button can be operated with the mouse or the keyboard (Space or Enter), the timer's count fills against its compare value, and the interrupt lines to the processor light while a request is active. Below are the processor's mode and trap registers, every device register (read without side effects), the UART terminal, a table of the interrupts with the cycles from request to handler, and the stimulus script of pin events; each pin you change is added to the script at the current cycle, so Reset and Step back replay it. The model is abstract: one cycle per instruction, 3 to take a trap, 4 to send a UART byte; these are not measurements of a real core.

The pin script, the bytes you send to the UART and the settings are kept with the program: after a reload and in links and settings files. The settings hold the options of the reference model: how often MTIME advances, the cycles to take a trap, mtval always 0, and a trap check that reports an interrupt handler which does not give back every register or returns to the wrong place. With Platform devices on the bus switched on in the Memory setting, the single-cycle, multicycle and pipelined views get the same devices and board; a program polls them with lw and sw, and stepping back restores them. Interrupts and traps exist only in the profile with traps.

The templates of the group Devices and traps are a running light, switches and a button by polling, a button interrupt, the timer by polling and by interrupt, a system call as a trap, and a serial port.

Exercises

File ▸ Exercise… lists 14 practice exercises written for MAVILERA — bit counting, Gray code, clamping, greatest common divisor, digit sums, Collatz steps, integer square root, reversing an array, palindromes, polynomials, printing a number, and three in C — each with a starter program and tests; no solutions are included.

A teacher can also give a task with tests in a file. Open it with File ▸ Open (or File ▸ Exercise…): the task is shown, Run the tests runs them on the program in the editor, and each test lists what it checks, the expected value and your program's. The file is read in the browser and kept there until you close the exercise; nothing is uploaded, and MAVILERA itself contains no exercises or answers.

The file format, for teachers

A JSON file with "format": "risc-vista-exercise" and "version": 1:

{
  "format": "risc-vista-exercise", "version": 1,
  "title": "Sum of an array",
  "task": "Write a procedure sum that returns in a0 the sum of the a1 words at the address in a0.",
  "lang": "asm",                       // or "c"
  "starter": "...",                    // optional: a program to start from
  "entry": "sum",                      // optional: call this label as a procedure in each test
  "tests": [
    { "name": "four numbers",
      "registers": { "a0": "arr", "a1": 4 },          // numbers, or labels of the program
      "memory": [{ "at": "arr", "words": [1, 2, 3, 4] }],
      "expect": { "registers": { "a0": 10 }, "abi": true },
      "limit": 100000 }
  ]
}

Expectations may check registers, memory (words, halves or bytes at a label or address), the console output, the exit code, and "abi": true (the calling convention is kept). With entry, each test calls that procedure with the test's registers and stops at its return; without it, the program runs from its start to its exit. Tests run in the ISA profile; a C program is compiled with the editor's translation settings.

Files, sharing and examples

Exports

ExportContents
.hex, .binThe program image, for $readmemh or as raw bytes.
ListingAddresses, machine words and source.
Trace (JSON lines, CSV)One record per instruction from reset to the halt: the PC, the instruction word, the register written and its value, the memory written (address, size, value); the CSV adds the disassembly.
Golden dumpThe state at the halt in a processor view, one word per line, as a testbench compares it.
Waveform (VCD)The signals of a processor view, cycle by cycle, under the names of the processor's modules. One cycle is 10 ns on the time axis; this is not hardware timing.
SVG, PNGThe datapath drawing of the current cycle, from Display.

The run exports replay the program from reset to its halt; the session you are in is not changed.

Offline use and privacy

Accessibility

Keyboard reference

KeysAction
Ctrl+EnterAssemble or compile
F5Run or pause
F10 / Shift+F10Step / step back (one clock cycle in a processor view)
F11 / Shift+F11Step over / step out (one instruction in the multicycle view)
Ctrl+F10Run to the editor's line
Ctrl+FFind in the editor
Esc, then TabLeave the editor (inside it, Tab indents)
↑ ↓, Enter, BIn the listing: move, show the fields, set or clear a breakpoint
↑ ↓, WIn the registers: move, watch
Arrow keys on a dividerResize panes (Shift for larger steps; Enter restores)
Enter on a drawn elementOpen its details
EscLeave the enlarged drawing

Limits of the models

Glossary

ABI
The calling convention: which registers carry arguments and results, and which a procedure must keep.
Bubble
An empty slot in a pipeline stage, inserted by a stall or left by a flush.
Clock period, Tc
The time of one clock cycle, set by the slowest path that must finish within it.
Control signal
An output of the control unit that sets a multiplexer, enables a write or selects an ALU operation.
CPI
Cycles per instruction: clock cycles divided by instructions completed.
Critical path
The slowest path through the logic between two clock edges.
Datapath
The registers, memories, ALU, adders and multiplexers that hold and move data.
Flush
Discarding instructions fetched on the wrong path after a jump or a mispredicted branch.
Forwarding
Passing a result to a later instruction before it is written to the register file.
Hazard
A case in which the next instruction in a pipeline cannot proceed as normal: a data dependence or a change of control flow.
Immediate
A constant encoded in the instruction word.
Load-use hazard
An instruction that needs the value of the load just before it; forwarding alone cannot supply it in time, so the pipeline stalls for one cycle.
Pipeline register
The register between two pipeline stages that carries an instruction's values to the next stage.
Pseudo-instruction
A convenient form that the assembler turns into one or more real instructions.
Stall
Holding an instruction in its stage for a cycle.

Licence

© 2026 Sajid Muhaimin Choudhury. MAVILERA, its content (processor drawings, tables, help texts, this documentation, example programs) and its logo artwork are licensed under the Apache License, Version 2.0. The names and the logo are not licensed as trademarks.

RISC-V® is a registered trademark of RISC-V International. MAVILERA is an independent educational project: it uses the name only to identify the instruction set it simulates, uses no RISC-V logo, and is not affiliated with or endorsed by RISC-V International. The RISC-V specifications are published by RISC-V International under the Creative Commons Attribution 4.0 International licence; this laboratory's assembler, simulator, drawings and texts are its own. Espressif, ESP32, Raspberry Pi, Western Digital, NVIDIA, Arm and Cortex are trademarks of their respective owners.