双向接口中的 SystemVerilog 时钟模块
SystemVerilog Clocking Blocks in Bi-Directional Interface
假设我有一个双向接口。我希望 TB 能够从 DUT 接收数据,并且我希望 TB 能够将数据驱动到 DUT。我需要在我的代码中放入一个 clocking
块,因为我有竞争条件问题。我可以通过在正确的位置放置一个小的#1 来解决这些问题,但我知道时钟块是正确的解决方案。我遇到困难的部分是双向部分。如果它是一个方向,我可能没问题,但双向接口的语法让我感到困惑。制作 2 个时钟块、2 个 modports 或其他完全正确的解决方案是什么?
interface MyInterface
(input bit i_Clk);
logic [15:0] r_Data;
logic r_DV = 1'b0;
clocking CB @(posedge i_Clk);
default input #1step output #1step;
endclocking : CB
task t_Clock_Cycles(int N);
repeat (N) @(posedge i_Clk);
endtask : t_Clock_Cycles
modport Driver (clocking CB, output r_Data, r_DV);
modport Receiver (clocking CB, input r_Data, r_DV);
endinterface : MyInterface
package MyPackage;
class MyDriver;
virtual MyInterface.Driver hook;
function new(virtual MyInterface.Driver hook);
this.hook = hook;
endfunction : new
task t_Drive(input [15:0] i_Data);
forever
begin
hook.CB.r_Data = i_Data;
hook.CB.r_DV = 1'b1;
hook.CB.t_Clock_Cycles(1);
end
endtask : t_Drive
endclass : MyDriver
endpackage : MyPackage
module MyModule;
import MyPackage::*;
logic r_Clk = 1'b0;
MyInterface hook(.i_Clk(r_Clk));
always #5 r_Clk = ~r_Clk;
MyDriver d1 = new(hook.Driver);
initial
begin
d1.t_Drive(16'hABCD);
end
endmodule // MyModule
使用时钟块的全部意义在于声明要同步访问哪些信号。您应该将信号添加到时钟块:
clocking CB @(posedge i_Clk);
default input #1step output #1step;
inout r_Data;
inout r_DV;
endclocking : CB
由于您还希望对 driver 和接收器具有不同的访问权限,这意味着您将需要两个不同的时钟块:
clocking CB_driver @(posedge i_Clk);
default input #1step output #1step;
output r_Data;
output_DV;
endclocking : CB_driver
// ... direction reversed for CB_receiver
不幸的是,不可能说您在 driver/receiver 类:
中引用了某个时钟块
class Driver
virtual MyInterface.CB_driver hook; // !!! Not allowed
endclass
如果你想限制你的 driver 只能通过 CB_driver
,你可以使用 modport
:
interface MyInterface;
modport Driver(CB_driver);
endinterface
class Driver;
virtual MyInterface.Driver hook;
endclass
通过这种方式,您可以在驱动信号时参考 hook.CB_driver
。您的接收器也是如此。
假设我有一个双向接口。我希望 TB 能够从 DUT 接收数据,并且我希望 TB 能够将数据驱动到 DUT。我需要在我的代码中放入一个 clocking
块,因为我有竞争条件问题。我可以通过在正确的位置放置一个小的#1 来解决这些问题,但我知道时钟块是正确的解决方案。我遇到困难的部分是双向部分。如果它是一个方向,我可能没问题,但双向接口的语法让我感到困惑。制作 2 个时钟块、2 个 modports 或其他完全正确的解决方案是什么?
interface MyInterface
(input bit i_Clk);
logic [15:0] r_Data;
logic r_DV = 1'b0;
clocking CB @(posedge i_Clk);
default input #1step output #1step;
endclocking : CB
task t_Clock_Cycles(int N);
repeat (N) @(posedge i_Clk);
endtask : t_Clock_Cycles
modport Driver (clocking CB, output r_Data, r_DV);
modport Receiver (clocking CB, input r_Data, r_DV);
endinterface : MyInterface
package MyPackage;
class MyDriver;
virtual MyInterface.Driver hook;
function new(virtual MyInterface.Driver hook);
this.hook = hook;
endfunction : new
task t_Drive(input [15:0] i_Data);
forever
begin
hook.CB.r_Data = i_Data;
hook.CB.r_DV = 1'b1;
hook.CB.t_Clock_Cycles(1);
end
endtask : t_Drive
endclass : MyDriver
endpackage : MyPackage
module MyModule;
import MyPackage::*;
logic r_Clk = 1'b0;
MyInterface hook(.i_Clk(r_Clk));
always #5 r_Clk = ~r_Clk;
MyDriver d1 = new(hook.Driver);
initial
begin
d1.t_Drive(16'hABCD);
end
endmodule // MyModule
使用时钟块的全部意义在于声明要同步访问哪些信号。您应该将信号添加到时钟块:
clocking CB @(posedge i_Clk);
default input #1step output #1step;
inout r_Data;
inout r_DV;
endclocking : CB
由于您还希望对 driver 和接收器具有不同的访问权限,这意味着您将需要两个不同的时钟块:
clocking CB_driver @(posedge i_Clk);
default input #1step output #1step;
output r_Data;
output_DV;
endclocking : CB_driver
// ... direction reversed for CB_receiver
不幸的是,不可能说您在 driver/receiver 类:
中引用了某个时钟块class Driver
virtual MyInterface.CB_driver hook; // !!! Not allowed
endclass
如果你想限制你的 driver 只能通过 CB_driver
,你可以使用 modport
:
interface MyInterface;
modport Driver(CB_driver);
endinterface
class Driver;
virtual MyInterface.Driver hook;
endclass
通过这种方式,您可以在驱动信号时参考 hook.CB_driver
。您的接收器也是如此。