4. DRP 接口原理
DRP 接口,说白了就是 GTY 内部的配置通道。你想动态改那些高速参数,比如 CDR 频率、差分摆幅、均衡强度,都得通过它。我个人觉得理解 DRP,基本就拿到了动态重配置的钥匙。
好,我们正式开始。这节内容分四个部分:总线协议、地址映射、读写时序、跨时钟域处理。
4.1 DRP 总线协议
DRP 用的是简单的同步并行总线。说白了就三组信号是核心:地址总线、数据总线和控制信号。
| 信号分类 | 信号名 | 方向 | 描述 |
|---|---|---|---|
| 地址总线 | DRPADDR[8:0] | 输入 | 9位地址,可寻址 512 个寄存器 |
| 数据总线 | DRPDI[15:0] | 输入 | 写数据通道 |
| 数据总线 | DRPDO[15:0] | 输出 | 读数据通道 |
| 控制信号 | DRPEN | 输入 | 操作使能 |
| 控制信号 | DRPWE | 输入 | 写使能(1=写,0=读) |
| 状态信号 | DRPRDY | 输出 | 操作完成标志 |
4.2 地址映射
GTY Quad 里的每个通道(CH0 ~ CH3)都有独立的 DRP 地址空间。记住一个关键点:地址的高位是通道选择位。
我个人习惯用这样的方式记忆:
- A[8:7]:通道选择。00=CH0,01=CH1,10=CH2,11=CH3
- A[6:0]:寄存器偏移地址。每个通道内部有 128 个寄存器
举个例子,CH1 的 TX 偏置控制寄存器,地址是 8'b01_0001010。这里的 01 就是 CH1,后面就是寄存器内部偏移。
4.3 读写时序
DRP 的时序比较简单。但它对时钟频率有要求——DRPCLK 最高只能跑到 200MHz。如果你用 300MHz 去敲它,数据可能就错了。
读操作时序
// 读操作步骤
// 1. 拉高 DRPEN,拉低 DRPWE(读模式)
// 2. 给出 DRPADDR
// 3. 等待 DRPRDY 拉高
// 4. 从 DRPDO 上读取数据
always @(posedge drp_clk) begin
if (drp_rd_start) begin
drp_state <= DRP_READ;
DRPEN <= 1'b1;
DRPWE <= 1'b0;
DRPADDR <= rd_addr;
end
if (drp_state == DRP_READ && DRPRDY) begin
rd_data <= DRPDO;
DRPEN <= 1'b0;
drp_state <= DRP_IDLE;
end
end
写操作时序
// 写操作步骤
// 1. 拉高 DRPEN,拉高 DRPWE(写模式)
// 2. 给出 DRPADDR 和 DRPDI
// 3. 等待 DRPRDY 拉高
// 4. 写完成
always @(posedge drp_clk) begin
if (drp_wr_start) begin
drp_state <= DRP_WRITE;
DRPEN <= 1'b1;
DRPWE <= 1'b1;
DRPADDR <= wr_addr;
DRPDI <= wr_data;
end
if (drp_state == DRP_WRITE && DRPRDY) begin
DRPEN <= 1'b0;
drp_state <= DRP_IDLE;
end
end
你看,每次操作只需要一个上升沿来发起,然后等待 DRPRDY 拉高就行了。但要注意:DRPRDY 不会在一个周期内就变高,中间会有几个周期的延迟,具体看 DRPCLK 的频率。
4.4 跨时钟域处理
你的用户逻辑多半跑在 300MHz 以上,但 DRP 只能跑 200MHz。这就引出了跨时钟域问题。
我的做法是搞一个异步 FIFO,专门做跨时钟域同步。用户侧写请求写 FIFO,DRP 侧从 FIFO 读操作去执行。这样两边时钟域就隔离开了。
为什么一定要这么做?因为你不能直接把用户时钟域的使能信号打到 DRP 时钟域去。单拍的亚稳态风险很高,尤其是在温度或电压波动大的时候。
好了,这节的核心知识点差不多就是这些。下面这张图把整个 DRP 交互路径画出来了,你对着看会更清楚。
图里把整个流程串起来了。从用户逻辑写入异步 FIFO,再到 DRP 状态机以慢时钟从 FIFO 读出指令、执行读写、等待 DRPRDY,最后把结果回写。这个 FIFO 既是跨时钟域的桥梁,也是流量控制的关键。