Easy RISC-V

原始链接: https://dramforever.github.io/easyriscv/

## 简易RISC-V:摘要 这次Hacker News讨论围绕“简易RISC-V”(dramforever.github.io),这是一个学习RISC-V汇编的互动指南。用户称赞该指南清晰且互动性强,尤其适合不熟悉汇编语言的人。 一个关键主题是RISC-V与较老的ISA(如MIPS)的关系。许多人认为汇编与MIPS非常相似,并能从先前使用帕特森和亨内西的“计算机组织与设计”教材的经验中受益,该教材现在有RISC-V版本。然而,一些人争论RISC-V保守的设计选择是否最优,并将其与AArch64的实用方法进行对比。 讨论还涉及向RISC-V添加新指令的难度,强调了可证明的益处和广泛采用的必要性。用户指出AArch64有效利用条件标志,尽管受到批评,以及理解链接器放松等概念在处理RISC-V时的重要性。最后,人们对潜在的项目(如使用RISC-V汇编重现“核心战争”)表示热情。
相关文章

原文
Easy RISC-V
Easy RISC-V

(Last updated: 2025-10-27 14:51)

(Emulators disabled version)

This page is not designed to be used on a narrow screen or without CSS. If you’re having issues using the emulator, try the emulators disabled version.

An interactive introduction to RISC-V assembly programming, by dramforever.

Interested in the code? Want to report an issue? Check out the GitHub page: https://github.com/dramforever/easyriscv

Inspired by Easy 6502 by Nick Morgan, this is a quick-ish introductory tutorial to RISC-V assembly programming. This tutorial is intended for those with a basic familiarity with low level computer science concepts, but unfamiliar with RISC-V. If you’re curious about RISC-V, I hope this will be a good start to your journey to learning about it.

RISC-V (pronounced “risk-five”), as its name suggests, is RISC (Reduced instruction set computer) architecture. Having started its life at UC Berkerley, RISC-V has bred a lively community of students, researchers, engineers and hobbyists working on software and hardware. Some highlights of RISC-V include:

  • Clean design: Although loosely based on many previous designs, RISC-V is at its core a new and clean design. It does away with integer status flags like “carry” or “overflow”, and does not have MIPS’s branch delay slots. RISC-V is designed primarily as a target for compilers, but writing RISC-V assembly by hand is still quite pleasant.
  • Open standard: RISC-V specifications are developed publicly and anyone can use them without copyright or patent licensing issues. Many researchers and companies around the world have made their own RISC-V processor cores and chips based on these specificaions.
  • Community support: If you want to make your own processors, rather than paying a hefty license fee to Arm, or designing your own architecture, you can just use RISC-V. Using RISC-V instead of a custom architecture allows you to make use of the existing and growing software ecosystem instead of having to maintain your own.

RISC-V is less mature than more established architectures like x86 or Arm, but it is quickly gaining steam and has found great success in many areas of application, such as embedded systems, custom processors, education, and research.

This article will cover the 32-bit bare bones RV32I_Zicsr instruction set with a tiny subset of the privileged architecture. You’ll probably never find a “real” chip with such bare bones instruction support. Most of them will have more extensions for other features like floating point or compressed instructions. However, I would still consider what we have here a “complete” instruction set. For example, Rust has Tier 2 support for the target riscv32i-unknown-none-elf which works completely fine with only the instructions we’ll cover here.

Speaking of instructions we will cover, why don’t we meet the 45 of them right here and now:

lui auipc
jal jalr
beq bne blt bge bltu bgeu
lb lh lw lbu lhu sb sh sw
addi slti sltiu xori ori andi slli srli srai
add sub slt sltu xor or and sll srl sra
ecall ebreak
csrrw csrrs csrrc csrrwi csrrsi csrrci

Some of these instruction names should ring a bell (add, or, xor). Others will look like they have some pattern to it. A few weird ones like auipc stand out. These instructions form the foundation of RISC-V, performing the basic tasks a processor would do.

You will also catch a glimpse of what creating an operating system on RISC-V is like, namely handling exceptions and privilege levels.

Let’s get started.

Throughout this article you will see emulator panes like these:

(If you just see a code block, there’s a JavaScript problem. Make sure you’ve enabled JavaScript, probably…)

start: addi x10, x0, 0x123 ebreak

You can use the buttons to control each emulator. Go ahead and click on ‘Start’. A register view should pop up showing the state of the emulator. Now click on ‘Run’. You’ll notice that:

a0 (x10) 0x00000000

Changed into:

a0 (x10) 0x00000123

And the emulator stopped. Congratulations, you’ve run your first RISC-V assembly program. First here, at least.

‘Start’ assembles your code and, well, starts the emulator. If there’s a problem with your code, it will tell you about it and the emulator will not start.

When the emulator is started, you can see the current state of the registers in the side pane. More controls also becomes available. ‘Run’ runs until the end or until you hit ‘Pause’. ‘Step’ runs a single step.

If you hit ‘Step’, you’ll notice that the above program takes two steps to run. You may have guessed correctly that the first step corresponds to addi, and the second corresponds to ebreak. The top of the register panel shows pc, the current instruction address, and in parentheses the current instruction.

‘Dump’ opens a new window containing some text. There are two sections: the first is the symbol table, which tells you about the labels in your code:

# Symbols
# 0x40000000 start

The second section is an annotated version of your code:

start:
{ 0x40000000: 12300513 } addi x10, x0, 0x123
{ 0x40000004: 00100073 } ebreak

This tells you that the addi instruction encodes to hex 12300513, and starts at address hex 40000000. Similarly, ebreak encodes as 00100073 at address hex 40000004.

(Note: RISC-V instructions are little-endian, meaning that the four bytes of addi are actually 13 05 30 12.)

We’ll talk in detail about all of pc, registers, instructions, labels, and the two checkboxes later.

Now you may have also guessed that addi x10, x0, 0x123 means x10 = x0 + 0x123. As for ebreak, for now, just remember that ebreak stops the emulator.

The program counter, or pc is the address of the current instruction. It points to the instruction to be executed.

RV32I has 31 general purpose registers numbered x1 through x31. These can contain any 32-bit data.

(If you’re wondering, there are no flags for RV32I.)

The register x0 is a special “zero register”. For computational instructions, you can use x0 anywhere a register is expected. Reading it always gives zero, and writing to it just gets ignored. The use of a special register simplifies the design of the architecture, and this design is shared by MIPS and Arm AArch64. We will make good use of x0 soon.

(Note: In the emulator, the instruction listed in parenthesis next to pc in the register view is provided as a convenience and is not part of the processor state.)

But before we can start talking about instructions themselves, we need a way to talk about the instruction syntax so I can, you know, write it down for you.

The syntax of an instruction is the instruction name and then several comma-separated operands. For example, for this instruction we’ve seen above:

addi x10, x0, 0x123

x10 is the destination register or rd. The next operand is the first (and only) source register or rs1. The last operand is an immediate value or imm. Using these abbreviations, we can summarize that the syntax for addi is:

addi rd, rs1, imm

Some other instructions have a second source register or rs2. For example, the non-immediate add instruction has this syntax:

add rd, rs1, rs2

Some other instructions have no operands, like ebreak. Others have slightly more complex operands.

Using the registers as a playground of numbers, we can use computational instructions to work with them.

Popek and Goldberg conditions of virtualization to work, specifically because being able to read the current privilege level at a lower-than-maximum privilege level would be a “sensitive” but “unprivileged” instruction.

If you’re writing a program for a certain privilege level, you should simply assume that it is correctly being run at that privilege level.

https://github.com/dramforever/easyriscv if you have suggestions, grievances, or just want to share some thoughts.

This tutorial is under the CC0 license. To the maximum extent permitted by law, this tutorial is dedicated to the public domain.