RISC-V汇编语言 汇编语言属于低级语言,这里的低级是相对于C、C++等高级语言而言的,并不是说汇编语言很“low”。汇编语言与具体的CPU架构(ARM、X86、RISC-V等)紧密关联,每一种CPU架构都有其对应的汇编语言。 汇编语言作为连接底层软件和处理器硬件(数字逻辑)的桥梁,要求做硬件和做底层软件的人都必须掌握的,只是要求掌握的程度不一样而已。有不少同学在数字方面很强,甚至整个处理器都写出来了,但是却不知道怎么写汇编语言或者C语言程序在上面跑。 虽然我对RISC-V汇编语言不是很熟悉,但我个人觉得RISC-V汇编语言还是很好掌握的(容易理解)。 RV32I有32个通用寄存器(x0至x31),PC寄存器不在这32个寄存器里面,其中x0为只读寄存器,其值固定为0。在RISC-V汇编语言程序里,我们一般看到的不是x0、x1、x2等这些名字,而是zero、ra、sp等名字,是因为这里的x0至x31有其对应的ABI(application
binary interface)名字,如下表所示: 在汇编程序里,寄存器名字和ABI名字是可以直接互换的。 下面是一些汇编指令,注意这些指令不是RISC-V特有的,而是GCC编译器都有的指令。 .align :2的N次方个字节对齐,比如.align 3,表示8字节对齐。 .globl :声明全局符号,比如.globl mytest,声明一个mytest的全局符号,这样在其他文件里就可以引用该符号。 .equ :常量定义,比如.equ MAX 10。 .macro :宏定义。 .endm :宏定义结束,与.macro配套使用。 .section :段定义,比如.section .text.start,定义.text.start段。 下面是一些常用的RISC-V整数指令。 - lui指令
语法:lui rd, imm,作用是将imm的低12位置0,结果写入rd寄存器。 - auipc指令
语法:auipc rd, imm,作用是将imm的高20位左移12位,低12位置0,然后加上PC的值,结果写入rd寄存器。 - jal指令
语法:jal rd, offset或者jal offset,作用是将PC的值加上4,结果写入rd寄存器,rd默认为x1,同时将PC的值加上offset。 - jalr指令
语法:jalr rd, rs1或者jalr rs1,作用是将PC的值加上4,结果写入rd寄存器,rd默认为x1,同时将PC的值加上符号位扩展之后的rs1的值。 - beq指令
语法:beq rs1, rs2, offset,作用是如果rs1的值等于rs2的值,则将PC设置为符号位扩展后的offset的值。 - bne指令
语法:bne rs1, rs2, offset,作用是如果rs1的值不等于rs2的值,则将PC设置为符号位扩展后的offset的值。 - blt指令
语法:blt rs1, rs2, offset,作用是如果rs1的值小于rs2的值(rs1和rs2均视为有符号数),则将PC设置为符号位扩展后的offset的值。 - bge指令
语法:bge rs1, rs2, offset,作用是如果rs1的值大于等于rs2的值(rs1和rs2均视为有符号数),则将PC设置为符号位扩展后的offset的值。 - bltu指令
语法:bltu rs1, rs2, offset,作用是如果rs1的值小于rs2的值(rs1和rs2均视为无符号数),则将PC设置为符号位扩展后的offset的值。 - bgeu指令
语法:bgeu rs1, rs2, offset,作用是如果rs1的值大于等于rs2的值(rs1和rs2均视为无符号数),则将PC设置为符号位扩展后的offset的值。 - lb指令
语法:lb rd, offset(rs1),作用是从rs1加上offset的地址处读取一个字节的内容,并将该内容经符号位扩展后写入rd寄存器。 - lh指令
语法:lh rd, offset(rs1),作用是从rs1加上offset的地址处读取两个字节的内容,并将该内容经符号位扩展后写入rd寄存器。 - lw指令
语法:lw rd, offset(rs1),作用是从rs1加上offset的地址处读取四个字节的内容,结果写入rd寄存器。 - lbu指令
语法:lbu rd, offset(rs1),作用是从rs1加上offset的地址处读取一个字节的内容,并将该内容经0扩展后写入rd寄存器。 - lhu指令
语法:lhu rd, offset(rs1),作用是从rs1加上offset的地址处读取两个字节的内容,并将该内容经0扩展后写入rd寄存器。 - sb指令
语法:sb rs2, offset(rs1),作用是将rs2的最低一个字节写入rs1加上offset的地址处。 - sh指令
语法:sh rs2, offset(rs1),作用是将rs2的最低两个字节写入rs1加上offset的地址处。 - sw指令
语法:sw rs2, offset(rs1),作用是将rs2的值写入rs1加上offset的地址处。 - addi指令
语法:addi rd, rs1, imm,作用是将符号扩展的立即数imm的值加上rs1的值,结果写入rd寄存器,忽略算术溢出。 - slti指令
语法:slti rd, rs1, imm,作用是将符号扩展的立即数imm的值与rs1的值比较(有符号数比较),如果rs1的值更小,则向rd寄存器写1,否则写0。 - sltiu指令
语法:sltiu rd, rs1, imm,作用是将符号扩展的立即数imm的值与rs1的值比较(无符号数比较),如果rs1的值更小,则向rd寄存器写1,否则写0。 - xori指令
语法:xori rd, rs1, imm,作用是将rs1与符号位扩展的imm按位异或,结果写入rd寄存器。 - ori指令
语法:ori rd, rs1, imm,作用是将rs1与符号位扩展的imm按位或,结果写入rd寄存器。 - andi指令
语法:andi rd, rs1, imm,作用是将rs1与符号位扩展的imm按位与,结果写入rd寄存器。 - slli指令
语法:slli rd, rs1, shamt,作用是将rs1左移shamt位,空出的位补0,结果写入rd寄存器。 - srli指令
语法:srli rd, rs1, shamt,作用是将rs1右移shamt位,空出的位补0,结果写入rd寄存器。 - srai指令
语法:srai rd, rs1, shamt,作用是将rs1右移shamt位,空出的位用rs1的最高位补充,结果写入rd寄存器。 - add指令
语法:add rd, rs1, rs2,作用是将rs1寄存器的值加上rs2寄存器的值,然后将结果写入rd寄存器里,忽略算术溢出。 - sub指令
语法:sub rd, rs1, rs2,作用是将rs1寄存器的值减去rs2寄存器的值,然后将结果写入rd寄存器里,忽略算术溢出。 - sll指令
语法:sll rd, rs1, rs2,作用是将rs1左移rs2位(低5位有效),空出的位补0,结果写入rd寄存器。 - slt指令
语法:slt rd, rs1, rs2,作用是将rs1的值与rs2的值比较(有符号数比较),如果rs1的值更小,则向rd寄存器写1,否则写0。 - sltu指令
语法:sltu rd, rs1, rs2,作用是将rs1的值与rs2的值比较(无符号数比较),如果rs1的值更小,则向rd寄存器写1,否则写0。 - xor指令
语法:xor rd, rs1, rs2,作用是将rs1与rs2按位异或,结果写入rd寄存器。 - srl指令
语法:srl rd, rs1, rs2,作用是将rs1右移rs2位(低5位有效),空出的位补0,结果写入rd寄存器。 - sra指令
语法:sra rd, rs1, rs2,作用是将rs1右移rs2位(低5位有效),空出的位用rs1的最高位补充,结果写入rd寄存器。 - or指令
语法:or rd, rs1, rs2,作用是将rs1与rs2按位或,结果写入rd寄存器。 - and指令
语法:and rd, rs1, rs2,作用是将rs1与rs2按位与,结果写入rd寄存器。 - ecall指令
语法:ecall,作用是进入异常处理程序,常用于OS的系统调用(上下文切换)。 - ebreak
语法:ebreak,作用是进入调试模式。
|