读书·计算机组成与设计:软硬件接口RISC-V版·第二章

本文详细阐述了RISC-V指令系统,涉及计算机语言、寄存器和存储器操作、有符号与无符号数处理、逻辑和决策指令、过程调用的栈与堆管理,以及链接器、加载器和动态链接库的概念。此外,还讨论了数组与指针在编程中的应用和比较。
摘要由CSDN通过智能技术生成

指令:计算机的语言

        指令:计算机语言的word

        指令系统:计算机语言的alphabet

 

 

硬件设计三条基本原则之一:简单源于规整

 

汇编语言需要大量代码

java解释器采用类RV汇编方式进行解释编译,所以代码会稍多

C的代码会较少

C>JAVA>汇编语言

计算机硬件操作数

寄存器是计算机的基本组成单位,计算机做成之后,程序员也可见到寄存器

算术逻辑运算必须依赖于寄存器,寄存器数量有限,RV架构通常32个,64位;

为什么寄存器个数限制为32个,可以从硬件设计原则之二找到:

 存储器操作数

计算机数据结构保存在内存之中

算术运算只作用于寄存器

所以,为了处理大量运算,RV必须有控制寄存器和内存之间通信的指令

叫做数据传输指令

内存👉寄存器: load指令;格式:操作名 + 数据待取的寄存器 + 寄存器 + 访存常量

访存常量就是offset;而第二个寄存器的内容就是base_reg

 

 

有符号数与无符号数

  

 

 

 总结

 

 

 ----------------------------

2.6 逻辑操作

        原则1:在一个字内,对一段bit来检测很有用

移位操作:逻辑左移右移可以替代乘除法,补的是零

算数移位:补的是符号位

用异或NOR,一方为11111....可以替代 取非 NOT 来进行处理

2.7用于决策的指令

        汇编里面有Label概念

位模式的比较必须处理有符号和无符号数之间的差别

一般的小于和大于等于是有符号数的二进制补码

bltu这些属于无符号数比较

        大小比较,相等不相等都属于分支跳转指令

        另一种提供额外分支指令的方式是根据  比较结果设置寄存器  然后使用beq/bne

        ARM指令系统使用的另一种方法是,保留额外的位来记录指令执行期间发生的情况,叫条件代码/标志位

条件分支利用这些代码组合成期望判断

缺点:如果总是被调用,会造成流水线困难的依赖关系

2.7.2 边界检查的简便方法

将有符号数当作无符号数处理

无符号数比较也检测了某个数是否为负数

例如:bgeu x20 ,x11,xxxxx

用bgeu来检测两个数的相对大小

2.7.3 case/switch 语句

switch 一般由一大堆if组成

更有效的方式是使用编码形成指令序列的地址表,叫做分支表

 执行 过程 的六个步骤

        1.参数放在过程可以访问到的位置

        2.将控制转交给过程

        3.获取过程所需的存储资源

        4.执行所需的任务

        5.将结果值放在调用程序可以访问到的位置

对于过程的跳转分支,有专门的指令--jal  jump and link

                link的是x1,叫返回地址寄存器

2.8.1 使用更多寄存器

背景

在某个过程中,需要很多很多参数寄存器,但是没那么多,

然后任务完成后你需要将原来的寄存器的值归还原位,这时候需要将寄存器换出到存储器,于是需要用栈(stack)---一种先进后出的队列

减小指针就是压栈,增大指针就是弹栈

2.8.2嵌套过程

不调用其它过程的叫 叶子过程

调用的话就是嵌套过程

               嵌套过程可能会出现返回地址寄存器被写覆盖的情况

                方法就是把子过程的所有寄存器压栈

递归程序到指令阶段就是不断的压栈弹栈

动态变量就是压栈弹栈的参数等等

静态变量就是在保存寄存器里面的数

只要是static声明或者过程之外声明的C变量都是静态变量

一下是 过程调用 期间 需要保存和不需要保存的东西

有时候有些方案也会采取保存全栈,以确保数据相同

栈中为新设立的数据来分配空间:比如局部变量等等

过程帧/活动记录:存在于栈内,是一个数据段,用于保存 一个调用/过程 中 所保存的寄存器和局部变量。

 帧指针拿来寻址比较好

刚开始帧指针没有,如果用的话就以SP的初始地址作为FP的地址,而且FP不会动,全依靠SP动来压栈弹栈,而且,FP的地址就是SP的初始地址,对于一个数据段来说,一个栈可能会有多个数据段,FP的存在可以防止这个数据段的SP越界访问别的数据段

        总之,静态 + 安全 就是FP 的主要职能

用不用fp其实对性能来说不怎么影响

我们也可以通过维护稳定的sp 来减少对FP的使用

        比如:仅在进入/退出的时候才调整栈

--------

堆是用来存放动态数据 动态数据结构的

存放于内存之中,栈和堆相向生长,可以此消彼长,栈也是存放于内存之中

注意看:栈指针初始化是自定义的,栈是向下增长的

        程序代码开始处由PC决定

        静态数据起始处是由程序代码的末端决定

        动态数据起始处由静态数据起始处决定,它的空间叫堆,和栈相向增长

 

对于字符串的处理:

        字符串表示: 1.头部给出长度     java

                               2.身体附加带有字符串长度的变量

                                3.尾部用助记符结尾    C 

加载字/半字/Byte/双字, 无符号都是填充0;有符号填充符号位;

用大立即数的寻址方式

32位长固然方便,但是用常量 + 基地址的方式更广泛

我们没有立即数拼接指令,只有高位拼接 + 低位相加 这样的方式;

以往的jal指令,有关立即数的地址偏移就20位,但是现在的内存都太大了,20位不够用,所以有了偏移量 + 寄存器内容 的 取指方式

问题在于:如何设置一个基地址寄存器?

        我们知道,条件分支跳转指令一般情况下是:你PC指令知道哪里了,然后基于你PC来进行一定范围的跳转和返回

        所以,以PC指令作为你的基地址是一种不错的选择

这种寻址方式叫做PC相对寻址

问题来了:对于过程调用可能会出现超距离跳转,如何处理?:双指令序列

        

RV指令长度为32bit 4字节,分支指令可以改换单位,也就是直接让offset的单位为字数而非字节数

这样单位一变大,范围自然就大了,

我们知道,存储器的单位是以Byte来计的,而指令是32位的,所以一次就是4Byte,换了单位:换成字就是一次变1

但是,这样的话可能会出现不对齐的奇数地址,于是干脆使用半字,一次变2,这样的话就可以长久保持偶数字地址

 寻址方式总结

指令与并行性

同步机制由软件实现,底层依赖于同步指令

        lock & unlock

简单来说,基本能力就是对内存进行划分,哪一块只有处理器1可以处理,哪一块只有处理器2可以处理。

        这些区域称之为“互斥区”

 

 

指令对操作代替原子操作

 上边是一次原子交换内容

翻译并启动程序

 

编译器

汇编器

伪指令应该是方便一些汇编程序编写而设立的类似“函数”的东西

 伪指令可以想象成汇编里的函数,可以拿来简化汇编程序编写

汇编器是分体系结构的

链接器/编辑器

简单来说就是能够单独编译每一个过程,好让你单独debug一行的工具

不用重新编译和汇编了

重定位信息 + 符号表 = 定义一个未知标签,链接器的第一步是找到程序指令里的跳转,用新地址替代它们

链接器解析完位置模块,替换完了地址之后,剩下的就是计算内存

汇编器不知道  模块的指令和数据  相对于其它模块的位置

所以链接器将模块放入内存的时候,必须重定位所有的绝对引用,以反映其真实地址

链接器可以生成可执行文件,它长得和目标文件格式相同,但是把一些引用给解析了

 

链接器的理解

        链接器就是把一段代码程序的模块给底层化,然后根据符号表和重定位信息算出代码大小和内存调用大小,并定义一个未知Label,然后整理综合大小,分发给内存的程序段和数据段。

        如果说指令是死的一个电路架构,那么参数就是活的,它需要不断的修改和调整,其中,地址跳转和分支指令的参数会需要大量调整,这里就需要汇编器去计算调整参数,

        上边三个情况就是针对不同的跳转指令,采取的参数调整策略,其中的参数计算的源数据应该全部来自于链接器消化理解后的 指令地址 和 数据大小 

总而言之,链接器先消化理解未知引用,形成可执行文件,得出程序大小和数据大小,然后将其存入内存,随后开始处理各个引用接口处的跳转指令的参数,算出 相对于亘古不变的 指令电路来说,活生生的跳转参数大小。

加载器

        我们已经通过链接器,生成了可执行文件,并且将其送到了内存条里;操作系统会读取并执行它们

        加载器的作用就是将可执行文件内包含的程序放在主存中准备执行。

说白了加载器就是复现链接器消化后的东西,然后控制系统开始跑代码

动态链接库

        动态链接库相当于替代了链接器,在程序执行的过程中,同步执行动态链接库来查找相应的例程,使用相关文件中的额外信息来更新所有的例程引用。

        

以C排序程序为例的汇总整理

        swap代码例子

      

 

        sort例子

数组与指针

 

数组实现clear

指针实现clear 

        

版本比较:指针更好 

 16-17为扩展介绍环节,暂时不细看

2.18 RISC-V指令系统的剩余部分

其实就是介绍介绍指令集,细看可以参考

《RISC-V:硬件架构设计之道》

2.19 谬误与陷阱

2.20本章小结

2.22练习

慢慢刷吧,不着急.....

这本最畅销的计算机组成书籍经过全面更新,关注现今发生在计算机体系结构领域的革命性变革:从单处理器发展到多核微处理器。此外,出这本书的ARM是为了强调嵌入式系统对于全亚洲计算行业的重要性,并采用ARM处理器来讨论实际计算机的指令集和算术运算,因为ARM是用于嵌入式设备的最流行的指令集架构,而全世界每年约销售40亿个嵌入式设备。与前几一样,本书采用了一个MIPS处理器来展示计算机硬件技术、流水线、存储器层次结构以及I/O等基本功能。此外,本书还包括一些关于x86架构的介绍。   本书主要特点   ·采用ARMv6(ARM11系列)为主要架构来展示指令系统和计算机算术运算的基本功能。   ·覆盖从串行计算到并行计算的革命性变革,新增了关于并行化的一章,并且每章中还有一些强调并行硬件软件主题的小节。   ·新增一个由NVIDIA的首席科学家和架构主管撰写的附录,介绍了现代GPU的出现和重要性,首次详细描述了这个针对可视计算进行了优化的高度并行化、多线程、多核的处理器。   ·描述一种度量多核性能的独特方法——“Roofline model”,自带benchmark测试和分析AMD Opteron X4、Intel Xeon 5000、Sun UltraSPARC T2和 IBM Cell的性能。   ·涵盖了一些关于闪存和虚拟机的新内容。   ·提供了大量富有启发性的练习题,内容达200多页。   ·将AMD Opteron X4和Intel Nehalem作为贯穿本书的实例。   ·用SPEC CPU2006组件更新了所有处理器性能实例。
计算机组成设计硬件/软件接口RISC-V(原书第2)》是由David A. Patterson与John L. Hennessy合著的一本经典教材。该书以RISC-V为基础,全面讲解了计算机系统的硬件软件接口设计。 这本书首先介绍了计算机组成设计的基本概念,包括指令集架构、数字逻辑、处理器和存储器等。然后详细讲解了RISC-V指令集架构,包括指令的格式、功能和编码方法。通过对不同指令的解释和示例,读者可以深入了解指令集架构的原理和设计。 接着,书中介绍了计算机系统的各个组成部分,包括流水线、存储器层次结构、输入输出系统和操作系统等。通过对这些组成部分的讲解,读者可以了解计算机系统的整体结构和工作原理。 此外,该书还介绍了一些实际的计算机系统案例,并详细介绍了它们的设计原理和实现方法。这些案例包括单周期处理器、多周期处理器、流水线处理器和超标量处理器等。 最后,书中还讨论了计算机系统的性能优化和节能方法。通过了解这些方法,读者可以学习如何提高计算机系统的性能和效率。 总结来说,《计算机组成设计硬件/软件接口RISC-V(原书第2)》是一本全面而深入的计算机组成设计教材,适用于计算机科学、电子工程等相关专业的学生和从业人员。它可以帮助读者理解计算机系统的硬件软件接口设计,提高计算机系统的性能和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值