Palladium 事务级实战 · 03 实现硬件侧 transactor
将接口调用转换为有界握手,用状态机执行 FIFO 操作并处理注册读延迟。
先修知识完成 Palladium FIFO 六章基础课程,理解同步 FIFO、非阻塞赋值与 VALID/READY。
适用环境本地 Python 3 + Icarus Verilog;目标参考 WXE 24.05 ISR5 / Xcelium 配套环境。
验证状态13 项本地 RTL 场景、6 项测量校验测试通过;Cadence 编译、Palladium 映射与设备性能尚未实测。
两层 transactor 各司其职
fifo_link 的 exchange 将固定参数转换为请求握手,并等待完整响应;batch_engine 执行 FIFO 引脚级操作。前者是面向官方 interface task 路径的参考,后者是普通可综合 RTL。官方 tb_export 用于导出硬件侧阻塞 task;本地 Icarus 不启用该映射,仅通过层次 task 调用验证逻辑行为。映射是否接受 task 中的循环与等待,仍必须由目标版本编译确认。
状态机如何处理 full、empty 与读延迟
pushed 和 popped 只在实际接受写入、读出时增加。rd_en 以固定周期暂停,让小深度 FIFO 真正遇到反压;popped 统计读请求,captured 统计已经采集的返回字节,两者不能混用。pending_read 延迟一拍读取 dout,恰好对应原 FIFO 的非阻塞注册输出。最后一次 capture 后才进入 RESPONSE,避免过早完成。
- 对照 course_fifo.sv 的输出更新方式
预期与判定:dout 在接受读操作的时钟沿更新
- 检查 pending_read / captured
预期与判定:下一拍才消费注册输出
- 运行 response-backpressure 场景
预期与判定:延后接收仍保持响应稳定
- 启用 COURSE_BUG 故障
预期与判定:逐字节 scoreboard 检出 TBA_DATA
实验包中的实际源码;本地 Icarus 已验证。商业工具脚本为待目标环境验证的参考。
// Original synthesizable transaction engine. One command in flight, max 32 bytes.
module batch_engine(input wire clk,rst,
input wire req_valid,output wire req_ready,input wire [15:0] req_id,
input wire [5:0] req_len,input wire [255:0] req_data,
output wire rsp_valid,input wire rsp_ready,output reg [15:0] rsp_id,
output reg [5:0] rsp_len,output reg [1:0] rsp_status,
output reg [255:0] rsp_data,output reg [31:0] rsp_cycles);
localparam IDLE=0,ACTIVE=1,RESPONSE=2;
reg [1:0] state=IDLE;
reg [255:0] data;
reg [5:0] length,pushed,popped,captured;
reg pending_read;
wire full,empty;wire [7:0] dout;wire [2:0] count;
wire wr_en=state==ACTIVE && pushed<length;
// A fixed, repeatable drain pause exercises FIFO full/backpressure.
wire rd_en=state==ACTIVE && popped<length && rsp_cycles[2:0]>=3;
wire [7:0] din=data[8*pushed+:8];
course_fifo dut_i(clk,rst,wr_en,rd_en,din,dout,full,empty,count);
assign req_ready=state==IDLE && !rst;
`ifdef DROP_RESPONSE
assign rsp_valid=1'b0;
`else
assign rsp_valid=state==RESPONSE && !rst;
`endif
always @(posedge clk) begin
if(rst)begin
state<=IDLE;data<=0;length<=0;pushed<=0;popped<=0;captured<=0;
pending_read<=0;rsp_id<=0;rsp_len<=0;rsp_status<=0;rsp_data<=0;rsp_cycles<=0;
end else case(state)
IDLE:if(req_valid)begin
data<=req_data;length<=req_len;pushed<=0;popped<=0;captured<=0;pending_read<=0;
`ifdef BAD_TAG
rsp_id<=req_id^16'h1;
`else
rsp_id<=req_id;
`endif
rsp_len<=req_len;rsp_data<=0;rsp_cycles<=0;
if(req_len==0 || req_len>32)begin rsp_status<=2;state<=RESPONSE;end
else begin rsp_status<=0;state<=ACTIVE;end
end
ACTIVE:begin
rsp_cycles<=rsp_cycles+1;
if(wr_en&&!full)pushed<=pushed+1'b1;
pending_read<=rd_en&&!empty;
if(rd_en&&!empty)popped<=popped+1'b1;
// FIFO dout updates on the read edge; consume it on the following edge.
if(pending_read)begin
rsp_data[8*captured+:8]<=dout;captured<=captured+1'b1;
if(captured+1==length)state<=RESPONSE;
end
end
RESPONSE:if(rsp_ready)state<=IDLE;
default:state<=IDLE;
endcase
end
endmodule
时钟模型不等于硬件频率
clk_gen 在语言级仿真里用延时产生时钟,而硬件执行依赖官方流程中的时钟转换选项。把模块移入硬件层次时必须同步修改 +iscDelay 的模块选择,不能仅凭本地波形的 10 ns 周期宣称设备运行在 100 MHz。参考脚本与原始模块一并保留,实际环境应检查时钟转换报告、运行进度和复位退出后的第一次请求。
| 项目 | 规定 / 观察结果 |
|---|---|
| 时钟没有推进 | 先检查模块层次、转换选项和设备运行状态 |
| req_valid 等待 | 检查 rst、IDLE 和 req_ready |
| popped 增加但 captured 不对 | 核对 registered dout 与 pending_read |
| 响应消失 | 检查 RESPONSE 是否保持到 ready,而非一拍脉冲 |
实验包中的实际源码;本地 Icarus 已验证。商业工具脚本为待目标环境验证的参考。
`timescale 1ns/1ps
// Palladium reference flow maps this generator using +iscDelay+clk_gen.
// Do not treat a free-running #delay as ordinary synthesizable RTL.
module clk_gen(output reg clk=0);
always #5 clk=~clk;
endmodule
故障练习:丢失响应的有界退出
交换函数对请求接受和响应完成分别限制最多 2048 个时钟沿,缺失响应返回 status=3。这是教学工程的周期级保护,不是设备失联时的墙钟 watchdog;若硬件时钟不再推进,循环本身也不会推进。生产运行还应在调度器或站点脚本中设置外部时间限制,并保存首个异常与设备状态后结束作业。
完成检查
- 读请求数与已收集字节数分开。
- 响应在反压期间保持稳定。
- 周期超时与墙钟超时没有混淆。
延伸阅读与来源
本文为黄河电子原创教学说明。产品命令与支持范围请以实际安装版本的官方文档为准。
- Cadence Palladium 官方入口;WXE 24.05 TBA Tutorial
TBA Tutorial 第 22–23、36–39 页;compileIXCOM 第 269 页。页码指用户提供的本地安装文档印刷页;公开链接为产品入口,并非受限手册下载。
继续阅读
硬件仿真首次使用前的工程检查清单
准备版本、输入和模型,减少第一次编译的无效往返。
如何选择 SA/ICE 及交互方式
根据测试环境所在位置与目标接口要求选择运行流程。
完成最小设计的编译运行
把第一次平台运行拆为有检查点的五个阶段。
黄河电子