VL8 使用generate_for语句简化代码

时间:2022-10-07 16:53:08

写在前面

  1. 这个专栏的内容记录的是Verilog题库刷题过程,附带RTL\TestBench,并进行代码覆盖率收集
  2. 该题库算是一个Verilog宝藏刷题网站了,提供在线仿真环境(题库),<刷题记录>专栏,持续打卡中…


一、题目

(1)题目描述

  在某个module中包含了很多相似的连续赋值语句,请使用generate…for语句编写代码,替代该语句,要求不能改变原module的功能。使用Verilog HDL实现以上功能并编写testbench验证。


(2) 原程序

module template_module( 
    input [7:0] data_in,
    output [7:0] data_out
);
    assign data_out [0] = data_in [7];
    assign data_out [1] = data_in [6];
    assign data_out [2] = data_in [5];
    assign data_out [3] = data_in [4];
    assign data_out [4] = data_in [3];
    assign data_out [5] = data_in [2];
    assign data_out [6] = data_in [1];
    assign data_out [7] = data_in [0];
    
endmodule

二、分析

1、generate语法结构

  • 定义genvar,作为generate中的循环变量。
  • generate语句中定义的for语句,必须要有begin
  • begin必须要有名称,也就是必须要有标签,因为标签会作为generate循环的实例名称。

  
2、generate:循环语句(loop)

//例子
'timescale 1 ns /1 ps
module nbic xor
#(parameter SIZE = 16)
(
	input  [SIZE-1 : 0] a, 
	input  [SIZE-1 : 0] b, 
	output [SIZE-1 : 0] y 
	);

	genvar gv_i; //这这类型的变量只能在generate循环语句中使用
	generate
		for (gv_i = o ; gv_i < SIZE ; gv_i = gv_i +1) begin : label
		// label用来表示generate循环的实例名称
		
			xor u_xor (y[gv_i] , a[gv_i] , b[gv_i]);
			//实例化后的结果如下:
			// label [0].u_xor (y[0] , a[0] , b[0]); 
			// label [1].u xor (y[1] , a[1] , b[1]);
			// label [2],u_xor (y[2] , a[2] , b[2]);
			// ... ...
			// label [SIZE-1].u_xor (y[SIZE-1] , a[SIZE-1] , b[SIZE-2]);
			//实例化后的层次路径如下:
			// nbit xor.label [0].u_xor;
			//... ...
			//同理,还可以引用别的已经定义的module在generate语句中实例化
		end 
	endgenerate
endmodule

  
3、generate:条件语句(conditional)

'timescale 1 ns /1 ps
module shift register 
#(parameter BITS = 8)
( 
	input shift_in , 
	inpuc clk      , 
	input resetn   ,
	output shift_out 
);
	wire [BITS-1 : 0] tq;
	
	genvar gv_1; //这种类型的变量只能在generateim环语句中使用
	// generate-condiciona1语句实质上是将条件语句放入到generate-for结构中
	/*在该条件语句结构中,if语句的条件必须是静态的,这样的条件表达式
		必须是由常数或者参数组成,也意味着在程序运行期间保持不变*/
	generate
		for (gv_1 =o : gv_i < BITS : gv_1 = gv_1 +1)begin : label
			if (gvi == BITS-1) begin//此条件成立时, u0dff
				dflip_flop uodff (
												 .d(serial_in) ,
												 .resetn (resetn) ,
												 .ck (clk) , 
												 .q(ta[gv_1])
											);
			end
			else begin
				if (gv_i == 0)begin //此条件成立时, uldff
					dflip_flop uldff (
												  .d(tg[gv_1 + 1]) , 
												  .resetn (resetn) , 
												  .ck (clk) , 
												  .g(serial_out));
				end
				else begin//其他情况下, u2dff
					dflip_flop u2dff (
													.d(tq[gv_i + 1]) ,
													.resetn (resetn) , 
													.ck(clk) , 
													.q(t[gv_11)
												);
				end
			end
	end 
endgenerate
endmodule

generate允许对语句进行条件选择,即将条件选择加入到generate中的for循环中,只例化条件成立时对应的语句或者module。


4、generate:分支语句(case)

'timescale 1 ns /1 ps
module adder
# (parameter N =4)
(
	input 		 	 ci,
	input  [N-1 : 0] ao, 
	input  [N-1 : 0] al,
	output 			 co,
	output [N-1 : 0] sum 
)//注意:未定义genvar变量//根据总线的位宽,调用相应的加法器
// 参数N在调用时可以重新定义,但是该值也是静态的,因为每次调用时N都是必须确定的
//调用不同位宽的加法器是根据不同的N来决定的
generate
	case (N)
		//N=1或者2时分别选用位宽为1位或2位的加法器
		1: adder_lbit adder1 (co , sum, ao , al , ci); // 1位的加法器
		2 : adder_2bie adder2 (co sum, ao, al , ci): // 2位的加法器1/默认的情况下选用位宽为N位的加法器
		default : adder_cla # (N) adder3 (co , sum , ao , al , ci);
	endcase
endgenerate
endmodule

三、RTL

module gen_for_module( 
  input  [7:0] data_in ,
  output [7:0] data_out
);

/*
  assign data_out [0] = data_in [7];
  assign data_out [1] = data_in [6];
  assign data_out [2] = data_in [5];
  assign data_out [3] = data_in [4];
  assign data_out [4] = data_in [3];
  assign data_out [5] = data_in [2];
  assign data_out [6] = data_in [1];
  assign data_out [7] = data_in [0];
*/
genvar gv_i;

generate
  for(gv_i=0;gv_i<8;gv_i=gv_i+1)begin:gv_label
    assign data_out[gv_i] = data_in[7-gv_i];
  end
endgenerate

endmodule



四、Testbench

`timescale 1ps/1ps
module tb_gen_for_module;
  reg [7:0] data_in ;
  reg [7:0] data_out;

/*-----------------------------------------------\
 --    --
\-----------------------------------------------*/
initial begin
    repeat(10000)begin
      d_case(data_in,{$random}%256);
      #5000 ;
  end
end

/*-----------------------------------------------\
 --    --
\-----------------------------------------------*/
task d_case;
  output  [7:0] a;
  input   [7:0] b;

  a = b;

endtask

/*-----------------------------------------------\
 --  display  --
\-----------------------------------------------*/
always @ (data_out)begin
  if(data_out == {data_in[0],data_in[1],data_in[2],data_in[3],
                  data_in[4],data_in[5],data_in[6],data_in[7]})begin
  end
  else begin
    $display($realtime,", error:gv_i = ;data_in = %d;data_out = %d",data_in,data_out);
  end
end

gen_for_module u_gen_for_module(
                                .data_in  (data_in  ),
                                .data_out (data_out )
                               );

initial #60000000 $finish;
initial begin
  $fsdbDumpfile("gen_for_module.fsdb");
  $fsdbDumpvars            ;
  $fsdbDumpMDA             ;
end
endmodule

五、结果分析

(1)TB结果

VL8 使用generate_for语句简化代码VL8 使用generate_for语句简化代码

display无打印错误信息


(2)波形图

VL8 使用generate_for语句简化代码

由上图可以知道,输出是输入的一个移位,使用generate-for简化代码的运行结果和原来一致。


(3)覆盖率

VL8 使用generate_for语句简化代码

代码覆盖率100%


✍✍☛ 题库入口
  经过一段时间的沉淀,发现入行IC行业,自己的底子还是很差,写的文章质量参差不齐,也没能解答大家的疑问。决定还是要实打实从基础学起,由浅入深。因此决定通过补充/完善基础知识的同时,通过题库刷题不断提高自己的设计水平,题库推荐给大家(点击直达),<题库记录>栏目不定期更新,欢迎前来讨论。


作者:xlinxdu
版权:本文版权归作者所有
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。