I want to assign for an array of interfaces with different sample clock. for example
//////////////
type_rx_if rx_vif[3:0] (clk1) ;
type_rx_if rx_vif[7:4] (clk2) ;
//////////////
but this report compile error. then I tried to assign the clock to each interface.
/////////////////
type_rx_if rx_vif[7:0] () ;
assign rx_vif[0].clk =clk1 ;
…
assign rx_vif[4].clk =clk2 ;
…
////////////////
this code pass the compile, but in simulation, it seems to change on the same clock edge of clk1.
is there any solution to assign different sample clock for the element in interface array? or I have to define it as 2 separated arrays?
I think the compiler error is because you can’t declare the same identifier twice, even if each declares an array of the same type with mutually exclusive index ranges.
this assignment also passed the compile and works the same as my individual assign, all data event is on the same clk1 edge. maybe there is other bug in my testbench, or did you really tried this usage of SV ?
I just worked the tb out with only clk1, now I want to change the clock domain of some interface and the corresponding drv, mon, I don’t want to modify the code of drv and mon. so I try to only modify the instantiation of the interface on the top level. is there some potential reasons that will cause bug with this. I just checked the waveform, the clock in the interface is correctly connected, but the signals in the drv and mon still change on the same clock.
I tried this code without uvm, it works fine, the data signal change on each clock assigned to the interfaces, is it possible that uvm_config_db did something to the virtual interface so that the signals in drv and mon does not perform as I expected?
//////////
OK, modify your example to use a virtual interface, and use the uvm_config_db to get the virtual interfaces. Most likely there is a problem with how you are setting the uvm_config_db, which until now, you had never mentioned.
Hi, I tried it with virtual if, but it still works on individual clocks. I suppose there is deep bug with my testbench. I post my code here:
`timescale 1ns / 1ps
import uvm_pkg::*;
`include "uvm_macros.svh"
interface type_rx_if(input bit clk);
wire done;
wire start;
clocking mck @(posedge clk);
inout done;
output start;
endclocking: mck
modport master(clocking mck);
endinterface
class test_case1 extends uvm_test;
`uvm_component_utils(test_case1)
virtual type_rx_if sigs[3:0];
function new(string name = "test_case1",
uvm_component parent=null);
super.new(name,parent);
endfunction : new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
for (int i=0; i < 4; i=i+1) begin
if (!uvm_config_db#(virtual type_rx_if)::get(this, "", {"rx_vif_", i}, sigs[i])) begin
`uvm_fatal("DRV/NOVIF", "No virtual interface specified for this driver instance")
end
end
endfunction : build_phase
virtual protected task run_phase(uvm_phase phase);
phase.raise_objection(this, "running ");
super.run_phase(phase);
#200;
this.sigs[0].mck.start <= 1'b0;
this.sigs[3].mck.start <= 1'b0;
#200;
this.sigs[0].mck.start <= 1'b1;
this.sigs[3].mck.start <= 1'b1;
phase.drop_objection(this, " done");
endtask: run_phase
endclass : test_case1
module test_top ();
reg reset, clk, clk_sfp ;
type_rx_if rx_vif[3:0] ({clk_sfp,{3{clk}}});
genvar i;
generate
for (i=0; i < 4; i=i+1) begin
initial
begin
uvm_config_db#(virtual type_rx_if)::set(uvm_root::get(), "*", {"rx_vif_", i}, rx_vif[i]);
end
end
endgenerate
initial begin
run_test();
end
initial begin
clk <= 1'b0;
clk_sfp <= 1'b0;
#200;
rx_vif[3].mck.done <= 1'b0;
rx_vif[0].mck.done <= 1'b0;
#200;
rx_vif[3].mck.done <= 1'b1;
rx_vif[0].mck.done <= 1'b1;
end
always
#62.5 clk = ~clk;
always
#40 clk_sfp = ~clk_sfp;
endmodule
in my TB , I created 8 agents, I want to use 4 with clk1,4 with clk2, and instantiate the vif in the drv and mon as here in the test, but I can’t imagine what is the difference between my TB and this code. is it because of the 8 mons and drvs are array of the same class? or is there any other possible bug? anyhow, I think the interface related code only exist in drv, mon, interface definition and TB top, I did not use config to pass it down.
There is a problem with the expression {“rx_vif_”, i} in these two statements:
if (!uvm_config_db#(virtual type_rx_if)::get(this, "", {"rx_vif_", i}, sigs [ i ])) begin
uvm_config_db#(virtual type_rx_if)::set(uvm_root::get(), "*", {"rx_vif_", i}, rx_vif [ i ]);
Since i is an int, not a string , the concatenation is treated as an integral concatenation creating an 88-bit value “rx_vif_” . This integral expression gets converted back to a string, but the first character in the expression truncates the string. Even when the last character goes to 1,2,3,… etc., the argument to the get/set method only sees “rx_vif_”.
Technically, this implicit conversion from an integral to a string type is illegal and the compiler should have flagged it as an error. However, because of bug compatibility that vendors are sometimes forced to implement, most simulators will not flag this error by default.
The correct way to write this expression is $sformatf(“rx_vif_%0d”,i)
I modified my TB according to your advice, but the result is the same, all clocks change on clk1.
finally I found out the reason for that. but I don’t know whether it’s a potential bug of UVM or I misused it.
The story is. I have a interface to config the registers of the dut. I have another 4 interfaces for packet transaction。
if I use all these with 1 clock, everything is ok.
if I use 2 packet ifcs and the register ifc with clk1, the other 2 ifcs with clk2, the transaction with clk1 work fine, but the transaction with clk2 is not working. since I used a virtual sequence which start reg sequence working on clk1 and afterwards packet sequence working on both clk1 and clk2. the code look like this.
//////////
virtual task body();
uvm_do_on(my_norm_reg_seq, p_sequencer.reg_sqr); //on clk1 repeat(sent_cnt) begin fork uvm_do_on(incr_send_pkt_seq_0, p_sequencer.eth_sqr_0); //drvs on clk1 uvm_do_on(incr_send_pkt_seq_1, p_sequencer.eth_sqr_1); //drvs on clk1 uvm_do_on(incr_send_pkt_seq_2, p_sequencer.eth_sqr_2); //drvs on clk2 uvm_do_on(incr_send_pkt_seq_3, p_sequencer.eth_sqr_3); //drvs on clk2 join end uvm_do_on(my_check_reg_seq, p_sequencer.reg_sqr); //on clk1
endtask : body
///////////
if I comment out the norm_reg_seq line without configure the register on clk1, the TB will send packet on both clk1 and clk2 in each port correctly. I doubt if the UVM can switch the clock of the sequence automatically. or is there anything I should tell UVM to do this?