不想错过我的推送,记得右上角-查看公众号-设为星标,摘下星星送给我
![755275be8d2441cd05e28952a76f7543.gif](https://i-blog.csdnimg.cn/blog_migrate/1b37a6b8848ee08c1206df2e2eb49519.gif)
![66c7e8fe2f60ea6e7adfc975e4fda668.gif](https://i-blog.csdnimg.cn/blog_migrate/b043ef2e12032dff723ea7d1c7a9bf23.gif)
欢迎大家加入2022届数字IC交流群,QQ群号 1060380138
动机
今天一个朋友问了这样一个问题
![62f304bfcd64bf6752400e12ad4a11cb.png](https://i-blog.csdnimg.cn/blog_migrate/f3b1903f71b3067e03d54e1da5382c40.png)
失败原因
首先介绍一下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
,也可以快速实现
![0ff88ed6eb03c9a5b35058ed417da634.gif](https://i-blog.csdnimg.cn/blog_migrate/25fc24538cea2e4081fdc9351ebcdbe4.gif)
同样的,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
如果在仿真器中查看模块名,模块会被自动进行编号
![7d5e4bf9e6b893c5fce2a238b997a203.png](https://i-blog.csdnimg.cn/blog_migrate/df09f7d5e145e228f926dcb80e5c0bfe.png)
通过路径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
可以看到访问成功
![d120fe4c0829bbb12ca4544d4a987ae4.png](https://i-blog.csdnimg.cn/blog_migrate/e5ef7a8d5a0cded195686c70eed2c8fa.png)
如果通过文章开头说的方式,就会出现错误
for (int i = 0; i<4 ; i++ ) begin
$display("c_f[%0d]:%h",i_test.genblk1[i].i_adder.c_f);
end
![ff49853cec0d54349af107a7cdde9518.png](https://i-blog.csdnimg.cn/blog_migrate/e638d8d274db0c4aace762ba029bef68.png)
其实主要原因是,这个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
有几个注意事项
- 在描述路径时,要传入绝对路径,不能使用相对路径
- 在描述路径时,使用
%0d
,否则字符串会与真实路径不匹配
可以看到访问成功
![dc35a19980f403daaf702333fe1e6ef3.png](https://i-blog.csdnimg.cn/blog_migrate/e5eb7ccadec80abb472e011b4c117293.png)
下面给出完整代码
// 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
一应俱全
![6b936a683dfd7bc7785c64f94d7c0ebf.png](https://i-blog.csdnimg.cn/blog_migrate/2939edc1e325a76dfaa9157677de4770.png)
如果有更好的办法,欢迎留言
END![e223a857ee728272e9272c2e3ed402d9.png](https://i-blog.csdnimg.cn/blog_migrate/454472d8e17187071b778538949b9678.png)
打个广告
路科验证V2课程大升级啦,升级后的V2pro,不仅保留了原本V2的所有内容,还添加了关于vim、linux、DVT的操作教程,以及寄存器模型自动化,更有定制的个性项目,为你的简历添砖加瓦。如果想要学习SV和UVM,想要入门或者转行验证,路科验证V2pro不容错过!如果对课程有兴趣可以后台联系我,可以获得优惠!
?路科拍了拍你 | 嘿 别忘了 V2Pro秋季班本周日就开班哟?
后台回复路科验证还可以享受200元优惠!!!欢迎报名~
精彩专辑
备战秋招专辑
验证工程师面试攻略专辑
《数字集成电路静态时序分析基础》笔记专辑
深入AXI4总线专辑
UVM实战专辑
秋招记录专辑
静态时序分析圣经翻译计划
点击在看,分享给你的朋友吧?