代码之家  ›  专栏  ›  技术社区  ›  Roman Andreevitch Biriukov

verilog合成中从外部源接收输入时出现多个驱动器问题

  •  0
  • Roman Andreevitch Biriukov  · 技术社区  · 7 年前

    我试图在GCD算法有限状态机上进行综合,该算法使用“如果较大,则减去”方法。我会附上代码,试着提出一个像样的问题。

    module GCD_R (A,B,out,nrst,act,clk,fla_g);
      input [31:0] A, B;
      input clk, act, nrst;
      output reg fla_g;     
      output reg [31:0] out;
      reg [3:0] state, next_state;
      reg [31:0] A_reg, B_reg, Aint_reg, Bint_reg, out_reg;//2 registers will keep intermediate numbers+out, and next numbers
      parameter IDLE = 3'b001;
      parameter ABIG = 3'b010;
      parameter BBIG = 3'b100;
      reg next_flag;
    
    
      always @(*)   
        case (state)
          IDLE: begin
            $display("start");
            if(act == 0) begin
              A_reg = A; //A,B are wires that contain numbers from an external source
              B_reg = B; //first assign to A_reg and B_reg
              out_reg = 31'bx;
              next_flag = 1'b0;
              next_state = IDLE;
            end
            if(act == 1)
              if(A_reg==0) begin
                out_reg = B_reg;
                next_flag = 1'b1; //testbench will know when we stopped 
                Aint_reg = A_reg; //taking care not to infer latches
                Bint_reg = B_reg; 
                next_state = IDLE;
              end
              else if (B_reg==0) begin  
                out_reg = A_reg;
                next_flag = 1'b1;
                Aint_reg = A_reg; //taking care not to infer latches
                Bint_reg = B_reg;
                next_state = IDLE;
              end                       
              else if (A_reg >= B_reg) begin
                out_reg = 31'bx;
                next_flag = 1'b0;
                Aint_reg = A_reg;
                Bint_reg = B_reg;
                next_state = ABIG;
              end
              else begin
                out_reg = 4'bxxx;
                next_flag = 1'b0;
                Aint_reg = A_reg;
                Bint_reg = B_reg;
                next_state = BBIG;
             end
           else
            begin
             Aint_reg = A_reg;
             Bint_reg = B_reg;
             out_reg = 4'bxxx;
             next_flag = 1'b0;  
             next_state = 4'bx;
            end
         end
    
         ABIG: begin
           if (A_reg==0 | B_reg==0) begin
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = IDLE;
             Aint_reg = A_reg;
             Bint_reg = B_reg;
           end
           else if (B_reg > A_reg) begin
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = BBIG;
             Aint_reg = A_reg;
             Bint_reg = B_reg;
           end
           else begin
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = ABIG; 
             Aint_reg = A_reg - B_reg;
             Bint_reg = B_reg;
           end
         end
    
         BBIG: begin 
           if (A_reg==0 | B_reg==0) begin
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = IDLE;
             Aint_reg = A_reg;
             Bint_reg = B_reg;
           end 
           else if (A_reg > B_reg) begin 
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = ABIG;
             Aint_reg = A_reg;
             Bint_reg = B_reg;
           end
           else begin 
             out_reg = 31'bx;
             next_flag = 1'b0;
             next_state = BBIG; 
             Aint_reg = A_reg;
             Bint_reg = B_reg - A_reg;
           end  
         end
    
         default: begin
           out_reg = 31'bx;
           next_flag = 1'b0;
           next_state = 4'bx;
           Aint_reg = A_reg;
           Bint_reg = B_reg;
           $display("%t: State machine not initialized/n",$time);
         end
       endcase
    
     always @(posedge clk or negedge nrst)
       if (~nrst) begin
         state <=  IDLE;//we get the new values by resetting first
         out <= 4'bx;//we don't want anything there at the reset
         fla_g <= 1'b0;
       end
       else begin
         state <=  next_state;//otherwise, get the next state and the next registers to the intermediate ones
         A_reg <=  Aint_reg;// 2nd assign to A_reg and B_reg- that's the problem
         B_reg <=  Bint_reg;
         out <=  out_reg;
         fla_g <= next_flag;
       end
    
    endmodule
    

    首先,A和B是通过外部源(测试台中的一些文本文件)接收要比较的数字列表的导线。

    A_reg和B_reg是中间寄存器,用于保存我们正在检查“if”语句的数字,

    Aint\U reg和Bint\U reg是在操作后保留寄存器中间值的寄存器,仅在时钟上升时将其发送回A\U reg和B\U reg,

    问题是如何形成的:

    您可以看到,在开始时 if(act == 0) 条件它放在那里是为了确保A、B导线(外部接收)上的值将进入那里的寄存器,而不是在我们处于 if(~nrst) 条件,因为在重置时输入动态值没有意义。

    这就把我们带到了当前的问题——我知道在顺序块和组合块中为a和B赋值是造成问题的原因,但我只是找不到替代方法。

    p、 我使用 A_reg = A 创建闩锁,因为我没有指定给 A_reg 在其他地方,这是自写作以来的另一个问题
    Aint_reg = A_reg; A_reg = Aint_reg;
    要满足我对闩锁的不满意。

    p、 s.2。我试着在网站上研究类似的问题,但由于我对这个问题缺乏足够的知识,我无法将我的问题与外面的问题联系起来

    我很乐意接受任何帮助,谢谢

    编辑: 我删除了if(~ nrst)顺序块中的非阻塞分配,以便不进行多次分配 A_reg <= 0 那里和 A\u reg=A 在组合块中,但多重赋值问题仍然存在某种缺陷

    编辑2: 似乎我忘记了一件基本的事情-不要在两个不同的“始终”块中分配给同一个变量,但我只是想不出一个足够好的解决方案来将导线a、B分配给寄存器,而不是在顺序块中再次分配给它

    1 回复  |  直到 7 年前
        1
  •  1
  •   Unn    7 年前

    您正确地确定了代码中的主要问题是没有正确处理寄存器和组合逻辑。只要你有一个寄存器(寄存器,而不是 reg 类型,它们不一样,对于那些刚接触Verilog的人来说,这很容易混淆),您需要以特定的方式定义它,以便合成和模拟工具能够处理它。最安全的做法是在组合逻辑和顺序存储(即实际寄存器)之间创建一个干净的分离。你开始这样做 Aint_reg , Bint_reg , out_reg 等但您需要对其值来自组合块的所有注册值执行此操作。因此,所有这些想法一起产生了这样的代码结构(不完全是您的代码,而是类似的东西):

    input [31:0] A, B;
    output reg [31:0] out;
    
    reg [31:0] regA, regB;
    reg [3:0] state, nextState;
    
    always @(posedge clk or negedge rst) begin
      if (~rst) begin
        regA <= '0;
        regB <= '0;
        state <= IDLE;
      end
      else begin
        regA <= nextA;
        regB <= nextB;
        state <= nextState;
      end
    end
    
    always @(*) begin
      // Default; I always do this here to ensure there are no cases in which I dont assign a combinational value for this block
      // it always helps me keep track of which variables are assigned in which block
      nextA = regA;
      nextB = regB;
      nextState = state;
    
      out = '0;
    
      case (state)
        // In here is your case body, where you can reassign nextA, nextB, nextState and out
        // where the assignments are only dependent on A, B, regA, regB and state (ie, the values NOT assigned in this block)  
      endcase
    end
    

    记住这一点,你只需要 Aint\u注册 , Bint\U注册 等;所以你不需要分配 A_reg , Breg ,等等。还请注意,如果这意味着输出的计时将被延迟,那么如果需要立即从组合块中推出值,则始终可以绕过寄存器。据我所知,您可能在重置期间遇到加载问题,只要重置,这是可以理解的( nrst )断言(即0),则不会加载任何内容。这就是重置的整个点,将系统保持在已知状态,直到其提升。所以直到 nrst公司 已取消评估,您的模块不应执行任何操作。其他几点:

    • 正确格式化代码非常重要,确保代码始终干净,因为它有助于发现错误。我重新格式化了它,似乎缺少一个 begin..end IDLE 状态
    • 总是 开始终止 你的区块,它将避免这么多的错误
    • 注意事物的大小,我看到您将变量声明为32位 reg [31:0] 但是只使用 31'd 这是31位。使用 '0 语法为零填充任何大小。
    • 将寄存器设置为 'x 这并不理想,您应该让寄存器保持其状态(正如您对寄存器值和下一个寄存器值所做的那样)。

    希望这能为你澄清一些事情。