Bootstrap

RISC-V常用汇编语言及常用数据结构-栈

 

这是我在上完浙大刘鹏老师的视频课后做的笔记。我觉得在学完后,自己写出来会记忆会更深刻,因为要重新梳理一遍。同时遇到不会的还可以重新复习以前的知识。

程序执行流程:

高级语言->汇编语言->逻辑块->数字电路

常用汇编语言:

1.算数指令和访存指令

在汇编语言里面,操作对象是寄存器,而不是高级语言的变量。在RSIC-V里只有32位的32个寄存器,当然也有64位的未来也会有128位的,这里用32 位的。32个寄存器分别命名为x0-x31。不同于高级语言先定义在使用,汇编语言不用定义。但是由于寄存器数量少,所以要从存储器里面加载。在RSIC-V存储系统中,是按照字节为单位来进行寻址的,其中每个字节可以拆分为4个字节大小。在小端系统里,某个字的地址与它最低位字节地址相同,这是因为不大。同时在存储器中存储顺序有大端和小端两种方式,大端是将一个字数据最低位字节存储在最高位字节地址上。小端相反,我国用大端。命令:

按字:

lw(load word)

eg:lw x10,12(x15)#注释符是#,这句表示将从保存在x15的地址上偏移12字节的数据加载到x10寄存器里

sw(store word)

sw x10,12(x15)#把x10的数据加载到保存在x15的地址上偏移12字节的字节上。

按字节(格式与按字指令一样,只针对一字节的数据):

lb(load byte)将字节地址中的1字节数据符号扩展后转载到对应寄存器中(符号扩展,将最高位扩展到其它位)

sb(store byte)将寄存器中最低字节位的1字节数据保存到对应字节地址中

把数据加载到寄存器里面,下面是算法指令:

add eg:add x1,x2,x3#把x2和x3里面的值加起来存到x1

sub 减法,格式和add一样

立即数操作:

addi和add格式一样,没有立即数减法。

2.条件判断分支转移指令

实现条件语句类似的作用。

条件判断分支转移指令:

beq:  beq x1,x2,l1#如果x1和x2相等,跳到l1标志符的指令地址空间继续执行指令。不等顺序执行下面的语句

bne:与beq相反,相等执行下面的语句,不等跳到别的状态。

blt:小于号,格式相同

bge:大于号格式相同

无条件分支转移指令:jump(j)

j加标识符,可以直接跳到标识符的指令目标地址

3.逻辑运算指令

都是按位有and(掩码),or,xor,没有逻辑非,逻辑非的实现是使用xor(异或),与0x1111-1111异或即可得到逻辑非

有两种:寄存器型

and x1,x2,x3#x1=x2&x3

立即数

and x1,x2,3#x1=x2&3

移位:

逻辑移位:寄存器型和立即数型

sll(shift left logical):左移,低位补零

slli

slli x1,x2,2#x1=x2<<2

srl:右移,高位补零

srli

算数移位(shift right arithmetic)右移:

sra:右移后空出的高位由原数最高比特位符号扩展得到,格式一样的

srai:

4.函数调用

rsicv里面寄存器的别称。
x1 (通常称为  ra ):返回地址寄存器,用于存储函数调用后的返回地址。
x2 (通常称为  sp ):栈指针,指向栈顶,用于管理栈内存。
x3 (通常称为  gp ):全局指针,用于访问静态数据区域。
x4  -  x7 :临时寄存器,可在函数调用中用于保存临时值或局部变量。
x8 (通常称为  tp ):线程指针,用于多线程环境。

x8-x9:s0和s1,x18~x27对应s2~s11,用来保存原进程中的关键数据,避免在函数调用的过程里被破坏。
x10  -  x17 :(a0-a7)被调用者保存寄存器,函数调用时被调用者负责保存这些寄存器的值用来传递参数,a0和a1常用来传递返回值。
 x28  -  x31 :保留寄存器,具体用途取决于特定的实现或应用。

指令大小为四个字节。在程序顺序执行时,在调用后要返回源代码的下一行,所以在调用前先把下一行代码所在的地址保存在ra寄存器里面,当调用完毕后,再用jr ra命令返回之前的代码位置。

jr指令:可以跳转到寄存器所对应的地址空间,用这条指令来实现函数的返回。可以用ret来取代jr ra的操作。

伪指令:mv rd,rs=addi rd,rs,0

li rd,13=addi rd,x0,13

5.栈的使用

在讲这部分前先复习一下栈;

栈:限定在仅在表尾进行插入或者删除的线性表。表尾是栈顶,表头是栈低。是后入先出的线性表(last in first out ,LIFO结构)

顺序栈:初始化时一般不限定大小,后面空间不够时,再加。栈底和栈顶相等时为空栈,插入新的栈顶元素,栈顶加一,删除减一,所以非空栈的栈顶指针一直在下一个元素上。图示为c语言下栈的一些操作。

547f5d6b4ad14d228aa7bf0f7c80a3c9.jpeg

 现在来看栈的使用,当使用寄存器时,调用前可能里面也保存了一些值,为了还原,需要将它保存在栈里面,栈也是存储器的一部分,需要以后指向它的寄存器来保存它的基地址(sp)。函数调用中保存的数据是按照一定顺序组织在一起的,这种组织结构称之为栈帧包括局部变量等等。

 

;