编辑:我尝试了下面提到的方法:我将接口设置为导线而不是逻辑,并且我从驱动器驱动Z以放弃对信号的控制,以便另一个司机可以接管。仍然不起作用,因为我看到u_slave_dut没有从我的界面驱动。什么错误的线索?我的工作示例:https://www.edaplayground.com/x/4SSP
我正在为具有许多子模块的顶级模块编写测试平台。我想实例化一个接口并将其连接到我的一个子模块,比如 my_submodule 。很容易,当切换 my_submodule 引脚时,我可以看到我的接口引脚切换。这可以很好地观察。
接下来,我决定自己能够从界面切换引脚(使用任务)。我意识到这会导致同一辆公交车上有2个司机。那么,有没有办法让我这样做?
我创建了一个edaplayground的小例子进行实验,在这里我看到我在界面中的任务中的所有写操作都没有实际切换u_slave_dut上的引脚。此外,我没有得到编译器的任何警告,这也是困扰我的。
我的工作示例如下:https://www.edaplayground.com/x/5fcP
testbench.sv
`include "my_interface.sv"
module tb;
bit clk = 1'b1;
bit control = 1'b0;
initial begin
forever begin
#5 clk = ~clk;
end
end
my_interface my_vif(clk);
assign my_vif.addr = (control)? tb.u_top.u_slave_dut.i_addr : 'hz;
assign my_vif.wdata = (control)? tb.u_top.u_slave_dut.i_wdata : 'hz;
assign my_vif.write = (control)? tb.u_top.u_slave_dut.i_write : 'hz;
top u_top(.clk(clk));
initial begin
#80 my_vif.master_write_something;
#160 $finish;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
interface.sv
interface my_interface(input clk);
logic [3:0] addr;
logic write;
logic [3:0] wdata;
logic [3:0] rdata;
logic resp;
clocking master_cb @(posedge clk);
input resp, rdata;
output addr, write, wdata;
endclocking
clocking slave_cb @(posedge clk);
input addr, write, wdata;
output resp, rdata;
endclocking
task master_write_something;
@(master_cb);
master_cb.write <= 1'b1;
@(master_cb);
master_cb.wdata <= 3'b101;
master_cb.addr <= 3'b111;
@(master_cb);
master_cb.write <= 1'b0;
endtask
task slave_write_something;
@(slave_cb);
slave_cb.resp <= 1'b1;
@(slave_cb);
slave_cb.rdata <= 3'b101;
@(slave_cb);
slave_cb.resp <= 1'b0;
slave_cb.rdata <= 3'b000;
endtask
endinterface
design.sv
module slave_dut (
input clk,
input [3:0] i_addr,
input [3:0] i_wdata,
input i_write,
output o_resp,
output [3:0] o_rdata
);
reg o_resp_reg;
reg [3:0] o_rdata_reg;
initial begin
o_resp_reg <= 1'b0;
o_rdata_reg <= 'h0;
end
always @(posedge clk) begin
if (i_write == 1'b1) begin
o_resp_reg <= 1'b1;
o_rdata_reg <= i_wdata;
end
else begin
o_resp_reg <= 1'b0;
o_rdata_reg <= 'h0;
end
end
assign o_resp = o_resp_reg;
assign o_rdata = o_rdata_reg;
endmodule : slave_dut
module master_dut (
input clk,
output [3:0] o_addr,
output [3:0] o_wdata,
output o_write,
input i_resp,
input [3:0] i_rdata
);
reg [3:0] o_addr_reg;
reg [3:0] o_wdata_reg;
reg o_write_reg;
initial begin
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
repeat (2) @(posedge clk);
o_addr_reg <= 'hF;
o_wdata_reg <= 'hB;
o_write_reg <= 1'b1;
@(posedge clk);
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
repeat (2) @(posedge clk);
o_addr_reg <= 'h4;
o_wdata_reg <= 'hD;
o_write_reg <= 1'b1;
@(posedge clk);
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
end
assign o_addr = o_addr_reg;
assign o_wdata = o_wdata_reg;
assign o_write = o_write_reg;
endmodule : master_dut
module top(input clk);
wire [3:0] addr;
wire [3:0] wdata;
wire write;
wire resp;
wire [3:0] rdata;
master_dut u_master_dut (
.clk(clk),
.o_addr(addr),
.o_wdata(wdata),
.o_write(write),
.i_resp(resp),
.i_rdata(rdata)
);
slave_dut u_slave_dut (
.clk(clk),
.i_addr(addr),
.i_wdata(wdata),
.i_write(write),
.o_resp(resp),
.o_rdata(rdata)
);
endmodule
知道我哪里错了吗?
答案 0 :(得分:1)
我相信您选择运行模拟器的一个模拟器不会发出任何警告或错误。任何其他模拟器都会正确地给出关于将连续分配与时钟块中的过程分配混合的错误。
如果要从两个不同的位置驱动相同的信号,则需要使用导线而不是变量来处理。您还需要通过将其设置为高阻抗('z
)来关闭其中一个驱动程序,以便其他驱动程序可以控制信号。无论两个驱动程序是在您的设计中还是在设计和测试平台之间,都需要这样做。几年前我写了一篇DVCon paper来更详细地解释这一点。
答案 1 :(得分:0)
正如Dave所说,这是通过一次只启动一个驱动器来控制多驱动器网络的唯一方法。从硬件角度来看,一次只能驱动任何一根线。
这可以通过使用其他reg
在您的设计中实现。
请参阅以下代码。
module tb;
bit clk = 1'b1;
reg control = 1'b1;
initial begin
forever begin
#5 clk = ~clk;
end
end
my_interface my_vif(clk);
assign my_vif.addr = (control)? tb.u_top.u_slave_dut.i_addr : 'hz;
assign my_vif.wdata = (control)? tb.u_top.u_slave_dut.i_wdata : 'hz;
assign my_vif.write = (control)? tb.u_top.u_slave_dut.i_write : 'hz;
top u_top(.clk(clk));
initial begin
#80 my_vif.master_write_something (control);
#160 $finish;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
// Interface Task
task master_write_something (ref reg x);
@(master_cb);
x = 1'b0;
master_cb.write <= 1'b1;
@(master_cb);
master_cb.wdata <= 3'b101;
master_cb.addr <= 3'b111;
@(master_cb);
master_cb.write <= 1'b0;
endtask
转储文件如下。