在没有定义的情况下分层调用任务
Calling a Task Hierarchically without Defines
我在层次结构深处实例化了供应商提供的 BFM 模块;让我们调用路径 top.dut.u1.u2.bfm1
。 BFM 的 API 对于我们的需求来说有点陈旧和混乱。我想写一个"object"(class?接口?别的什么?),给任务提供一个更简单的调用接口,可以调用已经[=29的具体BFM的任务=] 与。就是这个"linking"想不通
我有一个定义为模块的简单版本,它使用 `define 指定 BFM 的路径,类似于:
`define BFM top.dut.u1.u2.bfm1
module bfm_wrapper;
...
task read_burst(...);
...
`BFM.read_burst(...);
endtask;
...
endmodule
显然这不是很可重用。我如何用更便携或抽象到下一个更高级别的东西替换 `BFM?
我是 SystemVerilog 的相对新手,我什至还没有使用 UVM,但如果有什么帮助,我会冒险尝试。感谢任何帮助。
[更新]几个我没有提到的限制:
- 我无法更改或替换供应商提供的 BFM。我宁愿不包装它(即在我的包装器中实例化它)。
- 由于我不想在这里详述的原因,BFM 需要在 DUT 中实例化。改变它需要比我现在投入更多的努力。
与抽象接口一起绑定将帮助您连接到 BFM。看看我的两篇 DVCon 论文
http://www.doulos.com/downloads/events/DVCon_08_abstractBFM_final.pdf
http://events.dvcon.org/2012/proceedings/papers/01P_3.pdf
[更新]
package bfm_pkg;
interface class bfm_api;
pure virtual task read_burst(...);
endclass
endpackage
module bfm_wrapper;
import bfm_pkg::*;
...
class wrapper extends bfm_api;
task read_burst(...);
`BFM.read_burst(...);
endtask;
endclass
wrapper h = new();
endmodule
然后用你的类,你可以写
import bfm_pkg;:*;
class someclass
bfm_api h;
task foo;
...
h.read_burst(...);
endtask
endclass
现在您只需要将 bfm_wrapper 中的 h 句柄获取到对象 foo 中的 h。如果您使用的是 UVM,那么 uvm_config_db 在这里会有所帮助,否则您将需要创建自己的机制来复制句柄 h。
最终的答案(首先由@toolic 和@Greg 建议,后来由@dave_59 提出)是使用 bind
将包装器动态放置在供应商 BFM 可以通过 "upwards name referencing"(具体来说,通过将包装器放入供应商 BFM 中)。所以我上面的代码看起来像:
`define BFM top.dut.u1.u2.bfm1
module top;
...
// Instantiate my wrapper code inside of the vendor's BFM
bind `BFM bfm_wrapper my_bfm();
// BFM commands go here
initial begin
wait (`BFM.reset === 0) @(posedge `BFM.clk);
`BFM.my_bfm.my_read_burst(...);
...
end
endmodule
module bfm_wrapper;
...
task my_read_burst(...);
...
read_burst(...);
endtask;
...
endmodule
如果有任何打字错误,我深表歉意。我的代码最终看起来并不完全像这样。
请注意,我并没有完全摆脱 define
。这可能需要@dave_59 的论文中更优雅的技术。但我至少把它移出了代码的可重用部分,这对现在来说已经足够好了。
我在层次结构深处实例化了供应商提供的 BFM 模块;让我们调用路径 top.dut.u1.u2.bfm1
。 BFM 的 API 对于我们的需求来说有点陈旧和混乱。我想写一个"object"(class?接口?别的什么?),给任务提供一个更简单的调用接口,可以调用已经[=29的具体BFM的任务=] 与。就是这个"linking"想不通
我有一个定义为模块的简单版本,它使用 `define 指定 BFM 的路径,类似于:
`define BFM top.dut.u1.u2.bfm1
module bfm_wrapper;
...
task read_burst(...);
...
`BFM.read_burst(...);
endtask;
...
endmodule
显然这不是很可重用。我如何用更便携或抽象到下一个更高级别的东西替换 `BFM?
我是 SystemVerilog 的相对新手,我什至还没有使用 UVM,但如果有什么帮助,我会冒险尝试。感谢任何帮助。
[更新]几个我没有提到的限制:
- 我无法更改或替换供应商提供的 BFM。我宁愿不包装它(即在我的包装器中实例化它)。
- 由于我不想在这里详述的原因,BFM 需要在 DUT 中实例化。改变它需要比我现在投入更多的努力。
与抽象接口一起绑定将帮助您连接到 BFM。看看我的两篇 DVCon 论文
http://www.doulos.com/downloads/events/DVCon_08_abstractBFM_final.pdf
http://events.dvcon.org/2012/proceedings/papers/01P_3.pdf
[更新]
package bfm_pkg;
interface class bfm_api;
pure virtual task read_burst(...);
endclass
endpackage
module bfm_wrapper;
import bfm_pkg::*;
...
class wrapper extends bfm_api;
task read_burst(...);
`BFM.read_burst(...);
endtask;
endclass
wrapper h = new();
endmodule
然后用你的类,你可以写
import bfm_pkg;:*;
class someclass
bfm_api h;
task foo;
...
h.read_burst(...);
endtask
endclass
现在您只需要将 bfm_wrapper 中的 h 句柄获取到对象 foo 中的 h。如果您使用的是 UVM,那么 uvm_config_db 在这里会有所帮助,否则您将需要创建自己的机制来复制句柄 h。
最终的答案(首先由@toolic 和@Greg 建议,后来由@dave_59 提出)是使用 bind
将包装器动态放置在供应商 BFM 可以通过 "upwards name referencing"(具体来说,通过将包装器放入供应商 BFM 中)。所以我上面的代码看起来像:
`define BFM top.dut.u1.u2.bfm1
module top;
...
// Instantiate my wrapper code inside of the vendor's BFM
bind `BFM bfm_wrapper my_bfm();
// BFM commands go here
initial begin
wait (`BFM.reset === 0) @(posedge `BFM.clk);
`BFM.my_bfm.my_read_burst(...);
...
end
endmodule
module bfm_wrapper;
...
task my_read_burst(...);
...
read_burst(...);
endtask;
...
endmodule
如果有任何打字错误,我深表歉意。我的代码最终看起来并不完全像这样。
请注意,我并没有完全摆脱 define
。这可能需要@dave_59 的论文中更优雅的技术。但我至少把它移出了代码的可重用部分,这对现在来说已经足够好了。