RISC

您所在的位置:网站首页 汇编里的pc是啥意思 RISC

RISC

2024-07-16 21:44| 来源: 网络整理| 查看: 265

目录

运算指令

算术运算

逻辑运算

移位运算

数据传输指令

比较指令

条件分支指令

无条件跳转指令

  本篇介绍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的主存中读一个字节,符号扩展后存入rdlh rd,offset(rs1) :从地址为寄存器rs1的值加offset的主存中读半个字,符号扩展后存入rdlw rd,offset(rs1) :从地址为寄存器rs1的值加offset的主存中读一个字,符号扩展后存入rdlbu rd,offset(rs1) :从地址为寄存器rs1的值加offset的主存中读一个无符号的字节,零扩展后存入rdlhu rd,offset(rs1) :从地址为寄存器rs1的值加offset的主存中读半个无符号的字,零扩展后存入rdlwu rd,offset(rs1) :从地址为寄存器rs1的值加offset的主存中读一个无符号的字,零扩展后存入rdsb 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,否则置为0slti rd,rs1,imm :若rs1的值小于立即数imm,rd置为1,否则置为0

无符号数:

sltu rd,rs1,rs2 :若rs1的值小于rs1的值,rd置为1,否则置为0sltiu 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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3