引言
关于riscv操作数
32个寄存器 | X0~X31|快速定位数据。在riscv中,只对寄存器中的数据执行算术运算
2^61个存储字 | 只能被数据传输指令访问。riscv体系采用的是字节寻址。
一个寄存器是8bytes,64位(double word)
每次取的最小单位是一个byte
注意:当函数参数大于8个的时候,会占用内存。本来是都在寄存器的
riscv汇编语言
程序一定是加载到内存中执行的。
(如图)
计算机硬件的操作
riscv体系中,寄存器大小64位,成组的64位频繁,被命名为双字。32位组成字。
存储器操作数
处理器只能在寄存器中保留少量数据,但内存可以存储大量数据。因此,数据结构(数组和结构体)保存在内存中。
riscv是小端字节序的。比如说0x12345678。存储是高位地址是12.最低位存储的是78。
网络字节序统一用的是大端序列。
数据传输指令:在内存和寄存器之间传输数据的命令
载入指令:将数据从内存复制到寄存器的数据传输命令
例题:将 A [12] = h + A[8]转换为汇编代码。A的基址存储在X22,h存储在X9
代码为:
ld X9 , 64(X22) //Temporary reg X9 gets A[8] add X9 , X21 ,X9 //Temporary reg X9 gets A[8] + h sd X9, 96(X22) //stores h + A[8] back into A[12]
常数或立即数操作数
将常数4加到寄存器X22的两种方式:
ld X9 , AddrConstant4(x3) //X9 = constant4
add x22 , x22 ,x9 //x22 = x22 +4
//第二种
addi x22, x22, 4
第二种的addi指令可以避免加载指令,速度更加快。在许多体系中,字的起始地址必须是4的倍数,双字是8的倍数。
计算机中的指令表示
按照“简单源于规整的设计原则,Rsicv指令都是32位长。四位的对齐效率很高!
Riscv字段
opcode(操作码):指令的基本操作,这个是它的惯用名称
rd :目的操作数寄存器,用来存档操作结果
funct3 :一个另外的操作码字段
rs1 :第一个源操作数寄存器
rs2 :第二个源操作数寄存器
funct7 :一个另外的操作码字段
R型
用于寄存器,减少访问内存的开销
funct7与funct3是用来细化解析的
I型
用于常数的算术指令
S型
用于存储访问,将寄存器中的数据写入内存
汇编语言到机器语言
例:A[30] = h + A[30] + 1;(A的基址在x10,h存放于X21)
ld x9 , 240(x10) //Temporary reg x9 gets A[30]
add x9, x9 ,x21 //Temporary reg x9 gets h + A[30]
addi x9, x9 ,1 //Temporary reg x9 gets h + A[30] + 1
sd x9, 240(x10) //store h + A[30] + 1 back into A[30]
关于指令的判断
逻辑操作
移位指令使用I格式,由于移位不会大于63,immediate字段使用低6位就可以。 funct6用来当做操作码字段。
用于决策的指令
例:if(i ==j) f = g + h; else f = g - h;
汇编:
bne (branch not equal)x22, x23, Else
add x19, x20, x21
beq x0, x0,Exit(遇到此指令必定跳过)
Else : sub x19, x20, x21
Exit
循环
例: while(save[i]) == k) i+=1;
loop: sli x10, x22 ,3 //Temp reg x10 = i * 8
add x10 ,x10, x25 //x10 = address of save[i]
ld x9, 0(x10) //Temp reg x9 = save[i]
bne x9 ,x24 ,Exit
addo x22 ,x22, 1
beq x0, x0,loop
Exit
计算机硬件对过程的支撑
在执行程序过程时候,必须遵循六个步骤
将参数放到可以访问的位置
将控制转交给过程
获取所需的存储资源
将结果放在调用程序可以访问到的位置
将控制返回到初始点,因为过程可以从程序的多个点调用
Rsicv软件在为过程分配寄存器的时候遵循原则:
x10~x17:八个参数寄存器,用于传递参数或返回值
x1:一个返回地址的寄存器,用于返回到起始点
除了将这些寄存器分配之外,Riscv编程语言还包含一个仅用于过程的指令:跳转-链接指令。
jal x1,ProcedureAddress //jump to ProcedureAddress and write return address to x1 上述代码中x1中这个链接称为返回地址。返回地址是必须要的,因为同一过程可能在程序的不同部分被调用。 为了支持这种情况下面的过程返回,使用间接跳转jalr x0, (x1)
jalr x0, (x1) 是一种 RISC-V 指令,用于无条件跳转到 x1 寄存器中存储的地址,并将下一条指令的地址存储在 x0 寄存器中。这是一种间接跳转,因为它不是直接跳转到一个特定的地址,而是跳转到一个存储在寄存器中的地址。这个指令的机器码是 0x00008067。
使用更多的寄存器
假如对一个过程,要使用超过8个参数寄存器。必须要采用寄存器换出到存储器当中
换出寄存器的理想数据结构一种后进先出的stack)队列。栈需要一个指向栈中最新分配地址的指针,以指示下一个过程应该放置换出寄存器的位置或寄存器旧值的存放位置。
在RISC-V中,栈指针(stack pointer)是寄存器x2,也称为Sp。栈指针按照每个被保存或恢复的寄存器按双字进行调整。栈应用非常广泛,因而传送数据到栈或从栈传输数据都具有专业术语:将数据放入栈中称为压栈,从栈中移除数据称为弹栈
栈例子:
图示结构:
寄存器用途
x0: the constant value 0
x1: return address
x2: stack pointer
x3: global pointer
x4: thread pointer
x5 - x7, x28 - x31: temporaries
x8: frame pointer
x9,x18 - x27: saved registers
x10 - x11: function arguments/results
x12 - x17: function arguments
递归例子
内存模型
大立即数编址与寻址
RISC-V指令系统包括指令 load upper immediate(取立即数高位,lui),用于将20位常数加载到寄存器的第31位到第 12位。将第31位的值复制填充到最左边 32位,最右边的 12 位用0填充。例如,这条指令允许使用两条指令创建 32位常量。lui 使用新的指令格U型,因为其他格式不能支持如此大的常量。
分支寻址
SB格式(可表示-4096 - 4096的分支地址)
寻址模式的总结
在PC寻址的时候:Targetaddress = PC + immediate * 2
翻译并启动程序
过程:
C程序-->预处理(#开头的全部处理掉)-->编译(变为汇编语言) -->汇编(变为机器语言)-->链接(目标文件链接为整体)
图示: 动态链接器:
动态链接器是操作系统的一部分,用于在执行可执行文件时(在“运行时”),将可执行文件所需的共享库从持久存储复制到 RAM 中,并填充跳转表和重定位指针。具体的操作系统和可执行文件格式决定了动态链接器的功能和实现方式。动态链接器通常被称为在编译可执行文件时执行的过程,而动态链接器是操作系统的一个特殊部分,它将外部共享库加载到正在运行的进程中,然后动态地将这些共享库绑定到正在运行的进程中。这种方法也称为动态链接或后期链接。1
但是java不是编译成目标计算机的汇编语言,而是首先编译成易于解释的指令(Java字节码)
感谢您阅读本文,希望对您有帮助。
本文作者:Cr不是铬 QQ:2195821921,欢迎交流讨论。
转载请注明出处:Chapter2 指令:计算机的语言
本文由博客一文多发平台 OpenWrite 发布!