transaction、句柄与 package

返回 ALU 任务总览。

任务:用一笔对象表示一次操作

最初的 drive_and_check(op,a,b) 逐个传参数;改为 drive_and_check(input alu_transaction tr),由事务保存一次操作的字段。下面是教学用的核心片段;当前类还含随机约束与观测结果字段,见 约束随机。

class alu_transaction;
  rand logic [2:0] op;
  rand logic [7:0] a, b;
  logic [7:0] result;
  logic rsp_valid;
 
  function new(logic [2:0] op = 0,
               logic [7:0] a = 0, b = 0);
    this.op = op;
    this.a  = a;
    this.b  = b;
  endfunction
endclass
 
alu_transaction tr;               // 句柄,尚未有对象
tr = new(3'd0, 8'd7, 8'd9);        // 创建对象
drive_and_check(tr);

this.op 是对象成员,右侧 op 是构造参数。一个 tr 句柄可以多次指向新对象;new() 每次产生不同对象。当前测试按顺序调用时反复修改同一对象也可能运行,但将来 monitor、mailbox 等并行组件若仍持有同一对象,修改它会改变尚未处理的事务,所以每笔 new() 更安全。tr 默认可能是 null,使用前做句柄保护。

任务:解决报在 tr 附近的错误

// 错:类型名拼写缺下划线
task automatic drive_and_check(input alutransaction tr);
// 对:与类名一致
task automatic drive_and_check(input alu_transaction tr);

“near tr, expecting )”常是解析器读不懂其前面的类型,不一定是 tr 变量名有错。先核对类型拼写、定义可见性与编译日志第一条错误。

任务:让类定义对 top 可见

仅把 alu_transaction.sv 排在 tb_top.sv 前面,不能保证两个独立编译单元共享顶层 class。早期用 -mfcu 临时验证过同编译单元方案;也曾讨论在 top 直接 include。正式方案采用 package:

package alu_pkg;
  `include "alu_transaction.sv"
  `include "alu_driver.sv"
  `include "alu_monitor.sv"
  `include "alu_scoreboard.sv"
  `include "alu_coverage.sv"
endpackage

top 在用到类名之前写 import alu_pkg::*;。interface 不是 class,不放进此 package;包内被 include 的文件也不要再作为独立源文件重复编译。顺序是先 interface,再 package,最后 top;assertion 模块作为独立模块先于 top 编译。

+incdir+../tb 为这些 include 指定查找目录。如果误写为 +incdir+../rtl/simple_alu.sv,并没有把 RTL 加入编译列表;旧库可能掩盖遗漏。检查日志是否确实编译了 simple_alu。

自检问题

  • 声明句柄、调用 new()、复制句柄,分别发生了什么?
  • 为什么更改编译顺序不足以解决所有“unknown type”?
  • include 与 import 各处理什么问题?

下一步读 分层平台与 virtual interface。