Cxuan自己的Github很硬核,请教大家:https://github.com/crisxuan/bestJavaer.
汇编代码是计算机的低级表示。它是一种低级语言,可以从字面上理解,包括处理数据、管理内存、在存储设备上读写数据、使用网络通信。编译器生成的机器码经过了一系列的转换,这些转换遵循目标机器的编程语言、指令集和操作系统。
指令集有很多种,但一般分为两种,一种是简化指令集,一种是复杂指令集。具体描述如下
常见的精简指令集处理器包括ARM、AVR、MIPS、PARISC、RISC-V和SPARC.
所以你可以理解
这本书是关于什么的?
基于MIPS架构,逐一介绍了冯诺依曼系统五个组成部分的硬件实现和软件设计。更重要的是,它引入了很多并行计算的内容,这些内容在大多数教材中被忽略或很少。按照这个思路,它将把并行相关内容整合到新书中,结合OpenMP、CUDA和Hadoop/Spark。毕竟这是未来的发展趋势。
还有这本书。
这本书是关于什么的?
这本书讲的是RISC-V指令集,因为不同的指令集也区分三个版本,三个版本?嗯,还有下面这个。
这本书是关于ARM指令集的。
所以在阅读CASPP的时候,同时阅读这本书是一个非常好的选择。
精简指令集通常具有以下特征
统一指令代码通用寄存器,一般区分整数和浮点数的简单寻址方式,复杂的寻址方式用简单的指令序列代替,比如支持字节串类型的RISC。
复杂指令集包括System/360、VAX、x86等.
复杂指令集可以说是在简化指令集上做的改变。
复杂指令集的特点是指令数量众多且复杂,每条指令的字长不等,计算机必须对其进行解释,并为此付出性能代价。
一般来说,提高CPU性能的方法有以下几种。
增加寄存器大小提高内部并行性,增加缓存大小,增加内核时钟速度,增加其他功能,比如IO和定时器,增加向量处理器硬件多线程技术比较抽象,后面我们会组织一篇文章详细介绍。
c编译器会接收其他操作,转换成汇编语言输出,汇编语言输出是机器级的代码表示。前面我们提到过,C语言程序的执行过程分为以下几个步骤。
以下讨论基于汇编代码。
我们每天接触到的高级语言都是层层封装的结果,所以我们一般不会接触汇编语言,更不会用汇编语言编程,就像你不知道操作系统的存在一样,但其实你做的每一个操作,哪怕是双击一个图标,都和操作系统有关。
高级语言的抽象程度很高,但是经过层层抽象,高级语言的执行效率肯定没有汇编语言高,也没有汇编语言可靠。
但是高级语言有一个更大的优势,就是编译后可以在不同的机器上运行,汇编语言对不同的指令集有不同的表示。而且高级语言学习更容易理解,降低了计算机门槛,使内卷化更严重(当然这是个玩笑,请不要当真)。
话不多说,要懂底层必须懂汇编语言。否则,同步的底层实现会让您头疼。而且天天飘也不好,迟早要落地的。
了解汇编代码也有助于我们优化程序代码,分析代码中隐藏的低效,而这种优化方法一旦成功,将是一个数量级的提升,而不是改变如果.否则就使用新功能。
首先,定义机器级程序的格式和行为被称为指令集架构(instructionsetarchitecture)或指令集架构(ISA)。ISA定义了进程状态、指令格式以及每个指令对状态的影响。大多数指令集体系结构,包括ISA,都用来描述一个进程的行为,就好像它是顺序执行的,并且一条指令的执行结束。
后,另外一条指令再开始。处理器硬件的描述要更复杂,它可以同时并行执行许多指令,但是它采用了安全措施来确保整体行为与ISA规定的顺序一致。第二点,机器级别对内存地址的描述就是虚拟地址(virtualaddress),它提供了一个内存模型来表示一个巨大的字节数组。
编译器在整个编译的过程中起到了至关重要的作用,把C语言转换为处理器执行的基本指令。汇编代码非常接近于机器代码,只不过与二进制机器代码相比,汇编代码的可读性更强,所以理解汇编是理解机器工作的第一步。
一些进程状态对机器可见,但是C语言程序员却看不到这些,包括
程序计数器(Programcounter),它存储下一条指令的地址,在x86-64架构中用%rip来表示。程序执行时,PC的初始值为程序第一条指令的地址,在顺序执行程序时,CPU首先按程序计数器所指出的指令地址从内存中取出一条指令,然后分析和执行该指令,同时将PC的值加1并指向下一条要执行的指令。
比如下面一个例子。
这是一段数值进行相加的操作,程序启动,在经过编译解析后会由操作系统把硬盘中的程序复制到内存中,示例中的程序是将123和456执行相加操作,并将结果输出到显示器上。由于使用机器语言难以描述,所以这是经过翻译后的结果,实际上每个指令和数据都可能分布在不同的地址上,但为了方便说明,把组成一条指令的内存和数据放在了一个内存地址上。
整数寄存器文件(registerfile)包含16个命名的位置,用来存储64位的值。这些寄存器可以存储地址和整型数据。有些寄存器用于跟踪程序状态,而另一些寄存器用于保存临时数据,例如过程的参数和局部变量,以及函数要返回的值。这个文件是和磁盘文件无关的,它只是CPU内部的一块高速存储单元。有专用的寄存器,也有通用的寄存器用来存储操作数。条件码寄存器用来保存有关最近执行的算术或逻辑指令的状态信息。这些用于实现控件或数据流中的条件更改,例如实现if和while语句所需的条件更改。我们都学过高级语言,高级语言中的条件控制流程主要分为三种:顺序执行、条件分支、循环判断三种,顺序执行是按照地址的内容顺序的执行指令。条件分支是根据条件执行任意地址的指令。循环是重复执行同一地址的指令。顺序执行的情况比较简单,每执行一条指令程序计数器的值就是+1。条件和循环分支会使程序计数器的值指向任意的地址,这样一来,程序便可以返回到上一个地址来重复执行同一个指令,或者跳转到任意指令。下面以条件分支为例来说明程序的执行过程(循环也很相似)
程序的开始过程和顺序流程是一样的,CPU从0100处开始执行命令,在0100和0101都是顺序执行,PC的值顺序+1,执行到0102地址的指令时,判断0106寄存器的数值大于0,跳转(jump)到0104地址的指令,将数值输出到显示器中,然后结束程序,0103的指令被跳过了,这就和我们程序中的if()判断是一样的,在不满足条件的情况下,指令会直接跳过。所以PC的执行过程也就没有直接+1,而是下一条指令的地址。
一组向量寄存器用来存储一个或者多个整数或者浮点数值,向量寄存器是对一维数据上进行操作。机器指令只会执行非常简单的操作,例如将存放在寄存器的两个数进行相加,把数据从内存转移到寄存器中或者是条件分支转移到新的指令地址。编译器必须生成此类指令的序列,以实现程序构造,例如算术表达式求值,循环或过程调用和返回
我相信各位应该都知道汇编语言的出现背景吧,那就是二进制表示数据,太复杂太庞大了,为了解决这个问题,出现了汇编语言,汇编语言和机器指令的区别就在于表示方法上,汇编使用操作数来表示,机器指令使用二进制来表示,我之前多次提到机器码就是汇编,你也不能说我错,但是不准确。
但是汇编适合二进制代码存在转换关系的。
汇编代码需要经过汇编器编译后才产生二进制代码,这个二进制代码就是目标代码,然后由链接器将其连接起来运行。
汇编语言主要分为以下三类
汇编指令:它是一种机器码的助记符,它有对应的机器码伪指令:没有对应的机器码,由编译器执行,计算机并不执行其他符号,比如+、-、*、/等,由编译器识别,没有对应的机器码汇编语言的核心是汇编指令,而我们对汇编的探讨也是基于汇编指令展开的。
CPU是计算机的大脑,它也是整个计算机的核心,它也是执行汇编语言的硬件,CPU的内部包含有寄存器,而寄存器是用于存储指令和数据的,汇编语言的本质也就是CPU内部操作数所执行的一系列计算。
没有内存,计算机就像是一个没有记忆的人类,只会永无休止的重复性劳动。CPU所需的指令和数据都由内存来提供,CPU指令经由内存提供,经过一系列计算后再输出到内存。
磁盘也是一种存储设备,它和内存的最大区别在于永久存储,程序需要在内存装载后才能运行,而提供给内存的程序都是由磁盘存储的。
一般来说,内存内部会划分多个存储单元,存储单元用来存储指令和数据,就像是房子一样,存储单元就是房子的门牌号。而CPU与内存之间的交互是通过地址总线来进行的,总线从逻辑上分为三种
地址线数据线控制线CPU与存储器之间的读写主要经过以下几步
下面我们就来具体了解一下这三类总线
通过我们上面的探讨,我们知道CPU通过地址总线来指定存储位置的,地址总线上能传送多少不同的信息,CPU就可以对多少个存储单元进行寻址。
上图中CPU和内存中间信息交换通过了10条地址总线,每一条线能够传递的数据都是0或1,所以上图一次CPU和内存传递的数据是2的十次方。
所以,如果CPU有N条地址总线,那么可以说这个地址总线的宽度是N。这样CPU可以寻找2的N次方个内存单元。
CPU与内存或其他部件之间的数据传送是由数据总线来完成的。数据总线的宽度决定了CPU和外界的数据传输速度。8根数据总线可以一次传送一个8位二进制数据(即一个字节)。16根数据总线一次可以传输两个字节,32根数据总线可以一次传输四个字节。。。。。。
CPU与其他部件之间的控制是通过控制总线来完成的。有多少根控制总线,就意味着CPU提供了对外部器件的多少种控制。所以,控制总线的宽度决定了CPU对外部部件的控制能力。
内存结构
内存IC是一个完整的结构,它内部也有电源、地址信号、数据信号、控制信号和用于寻址的IC引脚来进行数据的读写。下面是一个虚拟的IC引脚示意图
图中VCC和GND表示电源,A0-A9是地址信号的引脚,D0-D7表示的是控制信号、RD和WR都是好控制信号,我用不同的颜色进行了区分,将电源连接到VCC和GND后,就可以对其他引脚传递0和1的信号,大多数情况下,+5V表示1,0V表示0。
我们都知道内存是用来存储数据,那么这个内存IC中能存储多少数据呢?D0-D7表示的是数据信号,也就是说,一次可以输入输出8bit=1byte的数据。A0-A9是地址信号共十个,表示可以指定0000000000-1111111111共2的10次方=1024个地址。每个地址都会存放1byte的数据,因此我们可以得出内存IC的容量就是1KB。
如果我们使用的是512MB的内存,这就相当于是512000(512*1000)个内存IC。当然,一台计算机不太可能有这么多个内存IC,然而,通常情况下,一个内存IC会有更多的引脚,也就能存储更多数据。
内存读取过程
下面是一次内存的读取过程。
来详细描述一下这个过程,假设我们要向内存IC中写入1byte的数据的话,它的过程是这样的:
首先给VCC接通+5V的电源,给GND接通0V的电源,使用A0-A9来指定数据的存储场所,然后再把数据的值输入给D0-D7的数据信号,并把WR(write)的值置为1,执行完这些操作后,即可以向内存IC写入数据读出数据时,只需要通过A0-A9的地址信号指定数据的存储场所,然后再将RD的值置为1即可。图中的RD和WR又被称为控制信号。其中当WR和RD都为0时,无法进行写入和读取操作。此篇文章我们主要探讨了指令集、指令集的分类,与汇编有关的硬件,总线都有哪些,分别的作用都是什么,然后我们以一次内存读取过程来连接一下CPU和内存的交互过程。
原创不易,如有帮助还请各位读者四连(点在、在看、分享、留言),感谢各位大佬
关注公众号程序员cxuan回复cxuan领取优质资料。
我自己写了六本PDF,非常硬核,链接如下
我自己写了六本PDF,非常硬核,链接如下
我自己写了六本PDF,非常硬核,链接如下
下一篇:长安汽车轿车换什么机油好