RISC |
您所在的位置:网站首页 › 汇编里的pc是啥意思 › RISC |
目录 运算指令 算术运算 逻辑运算 移位运算 数据传输指令 比较指令 条件分支指令 无条件跳转指令 本篇介绍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 |