RISC-V的常见指令
目录
运算指令
算术运算
逻辑运算
移位运算
数据传输指令
比较指令
条件分支指令
无条件跳转指令
本篇介绍RISC-V的常用指令,帮助建立汇编编程的初步印象。
我们已经知道,处理器执行的大部分指令都是在存取、运算、比较寄存器和主存中的数据,或是确定下一条指令的位置(PC的值)以实现循环、分支等功能。下面,我们来介绍RISC-V指令集中的各种指令,了解如何用RISC-V编写简单的程序。
历史上,指令集的设计有RISC(Reduced Instruction Set Computer)和CISC(Complex Instruction Set Computer)两种理念,从名字中可以看出,RISC强调指令集的精简,CISC则强调指令集的复杂。CISC中的指令种类要多得多,单条指令的功能也往往比RISC更复杂,同样的指令在RISC中可能需要多条指令实现。因此CISC完成任务需要的指令数更少,但代码的编写、CPU的设计也更为复杂。Intel的x86是CISC的代表,而移动端和嵌入式设备中常见的arm(Advanced RISC Machine)则是RISC的代表。
RISC-V读作“risk-five”,是加州大学伯克利分校设计的一种开源ISA(x86是闭源的),其目标是称为ISA领域的Linux。该项目发起于2010年,为解决常见指令集的诸多问题:闭源,扼制创新;过于复杂,不利于学术研究,且很多复杂性源于历史或设计问题;针对性强,如arm面向移动端,x86面向服务器,缺少统一性架构;商业指令集易受企业发展的影响。 {% endnote %}
运算指令
RISC-V中的运算指令包括算术运算,逻辑运算,移位运算。运算只在寄存器之间运行,即想要对内存中的数据进行运算,需要先将其取至寄存器。
这里介绍立即数的概念。汇编中立即数即为常数,一般在运算时会对其作符号扩展,关于符号扩展和零扩展会在介绍RISC-V的机器码表示时介绍。
值得注意的是,RISC-V中有一个寄存器x0被硬编码为0,其值无法修改,作为常数存在。
算术运算
- add rd,rs1,rs2
:将寄存器rs1与rs2的值相加并写入寄存器rd。 - sub rd,rs1,rs2
:将寄存器rs1与rs2的值相减并写入寄存器rd。 - addi rd,rs1,imm
:将寄存器rs1的值与立即数imm相加并存入寄存器rd。 - mul rd,rs1,rs2
:将寄存器rs1与rs2的值相乘并写入寄存器rd。 - div rd,rs1,rs2
:将寄存器rs1除以寄存器rs2的值,向零舍入并写入寄存器rd。 - rem rd,rs1,rs2
:将寄存器rs1模寄存器rs2的值并写入寄存器rd。
以上运算发生溢出时会自动截断高位。乘法可以用
mulh
,
mulhu
获得两个32位数乘积的高32位,细节不赘述。
逻辑运算
- and rd,rs1,rs2
:将寄存器rs1与rs2的值按位与并写入寄存器rd。 - andi rd,rs1,imm
:将寄存器rs1的值与立即数imm的值按位与并写入寄存器rd。 - or rd,rs1,rs2
:将寄存器rs1与rs2的值按位或并写入寄存器rd。 - ori rd,rs1,imm
:将寄存器rs1的值与立即数imm的值按位或并写入寄存器rd。 - xor rd,rs1,rs2
:将寄存器rs1与rs2的值按位异或并写入寄存器rd。 - xori rd,rs1,imm
:将寄存器rs1的值与立即数imm的值按位异或并写入寄存器rd。
移位运算
- sll rd,rs1,rs2
:将寄存器rs1的值左移寄存器rs2的值这么多位,并写入寄存器rd。 - slli rd,rs1,imm
:将寄存器rs1的值左移立即数imm的值这么多位,并写入寄存器rd。 - srl rd,rs1,rs2
:将寄存器rs1的值逻辑右移寄存器rs2的值这么多位,并写入寄存器rd。 - srli rd,rs1,imm
:将寄存器rs1的值逻辑右移立即数imm的值这么多位,并写入寄存器rd。 - sra rd,rs1,rs2
:将寄存器rs1的值算数右移寄存器rs2的值这么多位,并写入寄存器rd。 - srai rd,rs1,imm
:将寄存器rs1的值算数右移立即数imm的值这么多位,并写入寄存器rd。
左移会在右边补0,逻辑右移会在最高位添0,算数右移在最高位添加符号位。
区分算数右移和逻辑右移,是从计算的角度考虑的:左移一位等于乘2,右移一位等于除2是算数的规律;无论正数负数,在右边补0都等于乘2;而负数进行逻辑右移的结果不等于除以2,需要用算数右移;而若只有算术右移,则无符号数的运算又会受影响。
数据传输指令
前面讲到,想要对主存中的数据进行运算,需要先将其取至寄存器,数据传输指令实现了这个目的。
现代计算机以字节(byte,1byte=8bits)为基本单位,而内存本身可被视作由byte组成的一维数组,地址从0开始。字(word)则是存取数据的另一个单位,在RISC-V中1word=4Bytes=32bits,在其他体系结构中可能会发生变化。
- lb rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读一个字节,符号扩展后存入rd - lh rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读半个字,符号扩展后存入rd - lw rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读一个字,符号扩展后存入rd - lbu rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读一个无符号的字节,零扩展后存入rd - lhu rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读半个无符号的字,零扩展后存入rd - lwu rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读一个无符号的字,零扩展后存入rd - sb rs1,offset(rs2)
:把寄存器rs1的值存入地址为寄存器rs2的值加offset的主存中,保留最右端的8位 - sh rs1,offset(rs2)
:把寄存器rs1的值存入地址为寄存器rs2的值加offset的主存中,保留最右端的16位 - sw rs1,offset(rs2)
:把寄存器rs1的值存入地址为寄存器rs2的值加offset的主存中,保留最右端的32位
l是load的首字母,即加载数据;s是store的缩写,即存储数据。b,h,w分别是byte,half word,word的首字母,除此之外还有存取双字的d,即double word。
举例:
long long A[100];
A[10] = A[3] + a;
假设数组A首地址在寄存器x3,a在x2:
ld x10,24(x3) # long long占64bits=8bytes,A[3]的地址为A[0]+3*8
add x10,x2,x10
sd x10,80(x3)
比较指令
有符号数:
- slt rd,rs1,rs2
:若rs1的值小于rs1的值,rd置为1,否则置为0 - slti rd,rs1,imm
:若rs1的值小于立即数imm,rd置为1,否则置为0
无符号数:
- sltu rd,rs1,rs2
:若rs1的值小于rs1的值,rd置为1,否则置为0 - sltiu rd,rs1,imm
:若rs1的值小于立即数imm,rd置为1,否则置为0
条件分支指令
这部分用来实现控制流,即if语句,循环等。汇编中没有C等高级语言中的
{}
语句块,而是用
Lable:
的形式,下面会举例说明。
- beq rs1,rs2,lable
:若rs1的值等于rs2的值,程序跳转到lable处继续执行 - bne rs1,rs2,lable
:若rs1的值不等于rs2的值,程序跳转到lable处继续执行 - blt rs1,rs2,lable
:若rs1的值小于rs2的值,程序跳转到lable处继续执行 - bge rs1,rs2,lable
:若rs1的值大于等于rs2的值,程序跳转到lable处继续执行
blt
和
bge
也有无符号版本
bltu
,
bgeu
。举例:
int i = 0;
do{
i++;
}while(i<10)
add x2,x0,10 # x2 = 10
add x3,x0,0 # i = 0存储在x3
Loop:
add x3,x3,1 # i++
blt x3,x2,Loop # i<10则继续循环
无条件跳转指令
- j label
:程序直接跳转到lable处继续执行 - jal rd,label
:用于调用函数,把下一条指令的地址保存在rd中(通常用x1),然后跳转到label处继续执行 - jalr rd,offset(rs)
:可用于函数返回,把下一条指令的地址存到rd中,然后跳转到rs+offset地址处的指令继续执行。若rd=x0就是单纯的跳转(x0不能被修改)
这里详细解释一下
jal
和
jalr
。在调用函数时,我们希望函数返回后,继续执行下一条指令,所以要把这下一条指令的地址存起来,再跳转到函数的代码块。函数执行完之后,根据先前存起来的指令地址,再跳回到调用处继续执行。
- lw rd,offset(rs1)
:从地址为寄存器rs1的值加offset的主存中读一个字,符号扩展后存入rd
RV32I指令介绍
-- 符号扩展:--
(1)U-TYPE
LUI: 将20位立即数放32位的高位,低12位置0,将结果载入目标寄存器。
汇编写法:
lui rd, imm
RISC-V的常见指令相关推荐
- RISC V (RV32+RV64) 架构 整体介绍
文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...
- 【Linux】基础常见指令
目录 前言 一.Linux的环境搭建与远程控制 Linux 环境的搭建方式主要有三种 使用 XShell 远程登陆到 Linux 二.常见指令 1. ls 指令 2. pwd命令 3. ...
- 计组学习笔记2(RISC v版)
指令集解释 (规定:R[r]表示通用寄存器r的内容,M[addr]表示存储单元addr的内容,SEXT[imm]表示对imm进行符号扩展,ZEXT[imm]表示对imm进行零扩展) 整数运算类 -U型 ...
- Linux 常见指令及权限、OS(操作系统)基本概念
目录 一.OS(操作系统)基本概念 1.概念 二.Linux常见指令 1.ls指令 2.pwd指令 3.cd指令 4.touch指令 5.mkdir指令 6.rmdir指令 && rm ...
- linux基础(1)-常见指令及权限理解
1.常见指令及权限理解 初始Linux操作系统 初识shell命令 ,了解若干背景知识. 使用常用Linux命令 了解Linux权限概念与思想,能深度理解"权限" 初步了解Linu ...
- Git常见指令的本质
本文来说下Git常见指令的本质 文章目录 基本概念 基本概念
- Linux —— 常见指令及其英文全称
alias:给命令起别名 awk = "Aho Weiberger and Kernighan" ,三个作者的姓的第一个字母 bash:GNU Bourne-Again Shell ...
- Linux | 第一篇——常见指令汇总【超全、超详细讲解】
Linux之常见指令
- Linux下的常见指令以及权限理解(下)
Linux下的常见指令以及权限理解(下) Linux权限的概念 Linux权限管理 01.文件访问者的分类(人) 02.文件类型和访问权限(事物属性) 03.文件权限值的表示方法 a)字符表示方法 b ...
- 【Linux修炼】2.常见指令(中)
每一个不曾起舞的日子,都是对生命的辜负. Linux常见指令(中) 01. rmdir指令&&rm指令(重要): 1. rmdir指令 2. rm指令 02. man指令 03. cp ...
最新文章
- 技术图文:进一步完善自动化交易系统 - 02
- HTML图片瓦片,HTML5 可扩展瓦片式导航栏
- el-date-picker怎样获取选择的时间范围值并判断是否大于7天
- mysql-binlog日志恢复数据库
- Missing you is a kind of my deep-pain in my life
- osgi java_使普通的旧Java OSGi兼容
- python编程 从入门到实践-终于懂了python编程从入门到实践
- es6 提取数组对象一部分_ES6新特性你了解了多少呢?
- C++ Member Functions的各种调用方式
- C#获取电脑硬件信息(CPU ID、主板ID、硬盘ID、BIOS编
- 伍斯特理工学院计算机,世界排名领先,伍斯特理工学院到底有多厉害?
- 【莫烦Python】Matplotlib Python 画图教程 plot in plot图中图
- 搜狗输入法怎么打印间隔号
- unity3d:Matrix4x4矩阵位移,缩放,旋转
- umap算法_科学网—[转载]【源码】均匀流形近似与投影(UMAP)算法仿真 - 刘春静的博文...
- 全网最全面的npm包管理学习
- Java “constant string too long” 编译错误
- 前端leaflet框选下载bing遥感图
- 从公司管理到IT审计(ZT)
- 自动生成代码工具 模板工具类
热门文章
- 常见的引脚功能介绍(基于ADSP-SC589芯片)
- 中值滤波(python实现)
- 大数据与云计算学习(1)
- 为什么建议大家使用 Linux 开发?爽++
- 古典概型、几何概型与概率的区别与联系
- Our replica set configuration is invalid or does not include us
- oracle快速统计表条数_Oracle快速统计大表总记录数
- html 带边框的梯形,css clip-path画带边框梯形多边形
- SPSS—回归—多元线性回归(转)
- “羊毛党”们最喜欢用的手机号码分析