解决Verilog中for循环调用generate生成任务的非法索引错误
Verilog批量循环调用generate生成的task报错解决
问题描述
我用generate块批量创建了多个task实例,此前用该方式批量实例化模块可行,因此想同理批量生成无参task,并通过循环调用,调用数量由参数决定(示例中为4,实际为参数)。编写的代码中,当用for循环调用create_task[i].print_i时,出现**"A variable index into the for generate block is illegal"**错误;但单独逐个调用各task则无报错。请问如何正确实现批量循环调用的需求?
代码示例
task display; fork other_tasks(); for(int i=0; i<4; i++) begin create_task[i].print_i; end // create_task[0].print_i; // create_task[1].print_i; // create_task[2].print_i; // create_task[3].print_i; join endtask generate for(genvar i=0; i<4; i++) begin : create_task task print_i(); $display("%t, %m, Message #%0d", $time, i); #1; endtask end : create_task endgenerate
原因分析
generate块是编译阶段展开的,生成的create_task[0]、create_task[1]等是静态命名的标识符,属于编译时确定的层次结构。而你在display task里使用的是运行阶段的变量i作为索引,Verilog语法不允许用运行时变量来索引generate块生成的静态层次结构,因此触发报错。
解决方法
方法1:用generate块展开调用逻辑
把调用循环也放到generate块中,利用genvar的编译时特性展开调用语句,这样每个调用都是编译时确定的静态路径:
task display; fork other_tasks(); // 用generate块生成静态调用语句 generate for(genvar j=0; j<4; j++) begin : call_tasks create_task[j].print_i; end endgenerate join endtask generate for(genvar i=0; i<4; i++) begin : create_task task print_i(); $display("%t, %m, Message #%0d", $time, i); #1; endtask end : create_task endgenerate
方法2:封装task到模块,实例化模块数组
如果需要支持运行时动态索引调用,可以把task封装到模块里,实例化模块数组,模块数组支持用运行时变量索引:
// 封装task的模块 module task_module #(parameter ID = 0); task print_i(); $display("%t, %m, Message #%0d", $time, ID); #1; endtask endmodule task display; fork other_tasks(); for(int i=0; i<4; i++) begin task_arr[i].print_i; end join endtask // 实例化4个模块组成的数组 task_module #(.ID(0)) task_arr[3:0](); // 注:如果需要每个模块ID不同,可以用generate块设置参数 // generate // for(genvar i=0; i<4; i++) begin // task_module #(.ID(i)) task_arr[i](); // end // endgenerate
方法3:SystemVerilog下用句柄数组存储task
如果使用SystemVerilog,可以将生成的task句柄存入动态数组或队列,运行时直接遍历数组调用,这种方式更灵活:
// 定义task类型 typedef void task_print_t(); task_print_t task_list[]; generate for(genvar i=0; i<4; i++) begin : create_task task print_i(); $display("%t, %m, Message #%0d", $time, i); #1; endtask // 初始化时将task句柄加入数组 initial begin task_list.push_back(create_task[i].print_i); end end : create_task endgenerate task display; fork other_tasks(); // 遍历数组调用所有task foreach(task_list[idx]) begin task_list[idx](); end join endtask
内容的提问来源于stack exchange,提问作者zhao979
相关产品推荐
相关产品推荐

