在verilog综合中从外部源接收输入时出现多驱动问题

时间:2017-12-07 22:32:13

标签: verilog synthesis greatest-common-divisor elaboration

我试图做的综合是在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是中间寄存器,用于保存我们正在检查的数字&#34;如果&#34;声明,

Aint_reg和Bint_reg是在操作之后保持寄存器的中间值的寄存器,仅在时钟上升时将它们发送回A_reg和B_reg,

行动决定机器是否开启&#34;开启&#34;模式并可以执行算法

nrst是负重置切换

问题是如何形成的:

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

这将我们带到当前的问题 - 我知道在顺序和组合块中为A和B分配值是产生问题的原因,但我无法找到替代方案。

P.S。我使用A_reg = A这一事实会创建锁存,因为我不会在其他任何地方分配给A_reg,这是自写作以来的另一个问题 Aint_reg = A_reg; A_reg = Aint_reg;
满足闩锁并不适合我。

p.s.2。我试着在网站上查看类似的问题,但由于我对这个问题缺乏足够的了解,我无法将问题与那些问题联系起来

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

编辑:我删除了if(~nrst)顺序块中的非阻塞分配,以便不在组合块中多次分配A_reg <= 0A_reg = A,但多重分配问题仍然以某种方式存在错误

EDIT2:似乎我忘记了一个基本的事情 - 不要在两个不同的&#34;总是&#34;中分配相同的变量。块,但我想不出足够好的解决方案将线A,B分配给寄存器而不是在顺序块中再分配给它

1 个答案:

答案 0 :(得分:1)

您在识别代码中的主要问题时是正确的,即您没有正确处理寄存器和组合逻辑。无论何时你有一个寄存器(寄存器,而不是reg类型,它们都不一样,并且对于那些刚接触Verilog的人来说很困惑),你需要以特定的方式定义它,因此综合和仿真工具可以处理它。最安全的做法是在组合逻辑和顺序存储(即实际寄存器)之间创建一个干净的分离。您开始使用Aint_regBint_regout_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_regBint_reg等;所以你不需要在组合块中分配A_regBreg等。另请注意,如果这意味着out的时间将被延迟,那么如果需要立即从组合块中推出一个值,则可以始终绕过寄存器。根据我的理解,你可能在重置期间遇到加载问题,这是可以理解的,只要reset(nrst)被置位(即0),什么都不会加载。这是重置的整个点,用于将系统保持在已知状态直到它被提升。因此,在nrst置为无效之前,您的模块不应执行任何操作。其他几点:

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

希望这能为你澄清事情。