天天看點

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

動機

今天一個朋友問了這樣一個問題

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

我有一個朋友

失敗原因

首先介紹一下

generate

的用法,

generate

用于減少verilog的重複語句,批量進行操作。

雖然0202年了,綜合工具對于

for

的支援已經很好了,但是使用

generate

進行for循環,不僅可以實作普通的變量指派,還可以批量生成

assign

或者

always

語句,它的作用實際上和宏定義是一樣的,

直接将代碼展開

舉個例子,我有兩個數組

reg [7:0] a [7:0]

reg [7:0] b [7:0]

,我需要把他們對應元素相乘,那麼可以這麼做

genvar i;

reg [ 7:0] a [7:0];
reg [ 7:0] b [7:0];
wire [15:0] c [7:0];

generate
  for(i;i<8;i++) begin
    assign c[i] = a[i]*b[i];
  end
endgenerate

           

複制

這種寫法是完全等價于下面這種寫法的

genvar i;

reg [ 7:0] a [7:0];
reg [ 7:0] b [7:0];
wire [15:0] c [7:0];

assign c[0] = a[0]*b[0];
assign c[1] = a[1]*b[1];
assign c[2] = a[2]*b[2];
assign c[3] = a[3]*b[3];
assign c[4] = a[4]*b[4];
assign c[5] = a[5]*b[5];
assign c[6] = a[6]*b[6];
assign c[7] = a[7]*b[7];

           

複制

如果在代碼并不多的情況下,利用插件,例如

sublime

insert num

,也可以快速實作

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

sublime

同樣的,

generate

也可以批量進行例化,例如

module adder(
  input clk,rst_n,
  input  [2:0] a,b,
  output [3:0] c
);

  logic [3:0] c_f,c_ff;

  always_ff @(posedge clk or negedge rst_n) begin : proc_adder
    if(~rst_n) begin
      c_f   <= '0;
      c_ff  <= '0;
    end else begin
      c_f   <= a+b;
      c_ff  <= c_f;
    end
  end

  assign c=c_ff;


endmodule


module test (
  input clk,    // Clock
  input rst_n,  // Asynchronous reset active low
  input  [2:0] a [3:0],
  input  [2:0] b [3:0],
  output [3:0] c [3:0]
);

genvar i;

generate

  for (i = 0; i < 4; i++) begin
  adder i_adder (.clk(clk), .rst_n(rst_n), .a(a[i]), .b(b[i]), .c(c[i]));
  end

endgenerate

endmodule
           

複制

如果在仿真器中檢視子產品名,子產品會被自動進行編号

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

通過路徑

i_test.genblk1[3].i_adder.c_f

就能通路到對應的變量

//  Module: tb
//
module tb();

  
  logic clk,rst_n;
  logic [2:0] a [3:0];
  logic [2:0] b [3:0];
  logic [3:0] c [3:0];

  test i_test (.clk(clk), .rst_n(rst_n), .a(a), .b(b), .c(c));
  
  initial begin
    clk <= '0;
    forever begin
      #5 clk <= ~clk;
    end
  end

  initial begin
    rst_n <= '0;
    repeat(5) @(posedge clk);
    rst_n <= '1;
  end

  initial begin
    a <= '{4{'0}};
    b <= '{4{'0}};
    @(posedge clk iff rst_n);
    for (int i = 0; i<4 ; i++ ) begin
      a[i] <= i;
      b[i] <= i;
    end
    repeat(5) @(posedge clk);
    $display("c_f[3]:%h",i_test.genblk1[3].i_adder.c_f);
    @(posedge clk);
    $stop();
  end

endmodule: tb
           

複制

可以看到通路成功

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

如果通過文章開頭說的方式,就會出現錯誤

for (int i = 0; i<4 ; i++ ) begin
      $display("c_f[%0d]:%h",i_test.genblk1[i].i_adder.c_f);
    end
           

複制

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

其實主要原因是,這個

genblk1

根本就不是一個數組,也就無法通過這種索引的方法通路到對應變量

解決辦法

目前我能想到的方法就是通過

uvm

提供的函數

uvm_hdl_read

實作,他在底層通過

dpi

從外部通路變量,是以可以通過字元串通路到對應的變量。

uvm_hdl_read

的原型是

import "DPI-C" context function int uvm_hdl_read(
   		string 	path,
   	output 	uvm_hdl_data_t 	value
)
           

複制

傳回的

uvm_hdl_data_t

在uvm中的定義是

parameter int UVM_HDL_MAX_WIDTH = `UVM_HDL_MAX_WIDTH;

typedef  logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t;
           

複制

是以,我們可以通過下面的代碼通路

genblk1

中的變量

for (int i = 0; i<4 ; i++ ) begin
      uvm_hdl_read($sformatf("tb.i_test.genblk1[%0d].i_adder.c_f",i),temp)
      $display("c_f[%0d]:%2h",i,temp);
    end
           

複制

有幾個注意事項

  1. 在描述路徑時,要傳入絕對路徑,不能使用相對路徑
  2. 在描述路徑時,使用

    %0d

    ,否則字元串會與真實路徑不比對

可以看到通路成功

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

uvm讀取

下面給出完整代碼

//  Module: tb
//
module tb();
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  
  logic clk,rst_n;
  logic [2:0] a [3:0];
  logic [2:0] b [3:0];
  logic [3:0] c [3:0];

  test i_test (.clk(clk), .rst_n(rst_n), .a(a), .b(b), .c(c));
  
  initial begin
    clk <= '0;
    forever begin
      #5 clk <= ~clk;
    end
  end

  initial begin
    rst_n <= '0;
    repeat(5) @(posedge clk);
    rst_n <= '1;
  end

  initial begin
    uvm_hdl_data_t temp;
    a <= '{4{'0}};
    b <= '{4{'0}};
    @(posedge clk iff rst_n);
    for (int i = 0; i<4 ; i++ ) begin
      a[i] <= i;
      b[i] <= i;
    end
    repeat(5) @(posedge clk);
    $display("c_f[3]:%h",i_test.genblk1[3].i_adder.c_f);
    for (int i = 0; i<4 ; i++ ) begin
      uvm_hdl_read($sformatf("tb.i_test.genblk1[%0d].i_adder.c_f",i),temp)
      $display("c_f[%0d]:%2h",i,temp);
    end
    @(posedge clk);
    $stop();
  end

endmodule: tb

           

複制

當然,uvm不僅提供了讀取,還提供了全家桶服務,

force

deposit

一應俱全

通過字元串通路generate子產品内部的變量動機 失敗原因解決辦法

如果有更好的辦法,歡迎留言

END