通过字符串访问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];

如果在代码并不多的情况下,利用插件,例如sublimeinsert num,也可以快速实现

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

如果在仿真器中查看模块名,模块会被自动进行编号

通过路径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

可以看到访问成功

如果通过文章开头说的方式,就会出现错误

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

其实主要原因是,这个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,否则字符串会与真实路径不匹配

可以看到访问成功

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一应俱全

如果有更好的办法,欢迎留言

#Java#
全部评论

相关推荐

2025-12-17 13:34
复旦大学 算法工程师
回家当保安:复旦✌🏻,佬你的简历感觉挺好的,寒假日常hc比较少。佬可以过完年之后再试试,日常实习hc比较充足
点赞 评论 收藏
分享
2025-11-21 22:25
门头沟学院 HTML5
我是个没天赋的人,努力学习也只考上了个一本,家里条件也不怎么样。大一玩了一年,没怎么学技术,也没有卷绩点,全在游戏小说抖音中度过。大二上接触了牛客,看到了许多优秀的同龄人。很多双非的同学,甚至不少学院本的同学都进了大厂实习。我把他们作为榜样,决定好好学习。我每天都至少学八九个小时,很多次都想要放弃,想哭,我都坚持了下来。我总是告诉自己,只要努力,就一定能有好的结果。这几个月过的很累,但也很充实。转眼就到大二下了,我决定去找实习了,但是学校的认可度让我感到心底发凉,明明和广工这种知名双非分差不多,结果总被问是不是公办本科。两个月投了一千份实习,只有四个面试,最终去了个中小厂实习。结果就是改了两个月bug,虽然mt人挺好,但是实在学不了什么东西,所以就离职开始面试。凭借这段实习,确实多了不少中小厂面试,但是大厂依旧没有面试机会。除了字节腾讯所有大厂都投了,结果依旧是0面试。最终有幸获得美团的面试机会,面试也幸运的通过,然后入职了。为了省钱坐十几个小时硬座到北京,到北京的第一天,由于太激动想要租房,结果被坑了2600,之前实习的地方,房东也故意不退押金,加起来总共损失3000多。虽然很难过,但是我还是忍受了下来,我想着实习才刚开始,会好起来的。实习了大半个月,跟学校这边沟通一直不成功,我每天都寝食难安,精神都快崩溃了,经常凌晨两三点才睡着,想要跳楼。最后迫于无奈,我一大早我坐高铁回去,恳求院主任给我一个机会,我怎么恳求讲理都没用,甚至都磕头下跪了,还是没用。院主任一点机会都没给我,连让我跟各科老师沟通机会都不给,要不休学要不辞职。我没得选择,这段实习我看的比我的生命还重要,这不仅是我这大半年的心血,更是未来的一份希望。我只能休学,我想着现在好好实习,多学点技术,到时候秋招早点拿到offer,然后再补这学期的课也不是不行。但是,现实总是事与愿违。这三个月说实话并没有学到什么东西,前一个月很闲,这两个月事很多,每天基本都是九点后下班,但都是杂活。产出都是靠我看文档加上代码写上去的。我真的很想锻炼一下技术,但是总是不尽人意。三个月了,我到现在都还没做过一个像样点的需求。产出是能编,但有破绽不说还没锻炼到技术。我好想真正的做一下需求啊,我好想真正的走完一遍流程,去上线一次啊。接下来两个月,我不知道该怎么坚持下去了,现在每天都想哭,很焦虑,很难受。冒着将来可能延毕的风险,我赌上了一切,结果输的这么彻底,可能我就只是个小丑吧。如果家庭好点就不用卷了,如果我聪明一点就能上个好学校了,如果大一有人带我,我就不会摆烂了,如果院主任给我个机会,我就不用这么苦了,如果我实习能有机会好好锻炼自己,我就不用这么难受焦虑了。但是没办法,我又能怎么办呢,无非是咬紧牙关罢了,毕竟没人能够帮助我,只能靠自己我可真是个小丑啊
HasonoCell:你很棒了bro....其实我看网上休学一年的人很多的也都顺利毕业了,真的不用特别焦虑这个事。另外实习也是,有一段大厂实习已经比很多很多人厉害了,跟你一届的很多人现在估计都没意识到未来的压力呢,实习就算没产出也不用特别焦虑,好好总结一下已经做过的事情,然后趁着休学这年继续冲一下,要相信未来会有好结果的。你应该也挺眼熟我的,我之前字节横向挂的时候也是难过的不行,觉得自己好没用,结果百度出乎意料的offer了,很多事其实都很顺其自然,认真做事,好结果也许就在下个路口等着你。 很喜欢的一句话是:木已成舟。不要老是沉浸在过去的遗憾中无法自拔噢,要努力过好当下。 好好休息一下吧,辛苦了,你已经很棒了噢
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务