如果你有内存测试和内存地址Decode这方面的需求,可以私信我,我们一起进步!
内存单元的物理地址是由其所处的地址总线上的位置决定的,机器安装完成后,其物理地址是固定的、不变的,并不是由CPU分配的。
cpu只需要告诉控制器它要存取的内存单元地址;要找到这个地址单元则交给成组的地址译码器(如74LS138)实现。
物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输的内存地址都是物理内存地址,编号从0开始一直到可用物理内存的最高端。这些数字被北桥(Nortbridge chip)映射到实际的内存条上。物理地址是明确的、最终用在总线上的编号,不必转换,不必分页,也没有特权级检查(no translation, no paging, no privilege checks)。
逻辑地址:CPU所生成的地址。逻辑地址是内部和编程使用的、并不唯一。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址(偏移地址),不和绝对物理地址相干。
这里有一个可能会和你的认识冲突的事实:我们总是认为存储空间只是指内存(RAM),就是程序一直在读写的那个东西,实际上大部分处理器的读写请求也确实是被北桥转发给了内存模块,但并不是所有的。物理存储地址空间同时也被用来和一些主板上的其他设备通信(这种通信被称为memory-mapped I/O),比如显卡和大部分的PCI设备(扫描仪、SCSI设备之类的),还有存储有BIOS的闪存。
当北桥接收到一个物理地址请求,北桥会决定这个请求该转向哪里:内存?还是显卡?北桥根据存储地址映射表来决定。对物理存储地址的每一个区域,存储地址映射表都知道究竟是哪一个设备拥有这些地址。大部分的地址都映射到内存中,但当地址不属于内存时,存储地址映射表会告诉芯片组哪个设备该响应这些地址的请求。这种将地址分配到其他设备的映射导致了在老式PC存储中640KB到1MB之间的空洞,而保留给显卡和PCI设备的地址又造城了一个更大的空洞,这也是为什么32位操作系统不能完全使用4GB内存的原因。在Linux中/proc/iomem文件清楚的列出了这些被映射的地址。下图展示了Intel PC的前4GB地址空间中典型的映射关系:
实际的地址和范围取决于电脑中使用的主板和设备,不过大部分的Core 2系统和上图中展示的非常相似。所有棕色的区域都不属于内存,这里要明确一点,这里所说的地址是在主板总线中实际的物理地址,在CPU内部(例如程序中的运行、读写地址)使用的地址都是逻辑地址,并且在实际访问之前都必须被CPU转换成物理地址。
地址译码器:就是把输入的二进制数地址,指向相应的物理空间。这实际上就是一个转换或者翻译的过程。
地址译码器是在内存内部的,内存除了存储单元外,还包括:读写电路、地址译码器。
地址译码器,就是cpu通过地址总线给内存一个地址说:我要读这个地址,或者写这个地址了。内存中的地址译码器负责找到这个地址,然后通过读写电路进行读写。
存储器地址译码有两种方式,通常称为单译码与双译码。 (1) .单译码 单译码方式又称字结构,适用于小容量存储器。 (2) .双译码 在双译码结构中,将地址译码器分成两部分,即行译码器 ( 又叫 X 译码器 ) 和列译码器 ( 又叫 Y 译码器 ) 。 X 译码器输出行地址选择信号, Y 译码器输出列地址选择信号。行列选择线交叉处即为所选中的内存单元,这种方式的特点是译码输出线较少。
为了读取特定单元格的数据,在寻址时要首先确定是哪一个bank,然后在这个选定的bank中进行行列的寻址。在实际工作中,bank的地址与相应的行地址是同时发出的,此时这个命令称之为"行有效"或者“行激活”。在此之后,发送列地址寻址命令和具体的操作命令(读或写),这两个命令也是同时发送的。行列地址是可以复用的,一般来说DDR芯片的地址线为A0~A15,低地址线会被行列复用。以K4B4G1646B 4Gbit 256MB x 16bit内存芯片为例,A0~A14用做行地址,A0~A9用做列地址,这款芯片同时含有B0~B2用来选择bank。
在实际工作中,Bank地址与相应的行地址是同时发出的,此时这个命令称之为“行激活”(Row Active)。在此之后,将发送列地址寻址命令与具体的操作命令(是读还是写),这两个命令也是同时发出的,所以一般都会以“读/写命令”来表示列寻址。根据相关的标准,从行有效到读/写命令发出之间的间隔被定义为tRCD,即RAS to CAS Delay(RAS至CAS延迟,RAS就是行地址选通脉冲,CAS就是列地址选通脉冲),我们可以理解为行选通周期。
下面来看一个具体例子。
该例子中,用两个16bit的DDR3内存拼成了一个32bit的DDR3.
每块16bit DDR3的大小为512M Bytes.
看看硬件上连接:
第一片16bit DDR3的BA0, BA1, BA2连接到了CPU的BA0, BA1, BA2。
第二片16bit DDR3的BA0, BA1, BA2也连接到了CPU的BA0, BA1, BA2。
第一片16bit DDR3的A0~A14连接到了CPU的A0~A14。
第二片16bit DDR3的A0~A14连接到了CPU的A0~A14。
第一片16bit DDR3的D0~D15连接到了CPU的D0~D15。
第二片16bit DDR3的D0~D15连接到了CPU的D16~D31。
分析下该实例。
bank address有三个bit,所以单个16bit DDR3内部有8个bank.
表示行的有A0~A14,共15个bit,说明一个bank中有2^15个行。
表示列的有A0~A9,共10个bit,说明一个bank中有2^10个列。
来看看单块16bit DDR3容量:
2^3*2^15*2^10=2^28=256M
我们的内存是512M,到这儿怎么变成256M了?被骗了?
呵呵,当然没有。
忘了我们前面一直提到的16bit。
16bit是2个byte对吧。
访问一个地址,内存认为是访问16bit的数据,也就是两个字节的数据。
256M个地址,也就是对应512M的数据了。
每一块16bit DDR3中有8个bank,2^15个row,2^10个column。也就是有256M个地址。
看前面的连线可知,两块16bit DDR3的BA0~BA2和D0~D14其实是并行连接到CPU。
也就是说,CPU其实认为只有一块内存,访问的时候按照BA0~BA2和D0~D14给出地址。
两块16bit DDR3都收到了该地址。
它们是怎么响应的呢?
两块内存都是16bit,它们收到地址之后,给出的反应是要么将给定地址上2个字节送到数据线上,要么是将数据线上的两个字节写入到指定的地址。
再看数据线的连接,第一片的D0~D15连接到了CPU的D0~D15,第二片的D0~D15连接到了CPU的D16~D31。
CPU认为自己访问的是一块32bit的内存,所以CPU每给出一个地址,将访问4个字节的数据,读取/写入。
这4字节数据对应到CPU的D0~D31,又分别被连接到两片内存的D0~D15,这样一个32bit就被拆成了两个16bit.
反过来,也就是两个16bit组成了一个32bit.
CPU访问的内存地址有256M个,每访问一个地址,将访问4个字节,这样CPU能访问的内存即为1G.
参考文章:
https://www.cnblogs.com/felixfang/p/3420462.html
https://blog.csdn.net/qq_35623393/article/details/80277496
https://www.jianshu.com/p/5d3196f64a29
https://blog.csdn.net/joqian/article/details/17676485
http://blog.sina.com.cn/s/blog_730a3f0f0101kozi.html
http://www.doc88.com/p-7972044584992.html
https://blog.csdn.net/davion_zhang/article/details/50604934