原文出处:https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md

RISC-V Assembly Programmer's Manual

Copyright and License Information

The RISC-V Assembly Programmer's Manual is

© 2017 Palmer Dabbelt palmer@dabbelt.com © 2017 Michael Clark michaeljclark@mac.com © 2017 Alex Bradbury asb@lowrisc.org

It is licensed under the Creative Commons Attribution 4.0 International License (CC-BY 4.0). The full license text is available at https://creativecommons.org/licenses/by/4.0/.

Command-Line Arguments

I think it's probably better to beef up the binutils documentation rather than duplicating it here.

Registers

Registers are the most important part of any processor. RISC-V defines various types, depending on which extensions are included: The general registers (with the program counter), control registers, floating point registers (F extension), and vector registers (V extension).

General registers

The RV32I base integer ISA includes 32 registers, named x0 to x31. The program counter PC is separate from these registers, in contrast to other processors such as the ARM-32. The first register, x0, has a special function: Reading it always returns 0 and writes to it are ignored. As we will see later, this allows various tricks and simplifications.

In practice, the programmer doesn't use this notation for the registers. Though x1 to x31 are all equally general-use registers as far as the processor is concerned, by convention certain registers are used for special tasks. In assembler, they are given standardized names as part of the RISC-V application binary interface (ABI). This is what you will usually see in code listings. If you really want to see the numeric register names, the -M argument to objdump will provide them.

Register ABI Use by convention Preserved?
x0 zero hardwired to 0, ignores writes n/a
x1 ra return address for jumps no
x2 sp stack pointer yes
x3 gp global pointer n/a
x4 tp thread pointer n/a
x5 t0 temporary register 0 no
x6 t1 temporary register 1 no
x7 t2 temporary register 2 no
x8 s0 or fp saved register 0 or frame pointer yes
x9 s1 saved register 1 yes
x10 a0 return value or function argument 0 no
x11 a1 return value or function argument 1 no
x12 a2 function argument 2 no
x13 a3 function argument 3 no
x14 a4 function argument 4 no
x15 a5 function argument 5 no
x16 a6 function argument 6 no
x17 a7 function argument 7 no
x18 s2 saved register 2 yes
x19 s3 saved register 3 yes
x20 s4 saved register 4 yes
x21 s5 saved register 5 yes
x22 s6 saved register 6 yes
x23 s7 saved register 7 yes
x24 s8 saved register 8 yes
x25 s9 saved register 9 yes
x26 s10 saved register 10 yes
x27 s11 saved register 11 yes
x28 t3 temporary register 3 no
x29 t4 temporary register 4 no
x30 t5 temporary register 5 no
x31 t6 temporary register 6 no
pc (none) program counter n/a

Registers of the RV32I. Based on RISC-V documentation and Patterson and Waterman "The RISC-V Reader" (2017)

As a general rule, the saved registers s0 to s11 are preserved across function calls, while the argument registers a0 to a7 and the temporary registers t0 to t6 are not. The use of the various specialized registers such as sp by convention will be discussed later in more detail.

Control registers

(TBA)

Floating Point registers (RV32F)

(TBA)

Vector registers (RV32V)

(TBA)

Addressing

Addressing formats like %pcrel_lo(). We can just link to the RISC-V PS ABI document to describe what the relocations actually do.

Instruction Set

Official Specifications webpage:

Latest Specifications draft repository:

Instructions

RISC-V User Level ISA Specification

https://riscv.org/specifications/

RISC-V Privileged ISA Specification

https://riscv.org/specifications/privileged-isa/

Instruction Aliases

ALIAS line from opcodes/riscv-opc.c

To better diagnose situations where the program flow reaches an unexpected location, you might want to emit there an instruction that's known to trap. You can use an UNIMP pseudo-instruction, which should trap in nearly all systems. The de facto standard implementation of this instruction is:

  • C.UNIMP0000. The all-zeroes pattern is not a valid instruction. Any system which traps on invalid instructions will thus trap on this UNIMP instruction form. Despite not being a valid instruction, it still fits the 16-bit (compressed) instruction format, and so 0000 0000 is interpreted as being two 16-bit UNIMP instructions.

  • UNIMP : C0001073. This is an alias for CSRRW x0, cycle, x0. Since cycle is a read-only CSR, then (whether this CSR exists or not) an attempt to write into it will generate an illegal instruction exception. This 32-bit form of UNIMP is emitted when targeting a system without the C extension, or when the .option norvc directive is used.

Pseudo Ops

Both the RISC-V-specific and GNU .-prefixed options.

The following table lists assembler directives:

Directive Arguments Description
.align integer align to power of 2 (alias for .p2align)
.file "filename" emit filename FILE LOCAL symbol table
.globl symbol_name emit symbol_name to symbol table (scope GLOBAL)
.local symbol_name emit symbol_name to symbol table (scope LOCAL)
.comm symbol_name,size,align emit common object to .bss section
.common symbol_name,size,align emit common object to .bss section
.ident "string" accepted for source compatibility
.section [{.text,.data,.rodata,.bss}] emit section (if not present, default .text) and make current
.size symbol, symbol accepted for source compatibility
.text   emit .text section (if not present) and make current
.data   emit .data section (if not present) and make current
.rodata   emit .rodata section (if not present) and make current
.bss   emit .bss section (if not present) and make current
.string "string" emit string
.asciz "string" emit string (alias for .string)
.equ name, value constant definition
.macro name arg1 [, argn] begin macro definition \argname to substitute
.endm   end macro definition
.type symbol, @function accepted for source compatibility
.option {rvc,norvc,pic,nopic,push,pop} RISC-V options
.byte expression [, expression]* 8-bit comma separated words
.2byte expression [, expression]* 16-bit comma separated words
.half expression [, expression]* 16-bit comma separated words
.short expression [, expression]* 16-bit comma separated words
.4byte expression [, expression]* 32-bit comma separated words
.word expression [, expression]* 32-bit comma separated words
.long expression [, expression]* 32-bit comma separated words
.8byte expression [, expression]* 64-bit comma separated words
.dword expression [, expression]* 64-bit comma separated words
.quad expression [, expression]* 64-bit comma separated words
.dtprelword expression [, expression]* 32-bit thread local word
.dtpreldword expression [, expression]* 64-bit thread local word
.sleb128 expression signed little endian base 128, DWARF
.uleb128 expression unsigned little endian base 128, DWARF
.p2align p2,[pad_val=0],max align to power of 2
.balign b,[pad_val=0] byte align
.zero integer zero bytes

Assembler Relocation Functions

The following table lists assembler relocation expansions:

Assembler Notation Description Instruction / Macro
%hi(symbol) Absolute (HI20) lui
%lo(symbol) Absolute (LO12) load, store, add
%pcrel_hi(symbol) PC-relative (HI20) auipc
%pcrel_lo(label) PC-relative (LO12) load, store, add
%tprel_hi(symbol) TLS LE "Local Exec" lui
%tprel_lo(symbol) TLS LE "Local Exec" load, store, add
%tprel_add(symbol) TLS LE "Local Exec" add
%tls_ie_pcrel_hi(symbol) * TLS IE "Initial Exec" (HI20) auipc
%tls_gd_pcrel_hi(symbol) * TLS GD "Global Dynamic" (HI20) auipc
%got_pcrel_hi(symbol) * GOT PC-relative (HI20) auipc

* These reuse %pcrel_lo(label) for their lower half

Labels

Text labels are used as branch, unconditional jump targets and symbol offsets. Text labels are added to the symbol table of the compiled module.

  1. loop:
  2. j loop

Numeric labels are used for local references. References to local labels are suffixed with 'f' for a forward reference or 'b' for a backwards reference.

  1. 1:
  2. j 1b

Absolute addressing

The following example shows how to load an absolute address:

  1. .section .text
  2. .globl _start
  3. _start:
  4. lui a0, %hi(msg) # load msg(hi)
  5. addi a0, a0, %lo(msg) # load msg(lo)
  6. jal ra, puts
  7. 2: j 2b
  8. .section .rodata
  9. msg:
  10. .string "Hello World\n"

which generates the following assembler output and relocations as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 000005b7 lui a1,0x0
  3. 0: R_RISCV_HI20 msg
  4. 4: 00858593 addi a1,a1,8 # 8 <.L21>
  5. 4: R_RISCV_LO12_I msg

Relative addressing

The following example shows how to load a PC-relative address:

  1. .section .text
  2. .globl _start
  3. _start:
  4. 1: auipc a0, %pcrel_hi(msg) # load msg(hi)
  5. addi a0, a0, %pcrel_lo(1b) # load msg(lo)
  6. jal ra, puts
  7. 2: j 2b
  8. .section .rodata
  9. msg:
  10. .string "Hello World\n"

which generates the following assembler output and relocations as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 00000597 auipc a1,0x0
  3. 0: R_RISCV_PCREL_HI20 msg
  4. 4: 00858593 addi a1,a1,8 # 8 <.L21>
  5. 4: R_RISCV_PCREL_LO12_I .L11

GOT-indirect addressing

The following example shows how to load an address from the GOT:

  1. .section .text
  2. .globl _start
  3. _start:
  4. 1: auipc a0, %got_pcrel_hi(msg) # load msg(hi)
  5. ld a0, %pcrel_lo(1b)(a0) # load msg(lo)
  6. jal ra, puts
  7. 2: j 2b
  8. .section .rodata
  9. msg:
  10. .string "Hello World\n"

which generates the following assembler output and relocations as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 00000517 auipc a0,0x0
  3. 0: R_RISCV_GOT_HI20 msg
  4. 4: 00053503 ld a0,0(a0) # 0 <_start>
  5. 4: R_RISCV_PCREL_LO12_I .L11

Load Immediate

The following example shows the li pseudo instruction which is used to load immediate values:

  1. .section .text
  2. .globl _start
  3. _start:
  4. .equ CONSTANT, 0xcafebabe
  5. li a0, CONSTANT

which generates the following assembler output as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 00032537 lui a0,0x32
  3. 4: bfb50513 addi a0,a0,-1029
  4. 8: 00e51513 slli a0,a0,0xe
  5. c: abe50513 addi a0,a0,-1346

Load Address

The following example shows the la pseudo instruction which is used to load symbol addresses:

  1. .section .text
  2. .globl _start
  3. _start:
  4. la a0, msg
  5. .section .rodata
  6. msg:
  7. .string "Hello World\n"

which generates the following assembler output and relocations for non-PIC as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 00000517 auipc a0,0x0
  3. 0: R_RISCV_PCREL_HI20 msg
  4. 4: 00850513 addi a0,a0,8 # 8 <_start+0x8>
  5. 4: R_RISCV_PCREL_LO12_I .L11

and generates the following assembler output and relocations for PIC as seen by objdump:

  1. 0000000000000000 <_start>:
  2. 0: 00000517 auipc a0,0x0
  3. 0: R_RISCV_GOT_HI20 msg
  4. 4: 00053503 ld a0,0(a0) # 0 <_start>
  5. 4: R_RISCV_PCREL_LO12_I .L0

Constants

The following example shows loading a constant using the %hi and %lo assembler functions.

  1. .equ UART_BASE, 0x40003000
  2. lui a0, %hi(UART_BASE)
  3. addi a0, a0, %lo(UART_BASE)

This example uses the li pseudoinstruction to load a constant and writes a string using polled IO to a UART:

  1. .equ UART_BASE, 0x40003000
  2. .equ REG_RBR, 0
  3. .equ REG_TBR, 0
  4. .equ REG_IIR, 2
  5. .equ IIR_TX_RDY, 2
  6. .equ IIR_RX_RDY, 4
  7. .section .text
  8. .globl _start
  9. _start:
  10. 1: auipc a0, %pcrel_hi(msg) # load msg(hi)
  11. addi a0, a0, %pcrel_lo(1b) # load msg(lo)
  12. 2: jal ra, puts
  13. 3: j 3b
  14. puts:
  15. li a2, UART_BASE
  16. 1: lbu a1, (a0)
  17. beqz a1, 3f
  18. 2: lbu a3, REG_IIR(a2)
  19. andi a3, a3, IIR_TX_RDY
  20. beqz a3, 2b
  21. sb a1, REG_TBR(a2)
  22. addi a0, a0, 1
  23. j 1b
  24. 3: ret
  25. .section .rodata
  26. msg:
  27. .string "Hello World\n"

Floating-point rounding modes

For floating-point instructions with a rounding mode field, the rounding mode can be specified by adding an additional operand. e.g. fcvt.w.s with round-to-zero can be written as fcvt.w.s a0, fa0, rtz. If unspecified, the default dyn rounding mode will be used.

Supported rounding modes are as follows (must be specified in lowercase):

  • rne: round to nearest, ties to even
  • rtz: round towards zero
  • rdn: round down
  • rup: round up
  • rmm: round to nearest, ties to max magnitude
  • dyn: dynamic rounding mode (the rounding mode specified in the frm field of the fcsr register is used)

Control and Status Registers

The following code sample shows how to enable timer interrupts, set and wait for a timer interrupt to occur:

  1. .equ RTC_BASE, 0x40000000
  2. .equ TIMER_BASE, 0x40004000
  3. # setup machine trap vector
  4. 1: auipc t0, %pcrel_hi(mtvec) # load mtvec(hi)
  5. addi t0, t0, %pcrel_lo(1b) # load mtvec(lo)
  6. csrrw zero, mtvec, t0
  7. # set mstatus.MIE=1 (enable M mode interrupt)
  8. li t0, 8
  9. csrrs zero, mstatus, t0
  10. # set mie.MTIE=1 (enable M mode timer interrupts)
  11. li t0, 128
  12. csrrs zero, mie, t0
  13. # read from mtime
  14. li a0, RTC_BASE
  15. ld a1, 0(a0)
  16. # write to mtimecmp
  17. li a0, TIMER_BASE
  18. li t0, 1000000000
  19. add a1, a1, t0
  20. sd a1, 0(a0)
  21. # loop
  22. loop:
  23. wfi
  24. j loop
  25. # break on interrupt
  26. mtvec:
  27. csrrc t0, mcause, zero
  28. bgez t0, fail # interrupt causes are less than zero
  29. slli t0, t0, 1 # shift off high bit
  30. srli t0, t0, 1
  31. li t1, 7 # check this is an m_timer interrupt
  32. bne t0, t1, fail
  33. j pass
  34. pass:
  35. la a0, pass_msg
  36. jal puts
  37. j shutdown
  38. fail:
  39. la a0, fail_msg
  40. jal puts
  41. j shutdown
  42. .section .rodata
  43. pass_msg:
  44. .string "PASS\n"
  45. fail_msg:
  46. .string "FAIL\n"

RISC-V汇编指南的更多相关文章

  1. 计算机系统6-> 计组与体系结构3 | MIPS指令集(中)| MIPS汇编指令与机器表示

    上一篇计算机系统5-> 计组与体系结构2 | MIPS指令集(上)| 指令系统从顶层讲解了一个指令集 / 指令系统应当具备哪些特征和工作原理.这一篇就聚焦MIPS指令集(MIPS32),看看其汇 ...

  2. RV32I基础整数指令集

    RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器.RV32I指令集的目的是尽量 ...

  3. GCC、GDB、Makefile

    1.GCC程序编译 Linux系统下的gcc(GNUCCompiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一.gcc可以在多种硬体平台上编译出可执行程序,其执行效率与一 ...

  4. LDM与STM指令详解

    title: LDM与STM指令详解 date: 2019/2/26 17:58:00 toc: true --- LDM与STM指令详解 指令形式如下,这里的存储方向是针对寄存器的 Load Mul ...

  5. 适用于 Internet Explorer 11 的企业模式

    https://technet.microsoft.com/zh-cn/itpro/internet-explorer/ie11-deploy-guide/enterprise-mode-overvi ...

  6. SoC的Testbench中的简易bus_monitor(加入print函数)

    SoC的Testbench中的简易bus_monitor(加入print函数) 主要思路 向固定地址写信息 使用工具链将C写的print/printf函数编译成hex文件 在testbench中创建b ...

  7. SoC编译HEX脚本(基于RISC-V的SoC)

    SoC编译HEX脚本(基于RISC-V的SoC) 脚本使用 ./compile hello 脚本:设置RISC-V工具链riscv_set_env ############## RISC-V #### ...

  8. 程序员延寿指南「GitHub 热点速览 v.22.17」

    很多人对程序员的固有印象之一便是常加班.易"猝死"!近几年的许多报道似乎也进一步加深了这种印象.应该如何更好地健康地活着.敲喜欢的代码呢?HowToLiveLonger 教你如何从 ...

  9. 人体调优不完全指南「GitHub 热点速览 v.22.22」

    本周特推又是一个人体调优项目,换而言之就是如何健康生活,同之前的 HowToLiveLonger研究全因死亡率不同,这个项目更容易在生活中实践,比如,早起晒太阳这么一件"小事"便有 ...

随机推荐

  1. 浅谈CLOSE_WAIT

    浅谈CLOSE_WAIT 发表于2016-01-19 TCP 有很多连接状态,每一个都够聊十块钱儿的,比如我们以前讨论过 TIME_WAIT 和 FIN_WAIT1,最近时不时听人提起 CLOSE_W ...

  2. DES 加密 转码 脱敏

    from pyDes import des, CBC, PAD_PKCS5 import binascii # 秘钥 KEY = 'mHAxsLYz' from pyDes import des, C ...

  3. 好久木来了,一直忙于项目(加懒惰),今天讲讲vuecli3.0的使用

    vue更新换代很快,马上vue都要出3.0了,这是一个巨大的变革,不过今天讲的是vuecli3.0,里面使用的vue仍然是2的,所有可以放心大胆使用. Vue CLI 是一个基于 Vue.js 进行快 ...

  4. java 标准日期格式

    public static void main(String[] argv) { // 使用默认时区和语言环境获得一个日历 Calendar cale = Calendar.getInstance() ...

  5. kvm 学习(三)存储池

    创建kvm存储池 1.查看系统已经存储的存储池 [root@runstone ~ ::]#virsh pool-list Name State Autostart ------------------ ...

  6. ROUND() 函数

    ROUND() 函数 ROUND 函数用于把数值字段舍入为指定的小数位数. SQL ROUND() 语法 SELECT ROUND(column_name,decimals) FROM table_n ...

  7. Linux堆的一些基础知识

    目录 堆的概述 什么是堆 堆的基本操作 堆操作背后的系统调用 堆的相关数据结构 微观结构 malloc_chuck chunk相关宏 bin 宏观结构 arena heap_info malloc_s ...

  8. 代码检查p626

    1 编译运行p626 图10-3代码,提交编译运行的截图 2 STDOUT_FILENO的值是多少?提交在Ubuntu中查找这个值的命令截图

  9. 纯CSS画三角形(带边框)

    实例一: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  10. legend3---开发总结1

    legend3---开发总结1 一.总结 一句话总结: 管它柳绿花红,我自潇洒人间 1.数据库字段命名:比如l_id? 见名知意,字段唯一,方便连表 2.所有方法在服务端都要加验证? 比如先查数据再更 ...