1.dma概述
dma是外设与主存之间的一种数据传输机制。一般来说,外设与主存之间存在两种数据传输方法:(1)pragrammed i/o(pio)方法,也即由cpu通过内存读写指令或i/o指令来持续地读写外设的内存单元(8位、16位或32位),直到整个数据传输过程完成。 (2)dma,即由dma控制器(dma controller,简称dmac)来完成整个数据传输过程。在此期间,cpu可以并发地执行其他任务,当dma结束后,dmac通过中断通知cpu数 据传输已经结束,然后由cpu执行相应的isr进行后处理。
dma技术产生时正是isa总线在pc中流行的时侯。因此,isa卡的dma数据传输是通过isa总线控制芯片组中的两个级联8237 dmac来实现的。这种dma机制也称为“标准dma”(standard dma)。标准dma有时也称为“第三方dma”(third-party dma),这是因为:系统dmac完成实际的传输过程,所以它相对于传输过程的“前两方”(传输的发送者和接收者)来说是 “第三方”。
标准dma技术主要有两个缺点:(1)8237 dmac的数据传输速度太慢,不能与更高速的总线(如pci)配合使用。(2)两个8237 dmac一起只提供了8个dma通道,这也成为了限制系统i/o吞吐率提升的瓶颈。
鉴于上述两个原因,pci总线体系结构设计一种成为“第一方dma”(first-party dma)的dma机制,也称为“bus mastering”(总线主控)。在这种情况下,进行传输的pci卡必须取得系统总线的主控权后才能进行数据传输。实际的传输也不借助慢速 的isa dmac来进行,而是由内嵌在pci卡中的dma电路(比传统的isa dmac要快)来完成。bus mastering方式的dma可以让pci外设得到它们想要的传输带宽,因此它比标准dma功能满足现代高性能外设的要求。
随着计算机外设技术的不断发展,现代能提供更快传输速率的ultra dma(udma)也已经被广泛使用了。本为随后的篇幅只讨论isa总线的标准dma技术在linux中的实现。记住:isa卡几乎不使用bus mastering模式的dma;而pci卡只使用bus mastering模式的dma,它从不使用标准dma。
2.intel 8237 dmac
最初的ibm pc/xt中只有一个8237 dmac,它提供了4个8位的dma通道(dma channel 0-3)。从ibm at开始,又增加了一个8237 dmac(提供4个16位的dma通道,dma channel 4-7)。两个8237 dmac一起为系统提供8个dma通道。与中断控制器8259的级联方式相反,第一个dmac被级联到第二个dmac上,通道4被用于dmac级联,因此 它对外设来说是不可用的。第一个dmac也称为“slave damc”,第二个dmac也称为“master dmac”。
下面我们来详细叙述一下intel 8237这个dmac的结构。
每个8237 dmac都提供4个dma通道,每个dma通道都有各自的寄存器,而8237本身也有一组控制寄存器,用以控制它所提供的所有dma通道。
2.1 dma通道的寄存器
8237 dmac中的每个dma通道都有5个寄存器,分别是:当前地址寄存器、当前计数寄存器、地址寄存器(也称为偏移寄存器)、计数寄存器和页寄存器。其中,前两个是8237的内部寄存器,对外部是不可见的。
(1)当前地址寄存器(current address register):每个dma通道都有一个16位的当前地址寄存器,表示一个dma传输事务(transfer transaction)期间当前dma传输操作的dma物理内存地址。在每个dma传输开始前,8237都会自动地用该通道的address register中的值来初始化这个寄存器;在传输事务期间的每次dma传输操作之后该寄存器的值都会被自动地增加或减小。
(2)当前计数寄存器(current count register):每个每个dma通道都有一个16位的当前计数寄存器,表示当前dma传输事务还剩下多少未传输的数据。在每个dma传输事务开始之 前,8237都会自动地用该通道的count register中的值来初始化这个寄存器。在传输事务期间的每次dma传输操作之后该寄存器的值都会被自动地增加或减小(步长为1)。
(3)地址寄存器(address register)或偏移寄存器(offset register):每个dma通道都有一个16位的地址寄存器,表示系统ram中的dma缓冲区的起始位置在页内的偏移。
(4)计数寄存器(count register):每个dma通道都有一个16位的计数寄存器,表示dma缓冲区的大小。
(5)页寄存器(page register):该寄存器定义了dma缓冲区的起始位置所在物理页的基地址,即页号。页寄存器有点类似于pc中的段基址寄存器。
2.2 8237 damc的控制寄存器
(1)命令寄存器(command register)
这个8位的寄存器用来控制8237芯片的操作。其各位的定义如下图所示:
(2)模式寄存器(mode register)
用于控制各dma通道的传输模式,如下所示:
(3)请求寄存器(request register)
用于向各dma通道发出dma请求。各位的定义如下:
(4)屏蔽寄存器(mask register)
用来屏蔽某个dma通道。当一个dma通道被屏蔽后,它就不能在服务于dma请求,直到通道的屏蔽码被清除。各位的定义如下:
上述屏蔽寄存器也称为“单通道屏蔽寄存器”(single channel mask register),因为它一次只能屏蔽一个通道。此外含有一个屏蔽寄存器,可以实现一次屏蔽所有4个dma通道,如下:
(5)状态寄存器(status register)
一个只读的8位寄存器,表示各dma通道的当前状态。比如:dma通道是否正服务于一个dma请求,或者某个dma通道上的dma传输事务已经完成。
2.3 8237 dmac的i/o端口地址
主、从8237 dmac的各个寄存器都是编址在i/o端口空间的。而且其中有些i/o端口地址对于i/o读、写操作有不同的表示含义。如下表示所示:
slave dmac’s i/o port master dmac’si/o port read write
0x000 0x0c0 channel 0/4 的address register
0x001 0x0c1 channel 0/4的count register
0x002 0x0c2 channel 1/5 的address register
0x003 0x0c3 channel 1/5的count register
0x004 0x0c4 channel 2/6的address register
0x005 0x0c5 channel 2/6的count register
0x006 0x0c6 channel 3/7的address register
0x007 0x0c7 channel 3/7的count register
0x008 0x0d0 status register command register
0x009 0x0d2 request register
0x00a 0x0d4 single channel mask register
0x00b 0x0d6 mode register
0x00c 0x0d8 clear flip-flop register
0x00d 0x0da temporary register reset dma controller
0x00e 0x0dc reset all channel masks
0x00f 0x0de all-channels mask register
各dma通道的page register在i/o端口空间中的地址如下:
dma channel page register’si/o port address
0 0x087
1 0x083
2 0x081
3 0x082
4 0x08f
5 0x08b
6 0x089
7 0x08a
注意两点:
1. 各dma通道的address register是一个16位的寄存器,但其对应的i/o端口是8位宽,因此对这个寄存器的读写就需要两次连续的i/o端口读写操作,低8位首先被发送,然后紧接着发送高8位。
2. 各dma通道的count register:这也是一个16位宽的寄存器(无论对于8位dma还是16位dma),但相对应的i/o端口也是8位宽,因此读写这个寄存器同样需要两 次连续的i/o端口读写操作,而且同样是先发送低8位,再发送高8位。往这个寄存器中写入的值应该是实际要传输的数据长度减1后的值。在dma传输事务期 间,这个寄存器中的值在每次dma传输操作后都会被减1,因此读取这个寄存器所得到的值将是当前dma事务所剩余的未传输数据长度减1后的值。当dma传 输事务结束时,该寄存器中的值应该被置为0。
2.4 dma通道的典型使用
在一个典型的pc机中,某些dma通道通常被固定地用于一些pc机中的标准外设,如下所示:
channel size usage
0 8-bit memory refresh
1 8-bit free
2 8-bit floppy disk controller
3 8-bit free
4 16-bit cascading
5 16-bit fr ee
6 16-bit free
7 16-bit free
2.5 启动一个dma传输事务的步骤
要启动一个dma传输事务必须对8237进行编程,其典型步骤如下:
1.通过cli指令关闭中断。
2.disable那个将被用于此次dma传输事务的dma通道。
3.向flip-flop寄存器中写入0值,以重置它。
4.设置mode register。
5.设置page register。
6.设置address register。
7.设置count register。
8.enable那个将被用于此次dma传输事务的dma通道。
9.用sti指令开中断。
stm32/stm8
意法半导体/st/stm
区块链是如何给予数据可信的力量
日韩动力电池的竞你是如何看待
高通将在MWC2017展示多项新技术 扩大物联网及5G布局
三菱电机6轴工业机器人
传统数字系统的设计过程包括哪些
基于Linux嵌入式系统的ISA总线DMA的实现
宁德时代抢先探路中国智造 在灯塔工厂点亮5G
助力能源技术革命 莱姆电子深耕光储充市场
绘制金字塔程序实现
如何有效改善PCBA板焊接气孔的问题
GPS何时才能开辟新天地
LED显示屏在城市规划中的角色:智慧城市的未来之光|河南恒彩电子
OPPO的十年理想之作Find X3系列有多强?
选对连接器很重要,应急保供电更迅速
供墨系统的使用注意事项
基于CompactRIO的高级可编程自动控制器
蓝牙耳机续航多久正常?2021强续航蓝牙耳机推荐
苹果全新MacBook型号曝光 发布会将会推出三款便携本
基于Matlab的TMS320LF2407程序快速设计
基于一个能监控文件变化的Python神器