Palladium 事务级实战 · 02 定义批事务、完成和复位协议

固定 256 位载荷、单事务在途、显式状态与事务编号,避免把提交误认为完成。

先修知识完成 Palladium FIFO 六章基础课程,理解同步 FIFO、非阻塞赋值与 VALID/READY。

适用环境本地 Python 3 + Icarus Verilog;目标参考 WXE 24.05 ISR5 / Xcelium 配套环境。

验证状态13 项本地 RTL 场景、6 项测量校验测试通过;Cadence 编译、Palladium 映射与设备性能尚未实测。

本文目录先冻结协议,再编写驱动用可执行 host 检查协议的每一层响应必须保持,复位必须有边界故障练习:编号正确不代表结果完整

先冻结协议,再编写驱动

本例最大一次交换 32 字节,payload 为固定 256 位向量,最低八位装第一个字节,未使用字节补零。len 表示有效字节数而不是向量位数。固定参数便于检查映射边界,但 BATCH=1 依然携带固定宽度参数,因此调用次数降低不等于传输字节按同样比例降低。接口使用静态 task,仅允许一个调用者和一个在途事务。

接收请求、完成执行和软件收到返回值是三个不同事件。requestid / len / payloadacceptvalid && readyexecute写入 → 读回responseid / len / status / data先明确完成条件,再跨越软硬件边界
接收请求、完成执行和软件收到返回值是三个不同事件。(原创示意,非器件引脚图;窄屏可横向滑动)
工程契约与验收证据
项目规定 / 观察结果
id / len16 位编号;6 位长度,正常范围 1…32
data256 位;第 i 字节位于 [8*i +: 8]
status0 成功;2 非法长度;3 接口等待超时
复位启动或事务之间;不支持在途取消与自动重试

用可执行 host 检查协议的每一层

host 先检查 status,再比较返回 id 和长度,最后逐字节验证数据。任何一层失败立即终止本次运行,不能继续将后续结果混入性能样本。N=65、BATCH=16 的最后一批长度为 1,能够检查尾批处理;id 在当前 N 上限下不会回绕。跨运行重试或多个客户端需要 epoch 和更严格的关联规则,当前接口没有声称提供这些能力。

  1. 运行 python3 test.py

    预期与判定:batch1 / 4 / 16 / 32 全部对照通过

  2. 检查 partial-tail 场景

    预期与判定:65 字节、5 次 exchange、121 个 ACTIVE 周期

  3. 检查 bad-tag 故障

    预期与判定:TBA_TAG 被测试脚本识别为预期失败

  4. 检查 invalid-length 故障

    预期与判定:TBA_STATUS status=2,不能记录成功样本

实验包中的实际源码;本地 Icarus 已验证。商业工具脚本为待目标环境验证的参考。

systemverilog
module tb_host;
 integer n=64,batch=16,seq=0,j,len,calls=0,cycles=0,fd,meta,unused;
 reg [15:0] id=0,returned_id;
 reg [5:0] returned_len;
 reg [1:0] status;
 reg [255:0] request,result;
 reg [31:0] active_cycles;
 reg [7:0] expected;
 initial begin
  unused=$value$plusargs("N=%d",n);unused=$value$plusargs("BATCH=%d",batch);
  if(n<8||n>100000||batch<1||batch>32)$fatal(1,"TBA_CONFIG");
  fd=$fopen("transactions.csv","w");if(!fd)$fatal(1,"TBA_IO");
  $fdisplay(fd,"seq,data");
  hw_top.link.reset_hw();
  while(seq<n)begin
   len=(n-seq<batch)?n-seq:batch;request=0;
   for(j=0;j<len;j=j+1)request[8*j+:8]=((seq+j)*17+3)%256;
   if($test$plusargs("BAD_REQUEST")&&seq==0)len=0;
   hw_top.link.exchange(id,len,request,returned_id,returned_len,status,result,active_cycles);
   if(status!==2'b00)$fatal(1,"TBA_STATUS status=%0d id=%0d (2=length,3=timeout)",status,id);
   if(returned_id!==id)$fatal(1,"TBA_TAG expected=%0d actual=%0d",id,returned_id);
   if(returned_len!==len)$fatal(1,"TBA_LENGTH");
   for(j=0;j<len;j=j+1)begin
    expected=((seq+j)*17+3)%256;
    if(result[8*j+:8]!==expected)$fatal(1,"TBA_DATA seq=%0d expected=%0d actual=%0d",seq+j,expected,result[8*j+:8]);
    $fdisplay(fd,"%0d,%0d",seq+j,result[8*j+:8]);
   end
   calls=calls+1;cycles=cycles+active_cycles;id=id+1'b1;seq=seq+len;
   if($test$plusargs("RESET_BETWEEN"))hw_top.link.reset_hw();
  end
  $fclose(fd);meta=$fopen("result.json","w");if(!meta)$fatal(1,"TBA_IO");
  $fwrite(meta,"{\"status\":\"PASS\",\"transactions\":%0d,\"batch\":%0d,\"calls\":%0d,\"engine_cycles\":%0d}\n",n,batch,calls,cycles);
  $fclose(meta);$display("TBA_PASS transactions=%0d batch=%0d calls=%0d engine_cycles=%0d",n,batch,calls,cycles);$finish;
 end
`ifndef PALLADIUM_HOST
 // Local-only monitor. Excluded from the hardware migration reference TB.
 reg was_stalled=0;reg [279:0] held;
 always @(posedge hw_top.clk)begin
  if(hw_top.link.rst)was_stalled=0;
  else begin
   if(was_stalled && (!hw_top.link.rsp_valid || {hw_top.link.rsp_id,hw_top.link.rsp_len,hw_top.link.rsp_status,hw_top.link.rsp_data}!==held))$fatal(1,"TBA_RESPONSE_UNSTABLE");
   was_stalled=hw_top.link.rsp_valid&&!hw_top.link.rsp_ready;
   held={hw_top.link.rsp_id,hw_top.link.rsp_len,hw_top.link.rsp_status,hw_top.link.rsp_data};
  end
 end
 initial begin #10000000;$fatal(1,"TBA_GLOBAL_TIMEOUT");end
`endif
endmodule

响应必须保持,复位必须有边界

engine 进入 RESPONSE 后保持数据、状态、长度和编号,直到 rsp_valid 与 rsp_ready 同时成立。HOLD=9 场景刻意延后接收,让稳定性检查暴露“响应脉冲只保持一拍”的实现错误。reset_hw 只驱动 rst,避免多个 task 同时驱动握手寄存器;调用者只在初始状态或一个 exchange 完成后复位,超时后的恢复应重新初始化整个运行。

实验包中的实际源码;本地 Icarus 已验证。商业工具脚本为待目标环境验证的参考。

systemverilog
// Fixed packed arguments; single caller only. Reference blocking TBA interface.
interface fifo_link #(parameter HOLD=0)(input wire clk);
 reg rst=1,req_valid=0,rsp_ready=0;
 reg [15:0] req_id=0;reg [5:0] req_len=0;reg [255:0] req_data=0;
 wire req_ready,rsp_valid;wire [15:0] rsp_id;wire [5:0] rsp_len;
 wire [1:0] rsp_status;wire [255:0] rsp_data;wire [31:0] rsp_cycles;
`ifdef IXCOM_UXE
 initial begin
  $ixc_ctrl("tb_export", "reset_hw");
  $ixc_ctrl("tb_export", "exchange");
 end
`endif
 task reset_hw;
  begin
   @(posedge clk);rst<=1;
   repeat(4)@(posedge clk);
   rst<=0;
   repeat(2)@(posedge clk);
  end
 endtask
 task exchange(input [15:0] id,input [5:0] len,input [255:0] payload,
  output [15:0] returned_id,output [5:0] returned_len,
  output [1:0] status,output [255:0] result,output [31:0] active_cycles);
  integer guard;reg accepted,completed;
  begin
   accepted=0;completed=0;status=3;result=0;returned_id=0;returned_len=0;active_cycles=0;
   @(posedge clk);req_id<=id;req_len<=len;req_data<=payload;req_valid<=1;
   for(guard=0;guard<2048&&!accepted;guard=guard+1)begin
    @(posedge clk);if(req_ready)accepted=1;
   end
   req_valid<=0;
   if(accepted)begin
    for(guard=0;guard<2048&&!completed;guard=guard+1)begin
     @(posedge clk);if(rsp_valid)completed=1;
    end
    if(completed)begin
     repeat(HOLD)@(posedge clk);
     returned_id=rsp_id;returned_len=rsp_len;status=rsp_status;result=rsp_data;active_cycles=rsp_cycles;
     rsp_ready<=1;@(posedge clk);rsp_ready<=0;
    end
   end
  end
 endtask
endinterface

故障练习:编号正确不代表结果完整

只返回请求编号并不足以证明一次交换完成。错误实现可能在最后一次 rd_en 接受的当拍就发送响应,而 FIFO 的注册输出尚未进入结果向量;这通常表现为最后一个字节沿用旧值。先以 len=1 和尾批测试定位完成条件,再扩大批大小,不要用重复延时掩盖协议错误。

完成检查

  • 长度、字节顺序、状态码和在途数都有明确定义。
  • 尾批、响应保持和错误编号均有测试。
  • 超时不被自动重试或当作成功。

延伸阅读与来源

本文为黄河电子原创教学说明。产品命令与支持范围请以实际安装版本的官方文档为准。

继续阅读

硬件仿真

首次使用前的工程检查清单

准备版本、输入和模型,减少第一次编译的无效往返。

10 分钟
硬件仿真

如何选择 SA/ICE 及交互方式

根据测试环境所在位置与目标接口要求选择运行流程。

11 分钟
硬件仿真

完成最小设计的编译运行

把第一次平台运行拆为有检查点的五个阶段。

10 分钟