跳转至

简介

前言

RISC-V(发音为“risk-five”)是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。

与大多数指令集相比,RISC-V指令集可以自由地用于任何目的,允许任何人设计、制造和销售RISC-V芯片和软件。虽然这不是第一个开源指令集,但它具有重要意义,因为其设计使其适用于现代计算设备(如仓库规模云计算机、高端移动电话和微小嵌入式系统)。设计者考虑到了这些用途中的性能与功率效率。该指令集还具有众多支持的软件,这解决了新指令集通常的弱点。

该项目2010年始于加州大学柏克莱分校,但许多贡献者是该大学以外的志愿者和行业工作者。

RISC-V指令集的设计考虑了小型、快速、低功耗的现实情况来实做,但并没有对特定的微架构做过度的设计。

截至2017年5月,RISC-V已经确立了版本2.22的用户空间的指令集(userspace ISA),而特权指令集(privileged ISA)也处在草案版本1.10。

RISC-V可以用于很多方面,但看起来更偏向于单片机芯片。想要运行一个RISC-V指令集的程序,得需要一块RISC-V芯片。

汇编简介

RISC-V的指令一般是这种格式的:

1
2
3
4
op  rd, rs
op  rd, rs1, rs2
op  rd, imm
op  rs1, rs2, addr

这是一段RISC-V的汇编:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
00000000000100b0 <.text>:
   100b0:    00010197            auipc   gp,0x10
   100b4:    48818193            addi    gp,gp,1160 # 0x20538
   100b8:    89018513            addi    a0,gp,-1904
   100bc:    92018613            addi    a2,gp,-1760
   100c0:    8e09                sub     a2,a2,a0
   100c2:    4581                li      a1,0
   100c4:    2ee000ef            jal     ra,0x103b2
   100c8:    00000517            auipc   a0,0x0
   100cc:    23c50513            addi    a0,a0,572 # 0x10304
   100d0:    20a000ef            jal     ra,0x102da
   100d4:    26c000ef            jal     ra,0x10340
   100d8:    4502                lw      a0,0(sp)
   100da:    002c                addi    a1,sp,8
   100dc:    4601                li      a2,0
   100de:    0c8000ef            jal     ra,0x101a6
   100e2:    2040006f            j       0x102e6
   100e6:    8082                ret

总体上类似MIPS。RISC-V架构包含32个寄存器,参数通过寄存器传递,并且需要两条指令才能赋值一个32位立即数。

1
2
lui  r, A
addi r, r, B

相当于:

1
r = (A << 12) + B

寄存器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  index     name                 usage                  
---------+--------+---------------------------------+
x0        zero     Hardwired zero
x1        ra       Return address                
x2        sp       Stack pointer
x3        gp       Global pointer
x4        tp       Thread pointer
x5-x7     t0-x2    Temporary
x8        s0/fp    Saved register, frame pointer
x9        s1       Saved register
x10-x11   a0-a1    Function argument, return value
x12-x17   a2-a7    Function argument
x18-x27   s2-s11   Saved register
x28-x31   t3-t6    Temporary

index是寄存器编号,name则是在汇编中体现的名称。

RISC-V没有像x86一样的rax, eax, ax, ah, al这样分成两半的寄存器,即所有寄存器都是完整的32位。

另外还有存储当前指令地址的寄存器pc,相当于x86的ip

调用约定

调用过程与x86类似:

  1. 将参数存储到函数能够访问到的位置(一般是寄存器,除非参数很多才会放到内存)
  2. 跳转到函数开始位置(使用jal指令,类似x86的call)
  3. 获取函数需要的局部存储资源,按需保存寄存器
  4. 执行函数中的指令
  5. 将返回值存储到调用者能访问的位置,恢复寄存器,释放局部存储资源
  6. 返回调用者的位置(ret指令)

由于RISC-V拥有足够多的寄存器,变量可以被存放在寄存器中,而且寄存器原本的值也可以放在保存寄存器中,不用像x86一样push到栈。

函数调用中没被用到的参数寄存器,会被当做保存寄存器或临时寄存器使用。

保存寄存器及栈指针由调用者保存,临时寄存器及参数寄存器由被调用者保存

指令手册

中文文档第116页开始

参考资料

官方网站:https://riscv.org/(英文)

官方网站:http://crva.io/(中文)

中文网站似乎low一点,但是能找到中文的文档:http://crva.ict.ac.cn/documents/RISC-V-Reader-Chinese-v2p1.pdf

官方工具链:https://github.com/riscv/riscv-gnu-toolchain

整个源码有2.3g

工具链采用子模块的方式,根据Readme这四条命令都要执行:

1
2
3
4
$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
$ git clone https://github.com/riscv/riscv-gnu-toolchain
$ cd riscv-gnu-toolchain
$ git submodule update --init --recursive

之后根据不同系统装不同的依赖包

然后可以编译了

1
2
./configure --prefix=/opt/riscv
make linux

编译的时间会很久。。。

我首先是在虚拟机编译的,注意要把/opt的权限改成可写。如果用root编译的话生成的新文件也是由权限的了,没那么方便。

后面感觉虚拟机编译太慢了,用wsl又编译一遍,还是好慢。。。

评论