[SV]SystemVerilog中使用generate語句實現批量Interface連線

SystemVerilog中使用generate語句實現Interface批量連線

---UVM中連線和set interface的技巧

前言:在前文(Link)中我們談過generate語句在Verilog中的用法及案例,本文將詳細介紹generate在Testbench中的使用。通過引入generate,將大大減少連線或者set interface的工作量,從而避免一些低級的錯誤。

一、應用場景

  • 假如我們需要4個ckdly_agent,那麼我們應該在env中例化4份,並且要在top層中給每個agent都set interface,並且連線

1.1、在env中例化ckdly_agent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ckdly_env extends uvm_env;

  ckdly_agent               ckdly_agent_inst[4];

  `uvm_component_utils(ckdly_env)

endclass : ckdly_env


function void ckdly_env::build_phase(uvm_phase phase);
  super.build_phase(phase);
 
  foreach(ckdly_agent_inst[i]) begin
    ckdly_agent_inst[i] = ckdly_agent::type_id::create($sformatf("ckdly_agent_inst[%0d]", i), this);
    ckdly_agent_inst[i].is_active = UVM_PASSIVE; //不需要例化driver和sequencer
  end

endfunction : build_phase
  • 注意create方法中的$sformatf()函數,方括號裡面的佔位符一定不能寫成循環變量i,否則會在simulation中出現找不到agent實例的問題
  • 在agent中通過枚舉類型的變量is_active = {UVM_ACTIVE, UVM_PASSIVE}來控制是否create driver和sequencer,如果是UVM_PASSIVE,就只創建Monitor

1.2、在top中使用generate循環連線并完成set interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module top();
 
  logic        digrf_sys_clk[4];      //假設每個bit所代表的Clock的frequency不同
  logic        digrf_sys_rst_n[1];    //
 
  generate
    for(genvar i = 0; i < 4; i = i + 1) begin : dl_ckdly_intf
      ckdly_if                ckdly_vif(.clk_ck(digrf_sys_clk[i]), .rst_n(digrf_sys_rst_n[0]));
      assign dl_ckdly_intf[i].ckdly_vif.da_resync = top.u_serdes.u_l1_top.u_phya.da_resync;
      assign dl_ckdly_intf[i].ckdly_vif.da_rstdly = top.u_serdes.u_l1_top.u_phya.da_rstdly;

      initial begin
        uvm_config_db#(virtual ckdly_if.mon)::set(uvm_root::get(), $sformatf("uvm_test_top.top_env.dl_env.cal_ckdly_inst[%0d]", i), "mon_vif", dl_ckdly_intf[i].ckdly_vif.mon);
      end
    end
  endgenerate


endmodule

1.3、案例詳解

  • 注意上面的assign語句,左值一定要指明Hierarchy,如上面的例子,給信號賦值時是帶著Hera仍處於的: assign dl_ckdly_intf[i].ckdly_vif.da_resync = top.u_serdes.u_l1_top.u_phya.da_resync;
  • 注意uvm_config_db中的set方法,其中的第四個參數(需要set的value)也需要帶上Hierarchy:dl_ckdly_intf[i].ckdly_vif.mon
  • 上面的generate for語句的作用是generate 4個層次,每一層都會有一個ckdly_vif Interface

二、generate用二重循環的例子

2.1、應用場景

  • 假如現在有6個sub_env,在top_env中會例化這6個sub_env

2.2、top中連線的實現

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top();

  logic                digrf_syc_clk[5];
  logic                digrf_reset_n[5];


  generate
    for(genvar i = 0; i < 6; i = i + 1) begin : clk_i_intf
      for(genvar j = 0; j < 6; j = j + 1) begin : clk_j_intf
        clk_if    sys_clk_vif(.clk(digrf_syc_clk[i][j]));
       
        initial begin : set_digrf_clk_intf
          uvm_config_db#(virtual clk_if.mst)::set(uvm_root::get(), $sformatf("uvm_test_top.top_env.slv_env[%0d].clk_agent_inst[%0d]*", i, j), "vif", clk_i_intf[i].clk_j_intf[j].sys_clk_vif);
        end
      end
    end
  endgenerate
endmodule

  • 如上面的例子,第一層for循環,創建了Hierarchy:clk_i_intf,主要用於Maping不同的sub_env
  • 第二層for循環創建了Hierarchy:clk_j_intf,主要是對應於不同的Clock frequency

2.3、總結

  • Interface的聲明要放在generate for裡面
  • set interface要用initial begin end包起來,也放在generate for裡面
  • initial begin end中不能放assign語句
  • 採用generate for begin之後,Hierarchy將發生變化,無論是assign還是set,在對generate for begin下面的變量做操作是都要帶上Hierarchy --- 即begin之後的label