906-直接存储器访问方式
# 906-直接存储器访问方式
我们还是来说快递的事。 有一天,你在这坐着运算,突然来电话了, 然后你接了一听,啊, 又有快递啦,啊什么?一千本书, 现在就得去拿,哎呀,好好好。 这个怎么办呢?这个,这搬一千本书又得浪费很多时间, 呃,好办,啊那我们就叫一个搬家公司, 跟他们说好,我们要从哪搬到哪谈好价钱,他们就去搬, 并且告诉他们搬完之后呐给我来一个电话,然后我去检查,这就可以了。 那么,虽然要多花一些钱,但是如果能够运算更重要的任务, 那还是值得的。这就是我们要说的 DMA 方式。
现在的计算机中有很多复杂的外设比如像显示器,网络,硬盘, 这些外设需要传输的数据量很大,而且对传输的速率也有很高的要求, 如果这些数据都要靠 CPU 一个一个来搬运的话,那恐怕就难以应对了,所以这就需要用到 DMA 这种 IO 控制方式。
DMA 就是直接存储器访问的简称。 那如果采用 DMA 方式进行 I/O 数据的传送在传送的过程中是不需要 CPU 干预的,这个数据传送的工作是由一个专门的硬件电路控制,可以直接将外设的数据传到存储器或者将存储器中的数据传到外设, 而这个专门的硬件控制电路就称为 DMA 控制器,简称为 DMAC, 其实 DMA 控制器本身也是一个 I/O 口, 和其他 I/O 接口类似,它早期也是采用独立芯片的形式, 而现在通常是寄存在其他多功能的芯片当中。
那我们来看 DMA 控制器的基本工作步骤。 这是一个简化的系统,里面有一个 CPU,一个存储器, 一个 I/O 接口,还有一个 DMA 控制器,它们通过系统总线连接在一起, 这里还(给部件)增加了 m 和 s 这两种标记,m 是 master 的缩写, 表示这个部件可以在系统总线上主动发起传输, 比如 CPU 就是这样的部件,它可以在系统总线上主动发起读写的传输。 而 s 是 slave 的缩写,它表示这个部件只能被动地接受来自系统总线的传输。 那存储器就是一个典型的只有 slave 接口的设备。 一般的 I/O 接口也是这样,只会接受来自 CPU 的访问, 而 DMA 控制器则是既有 master 接口又有 slave 接口。
那我们就要用这个 DMA 控制器进行一次外设到内存的传送, 我们可以把这个 I/O 接口看成是网卡,外面接着网线, 现在我们需要用 DMA 的方式接收一个网络包,并保存到存储器的某个区域, 那要完成这个操作,CPU 首先需要设置 DMA 内部的配置寄存器,那对于 x86CPU,我们就要用 out 指令续写 DMA 控制器当中的一些 I/O 端口,以配置好它的工作模式, 然后这个 DMA 控制器就处于空闲等待状态,而 CPU 也可以去执行其他的程序了。
那当外设送来数据到 I/O 接口的时候, I/O 接口就会像 DMA 控制器发出 DMA 传送的申请, 这个申请需要通过一根额外的连线发出, 那 DMA 控制器收到 I/O 接口的申请之后,还会通过另一个连线响应这个申请, 然后 DMA 控制器就会通过它的 master 接口发起总线读传输, 而这个读传输的地址就是这个 I/O 接口当中的数据输入缓冲寄存器。 那这样数据就会从 I/O 接口被读到了 DMA 控置器当中,然后 DMA 控制器会向存储器发起总线的写传输,将刚才读回的这个数据写到存储器的某个区域。
我们注意在有 DMA 控制器之前, 这个系统当中只有 CPU 可以发起总线传输, 而现在 DMA 控制器可以主动发起总线传输了。 那接下来 DMA 控制器会重复五和六这两个动作, 不断地从 I/O 接口中读出数据再写到存储器当中去, 那如果这时网络传输一直到收完一个网络包, 就次 DMA 传送才算完成,然后 DMA 控制器会返回到第二步,等待 I/O 发起下一次 DMA 传送的申请。
那一次 DMA 传送的数据可能很多, 所花的时间也很长,但是在这段时间 CPU 一直可以在执行其他的程序, 这样就和数据传送的工作并行起来,可以获得很好的系统性能。 但是 CPU 怎么知道 DMA 传送已经完成了呢?那通常情况下 DMA 传送完成后,DMA 控制器会发出一个中断请求信号,通过中断控制器通知 CPU, 那这个 DMA 控制器发出的中断,也是一个外部中断,后面的处理过程就和其他 I/O 接口发出的中断是一样的, 只不过它对应的中断服务程序是让 CPU 来对这一次的 DMA 传输进行处理。
所以从这个步骤我们可以看出 DMA 方式也不是完全不用 CPU 来干预,在 DMA 启动的时候 CPU 来进行配置 而传送完成后 CPU 还需要来进行处理。 那后续的处理根据任务的需要各有不同,而初始化的配置却大体是一样的。
在 DMA 传送开始前 CPU 要设置 DMA 控制器内部的寄存器, 一般至少要设置这么几项,既然等一会儿 DMA 控制器要进行数据的传送, 那就需要先设置好从哪里开始传,这也就是源地址的初始值。 还需要设置在传送的过程中这个源地址是递增还是递减,然后还需要 设置这些数据传输到哪里,也就是目的地址的初始值以及传送时的地址增减方式。 最后还要设置需要传送多少数据。
那么我们还是以刚才提到的外设到内存的传送为例。 那 CPU 在初始化配置时,会将某个源地址设为 I/O 端口, 比如就是一个网络控制器的数据输入寄存器端口, 而且传送时这个源地址是不变的。 因为每一次 DMA 控制器都是从同一个 I/O 端口读出数据,
而目的地址要设置为存储器的某个地址, 而且传送时是递增的,这样 DMA 控制器每次从 I/O 接口当中读出一个数就把这个数写到存储器当中去, 下一次再读出一个数再写到存储器当中时地址就应该递增, 这样才不会覆盖刚才传过来的这个数。
第三要设置待传送数据的长度,那如果是从外设接收数据, CPU 在配置时可能不知道究竟这个数据有多长, 那就可以不设置这个参数。
最后根据 I/O 接口的控制信号来判断是否传输完成。
那如果是从存储器发送一组数据到 I/O 接口, 这个时候 CPU 在初始化时就是知道究竟要发送多长的数据。 那就需要设置这个待传送数据的长度的这个参数。
那需要强调的是, 这些参数都是 DMA 控制器内部的寄存器,一般各自都有一个 I/O 端口的地址, 那么编程时通过 out 指令让 CPU 去写这些 I/O 端口,从而配置好了源地址,目的地址和待传送数据的长度等信息,DMA 控制器在运行的过程中就不需要再靠 CPU 执行程序来控制,而是直接查看内部的源地址寄存器,就把对应的地址发到系统总线上, 就从 I/O 接口读回了相应的数据,然后再查看自己的目的地址寄存器, 把这个地址和刚才读回来的数据一起发到系统总线上,这样就写入到了存储器当中去。 而每读写一次, 就在内部累计已经传送的数据的长度,并和这个待传送数据的长度的寄存器的内容进行比较, 如果相等则意味着传输已经完成,如果还不等则继续传输。 所以 CPU 在一次配置完之后,后续的工作都由 DMA 控制器的内部硬件自动完成, 不再需要 CPU 的干预了。这就是所谓直接存储器访问的含义。
# 独立的 DMA 控制器
那在最早的个人计算机当中是没有 DMA 控制器的, 那后来为了提高输入输出的效率,就增加了独立的 DMA 控制器的芯片。例如刚才提到的 8237, 那通过 CPU 设置 DMA 控制器当中的不同的地址就可以为不同的 I/O 接口提供 DMA 的服务。
但是随着计算机的发展有一些 I/O 接口的速度越来越快, 对 DMA 传输的要求也越来越高。 那多个 I/O 接口共享一个独立的 DMA 控制器的方式可能就没有办法满足部分 I/O 接口的需求了。
这时就出现了自带 DMA 控制器的 I/O 接口, 那这样的 I/O 接口内部带有一个专属的 DMA 控制器,只为这个 I/O 接口提供服务,那这个 I/O 接口现在也有了 master 的总线接口。 那在显卡、网卡、硬盘控制器这些对传送率要求很高的 I/O 接口中一般都会自带 DMA 控制器, 那在系统初始化时,CPU 要配置好各个 DMA 控制器, 然后外设有传输需求时这些 DMA 控制器就可以自动地开始工作了。
那如果我们把这个独立的 DMA 控制器比作一个搬家公司, CPU 就请这个搬家公司来完成 I/O 接口和存储器之间的数据搬运工作。 而有些部门的搬运工作量非常大, 实际上需要一个搬家公司全时地为他们服务才能够满足需求。 于是他就在部门内部自己组建了一个搬运队。 那这样一旦有数据传送的需求就可以马上开始工作,而不需要去申请外部的这个 DMA 控制器了,传输的效率自然会大大提升。
而且不同的 I/O 接口有不同的传输的特点,比如显示、网络、硬盘传输的行为肯定有不同的特征,而内线的 DMA 控制器就可以根据 I/O 接口的特点进行定制,从而更加高效地完成传输。
那在现代的计算系统当中, 大部分对数据传输率有比较高要求的设备都会自带 DMA 控制器, 而其他对数据传输率要求比较低的设备则可以共享系统中独立的 DMA 控制器。 另外这个独立的 DMA 控制器一般还会提供从内存到内存传送的服务。 那当我们编程时需要将内存中的一大块数据复制到内存的另一个区域的时候, 虽然不涉及输入输出,但是也可以享受到 DMA 带来的好处。 那当然也不是所有的输入输出设备都需要使用 DMA 的方式。 毕竟增加一个 DMA 控制器需要增加制造的成本, 而且 CPU 来配置 DMA 控制器以及进行后续的处理还是要靠执行程序来完成的,也都需要花时间。 如果要传输的数据量很小,性能反而会变差了。
那现在用 DMA 方式的这些设备不见得是这些工作 CPU 不愿意干,有可能是根本干不了。 比如说我们快递要送来的不是一千本书而是一万本书,而且非得一个小时内办完, 那你能干得了吗?非得叫搬家公司不可了,对不对? 但是不是说所有的事情都用 DMA 方式都能好好的解决的。 比如送来的不是一千本一万本书,而就是一本书, 那你也去叫一个搬家公司把这本书给你运来?那样就得不偿失了。 而且有时候你可能送来的根本不是书, 而是你的午饭,对吧,订了一份盒饭,难道你也叫一个搬家公司来给你收这个盒饭?那他们可能过了两个小时才来, 然后用他们规范的方法把你这顿饭给打包装箱送到他们的大货车, 然后运到你的楼下,再拆包,再给你送上来, 能赶上吃晚饭就不错了。