外设请求接口
上图展示了外设请求接口,由一个外设请求总线和一个DMAC确认总线组成,其中:
dr表示外设请求中线,da表示DMAC确认总线
两条总线都使用valid/ready握手机制(AXI协议所描述)。对于握手机制详细信息,请查看AMBA AXI Protocol v1.0 Specification
外设使用 drtype[1:0]:
- 请求单次传输
- 请求burst传输
- 确认一个flush请求
DMAC使用datype[1:0]:
- 当它完成了请求的单次传输后发起信号
- 当它完成了请求的burst传输后发起信号
- 发起一个flush请求
(关于burst,参考https://www.pianshen.com/article/2653254175/)
drlast让外设能够在最后一个DMA传输开始时通知DMAC
如果DMAC被配置为支持多个外设请求接口,每个接口要分配一个唯一的ID号_<x>.
映射到一个DMA channel
DMAC支持分配一个外设请求接口到任意的DMA channel。当一个DMA channel执行DMAWFP时,其中的peripheral[4:0]字段指定了这个channel所关联的外设。
握手规则
DMAC使用DMA握手规则(当一个DMA channel线程处于active状态,即非Stopped状态时)如下表所示:
外设长度管理
外设请求接口能够让一个外设控制一个DMA周期所包含的数据量,不需要让DMAC感知它包含多少数据传输数。外设通过:
drtype[1:0]选择是单次传输还是burst传输
drlast用来通知DMAC最后一次传输开始
DMAC长度管理
如果使用外设请求接口并且DMAC在控制一个DMA周期所包含的数据量,那么必须使用DMALDP<S|B>和DMASTP<S|B>指令。使用这些指令会让DMAC能够更新datype[1:0]来通知外设它完成了最后的DMA传输
外设请求接口时序图
Burst请求
T1 | DMAC检测到了一个burst传输请求 |
T3-T6 | DMAC执行burst传输 |
T7 | DMAC设置davalid为HIGH,并且设置datype[1:0]来指示burst传输完成 |
单次和burst请求
T1 | DMAC检测到单次传输请求 |
T3 | DMAC忽略了单次传输请求,因为DMA channel线程执行过了一个DMAWFPB指令 |
T5 | DMAC检测到了一个burst传输请求 |
T7-T10 | DMAC执行burst传输 |
T11 | DMAC设置davalid为HIGH,并且设置datype[1:0]指示burst传输完成 |
DMAC对一个burst请求执行单次传输
下图表示当一个外设请求一次burst传输时,DMAC的MFIFO里没有足够的数据产生一次burst的情况下,DMAC通过多个单次传输来完成请求的时序。
T1 | DMAC检测到一个burst传输请求 |
T3 | MFIFO没有足够多的数据让DMAC产生一次burst传输,因此DMAC执行了一次单次传输 |
T4 | DMAC产生davalid和datype[1:0]信号来指示一次单次传输的完成 |
T5-T10 | DMAC执行剩下的三个单次传输 |
T11 | DMAC设置davalid和datype[1:0]来请求外设flush掉所有和当前DMA周期相关的控制寄存器 |
T12 | 外设通过drvalid和drtype[1:0]来确认flush请求 |
使用事件和中断
通过编程Intterupt Enable寄存器,可以使用DMASEV指令来:
产生一个event给DMAC来处理
使用irq[x]中的一个来发起中断
使用event重启DMA channel
当编程Interrupt Enable寄存器来产生event时,可以用DMASEV和DMAWFE指令来重启一个或多个DMAchannel。
要重启一个单独的DMA channel:
-
第一个DMA channel执行DMAWFE,并且在它等待event发生的时候停住
-
另一个DMA channel执行DMASEV,使用相同的event号。这样会产生一个event,第一个DMA channel会重启。DMAC会在它执行DMASEV后的一个时钟周期后清除掉event。
可以编程让多个cahnnel等待相同的event。例如,如果四个DMA cahnnel都执行DMAWFE等待event 12,当另一个DMA channel对event 12执行DMASEV时,这四个channel全部在同一时间重启。DMAC在它执行了DMASEV的一个时钟周期后清除这个event。
由于event只有一个时钟周期长度,如果某一个DMA channel没有在DMASEV发生前执行DMAWFE,那么这个DMA channel必须等到event再次产生。
event只有在一种情况下回存在长于一个时钟周期,是在一个DMA channel执行DMASEV并且没有任何其它DMA channel执行过使用相同event号的DMAWFE的时候。
中断微处理器
DMAC提供irq[x]信号用于产生高有效,电平触发的中断到外部微处理器。当编程使用Interrupt Enable寄存器来产生中断时,在DMAC执行完DMASEV后它会设置对应的irq[x]为高电平。
外部微处理器能够写Interrupt Clear寄存器来清除中断(执行DMAWFE不会清除中断)。
Abort
Abort类型
当一个abort发生时,根据DMAC是否提供了带DMAC的精确状态(precise state)的abort handler,abort可以被定义为“精确的”还是“不精确的”:
precise DMAC会更新PC寄存器,值是产生abort的指令地址
imprecise PC寄存器可能会包含没有触发abort的指令地址
Abort源
percise abort
非安全状态下,一个DMA channel线程尝试编程Channel Control寄存器并产生一个安全的AXI事务 |
非安全状态下,一个DMA channel线程对于一个被设置为安全的event执行DMAWFE或DMASEV。 (对于每个event,Interrupt Enable寄存器控制DMAC是产生event还是发出一个中断信号) |
非安全状态下,一个DMA channel线程对于一个被设置为安全的外设请求接口执行DMAWFP,DMALDP,DMASTP或DMAFLUSHP。 |
非安全状态下,DMA管理线程执行DMAG0试图启动一个安全的DMA channel线程 |
当DMAC取指时,在AXI master接口上收到一个ERROR响应 |
一个线程执行了一条未定义指令 |
一个线程执行了一条指令,该指令带有针对DMAC配置的非法操作数。 (当DMAC发起信号通知一个精确abort时,触发abort的指令没有被执行,相反,DMAC会执行一个DMANOP) |
imprecise abort
DMAC在执行一个data load操作时接收到了AXI master接口上的ERROR响应 |
DMAC在执行一个data store操作时接收到了AXI master接口上的ERROR响应 |
一个DMA channel线程执行DMALD,并且MFIFO空间太小,不够保存数据时 |
一个DMA channel线程执行DMAST,并且MFIFO空间不够完成数据传输时 |
一个DMA channel线程由于资源饥饿导致锁住,这会导致内部watchdog timer超时 |
watchdog abort
DMAC包含了逻辑来确定什么时候一个或多个channel由于资源饥饿导致锁住。举个例子,如果MFIFO或load/store队列满了,这可能会阻止DMAC执行指令。如果锁定的条件持续了1024个aclk周期,则DMAC会abort这个DMA channel线程。
Abort处理
DMAC的架构没有设计从abort中恢复的机制,因此必须使用一个外部agent,比如微处理器,在一个abort发生时来终止线程。下图展示了DMA管理线程和channel线程在abort发生后的运行状态。
DMA channel线程 | 线程立即进入Faulting completing状态,DMAC会: 设置irq_abort为高 停止这个DMA channel的指令执行 对这个DMA channel的所有cache表项进行invalidate 更新Channel Program Counter寄存器,值为abort指令的地址(假设abort是精确的) 在read和write queue中剩余的任何指令都不再产生AXI访问 允许当前active的AXI事务完成 (当DMA channel对应的事务完成后,线程进入Faulting状态) |
DMA 管理线程 | 线程立即进入Faulting状态,并且DMAC设置irq_abort为高 |
外部agent响应irq_abort置为有效的方式:
-
读Fault Status DMA Manager寄存器的状态来确定DMA管理器是否处于Faulting。Fault Type DMA manager寄存器在Faulting状态下会提供abort发生原因。
-
读Fault Status DMA Channel寄存器的状态来确定DMA管理器是否处于Faulting。Fault Type DMA Channel寄存器在Faulting状态下会提供abort发生原因。
为了让处于Faulting状态的线程进入Stopped状态,外部agent必须:
-
编程Debug Instruction-0寄存器,使用DMAKILL指令的编码
-
写Debug Command寄存器
(注意如果abort的线程是安全态的,必须用安全态APB接口来更新这些寄存器)
处于Faulting状态的线程执行完DMAKILL后,它会进入Stopped状态。