DDR Core and Transaction Scheduler (DDRC)是内存管理系统中一个关键组件,它主要负责管理和调度对DDR(Double Data Rate,双倍数据率)内存的读写操作。这个组件对于确保系统能够高效地访问内存至关重要,特别是在处理多个并发内存请求时。
DDRC由未决读写事务的队列和从队列中弹出并将下一个事务发送到DDR PHY的调度器组成。在DDRI和DDRC之间,有仲裁逻辑来决定下一个将哪个事务发送到DDRC。
行(Row)、Bank和列(Column)地址映射
DDRC负责将PS(Processing System)和PL(Programmable Logic)AXI主设备使用的字节可寻址的物理地址映射到DDR的行(Row)、Bank和列(Column)地址。这种地址映射具有一定的可配置性,允许用户根据特定的数据访问模式进行优化,以提高DDR的利用率并减少页面和行变更的开销。
许多地址重映射组合不可用,特别是完整的存储体行列映射。
地址映射器负责将线性的请求地址(通常来自PS或PL的AXI主设备)映射到DRAM的实际地址上。这个映射过程通过选择AXI地址中的特定位来对应DRAM地址中的每一位来实现。然而,要使整个可用的地址空间对用户完全可访问,必须确保DRAM地址中的每一位都是由AXI地址中唯一的一位来确定的,即不能有两位DRAM地址位由AXI地址中的同一位来同时决定。
在DDR控制器(DDRC)中,DRAM行(Row)、Bank和列(Column)地址的每一位都通过相应的寄存器向量与AXI地址的某一位相关联,这些寄存器向量通常包括DRAM_addr_map_bank
、DRAM_addr_map_row
和DRAM_addr_map_col
。这种映射机制允许用户根据需要配置AXI地址空间如何映射到DRAM的物理地址空间上。对于每个DRAM地址位(无论是行、Bank还是列),其关联的AXI地址位是通过将给定寄存器的内部基址与为该寄存器编程的值相加来确定的。这个过程可以用以下公式来描述:
[internal base] + [register value] = [AXI address bit number]
例如,从reg_ddrc_addmap_col_b3的描述中可以看出,该寄存器确定了DRAM列位4的映射,其内部基址为6。当使用全数据总线时,DRAM列位4由以下决定:
[internal base] + [register value]
如果reg_ddrc_addmap_col_b3寄存器被编程为2,则AXI地址位为:
6 + 2 = 8
换句话说,发送到DRAM的列地址位4被映射到AXI地址位*_ADDR[8]。
在半总线宽度模式(包括ECC)下,所有列位左移一位。在这种情况下,reg_ddrc_addmap_col_b2确定DRAM列地址位4的映射。在全总线宽度的情况下,reg_ddrc_addmap_col_b3确定DRAM列地址4。
DDRC仲裁
DDRC Arbitration(DDRC仲裁)主要涉及在DDR(Double Data Rate,双倍数据速率)内存系统中,对多个访问请求进行管理和调度,以确保数据访问的有序性和高效性。
DDRC仲裁分为三个阶段(见图10-5):
- 第一阶段是AXI读/写端口仲裁
- 第二阶段是读写比赛的获胜者
- 第三阶段是事务调度程序
优先级、老龄计数器和紧急信号
DDR控制器仲裁是基于老化循环的。循环机制循环扫描所有请求设备,并在再次为同一设备提供服务之前为所有未完成的请求提供服务。老化机制测量每个请求等待的时间,并为等待时间较长的请求分配更高的优先级。
每个DDRC读写端口都被分配了一个10位优先级值(如寄存器axi_priority_wr_port0-3和axi_priority _rd_port0-3)。此值用作倒计时老化计数器的初始值。因此,在任何时刻,较低的老化计数器值都优先于较高的值。
此外,每个DDRC读写端口都有一个紧急输入信号。此信号可重置老化计数器。当断言紧急时,该端口的老化计数器会重置,立即使该端口的优先级最高。紧急位的来源可通过SLCR主机可编程寄存器(DDR_urgent_SEL)选择为以下之一:
- 端口AXI接口中4位QoS信号的最高有效位(除用于CPU和APU使用的内存端口0)
- 可编程SLCR寄存器值(DDR_URGENT)
- PL信号DDRARB[3:0]位之一
虽然优先级值本质上是静态的,但可以操纵紧急比特和QoS信号动态。
页面匹配
为了提高DDR利用率,将每个新请求的地址与前一个请求的地址进行比较。DDRC倾向于接收与前一个请求位于同一页面的新请求。内存端口比较地址以确定是否存在页面匹配。只要继续有页面点击,仲裁器选择的端口就会继续获得优先级(优先级0)。它们将与优先级为0的其他端口竞争。
页面大小由page_MASK(所有位都是掩码的32位寄存器)定义,并且始终是地址对齐的。为了正常运行,软件必须对page_MASK中的页面大小进行编程,以匹配DDR内存的大小。将此寄存器设置为0将禁用仲裁的页面匹配步骤。
老化计数器
当请求处于挂起状态且未得到服务时,会启用递减老化计数器。此计数器的起始值从优先级寄存器中的10位值加载(axi_priority_<rd/wr>_port<n>,有8个寄存器,每个端口一个)。当请求得到处理时,计数器会重新加载。此计数器的值用于帮助指示AXI内存端口的优先级。此计数器的数值越低,优先级越高。当优先级达到0时,请求具有最高优先级。
出于仲裁目的,仅使用最高位的5位来区分端口之间的优先级。这使仲裁机制保持在可管理的大小和延迟,同时仍然理解每个端口基于年龄的优先级的近似值。
在正常使用模式下,建议启用老化功能。禁用老化可能会导致低优先级端口的过度延迟/饥饿。
第一阶段——AXI端口仲裁
八个端口(四个读端口和四个写端口)竞争以使DDRC接受他们的请求。仲裁器根据许多因素批准请求。读和写请求被同等对待,这意味着它们经过相同的仲裁。每个端口都保持一个优先级,该优先级从预设状态稳定地移动到最高状态或0。此机制对于保持端口上的最小带宽非常重要。每个端口也有不同的方式来通知紧急情况,无论是基于每个事务(QoS)还是针对多个事务。对于低延迟主设备来说,每个事务的紧迫性可能很好。
图10-6所示的优先级具有以下逻辑。如果老化计数器中有优先级为0或0的端口(最高优先级),则获胜。如果没有优先级为0的端口,仲裁将检查正在服务的端口是否具有页面匹配。如果没有页面匹配,则老化计数器中的最低值获胜。如果老化计数器中的最低值出现平局,则使用循环来解决任何平局。
第二阶段——读与写
读取和写入在DDR Core中都有一个队列。然后,这些队列中的条目争夺下一级仲裁,如图10-7所示。
如图10-7所示,仲裁的这一阶段从老化计数器开始。如果存在优先级为0的同类交易,则获胜。例如,如果一个读取赢得了最后一轮仲裁,并且有一个优先级为0的读取,则它获胜。如果不存在优先级为0的同一类型的事务,并且存在优先级为零的另一类型的交易,则获胜。如果队列中没有优先级0,则它将保持相同类型的事务。在上述所有情况下,在选择任何请求之前,都会进行适当的信用可用性检查。
高优先级读取端口
在进入仲裁的第三阶段之前,需要描述DDRC的一个特征,即高优先级读取。HPR或高优先级读取功能允许将DDRC内的读取数据队列(32个字)拆分为两个单独的队列,分别用于低优先级和高优先级。四个读取端口中的每一个都可以被分配低或高优先级。默认情况下,此功能处于禁用状态。使用时,高优先级读取设备不会因低优先级设备的读取数据速率(可能较慢)而减慢速度。在典型的用例中,HPR在端口0(CPU)上启用,从而降低了CPU的平均读取延迟。读取数据队列的分割不必是两个相等的部分。因此,为CPU提供了一个小队列,以绕过较大的队列,为需要较低延迟的读取提供服务。图10-8显示了读取队列的分割位置。
这可以通过将AXI端口的reg_arb_set_hpr_rd_port<n>位设置为1'b1来更改(见AXI_priority_<rd/wr>_port<n>寄存器)。DDRC默认配置为仅服务LPR。默认情况下,读取的CAM只能为LPR提供服务。读取的CAM总深度为32(始终为ECC分配一个插槽)。ddrc ctrl_reg1寄存器中的reg_ddrc_lpr_num_entrys寄存器字段指定了为lpr保留的条目数。取31并减去reg_ddrc_lpr_num_entrys,得到为HPR保留的条目数。
如果端口配置为HPR端口,则有必要更改REG_DDRC_LPR_NUM_ENTRIES字段,以避免信用机制中的死锁。
第三阶段——交易状态
事务状态是事务进入DDR PHY和DDR设备之前的最后一个仲裁阶段。可以读取或写入事务状态。要更改事务状态,必须不再有该类型的事务,否则可能会有其他类型的关键事务。图10-9显示了用于此的简单状态机。
事务状态保持不变,直到另一种类型的事务变得关键或不再有这种类型的事务。状态机默认为读取状态。表10-4显示了队列中的事务如何从正常状态变为关键状态。
正常 | 关键 | 此事务存储的一个事务一直处于挂起状态,并且在32个周期计时器的*_max_starve_x32个脉冲计数内未得到服务。 |
关键 | 硬非关键 | *_xact_run_length此事务存储已处理的事务数。 |
硬非关键 | 正常 | *_在这种状态下已经过了min_non-critical循环数。 |
以低优先级读取事务存储为例,预计事务存储通常基于以下信号独立运行:
- lpr_max_starvex32
- lpr_xact_run_length
- lpr_min_non-critical
DDRC ctrl_reg2寄存器中的reg_arb_go2critical_en字段使仲裁器能够将co_gs_go2critical_*信号驱动到DDRC。AXI上有侧带信号(awurgent 和 arurgent)驱动co_gs_go2critical_*信号。如果任何端口断言其紧急侧带信号,并且启用了此功能,则仲裁器向控制器断言相应的co_gs_go2critical_*信号。
在控制器内部,该信号的断言导致状态机从一个状态切换到另一个状态。例如,如果DDRC当前正在为读取提供服务,并且co_gs_go2critical_wr变为高,则控制器会忽略正常的状态切换方法(饥饿计数器等),并跳到为写入提供服务。控制器中有一个寄存器,用于控制在切换到另一种命令类型之前,为当前命令类型提供服务的时间(ddrc ctrl_reg2中的reg_ddrc_go2critical_hysteresis字段)。
总之,此go2critical功能用于控制器中,可确保在具有超高优先级的事务的读写之间快速切换。
注意:
- 正常编程条件预计为reg_ddrc_preform_Write=0。(这是DRAM_param_reg4寄存器中的一个位字段)这意味着当空闲控制器接收到读取请求时,总是会立即提供服务。此外,通常希望将reg_ddrc_rdwr_idle_gap(此字段位于ddrc_ctrl寄存器中)设置为非常低的数字(如0、1或2),以确保写入不会在空闲的控制器中持续任何时间,从而浪费带宽。(这里的权衡是,通过更快地为写入提供服务,在写入后立即向控制器发出的读取可能会导致额外的延迟,从而允许对写入进行服务并扭转总线局面。)
- 由于向控制器发出的所有请求都保证了顺序,因此写入延迟不应成为系统设计的问题。(如果后续读取需要写入数据,控制器会在为读取提供服务之前自动强制将写入数据输出到DRAM。)
读优先级管理
通常在读取模式下,高优先级读取请求比低优先级读取请求更适合服务。然而,如果低优先级读取事务存储是关键的,而高优先级读取事务存储器不是,那么低优先级读取请求比高优先级读取请求更可取。这可以防止低优先级读取的饥饿。
写入组合
写入组合功能允许将对同一地址的多次写入合并为对DRAM的一次写入。当新写入与CAM中的排队写入冲突时:
- 如果启用了写合并,DDRC会用新写的数据覆盖旧写的数据,并且只执行一个写事务(写合并)。
- 如果禁用写组合,DDRC将遵循以下操作顺序:
- 将新的写入事务保存在临时缓冲区中
- 将流控制应用回核心,以防止更多事务到达
- 刷新包含冲突事务的内部队列,直到该事务得到处理
- 接受新交易并取消流量控制
信用机制
DRAM控制器采用信用机制来确保缓冲区不会溢出(未决DDR事务)。向控制器发出请求的接口只能请求已被授予信用或队列中开放插槽的命令。
以下三种命令类型的积分分别跟踪:
- 高优先级读取
- 低优先级读取
- 写
每种命令类型的信用点数(credits)是根据一定的规则独立计算的。这些规则旨在管理接口向控制器发送请求的能力,确保不会因请求过多而导致控制器过载。
- 初始状态:接口开始时拥有零个信用点数。这意味着在没有从DRAM控制器接收到任何信用点数之前,接口不能发送任何命令请求。
- 信用点数的发放:当DRAM控制器的复位信号被释放(即去断言)后,控制器会根据需要向接口发放信用点数。这通过在每个时钟上升沿上断言(即激活)相应的
*_credit
信号来实现,其中*
代表不同类型的命令。对于每种命令类型,都有一个独立的信用点数计数器。每当相应的*_credit
信号被断言时,对应类型的信用点数计数器就会增加。 - 发送请求:当某种类型的信用点数计数器大于零时,接口可以向DRAM控制器发送该类型的请求。这表示接口有足够的“权限”或“信用”来发送这种类型的命令。每次向控制器发送请求时,与该请求类型相关的信用点数计数器就会减少。这是为了确保接口不会发送超出其被授权范围的请求数量。