Verilog的一些思考

一、怎么表示可变位宽变量的最大值?

  在对RTL模块的设计时,我们有时候需要取某个变量能表示的最大值,对于我们确定位宽的变量,我们可以直接表示其最大值,例如:

// 变量位宽为4
module tb
(
);
reg  [3:0]  temp;
  always @(*) temp <= 4'b1111;

endmodule  

  实际上,要求模块的可复用性,在很多时候内部变量的位宽在模块例化的时候是可以修改的,例如:

// 变量位宽为4
module tb
#(
  paramter  Dat_W = 4
)
();
reg  [Dat_W-1:0]  temp;
  always @(*) temp <= 4'b1111;

endmodule  

  这里,如果我们在例化该模块时修改了Dat_W的值,修改为更大的值,比如6,那么这里4’b1111所表示的并不是位宽为6所能表示的最大值,实际上的最大值应该为6’b111111。那么,我们可以通过位拼接的方式取其最大值,如下:

// 变量位宽为4
module tb
#(
  paramter  Dat_W = 4
)
();
reg  [Dat_W-1:0]  temp;
  always @(*) temp <= {(Dat_W){1'b1}};

endmodule  

可以参考:HDL Bits例题

二、怎么快速计算某个变量二进制表达中“1”的个数?

  怎么统计一个二进制数中1的个数?比如,二进制数8’b11001010中1的个数为4,怎么得到4?参考博客《统计1的个数(Verilog)》,其代码如下:

module test(
	input [7:0]data_in,
	output [3:0]out
);

// 写法一:
	reg [3:0]width;
	reg [3:0]cnt;
	
	always@(data_in)begin
		cnt = 'd0;
		for(width = 0; width < 8; width = width + 1)begin
			if(data_in[width])
				cnt = cnt + 1'b1;
			else
				cnt = cnt;
		end
	end
	
	assign out = cnt;

// 写法二:
//	assign 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];

endmodule

  为了方便对不同位宽的数据进行统计,而不需重复修改代码内部,也可以这么写:

module test
#(
	parameter Din_W = 8,
	parameter Dout_W = $clog2(Din_W)
) 
(
	input [Din_W-1:0]data_in,
	output [Dout_W-1:0]out
);

// 写法三:
	wire [Dout_W-1:0] out_wire [Din_W-1:0];
	genvar i;
	generate
		for(i = 0;i<Din_W;i = i + 1) begin:number_cal
			if(i == 0)
				assign out_wire[i] = data_in[i];
			else
				assign out_wire[i] = data_in[i] + out_wire[i-1];
		end		
	endgenerate
	
	assign out = out_wire[Din_W-1];
endmodule

写法一:RTL视图
在这里插入图片描述
资源使用报告
在这里插入图片描述
写法二:RTL视图
在这里插入图片描述
资源使用报告
在这里插入图片描述
写法三:RTL视图
在这里插入图片描述

资源使用报告
在这里插入图片描述

三、位索引[0:3]与[3:0]的区别?

  在Verilog中对变量进行声明时,有时候会见到以下两种声明情况:

wire [7:0] a;
wire [0:7] b;
wire [3:0] c;
wire [0:3] d;

  那么这两种的区别在哪里?
  第一,对于变量的部分索引必须与变量声明的顺序一致(升序或者降序),比如:

assign c = a[7:4]; //正确索引
assign c = a[4:7]; //错误索引
assign d = b[0:3]; //正确索引
assign d = b[3:0]; //错误索引

  第二,对于变量赋同一值,两种低位和高位是不一致的,比如:

assign a = 8'b10101100; //左边第一位为最高位,即a[7]=1;右边第一位为最低位,即a[0]=0;
assign b = 8'b10101100; //左边第一位为最低位,即a[0]=1;右边第一位为最高位,即a[7]=0;

wire e,f;
assign e = a[0]; //e=0
assign f = b[0]; //f=1

  在有些设计中,我们需要使用正序索引,而有些情况下使用反序索引会更方便,可以根据需求进行选择。
参考:HDL Bits例题

四、if-else在组合逻辑中的等价替换——三目运算符的嵌套

  在时序逻辑中,对于一个变量在不同条件下进行赋值,我们可以使用if-else进行条件判断,然后进行赋值,那么在组合逻辑中,我们可以使用三目运算符进行替换,比如:

always @(posedge clk)
	if(条件1)
		a = 数值1;
	else
		a = 数值2;

  那么,在组合逻辑中,我们可以用三目运算符进行替换,如下:

assign a = (条件1) ? 数值1 : 数值2;

  而对于if-else的多级嵌套,同样可以使用三目运算符替换,例如:

always @(posedge clk)
	if(条件1)
		a = 数值1;
	else if(条件2)
		a = 数值2;
	else if(条件3)
		a = 数值3;
	else
		a = 数值4;

  同样,在组合逻辑中可以使用三目运算符嵌套进行替换,如下:

assign a = 条件1 ? 数值1 : 条件2 ? 数值2 : 条件3 ? 数值3 : 数值4;

  再比如:

always @(posedge clk)
	if(条件1)
		a = 数值1;
	else if(条件2)
		if(条件3)
			a = 数值2;
		else
			a = 数值3;
	else
		a = 数值4;

  在组合逻辑中可以替换为:

assign a = 条件1 ? 数值1 : 条件2 ? (条件3 ? 数值2 : 数值3) : 数值4;

  虽然if-else在组合逻辑的等价替换——三目运算符可以实现同样的功能,但是这样一来,对于多重的三目运算符嵌套,会造成路径延时过大的问题。

五、

六、

未完待续… … …

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值