项目场景:
今天练习Verilog语法遇到了一个这样的问题,是以下练习的延伸拓展:原题如下:
A linear feedback shift register is a shift register usually with a few XOR gates to produce the next state of the shift register. A Galois LFSR is one particular arrangement where bit positions with a “tap” are XORed with the output bit to produce its next value, while bit positions without a tap shift. If the taps positions are carefully chosen, the LFSR can be made to be “maximum-length”. A maximum-length LFSR of n bits cycles through 2n-1 states before repeating (the all-zero state is never reached).
The following diagram shows a 5-bit maximal-length Galois LFSR with taps at bit positions 5 and 3. (Tap positions are usually numbered starting from 1). Note that I drew the XOR gate at position 5 for consistency, but one of the XOR gate inputs is 0.

原题需要我们设计一个线性反馈移位寄存器,其中的抽头端口需要前一级寄存器输出和最后一级输出作异或运算,我采用了以下解法:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output [4:0] q
);
wire q3_xor,q5_xor;
reg [4:0] q_reg;
always@(posedge clk)begin
if(reset)begin//复位置1
q_reg <= 5'd1;
end
else begin//循环赋值
q_reg[0] <= q_reg[1];
q_reg[1] <= q_reg[2];
q_reg[2] <= q3_xor;
q_reg[3] <= q_reg[4];
q_reg[4] <= q5_xor;
end
end
assign q5_xor = q_reg[0] ^ 1'b0;
assign q3_xor = q_reg[0] ^ q_reg[3];
assign q = q_reg;
endmodule
问题描述
随后在延伸题中要求搭建32位宽的线性反馈移位寄存器,并且在数据第1、2、22、32bit处设置抽头。我的思路沿用上一题的主要思路。采用 generate - for 语句设计,当数据位在需要设置抽头处时,将数据由组合逻辑异或运算后得到的数据进行移位寄存,设计代码如下:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
wire q1_xor,q2_xor,q22_xor,q32_xor;
reg [31:0] q_reg;
genvar i;
generate
for(i=0;i<32;i=i+1)begin:LFSR
always@(posedge clk)begin
if(reset)begin
//正确写法:
if(i==0)begin
q_reg[i] <= 1'b1;
end
else begin
q_reg[i] <= 1'b0;
end
//错误写法
//q_reg <= 32'h1;
end
else if(i==0)begin
q_reg[0] <= q1_xor;
end
else if(i==1)begin
q_reg[1] <= q2_xor;
end
else if(i==21)begin
q_reg[21] <= q22_xor;
end
else if(i==31)begin
q_reg[31] <= q32_xor;
end
else begin
q_reg[i] <= q_reg[i+1];
end
end
end
assign q1_xor = q_reg[1] ^ q_reg[0];
assign q2_xor = q_reg[2] ^ q_reg[0];
assign q22_xor = q_reg[22] ^ q_reg[0];
assign q32_xor = 1'b0 ^ q_reg[0];
assign q = q_reg;
endgenerate
endmodule
原先的设计中复位部分采用被注释掉的部分代码,即对整个32位宽的变量直接进行复位赋值操作,编译后系统报错:
Error (10028): Can't resolve multiple constant drivers for net "q[31]" at top_module.v(12) File: /home/h/work/hdlbits.7271746/top_module.v Line: 12
原因分析:
刚开始我在看到这个报错的时候考虑到会不会是我哪里变量命名重复了,修改代码发现把同步复位32位宽的变量赋值去掉就不会报错了。但是for循环的begin - end 是顺序执行的,所以在满足复位条件后应该不会出现重复赋值的情况才对。把同步复位的赋值操作改为单bit位赋值操作后编译通过了,我的理解应该是在generate - for 语句的 for循环的执行语句中,应该是只能对单个bit位进行赋值操作,而不能对多个位宽的变量同时进行多个位宽的赋值。
解决方案:
只要在generate - for 循环的执行程序换成对单bit进行赋值的语句即可,同时本题也有更加简便的做法:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
reg [31:0] q_next;
always@(posedge clk)begin
if(reset)
q <= 32'd1;
else
q <= q_next;
end
always@(*)begin
q_next = {q[0],q[31:1]};//shift operation
q_next[21] = q[0] ^ q[22];//to get the xor bit
q_next[1] = q[0] ^ q[2];
q_next[0] = q[0] ^ q[1];
end
endmodule
将组合逻辑和时序逻辑分开,采用组合逻辑数据进行移位操作和抽头的设置,其中的移位操作必须要放在首位执行,剩余的阻塞赋值没有顺序要求。
总结:
我没有按照答案的思路一开始就采用组合和时序电路分开的写法,而是采用了generate - for 语句来实现,反而发现了一个以前都没有注意到的bug,真是应了那一句“你走过的路,都会成为你的财富”呀,与大家共勉!

本文探讨了如何在Verilog中设计一个32位线性反馈移位寄存器(LFSR),重点在于如何在特定位(1、2、22、32)设置抽头。作者分享了使用generate-for语句的实践过程,遇到的编译错误及其解决方案,最后提出了一种更简洁的代码结构,将时序逻辑和组合逻辑分开处理。
1128

被折叠的 条评论
为什么被折叠?



