4. UHCI与DMA的协同工作:UHCI如何利用DMA进行数据传输、帧列表(Frame List)与传输描述符(TD)的关系
在USB 1.x全速/低速主机控制器中,UHCI(Universal Host Controller Interface)通过直接存储器访问(DMA)实现与系统内存的高效数据交换,而无需CPU逐字节干预。UHCI本身不包含数据缓冲区,所有传输描述符(TD)、帧列表(Frame List)以及实际数据缓冲区均驻留在系统内存中,UHCI通过总线主控DMA引擎自主读取这些数据结构并执行传输。理解帧列表与传输描述符的层次关系,是FPGA验证中定位DMA传输异常的关键。
核心概念:UHCI的DMA传输并非简单的内存拷贝,而是基于链表结构的描述符轮询与执行机制。帧列表作为时间基准索引,传输描述符作为传输任务单元,两者通过硬件指针串联,形成完整的等时/批量/中断传输调度流水线。
4.1 帧列表(Frame List)——时间基准索引
帧列表是UHCI调度传输的时间基准。UHCI将USB帧(每帧1ms)编号为0~1023,帧列表基地址寄存器(FLBASEADD)指向系统内存中一个1024×4字节的页对齐数组。每个表项(Frame List Pointer, FLP)指向一个传输描述符链表的起始节点。
| 帧列表属性 | 值/说明 |
|---|---|
| 表项数量 | 1024(对应0~1023帧号) |
| 每项大小 | 4字节(32位) |
| 对齐要求 | 帧列表基地址必须256字节对齐 |
| 表项内容 | 指向TD链表的物理地址(低4位为控制位) |
| 更新时机 | 每帧开始前由UHCI硬件读取当前帧号对应的表项 |
FPGA验证要点:帧列表的DMA读取发生在SOF(Start of Frame)包发送之后。验证时应检查FLBASEADD寄存器配置是否正确、帧列表所在内存区域是否可被UHCI总线主控访问、以及帧号计数器(Frame Number Register)是否与帧列表索引同步。
4.2 传输描述符(TD)——传输任务单元
传输描述符是UHCI执行DMA传输的基本任务单元。每个TD固定为32字节,包含链路指针、传输控制信息、数据缓冲区指针以及状态信息。UHCI通过DMA读取TD后,解析其中的控制字段,发起对数据缓冲区的DMA读写,并在传输完成后更新TD状态。
| TD字段(32位宽) | 偏移 | 功能描述 |
|---|---|---|
| Link Pointer | 0x00 | 指向下一个TD的物理地址(含深度/宽度遍历控制位) |
| Control/Status | 0x04 | 传输方向、速度、中断使能、错误状态、完成状态 |
| Token | 0x08 | 设备地址、端点号、PID(IN/OUT/SETUP) |
| Buffer Pointer | 0x0C | 数据缓冲区物理地址(必须页对齐) |
| Buffer Size | 0x10 | 最大数据字节数(0~1023) |
| Reserved/Status Ext | 0x14~0x1C | 保留或扩展状态位 |
常见调试陷阱:在FPGA验证中,TD的Buffer Pointer必须指向物理连续且对齐的内存区域。如果数据缓冲区跨越4KB页边界,UHCI可能产生不可预期的DMA行为。建议在验证环境中强制缓冲区页对齐,并监控DMA地址是否越界。
4.3 UHCI的DMA传输流程
UHCI通过以下步骤完成一次基于DMA的USB传输:
- 帧起始同步:UHCI内部帧号计数器递增,硬件读取帧列表对应表项,获取TD链表头指针。
- TD获取(DMA读):UHCI作为总线主控,发起内存读事务,将TD的32字节内容加载到内部寄存器。
- 令牌包发送:根据TD中的Token字段,UHCI在USB总线上发送令牌包(IN/OUT/SETUP)。
- 数据阶段DMA:
- 对于OUT传输:UHCI从TD指定的缓冲区DMA读取数据,通过USB总线发送。
- 对于IN传输:UHCI接收USB数据,通过DMA写入TD指定的缓冲区。
- 状态更新(DMA写):传输完成后,UHCI将状态信息写回TD的Control/Status字段。
- 链表遍历:读取Link Pointer,若有效则重复步骤2~5,否则结束当前帧调度。
4.4 帧列表与TD的协同调度机制
UHCI通过帧列表实现时间确定性调度,而TD链表提供传输任务灵活性。两者协同的核心规则如下:
- 每帧独立调度:每个帧号对应的帧列表表项可以指向不同的TD链表头,实现每帧传输任务的动态调整。
- 链表深度遍历:UHCI从帧列表表项获取第一个TD后,通过TD内部的Link Pointer遍历整个链表,直到遇到Vf(Valid Flag)为0的TD或链表结束。
- 等时传输优先:在链表遍历过程中,等时传输TD(Isochronous)不等待握手包,UHCI连续执行后续TD,确保每帧的等时数据准时发送。
- 中断传输插入:中断TD可以在链表任意位置插入,UHCI在完成中断TD后根据中断使能位决定是否触发系统中断。
- 批量传输填充:批量TD通常放置在链表尾部,利用帧剩余时间进行传输,若帧时间不足则延迟到下一帧。
| 传输类型 | TD在链表中的位置 | DMA行为特点 | 帧时间敏感性 |
|---|---|---|---|
| 等时传输 | 链表头部 | DMA读写数据缓冲区,不等待握手 | 高,必须每帧完成 |
| 中断传输 | 链表中部 | DMA读写后检查中断使能位 | 中,可延迟1~2帧 |
| 批量传输 | 链表尾部 | DMA读写,等待握手,可重试 | 低,利用帧剩余时间 |
| 控制传输 | 链表任意位置 | DMA读写,包含SETUP/IN/OUT阶段 | 中,需保证完整事务 |
FPGA验证策略:在验证UHCI与DMA协同工作时,建议构造以下测试场景:
1. 单帧单TD:验证最基本的DMA读取TD、数据缓冲区DMA传输、状态写回流程。
2. 单帧多TD链表:验证链表遍历、Link Pointer解析、Vf位终止逻辑。
3. 多帧交替链表:验证帧列表不同表项指向不同链表,帧号切换时DMA地址的正确切换。
4. 等时+批量混合:验证等时TD不等待握手、批量TD等待握手、帧时间耗尽时批量TD延迟到下一帧。
1. 单帧单TD:验证最基本的DMA读取TD、数据缓冲区DMA传输、状态写回流程。
2. 单帧多TD链表:验证链表遍历、Link Pointer解析、Vf位终止逻辑。
3. 多帧交替链表:验证帧列表不同表项指向不同链表,帧号切换时DMA地址的正确切换。
4. 等时+批量混合:验证等时TD不等待握手、批量TD等待握手、帧时间耗尽时批量TD延迟到下一帧。
4.5 DMA地址生成与总线主控协议
UHCI作为PCI/PCIe总线主控设备,其DMA地址生成遵循以下规则:
- 帧列表基地址:由FLBASEADD寄存器提供,UHCI内部将帧号(0~1023)左移2位后与基地址相加,生成帧列表表项的DMA读地址。
- TD地址:从帧列表表项或前一个TD的Link Pointer中获取,UHCI直接使用该物理地址发起DMA读事务。
- 数据缓冲区地址:从TD的Buffer Pointer字段获取,UHCI根据传输方向发起DMA读(OUT)或DMA写(IN)事务。
- 状态写回地址:与TD读取地址相同,UHCI在传输完成后对TD的Control/Status字段执行DMA写操作。
调试建议:在FPGA验证环境中,使用逻辑分析仪或总线监视器捕获UHCI发起的DMA事务。重点关注:
- DMA读事务的地址是否落在帧列表/TD/数据缓冲区的预期范围内。
- DMA写事务的地址是否与TD读取地址一致(状态写回)。
- 等时传输的DMA事务是否在帧时间窗口内完成,避免影响下一帧调度。
- DMA读事务的地址是否落在帧列表/TD/数据缓冲区的预期范围内。
- DMA写事务的地址是否与TD读取地址一致(状态写回)。
- 等时传输的DMA事务是否在帧时间窗口内完成,避免影响下一帧调度。
4.6 帧列表与TD的典型异常场景
在FPGA验证中,帧列表与TD协同工作的异常通常表现为以下模式:
| 异常现象 | 可能原因 | 验证检查方法 |
|---|---|---|
| 帧列表DMA读返回全0 | FLBASEADD配置错误、内存未初始化、DMA地址越界 | 检查寄存器配置、内存初始化序列、地址对齐 |
| TD链表遍历提前终止 | Link Pointer的Vf位被错误清零、链表断裂 | 检查TD的Link Pointer字段、链表完整性 |
| 数据缓冲区DMA地址错误 | Buffer Pointer未页对齐、缓冲区被覆盖 | 验证缓冲区地址对齐、内存保护机制 |
| 状态写回未生效 | DMA写事务未完成、TD所在内存只读 | 检查DMA写完成信号、内存属性配置 |
| 等时传输数据错位 | 帧列表更新与帧号不同步、DMA延迟过大 | 检查帧号计数器与帧列表索引的同步时序 |
| 中断丢失 | TD中断使能位未设置、中断控制器未响应 | 检查TD的Interrupt on Complete位、中断路由 |
关键验证指标:在FPGA验证中,必须确保UHCI的DMA引擎在每帧1ms时间内完成所有TD的获取、数据缓冲区DMA传输和状态写回。对于等时传输,建议预留至少30%的帧时间余量,以应对DMA延迟抖动。如果DMA事务超过帧时间边界,UHCI将截断当前传输并强制开始下一帧,导致数据丢失。
通过深入理解帧列表与传输描述符的层次关系、DMA地址生成机制以及协同调度规则,FPGA验证工程师可以快速定位UHCI等时传输中的DMA异常,确保USB主机控制器在FPGA平台上的正确实现。