<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=ISA_DMA</id>
	<title>ISA DMA - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=ISA_DMA"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=ISA_DMA&amp;action=history"/>
	<updated>2026-04-06T23:31:34Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=ISA_DMA&amp;diff=818&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“;有关ISA DMA的要点有： * ISA DMA与PCI总线主控DMA不是一回事； * ISA DMA通道1、2和3可用于8位传输到ISA外围设备; * ISA DMA通道5、6和7可用于向ISA外围设备进行16位传输； * 传输不得跨越物理64KB边界，且不得大于64KB； * 传输必须是物理上连续的，并且只能针对最低的16 MB物理内存; * ISA DMA速度很慢——理论上是4.77 MB/秒，但由于ISA总线协议，速度更接近400 KB/秒…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=ISA_DMA&amp;diff=818&amp;oldid=prev"/>
		<updated>2022-03-10T12:43:36Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“;有关ISA DMA的要点有： * ISA DMA与PCI总线主控DMA不是一回事； * ISA DMA通道1、2和3可用于8位传输到ISA外围设备; * ISA DMA通道5、6和7可用于向ISA外围设备进行16位传输； * 传输不得跨越物理64KB边界，且不得大于64KB； * 传输必须是物理上连续的，并且只能针对最低的16 MB物理内存; * ISA DMA速度很慢——理论上是4.77 MB/秒，但由于ISA总线协议，速度更接近400 KB/秒…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;;有关ISA DMA的要点有：&lt;br /&gt;
* ISA DMA与PCI总线主控DMA不是一回事；&lt;br /&gt;
* ISA DMA通道1、2和3可用于8位传输到ISA外围设备;&lt;br /&gt;
* ISA DMA通道5、6和7可用于向ISA外围设备进行16位传输；&lt;br /&gt;
* 传输不得跨越物理64KB边界，且不得大于64KB；&lt;br /&gt;
* 传输必须是物理上连续的，并且只能针对最低的16 MB物理内存;&lt;br /&gt;
* ISA DMA速度很慢——理论上是4.77 MB/秒，但由于ISA总线协议，速度更接近400 KB/秒；&lt;br /&gt;
* ISA DMA释放了CPU资源，但给内存总线增加了极重的负载；&lt;br /&gt;
* 目前还在使用ISA DMA的设备很少 -- 只有内部软盘、一些嵌入式声音芯片、一些并行端口和一些串行端口。&lt;br /&gt;
&lt;br /&gt;
注：&lt;br /&gt;
* Sound Blaster和Sound Blaster PRO仅支持8位DMA；&lt;br /&gt;
* Sound Blaster16+两者都支持;&lt;br /&gt;
* 软盘控制器仅支持8位DMA，并通过硬连线使用DMA通道2。&lt;br /&gt;
&lt;br /&gt;
== PC上有多种DMA ==&lt;br /&gt;
现代PCI控制器总是有自己的 “总线控制DMA（Busmastering DMA）”，这远远优于ISA DMA。 甚至USB软驱也通过PCI USB控制器使用PCI Busmastering发送DMA数据。&lt;br /&gt;
PCI Busmasters可以使用32位寻址访问内存。 较新的PCI卡开始支持64位寻址 (尽管目前大多数还不支持)。 通常PCI卡使用“scatter-gather”总线管理，其中单页用作数据页的目录。 这几乎完全克服了所有形式的DMA“仅限物理内存”的限制。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ISA DMA背景 ==&lt;br /&gt;
与ISA本身一样，'''ISA DMA'''（“Industry Standard Architecture Direct Memory Access”）也是现代PC架构的早期产物。 它由内部软盘控制器、ISA声卡、ISA网卡和并行端口(如果它们支持ECP模式)使用。 尽管中断，键盘和计时器接口电路具有相关明显的用途，但ISA DMA控制器及其编程接口仍然基本停留在最初设计的20世纪70年代中。&lt;br /&gt;
&lt;br /&gt;
DMA背后的想法是，你可以设置一个“通道”，地址指向内存，数据传输的长度。 一旦设置好，CPU就可以告诉拥有通道的外设独立去做它应该做的事情(例如，读取扇区)。 然后中央处理器可以去做别的事情。&lt;br /&gt;
当CPU不使用内存总线时，DMA芯片在外围设备和内存之间接管并传输数据，而不涉及CPU。 当传输完成时(例如，整个扇区已被发送到软盘驱动器)，DMA芯片随后发出完成的信号。 如果数据用完，DMA芯片甚至可以发出信号，从而使系统能够在同一DMA事务上定位要传输的下一个数据块。&lt;br /&gt;
DMA可以大大提高系统的速度，它是由Intel（设计DMA控制器芯片的人）从上世纪60年代的旧大型机上借来的，当时哪些大型机的所有设备都有DMA通道（CPU当时非常慢，且不全在一个芯片上）。&lt;br /&gt;
&lt;br /&gt;
当然，所有好的想法都会有不利之处，虽然Intel不能真的为即将被描述的事情而受到指责，但IBM肯定要背这个锅。&lt;br /&gt;
&lt;br /&gt;
一开始有PC，但是PC很慢。 IBM从天堂上往下看，说“装上DMA控制器——这应该会加快速度。” IBM的用心是正确的； 但是DMA的控制大脑总是在状况外，导致DMA控制器一直无法匹配系统需求。 PC/AT标准包含2块Intel 8237A DMA芯片，作为主/从芯片连接。 第二个芯片是Master，它的第一条线路(通道4)由第一个芯片Slave使用。 (这与中断控制器不同，中断控制中第一个芯片是Master。) 8237A是为旧的8080 8位处理器设计的，这可能是造成如此多DMA问题的主要原因。 IBM为其PC选择的8088和8086处理器相对于DMA控制器来说太先进了。&lt;br /&gt;
&lt;br /&gt;
前面提到DMA控制器应该能够发出完成信号，或者甚至能发出请求需要更多信息。 不幸的是，这会使扩展槽太大，所以IBM切断了与DMA芯片的所有连接。 知道传输何时完成的唯一时间是外设发出中断信号。 这意味着所有使用ISA DMA通道的外围设备都被限制为不超过64 KB的传输，因为担心会扰乱DMA控制器。&lt;br /&gt;
&lt;br /&gt;
即使在PC/AT中，IBM也开始绕过PC/XT中使用的ISA DMA，并对硬盘使用[[ATA PIO Mode]]。 正是因为上面概述的64KB限制，以及286处理器可以在6 MHz下执行16位事务的事实。 甚至ISA总线也可以以高达12 MHz的速度运行，远远快于DMA控制器运行的4.77 MHz。&lt;br /&gt;
&lt;br /&gt;
扩展卡设计人员也对DMA的功能不足感到不满，尤其是依赖数据传输速度的“硬盘”扩展卡制造商。&lt;br /&gt;
&lt;br /&gt;
为了绕过“板载”DMA控制器的限制，扩展卡制造商开始在他们的扩展卡上安装他们自己的DMA控制器。 它们的功能与 “机上” DMA完全相同，在处理器不看时 “窃取内存总线周期”，从而提高了整个系统的性能。 这些“ISA总线主控器”传输通常仍限于较低的16 MiB内存，但没有4.77 MHz的问题。&lt;br /&gt;
这一趋势通过PCI总线的创建继续发展，PCI总线也最终完全取代了PC中的ISA总线。&lt;br /&gt;
&lt;br /&gt;
== 技术细节 ==&lt;br /&gt;
每个8237 DMA芯片有4个DMA通道。 第一个芯片上有DMA0-DMA3，第二个芯片上有DMA4-DMA7。 第一个DMA控制器连接起来进行8位传输，而第二个连接起来进行16位传输。 在一些教程或其他wiki文章中，你有时会看到“第二个”DMA芯片（通道4到7）标记为“主”控制器，第一个（通道0到3）标记为“从”。 这非常令人困惑，这里不会再使用这些术语。&lt;br /&gt;
&lt;br /&gt;
DMA通道0不可用，因为它在短时间内用于DRAM内存刷新，因此保留 (即使现代计算机不使用它)。 DMA通道4不能用于外围设备，因为它用于级联其他DMA控制器。&lt;br /&gt;
&lt;br /&gt;
DMA控制器的内部地址寄存器只有16位。 为了扩展这一点，IBM在每个通道增加了一个 “外部（external）” “页面寄存器（page register）” 字节，允许访问16 MB的内存 (总共24位)。 如果DMA传输跨越64 KB的边界，内部地址寄存器将变为零，外部页面寄存器将“不”递增。 这时DMA控制器将用它在新地址找到的任何数据继续传输。&lt;br /&gt;
&lt;br /&gt;
基于ISA的DMA控制器被指定为以4.77 MHz运行。'''没有例外'''。 如果系统的“前端”（内存）总线以133 MHz的频率运行，在传输每个ISA DMA字节/字时，它将被人为地降低到4.77 MHz。 这包括EISA和PS/2 32位控制器，即使这些控制器具有额外的页面寄存器(允许4GiB寻址空间)和执行32位传输的能力。 (这些DMA控制器仅存在于EISA和MCA系统上，这两个系统现已过时，此处不再进一步介绍。)== 编程细节 ==&lt;br /&gt;
&lt;br /&gt;
=== 16位问题===&lt;br /&gt;
16位通道(5、6和7)具有特殊的寻址方案来处理它们递增地址的方式。 内部寄存器增加1，但每次访问之间需要将内存地址增加2。 解决方案是，CPU存储在DMA控制器中的“起始地址”需要右移1位。 在每次存储器访问时，该内部16位地址值递增1，然后取该值并将其左移一位(清除低位)，然后将其用作地址。 然后以正常方式附加外部 “页寄存器” 寻址字节。 重要的是要注意，内部地址的高位在向左移位时是“丢失的”——它不会被或运算到页面寄存器字节中。&lt;br /&gt;
因为地址寄存器将有效位绕回到零，而不会递增页面寄存器字节，这会阻止大于64 KB的DMA传输工作，即使它们在技术上对于16位通道是可行的。&lt;br /&gt;
&lt;br /&gt;
=== 物理内存与分页 ===&lt;br /&gt;
分页内存映射完全由CPU控制。 DMA的全部意义在于绕过CPU。（译者注：也就不知道MMU分页表的存在） 因此，DMA不可以访问任何虚拟内存地址。 所有DMA始终仅在物理内存地址上完成。 ISA DMA的物理地址限制为16 MB。&lt;br /&gt;
&lt;br /&gt;
由于DMA独立于CPU运行，因此重要的是，OS要为为DMA传输分配一个连续的物理内存块，以防止该内存用于任何其他目的或交换出去，直到DMA传输完成。&lt;br /&gt;
&lt;br /&gt;
注：VM86模式不使用“物理”寻址。 内存地址是“假的”。 在VM86模式下，操作系统必须代表应用程序模拟任何DMA事务。&lt;br /&gt;
&lt;br /&gt;
===缓冲区大小===&lt;br /&gt;
一张典型的1.44MB软盘可以在一次传输中轻松地传输36个扇区的数据。 这只有18 KB。 最大的内部软盘使用最差格式，一次可以传输84个扇区。 这仍然只有42KB。 Soundblaster卡使用64 KB缓冲区可以最佳运行。 从来没有必要尝试将缓冲区ISA DMA传输加倍，因为它们无论如何都非常慢。 最多有6个可用DMA通道，不需要为每个通道分配完整的64KB。 将所有这些放在一起，任何操作系统都应该能够轻松地从256 KB的池中分配所需的所有ISA DMA物理内存，甚至有时只需一半。&lt;br /&gt;
&lt;br /&gt;
===  Flip-Flop ===&lt;br /&gt;
PC上的许多设备(例如ATA磁盘驱动器)使用8位IO端口来接收16位值。 这是使用flip-flop完成的。 设备首先需要低字节。 一旦接收到一个字节，flip-flop就会改变状态，然后器件就会等待高位字节。 当接收到高字节时，flip-flop再次改变状态，并且设备期望一个新的低字节。 通常，每个16位“寄存器”都有自己的Flip-Flop，但ISA DMA控制器在这方面存在问题。&lt;br /&gt;
&lt;br /&gt;
在8237芯片上，'''只有一个'''Flip-Flop。 有8个16位寄存器。 最多可以有三个设备驱动程序同时竞争使用一个触发器。&lt;br /&gt;
&lt;br /&gt;
这就产生了两个严重的问题。 一是 “争用问题”。 另一个问题是，很难确定触发器当前处于什么状态。&lt;br /&gt;
处理触发器状态问题的标准解决方案是在你每次想要使用Flip-Flop时将其重置为“低字节”状态，这样你就可以在发送字节之前确定它处于正确的状态。 “争用” 只有两种解决方案: 要么使用 [[lock|锁]]，要么只允许存在一个ISA DMA驱动程序，则无法进行争用。&lt;br /&gt;
&lt;br /&gt;
=== 屏蔽DRQ(DMA Request) ===&lt;br /&gt;
设置DMA传输总是需要设置传输的两端。 也就是说，无论哪个外围设备拥有DMA通道，都需要被告知如何通过DMA传输数据块。 DMA控制器需要被告知内存地址、传输长度、传输“模式”和传输方向（读或写）。 因此，外围设备和内存两者中总有一个需要“先”完成--通常是外围设备在准备好传输第一个字节之前有很长的延迟时间。 如果首先设置外围设备，则在设置DMA控制器的过程中，它的第一个DMA请求信号 (通常称为DMA request signal-DRQ) 就可能会到达。&lt;br /&gt;
&lt;br /&gt;
答案是在初始化DMA控制器时屏蔽特定信道的DRQ。 下面会介绍三种临时禁用通道的方式。&lt;br /&gt;
&lt;br /&gt;
=== 传输长度 ===&lt;br /&gt;
存储在每个计数寄存器中的值始终是传输长度（字节或字）“-1”。 如果你忘了减去1，你在传输时会出错。&lt;br /&gt;
&lt;br /&gt;
=== 完成时中断 ===&lt;br /&gt;
在PC机上实现时，DMA控制器不能发送中断。 希望在传输完成时，无论哪个外设“拥有”的每个DMA通道，都会向CPU发送中断。 但是，如果传输失败并出现错误，某些外围设备可能会 “不” 发送中断。 和其它类似场景一样，有超时策略很重要。&lt;br /&gt;
&lt;br /&gt;
===寄存器===&lt;br /&gt;
主从DMA控制器非常相似，因此 (为了节省空间) 它们都已合并到下表中。 希望你不要为这种排版困惑。&lt;br /&gt;
注：有关通道5至7上的地址和计数寄存器，请参见上面的[[#16位问题|16位问题]]。&lt;br /&gt;
&lt;br /&gt;
每个8237A都有18个寄存器，通过I/O端口总线寻址:&lt;br /&gt;
&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
!Channels 0-3&lt;br /&gt;
!Channels 4-7&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!IO Port&lt;br /&gt;
!IO Port&lt;br /&gt;
!Size&lt;br /&gt;
!Read or Write&lt;br /&gt;
!Function&lt;br /&gt;
|-&lt;br /&gt;
|0x00&lt;br /&gt;
|0xC0&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
| 起始地址寄存器通道0/4（不可用）&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|0xC2&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
|计数寄存器通道0/4(不可用)&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|0xC4&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
| 开始地址寄存器通道1/5&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|0xC6&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
| 计数寄存器通道1/5&lt;br /&gt;
|-&lt;br /&gt;
|0x04&lt;br /&gt;
|0xC8&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
|起始地址寄存器通道2/6&lt;br /&gt;
|-&lt;br /&gt;
|0x05&lt;br /&gt;
|0xCA&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
| 计数寄存器通道2/6&lt;br /&gt;
|-&lt;br /&gt;
|0x06&lt;br /&gt;
|0xCC&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
|起始地址寄存器通道3/7&lt;br /&gt;
|-&lt;br /&gt;
|0x07&lt;br /&gt;
|0xCE&lt;br /&gt;
|Word&lt;br /&gt;
|W&lt;br /&gt;
|计数寄存器通道3/7&lt;br /&gt;
|-&lt;br /&gt;
|0x08&lt;br /&gt;
|0xD0&lt;br /&gt;
|Byte&lt;br /&gt;
|R&lt;br /&gt;
| 状态寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x08&lt;br /&gt;
|0xD0&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|命令寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x09&lt;br /&gt;
|0xD2&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|请求寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0A&lt;br /&gt;
|0xD4&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
| 单通道屏蔽寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0B&lt;br /&gt;
|0xD6&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|模式寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0C&lt;br /&gt;
|0xD8&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|Flip-Flop复位寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0D&lt;br /&gt;
|0xDA&lt;br /&gt;
|Byte&lt;br /&gt;
|R&lt;br /&gt;
| 中间（Intermediate）寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0D&lt;br /&gt;
|0xDA&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|主复位寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0E&lt;br /&gt;
|0xDC&lt;br /&gt;
|Byte&lt;br /&gt;
|W&lt;br /&gt;
|屏蔽复位寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x0F&lt;br /&gt;
|0xDE&lt;br /&gt;
|Byte&lt;br /&gt;
|RW&lt;br /&gt;
| 多通道屏蔽寄存器 (文章中没有说明有读取操作，但可以读!)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
每个通道还有一个外部R/W页地址寄存器，还要和24位传输存储器地址的上8位组成数据：&lt;br /&gt;
&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|0x87&lt;br /&gt;
|通道0页地址寄存器(不可用)&lt;br /&gt;
|-&lt;br /&gt;
|0x83&lt;br /&gt;
| 通道1页地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x81&lt;br /&gt;
|通道2页面地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x82&lt;br /&gt;
|通道3页地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x8F&lt;br /&gt;
| 通道 4页面地址寄存器 (不可用)&lt;br /&gt;
|-&lt;br /&gt;
|0x8B&lt;br /&gt;
|通道5页面地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x89&lt;br /&gt;
|通道6页地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|0x8A&lt;br /&gt;
| 通道7页面地址寄存器&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== 有用的寄存器说明====&lt;br /&gt;
&lt;br /&gt;
; 单通道掩码寄存器0x0A和0xD4(写入)&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|Bit 7&lt;br /&gt;
|Bit 6&lt;br /&gt;
|Bit 5&lt;br /&gt;
|Bit 4&lt;br /&gt;
|Bit 3&lt;br /&gt;
|Bit 2&lt;br /&gt;
|Bit 1&lt;br /&gt;
|Bit 0&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|MASK_ON&lt;br /&gt;
|SEL 1&lt;br /&gt;
|SEL 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
这些寄存器仅用于在主DMA芯片或从DMA芯片上屏蔽（或取消屏蔽）单个通道的DRQ。&lt;br /&gt;
也就是说，如果你不想计算出所有其他通道的屏蔽状态，你可以一次屏蔽/取消屏蔽一个通道的DRQ。&lt;br /&gt;
使用SEL 0和1位选择通道，并使用MASK_ON位为其设置或清除屏蔽。&lt;br /&gt;
注意，由于级联关系，屏蔽DMA信道4将屏蔽7、6、5和4。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;多通道掩码寄存器0x0F和0xDE(读和写)&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|Bit 7&lt;br /&gt;
|Bit 6&lt;br /&gt;
|Bit 5&lt;br /&gt;
|Bit 4&lt;br /&gt;
|Bit 3&lt;br /&gt;
|Bit 2&lt;br /&gt;
|Bit 1&lt;br /&gt;
|Bit 0&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|MASK3&lt;br /&gt;
|MASK2&lt;br /&gt;
|MASK1&lt;br /&gt;
|MASK0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
将适当的位设置为0或1允许你取消屏蔽或屏蔽 (分别) 这些通道的DRQ。 使用此寄存器意味着你的驱动程序需要知道此时“所有”通道的所需掩码状态。 有几种方法可以做到这一点，这里可以考虑简单地读取该寄存器。&lt;br /&gt;
注意，由于级联，屏蔽DMA通道4将屏蔽7、6、5和4。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;DMA模式寄存器0x0B和0xD6（写入）&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|Bit 7&lt;br /&gt;
|Bit 6&lt;br /&gt;
|Bit 5&lt;br /&gt;
|Bit 4&lt;br /&gt;
|Bit 3&lt;br /&gt;
|Bit 2&lt;br /&gt;
|Bit 1&lt;br /&gt;
|Bit 0&lt;br /&gt;
|-&lt;br /&gt;
|MOD1&lt;br /&gt;
|MOD0&lt;br /&gt;
|DOWN&lt;br /&gt;
|AUTO&lt;br /&gt;
|TRA1&lt;br /&gt;
|TRA0&lt;br /&gt;
|SEL1&lt;br /&gt;
|SEL0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
设置该寄存器有点棘手，因为它在很大程度上取决于要为其编程DMA控制器的外设。 但是，外围设备的驱动程序是需要设置此寄存器的主体，它应该知道外围设备需要什么模式。&lt;br /&gt;
&lt;br /&gt;
* '''SEL0'''和'''SEL1'''选择要更改的通道；&lt;br /&gt;
* '''TRA0'''和'''TRA1'''选择传输类型；&lt;br /&gt;
** 0b00 运行控制器的自检;&lt;br /&gt;
** 0b01 外围设备正在写入内存；&lt;br /&gt;
** 0b10 外设正在从存储器中读取；&lt;br /&gt;
** 0b11无效。&lt;br /&gt;
* '''AUTO'''：设置此位时，在传输完成后，通道将自身重置为编程到其中的地址和计数值。 这对于软盘传输非常有用。  在磁道中读的时候-这些值可以设置好它们，以便立即再次读数据。 对于写操作，你只需要更改传输模式，而不需要更改地址。 某些扩展卡不支持自动初始化DMA，如Sound Blaster 1.x。 如果与auto-init DMA一起使用，这些设备将崩溃。 Sound Blaster 2.0及更高版本确实支持自动初始化DMA。&lt;br /&gt;
* '''DOWN'''：设置时颠倒数据的内存顺序。 从高地址到低地址访问内存 (每次传输之间地址递减)。&lt;br /&gt;
* '''MOD0'''和'''MOD1'''：基于DMA控制器所连接的外围设备，这可能会出现一些问题。 DMA控制器有几种模式：&lt;br /&gt;
** 0b00 = 按需传输;&lt;br /&gt;
**0b01 = 单DMA传输（Single DMA Transfer）；&lt;br /&gt;
**0b10 = 块DMA传输（Block DMA Transfer）；&lt;br /&gt;
** 0b11 = 级联模式 (用于级联另一个DMA控制器)。&lt;br /&gt;
&lt;br /&gt;
单传输模式对外围设备来说是一种好方法，因为它不能同时缓存大量数据。&lt;br /&gt;
非82077AA软盘控制器、Sound Blaster和Sound Blaster Pro应使用单传输DMA模式。&lt;br /&gt;
&lt;br /&gt;
块传输模式对于可以缓冲整个信息块的外围设备是很好的。 硬盘控制器板就是一个例子。&lt;br /&gt;
&lt;br /&gt;
按需传输模式适用于间歇性启动和停止的外围设备，如磁带机。 驱动器可以读取整个信息负载，只要它可以，并暂停传输以移动到磁带的另一部分。 较新的软盘控制器也适用于按需传输，因为它们有FIFO缓冲区来存储读取和写入的信息（但需要正确设置FIFO）。 外围设备控制流量，由于信息流不中断，因此可以获得好的性能。 一些后来的计算机中的cpu通常具有缓存，并且可以在需求DMA传输期间继续不间断地工作。 较旧的计算机会在CPU等待内存总线可用时可能会减慢速度。&lt;br /&gt;
&lt;br /&gt;
;Flip-Flop复位寄存器0x0C和0xD8(写入)&lt;br /&gt;
;主复位寄存器0x0D和0xDA (写)&lt;br /&gt;
;屏蔽重置寄存器0x0E和0xDC（写入）&lt;br /&gt;
&lt;br /&gt;
将需要的值发送到复位寄存器以激活它们。&lt;br /&gt;
主复位将Flip-Flop设置为低电平，清除状态，并将所有掩码位设置为ON。&lt;br /&gt;
屏蔽重置将关闭所有掩码位。&lt;br /&gt;
&lt;br /&gt;
“必须在任何“16位事务之前发送复位触发器命令。（以前的维基文章中的会说明需要在真实硬件上进行验证，因为它很可能在模拟器上是错误的） 在DMA控制器收到第二个字节后，Flip-Flop “不重置”。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 其他寄存器====&lt;br /&gt;
&lt;br /&gt;
;状态寄存器0x08和0xD0(读取)&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|Bit 7&lt;br /&gt;
|Bit 6&lt;br /&gt;
|Bit 5&lt;br /&gt;
|Bit 4&lt;br /&gt;
|Bit 3&lt;br /&gt;
|Bit 2&lt;br /&gt;
|Bit 1&lt;br /&gt;
|Bit 0&lt;br /&gt;
|-&lt;br /&gt;
|REQ3&lt;br /&gt;
|REQ2&lt;br /&gt;
|REQ1&lt;br /&gt;
|REQ0&lt;br /&gt;
|TC3&lt;br /&gt;
|TC2&lt;br /&gt;
|TC1&lt;br /&gt;
|TC0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* REQ3-0: 设置1时: DMA请求待处理。&lt;br /&gt;
*TC3-0：设置1时：传输完成。&lt;br /&gt;
* 读取该寄存器将清除TC位。&lt;br /&gt;
&lt;br /&gt;
鉴于8237不能发送IRQ来告诉你它已经完成，这个寄存器不是很重要。 通常不需要轮询该寄存器，因为当事务完成时，外围设备（在DMA的另一端）将发送一个中断。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;命令寄存器0x08和0xD0(写入)&lt;br /&gt;
{| {{wikitable}}&lt;br /&gt;
|-&lt;br /&gt;
|Bit 7&lt;br /&gt;
|Bit 6&lt;br /&gt;
|Bit 5&lt;br /&gt;
|Bit 4&lt;br /&gt;
|Bit 3&lt;br /&gt;
|Bit 2&lt;br /&gt;
|Bit 1&lt;br /&gt;
|Bit 0&lt;br /&gt;
|-&lt;br /&gt;
|DACKP&lt;br /&gt;
|DRQP&lt;br /&gt;
|EXTW&lt;br /&gt;
|PRIO&lt;br /&gt;
|COMP&lt;br /&gt;
|COND&lt;br /&gt;
|ADHE&lt;br /&gt;
|MMT&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
此寄存器也确实表现出了8237与PC硬件的不兼容程度。&lt;br /&gt;
* 让我们从EXTW和COMP开始。 这些使DMA传输速度提高了25%，消除了一个时钟周期。 它能用吗？ 不能。&lt;br /&gt;
* PRIO。 置零时，这允许DMA优先级轮换，从而允许共享数据总线的所有外设的自由。它能用吗？不能。&lt;br /&gt;
* MMT和ADHE。 你是否知道IBM PC可以1981年进行内存到内存（memory to memory）的传输？ 没错，一种硬件精灵（hardware sprites）技术，从一个位置到另一个位置的硬件帧缓冲。它能用吗？不能。&lt;br /&gt;
* COND。 Hooray是控制寄存器中唯一有用的部分。 设置此位将禁用DMA控制器。 这是在不屏蔽每个通道的情况下设置多个DMA通道的一种方式。&lt;br /&gt;
&lt;br /&gt;
; 请求寄存器0x09和0xD2 (写)&lt;br /&gt;
用于内存到内存的传输和设置优先级轮换——绝对没有用。&lt;br /&gt;
&lt;br /&gt;
；“Intermediate”寄存器0x0D和0xDA(读取)&lt;br /&gt;
从未在个人电脑上实现。没用。&lt;br /&gt;
&lt;br /&gt;
==示例==&lt;br /&gt;
&lt;br /&gt;
=== 软盘DMA初始化 ===&lt;br /&gt;
&lt;br /&gt;
你只需要实现1到3个小例程即可执行DMA传输。 这个例子是软盘驱动器控制器（可能是最常见的，其次是SoundBlaster）。&lt;br /&gt;
&lt;br /&gt;
注意：以下代码不是最佳代码，因为存在两次到同一IO端口的输出(在两个位置)。 这会导致IO端口总线上的额外延迟。 真正的代码应该将两个“out 0x4”和“out 0x5”调用与另一个端口的“out”分开。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
initialize_floppy_DMA:&lt;br /&gt;
; 将DMA通道2设置为在内存中传输来自0x1000-0x33ff的数据&lt;br /&gt;
; 分页必须将此 _物理_ 内存映射到其他地方，并且进行从分页到磁盘 _pin_ !&lt;br /&gt;
; 将计数器设置为0x23ff，即1.44 MiB软盘上的磁道长度-1（假设是512字节扇区）&lt;br /&gt;
; transfer length = counter + 1&lt;br /&gt;
    out 0x0a, 0x06      ; 屏蔽DMA通道2和0(假设0已屏蔽)&lt;br /&gt;
    out 0x0c, 0xFF      ; 重置主Flip-Flop&lt;br /&gt;
    out 0x04, 0         ; 地址为0（低字节）&lt;br /&gt;
    out 0x04, 0x10      ; 地址设为0x10(高字节)&lt;br /&gt;
    out 0x0c, 0xFF      ; 重置主Flip-Flop (再次!)&lt;br /&gt;
    out 0x05, 0xFF      ; 计数为0x23ff（低字节）&lt;br /&gt;
    out 0x05, 0x23      ; 计数为0x23ff(高字节)，&lt;br /&gt;
    out 0x81, 0         ; 外部页寄存器为0，总地址为00 10 00&lt;br /&gt;
    out 0x0a, 0x02      ; 解除DMA信道2的屏蔽&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
一旦你设置了起始地址和传输长度，如果你使用的是autoinit，则不需要再次管它。 一旦选择了读或写，你也不需要改变它。 要“更改”选择读取或写入，请使用模式寄存器。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
prepare_for_floppy_DMA_write:&lt;br /&gt;
    out 0x0a, 0x06      ; 屏蔽DMA通道2和0(假设0已屏蔽)&lt;br /&gt;
    out 0x0b, 0x5A      ; 01011010&lt;br /&gt;
                        ; single transfer, address increment, autoinit, write, channel2)&lt;br /&gt;
    out 0x0a, 0x02      ; 解除DMA通道2的掩码&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
prepare_for_floppy_DMA_read:&lt;br /&gt;
    out 0x0a, 0x06      ; 屏蔽DMA通道2和0(假设0已屏蔽)&lt;br /&gt;
    out 0x0b, 0x56      ; 01010110&lt;br /&gt;
                        ; single transfer, address increment, autoinit, read, channel2)&lt;br /&gt;
    out 0x0a, 0x02      ; 取消屏蔽DMA通道2&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
有些硬件以及VirtualPC不支持autoinit。 在上述例程中，你可能要将模式寄存器设置为0x4A和0x46。&lt;br /&gt;
&lt;br /&gt;
上述例程使用single transfer模式来实现兼容性，但是在你的软盘驱动程序初始化期间，如果你检测到 “高级” 软盘控制器 (使用Version命令)，则应使用 “demand transfer” 来减少开销。&lt;br /&gt;
&lt;br /&gt;
==参考文献==&lt;br /&gt;
&lt;br /&gt;
=== 相关文章 ===&lt;br /&gt;
* [[Floppy Disk Controller|软盘控制器]]&lt;br /&gt;
&lt;br /&gt;
===外部链接===&lt;br /&gt;
* [http://www.intel-assembler.it/PORTALE/4/231466_8237A_DMA.pdf Intel 8237A datasheet]&lt;br /&gt;
*[http://bos.asmhackers.net/docs/dma/docs/ http://bos.asmhackers.net/docs/dma/docs/]&lt;br /&gt;
&lt;br /&gt;
[[Category:Storage]]&lt;br /&gt;
[[de:DMA]]&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>