62 / 63 · 概念
寄存器接口与副作用发生时刻
规定地址、字节写入与响应暂停,使一个请求准确对应一次状态改变。
课时内容可免费阅读,选课后可保存学习进度。
定义“写寄存器”这一行为
先修知识:地址译码器译码器 激活与二进制编码对应的输出线的电路。带 enable 时,可在禁用状态下将所有输出置 0。了解更多、ready/valid握手 发送端 valid 与接收端 ready 在同一边沿均为 1 时,确认传输的约定,也包括等待期间的数据保持规则。了解更多、enable 与状态更新优先级。
将配置寄存器寄存器 存储多位状态的电路。本课程中的同步寄存器在时钟边沿存储指定输入。了解更多连接到外部控制器时,只检查地址匹配并不够。还要定义请求接受时刻、响应等待期间的保持条件,以及写入只读地址时的行为。这里采用同一时钟下简单的单请求、单响应接口。
下列地址为按字节编址,并采用 32 位对齐。每个请求准确生成一个成功或错误响应。
| 地址 | 名称 | 行为 |
|---|---|---|
| 0x0 | CONFIG | 可读写,应用字节选通 |
| 0x4 | STATUS | 只读,返回接受请求时的值 |
| 0x8 | COMMAND | 读取为 0,写入 byte 0 的 bit 0 时产生 start 脉冲 |
| 其他 | 未定义 | 错误响应,不改变状态 |
响应槽为空或即将腾空的边沿才接受
module register_interface (
input logic clk, rst,
input logic req_valid, req_write,
output logic req_ready,
input logic [3:0] req_addr,
input logic [31:0] req_wdata,
input logic [3:0] req_wstrb,
output logic rsp_valid,
input logic rsp_ready,
output logic [31:0] rsp_rdata,
output logic rsp_error,
input logic [31:0] status_value,
output logic [31:0] config_value,
output logic start_pulse
);
assign req_ready = !rsp_valid || rsp_ready;
always_ff @(posedge clk) begin
if (rst) begin
rsp_valid <= 1'b0;
config_value <= 32'd0;
start_pulse <= 1'b0;
end else begin
start_pulse <= 1'b0;
if (req_ready) begin
rsp_valid <= req_valid;
if (req_valid) begin
rsp_rdata <= 32'd0;
rsp_error <= 1'b0;
case (req_addr)
4'h0: begin
if (req_write) begin
for (int i=0; i<4; i++)
if (req_wstrb[i])
config_value[8*i +: 8]
<= req_wdata[8*i +: 8];
end else rsp_rdata <= config_value;
end
4'h4: begin
if (req_write) rsp_error <= 1'b1;
else rsp_rdata <= status_value;
end
4'h8: begin
if (req_write)
start_pulse <= req_wstrb[0] && req_wdata[0];
end
default: rsp_error <= 1'b1;
endcase
end
end
end
end
endmodule响应受阻时 req_ready=0,因此配置写入和命令脉冲不会重复执行。已接受请求的副作用可能已经发生,只是响应仍在等待。若仅因响应延迟就无条件重发请求,命令可能重复执行。
计算字节选通的含义
CONFIG=32'h11223344 时,写入 req_wdata=32'hAABBCCDD、req_wstrb=4'b0101,只有 byte 0 与 byte 2 改变,结果为 32'h11BB33DD。应分别确认地址对齐、位位置与存储器字节顺序。wstrb=0000 的写入生成成功响应,但不改变数值。
从 MSBMSB 权重最高的比特。其索引取决于向量声明方向,不能总认为它是编号最大的位。了解更多 起依次为 byte3、2、1、0。strobe=0101 选择 byte2 与 byte0,因此只写入 BB 和 DD。strobe 的每一位控制一个字节写使能,而非只控制一个数据比特。
- 旧 CONFIG: 11 | 22 | 33 | 44
- 写入数据: AA | BB | CC | DD
- strobe 0101: 保持 | 替换 | 保持 | 替换
- 新 CONFIG: 11 | BB | 33 | DD
状态值属于哪个时刻?
STATUS 读取响应保存请求被接受时的 status_value。此后即使响应暂停期间实际 status 改变,rsp_rdata 也必须保持。rsp_valid=1、rsp_ready=0 时,若将组合 status 直接连接到响应,响应内容会变化,违反协议。
连续两个边沿 req_valid 与 req_ready 都为 1,就表示两个不同请求。发送方在接受后应撤销 valid,或更新为下一个请求,不能持续保持同一请求却期待只处理一次。
验证的三个方面
- 地址与访问权限:检查有效地址、未对齐地址、STATUS 写入和未定义地址的错误响应与副作用。
- 数据选择:穷举四个 strobe 位,确认未使能字节得到保留。
- 流量控制:即使阻塞响应多个周期,响应与状态也应保持;响应消费与下一请求接受重叠时,事务计数仍须一致。
自己试试
接受 req_wstrb[0]=1、req_wdata[0]=1 的 COMMAND 写入后,rsp_ready=0 持续三个周期。start_pulse 是否应连续重复三个周期?写 STATUS 可以改变 config_value 吗?
阅读解释
start_pulse 只在接受请求后的一个周期为 1,随后归 0。响应暂停不是重复执行命令的条件。STATUS 写入生成错误响应,不改变 config_value 或其他状态。响应完成前的重试策略也必须由收发双方共同约定。