【Verilog】generate-for循环语句执行语句不能对多位宽数据赋值

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

今天练习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,真是应了那一句“你走过的路,都会成为你的财富”呀,与大家共勉!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值