2016-11-17 10 views
0

EDIT: Я опробовал методы, упомянутые ниже: я установил свой интерфейс для проводов вместо логики, и я управляю «Z» от драйвера, который хочет отказаться от управления сигнал, чтобы другой драйвер мог взять верх. Все еще не работает, поскольку я вижу, что u_slave_dut не выводится из моего интерфейса. Какие-нибудь подсказки о том, что не так? Мой рабочий пример: https://www.edaplayground.com/x/4SSPВождение внутреннего провода в моем модуле из моей задачи интерфейса

Я пишу testbench для модуля верхнего уровня, который имеет несколько подмодулей. Я хочу создать экземпляр интерфейса и подключить его к одному из моих подмодулей, скажем 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 

Любая идея, в которой я ошибаюсь?

ответ

1

Я считаю, что один симулятор, который вы выбрали для запуска симулятора, не дает никаких предупреждений или ошибок. Любой другой симулятор будет корректно давать ошибки о смешении непрерывных заданий с процедурными присвоениями из блока синхронизации.

Если вы собираетесь использовать один и тот же сигнал из двух разных мест, вам нужно иметь дело с этим, используя провод вместо переменной. Вам также необходимо отключить один из драйверов, установив его на высокий импеданс ('z), поэтому другой драйвер может управлять сигналом. Это необходимо сделать независимо от того, находятся ли эти два драйвера в рамках вашего проекта или между дизайном и тестовым узлом. Несколько лет назад я написал DVCon paper, что объясняет это более подробно.

+0

Благодарим за отзыв. Я прочитал статью и попытался реализовать то, что понял: (1) Я изменил свой интерфейс на провода вместо логики. (2) Я повел сигналы в «hZ» в u_master_dut. Кажется, я все еще не могу управлять входами u_slave_dut из my_interface. Что мне здесь не хватает? У меня также есть еще 2 вопроса: (3) Я использую процедурное задание для подключения провода в моем интерфейсе. Как это разрешено? (4) У меня не будет доступа к внутреннему драйверу изнутри, чтобы установить его на «hZ, как я сделал в своем примере в u_master_dut. https://www.edaplayground.com/x/2Y6x – noobuntu

+0

(2) Мне нужно будет увидеть обновленный код, чтобы узнать, что вы пропустили. (3) вы делаете приводы блоков синхронизации в провод, а не процедурные назначения. проверьте мою бумагу и LRM (4), вам может потребоваться использовать «force/release» –

+0

https://www.edaplayground.com/x/2Y6x – noobuntu

0

Как пояснил Дэйв, это единственный способ управлять сетями с несколькими драйверами, позволяя только одному драйверу управлять сетью за раз. И, с точки зрения аппаратного обеспечения, только один драйвер должен вести любой провод за раз.

Это может быть достигнуто в вашем дизайне с использованием дополнительных 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

+0

Я пробовал то, что вы сказали, и это не сработало. Пожалуйста, проверьте мое редактирование выше и рабочий пример. – noobuntu

+0

Инициализация 'control' с' 1'b1' (в вашем примере она инициализируется '1'b0'). В этом случае у вас будет одно состояние Z, в волне, потому что управление = 1'b0, и задача ждет сигнала '@ (master_cb) (вы можете управлять управляющим сигналом из этой задачи). Но кроме этого он работает –

+0

Инициализация 'control = 1'b0' первоначально устанавливает интерфейсные сигналы на« hZ ». Затем, когда я хочу работать с интерфейсом, я устанавливаю 'control = 1'b1' и вызываю' master_write_something'. В любом случае, я попробовал метод установки 'control = 1'b1', и он не работает ... Вы используете мой пример? Можете ли вы показать мне волну, если возможно, пожалуйста? – noobuntu