从界面任务

时间:2016-11-17 23:10:23

标签: verilog system-verilog verification uvm

编辑:我尝试了下面提到的方法:我将接口设置为导线而不是逻辑,并且我从驱动器驱动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

知道我哪里错了吗?

2 个答案:

答案 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

转储文件如下。

enter image description here