第二章-计算机的语言
一、指令
RV32I指令编码如下所示
1. 指令类型
①基础指令集
指令的编排方式如下所示:
R型指令
R型指令是寄存器型指令,由两个源寄存器操作数(5位宽)rs1和rs2以及一个目标寄存器操作数(5位宽)rd,操作码(7位宽)opcode,func3字段和func7字段组成。
如这条加法指令:add x9, x21,x9 其指令编码如下所示:
I型指令
R型指令为立即数操作指令,其指令格式由R型指令的功能码func7字段与源寄存器操作数rs2组合成了一个12位的立即数。
如这条立即数加法指令:addi x9,x9,1 其指令编码格式如下所示:
在这里就有一个疑问,这个立即数是12位长的,有些数大于12位要怎么办,具体内容在小节大立即数将会有相应的处理方法。
S型指令(访存)
以sd(store double world)指令为例: sd x1,1000(x2) 其指令格式如下:
需要注意的是,sd访存指令操作的立即数(12位)被分成了高7位和低五位,由于高位的字段已经包含了低五位的值,所以需要通过除以2^5来分解,或者直接将1000转化为二进制。要将十进制的1000分解,方法如下:
高七位:1000/2^5 = 31 = 0011111
低五位:1000%2^5 = 8 = 01000
B型指令
B型指令和S型指令非常相似,都有两个源寄存器和一个12位的立即数,但是B型指令的立即数表示的是:从-4096到+4096以2-Byte的单位的地址增量 正是由于增量以2字节为单位,所以12位立即数可以认为是13位数最低位始终为0。(即无需保留最低位)
以beq 指令为例: beq x19,x10,end
LOOP:beq x19,x10,END
add ....
addi ....
j LOOP
需要更据如上代码片段计算出偏移量,4(条)32bit = 16B = 82B ,
则12位立即数为:00_000000_1000 则其指令格式如下所示:
U型指令
LUI指令,将立即数的高20位加载到目的寄存器,并将低12位清零,如:
lui x10,0x87654 #x10 = 0x87654000
addi x10,x10,0x321 #x10 = 0x87654321
便可向寄存器中写入一个32位的立即数,但是,假设addi指令加载的是12位负数立即数,则结果可能出现问题,原因是当这个12位的数最到位为1时,得到的结果为高20位减1在和低12位拼接而来,如:
lui x10, 0xdeadb
addi x10,x10 ,oxeef #结果是0xdeadaeef
要解决此问题,只需在装入高20位时预先加1
AUIPC该指令可以将当前PC值加上高位的立即数值的结果保留在目的寄存器中,这也是PC相对寻址的一种方式,如:SET:auipc x10,0 指令就是把当前PC值放入x10寄存器
J型指令
JAL指令,该指令保存当前PC值到目的寄存器,然后将当前的PC值加上立即数对应的偏移量得到转移地址值,更新PC寄存器。访问范围是以2bytes为单位的正负2^19 或4bytes为单位的前后正负 2^18地址空间
JALR 该指令将当前PC值加4的结果写入目的寄存器,然后设置PC值为源寄存器加立即数为新PC的值。(与分支指令不同)。
ret = jr ra = jalr x0,ra,0
实现32位偏移量的相对寻址跳转
lui x1,<高20位地址>
jalr ra,x1,<低12位地址>
②扩展指令集
占位,暂未学习到该方面的知识
2.寄存器功能
函数调用过程中需要做现场保护及恢复现场(截图来自Computer Organization and Design RISC-V Edition The Hardware Software Interface )
RV32I 下的寄存器的功能如下(截图来自Computer Organization and Design RISC-V Edition The Hardware Software Interface )
3.RISC-V寻址方式
①采用LUI指令便可以完成,具体在U型指令介绍。
②采用分支跳转指令如BEQ,BENQ
③采用无条件跳转指令如JAL,JALR 实现远距离跳转
上述的指令主要实现了RISC-V的四种寻址方式:立即数寻址、寄存器寻址、基址寻址、PC相对寻址
如下图所示(截图来自Computer Organization and Design RISC-V Edition The Hardware Software Interface ):
二、程序编译到启动过程
1.过程综述
C程序到可执行文件一般要经过预处理,编译汇编和链接等过程。预处理过程主要是处理 C 文件中的条件编译和预编译指令、删除所有的#define、并且展开所有的宏定义、删除代码注释等保留所有的#pragma 编译器指令。编译汇编过程就是把预处理后的文件进行语义和语法分析及优化,然后生成汇编代码,再由汇编器将汇编代码转化成能够识别和执行的机器代码。链接过程就是将有关的目标文件彼此相连接,生成一个可执行文件。最后再由加载器加载程序。过程图如下所示(截图来自Computer Organization and Design RISC-V Edition The Hardware Software Interface ):
2.各部分概述
编译器 无
汇编器 无
链接器的工作主要有三步:①将代码和数据模块按符号特征放入内存。②决定数据和指令标签的地址。③修正内部和外部引用。
加载器在UNIX系统中主要有以下步骤:①读取可执行文件收不以确定正文段与数据段的大小。②为正文和数据创建地址空间。③将可执行文件中的指令和数据复制到内存中。④将主程序的参数复制到栈顶。⑤初始化处理器寄存器并将栈指针指向第一个空闲位置。⑥跳转到启动例程,将参数复制到参数寄存器并调用主例程,主例程泛会所,启动例程通过exit系统调用终结程序
动态链接库 相对于静态库占用空间小,要用到的例程才会被载入。
三、边角知识点
1.二进制补码表示数据
计算机程序可以计算正数和负数,因此需要一种方法来区分正数和负数,最容易想到的是增加一个单独的符号位来表示,这种表示方式称为原码(sign and magnitude),这种表示方法有很多缺点,于是采用:前导0表示正数,前导1表示负数。这种方式叫做二进制补码。
正数的补码为它本身,负数的补码为除符号位外所有位取反加1。
2.栈与堆
RISC-V的栈指针寄存器(SP)为X2,栈的地址按照从高到低的顺序“增长”,意思是减指针将值压栈,加指针出栈。栈具有先进后出的特点。
代码段,动态数据如malloc函数分配的,静态数据都保存在堆中,堆与栈相相生长以达到内存的高效使用。
3. gcc的基本操作
见我的另一篇博客:gcc基本操作(带例子)
4. 指令与并行性
5.大小端模式
risc-v 属于小端模式
var code = “636b400c-d8be-4aac-b8b6-9cc2c3a029d0”
今天的文章计算机组成与设计(RISC-V版)学习记录二分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/88922.html