1vonzhang
2023-04-18 18:58:36 +08:00
很开心在 V2 看到这种讨论具体技术、理论的帖子顶上热门,这是我理想中 V2 的样子之一。
看了你最新的回复,区分字和字节的概念是正确的,整体的理解还是有些抽象。
我尝试举个例子。
假设我有一大片空地(整个内存),上面建了一排紧挨着彼此、大小一样的仓库(内存单元),一共 256 个仓库从 0 (0x00) 到 255 (0xFF) 连续编号(内存地址)。
如果我想让你去找到其中一间仓库,我需要给你一个 0 到 255 之间的门牌号。换成二进制就是 0000 0000 到 1111 1111 ,也就是说 [8 个二进制位就可以涵盖所有仓库] 。如果我只能把门牌号用 1 和 0 写在纸上(地址总线),而纸上只写的开 4 个二进制位,那我最多也只能写到 1111 (15),也就是说我没有办法指示你去 16~255 这些仓库;反过来,如果纸上最多能写上 16 个二进制位,因为我们最后一个仓库的门牌号是 255 (0000 0000 1111 1111),所以前八位永远是 0 ,永远用不到。
这就是你在某层楼回复说的 [地址总线的条数决定寻址空间大小] 。每条线上可以是 1 也可以是 0 ,一条地址线就是一个二进制位。地址总线越宽(位数越多),能写开的门牌号就越多,能找到的仓库就越多。
下面我们来区分“字节”和“字”。“字” 的概念但看内存没有意义,它主要来自于 [CPU 一次性处理的数据的大小(位宽)] 。
假设我们有一个工厂( CPU ),投入**一份原料**或者两份(运算数),同时说明要做的操作(运算类型),就可以生产出相应的产品(运算结果)。有的工厂比较大 (64 bit CPU),一份原料需要 8 个仓库装,也有的比较小 (8 bit CPU),一份原料一间仓库就够。我们这里规定,在这个例子里,**一份原料**需要 4 个仓库才能放得下( 1 word == 4 bytes)。我们就约定,把每份原料存在相邻的四个仓库里,比如仓库 0~3 存放一份,4~7 存放一份。
我们建仓库是因为有工厂,工厂是我们的核心,所以一切都以工厂运作的最小单位——一份原料的大小来定。这个就是“字” (word)。而“字节” (byte) 只是一间仓库的大小,永远是 8 位,和什么样的工厂没有关系。
工厂有两个进货口,有些产品需要一种原材料 ( e.g. 一斤生鸡肉,在工厂 “加热” 的操作下,生产出一斤熟鸡肉),有些产品需要两种( e.g. 一斤生鸡肉+一斤油,在工厂“加热”的操作下,生产出一斤炸鸡)。这里注意,工厂的产品有可能还要当作新的原料加工别的产品,要运回仓库储存,所以一份产品的大小也是 4 间仓库。
为了能*一次性*投入一整份材料(而不是 1/4 份、半份...),我们需要找到合适的卡车,一次性能装下一份原料、即四个仓库的卡车。用来运输原料(数据)的卡车就是**数据总线**。如果工厂投料生产的单位是 4 间仓库( 1 word == 4 bytes == 32 bits) 那么卡车的大小就是 4 间仓库 (数据总线是 32 位)。
下面我们来解释一下你问题补充里说的“每次取出一个字的数据送到数据总线传给 CPU ”。特别是这个“每次”。
这里需要一个背景知识。如果你没有学过数字电路,可以简单记住:电路的工作不是连续的,而是一下一下的,每一下都可以做一个最基本的动作。像一个“滴答滴答”走的时钟秒表。这个表走的越快(时钟频率越高),一定时间内能做的动作就越多。
你的理解抽象的地方,在于这个“每次”。因为对于内存那边和 CPU 那边,“每次”的概念可能是不同的( CPU 操作和内存内部的操作用不同频率的时钟)。在仓库那边有一个仓库管理员,时钟每滴答一次,他就把当前门牌号对应的仓库装到卡车上,并把门牌号+1 。一次操作的基本单位是一个仓库(一个字节)。4 个滴答之后,卡车才能装满。而在工厂那边,有另一个时钟,每滴答一次,工厂就把进货口的两卡车原料加工成产品。一次操作的基本单位是一个卡车( 4 个字节)。
当然了,如果一份材料就是一个仓库的大小,那么就不需要仓库管理员来管理“卡车到底装没装满”,因为卡车只能装一间仓库,装了就是装满,没装就是空的。那么这时候内存和 CPU 的时钟(或者“一次”)就是同样的速度、甚至可以用同一个钟。如果你不关心仓库里面具体发生了什么,只是从工厂的角度看,那么可以认为,工厂每运作一次,就有一卡车新的原料从仓库里出来,他们的“一次“也是一样的。
59 楼说的很好,他说的 “CPU 在访问内存时,一次可以访问多个字节,这就是字长的概念”,其实就是从内存外部,从 CPU 的角度看的,也确实是你在弄清楚具体内部细节之后,应该保持的角度。只是这种从外部看的角度不足以解释你对”8 位的储存怎么*一下子*取出 32 位甚至 64 位的数据“的疑问。
这里我们只讨论了数据内存,其实指令内存也是类似的,不管是冯诺依曼架构(放指令的和放数据的是两套不同的仓库)还是哈佛架构(同一片仓库,规定某些仓库用来放指令,某些仓库用来放数据)。题主读到取指令的时候,特别是有的指令很长、需要存放在两个连续的单元、读两次之后再执行指令,应该就能够更好的理解储存单元大小(字节)和运算单元大小(字)之间的差异了。
这个例子有很多不严谨的地方,因为主要目的是提供一个符合直觉的、具象的理解。题主学习计组主要目的也是从概念层面上理解计算机的组成,而不是现实生活中计算机具体是怎么造的。
例如:
- 字节永远是 8 位只是针对绝大多数通用计算机来说。
- 64 位 CPU 的计算机并没有 64 位地址线,因为没有那么大的内存,高位的地址线永远是 0 。
- CPU 和 ALU 在这个例子里当作了同一个东西处理,但其实数据加载到 CPU 的寄存器内,和 ALU 读取寄存器数据进行运算,是不同的事情。
- 内存和 CPU 速度不一样并不需要两个时钟,只要 CPU 每 4 个时钟周期才运算一次,就可以达到例子里的同步。现实生活中根据指令的不同,CPU 每几个时钟周期运算一次并不是固定的。
- ……