【问题标题】:multiple drive issue when receiving inputs from external source in verilog synthesis在 Verilog 综合中从外部源接收输入时出现多驱动问题
【发布时间】:2018-05-22 03:26:42
【问题描述】:

我正在尝试进行的合成是在 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_reg 和 Bint_reg 是寄存器,保存操作后寄存器的中间值,只在时钟上升时将它们发送回 A_reg 和 B_reg,

act 决定机器是否处于“开启”模式并可以执行算法

nrst 是负复位切换

问题是如何形成的:

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

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

附言我使用A_reg = A 的事实创建了闩锁,因为我没有分配给其他任何地方的A_reg,这是自编写以来的另一个问题
Aint_reg = A_reg; A_reg = Aint_reg;
满足闩锁不适合我。

p.s.2。我尝试在网站上查看类似的问题,但由于我对该主题缺乏足够的知识,我无法将我的问题与那里的问题联系起来

很高兴得到任何帮助,谢谢

编辑:我删除了 if(~nrst) 顺序块中的非阻塞分配,以免在组合块中多重分配 A_reg &lt;= 0A_reg = A,但多重分配问题仍然以某种方式困扰它

EDIT2: 似乎我忘记了一个基本的事情——不要在两个不同的“总是”块中分配给同一个变量,但我只是想不出一个足够好的解决方案来分配将 A、B 线连接到一个寄存器,而不是在顺序块中再次分配给它

【问题讨论】:

  • 我会尝试提出一个体面的问题 - 不幸的是我没有看到一个:(
  • 抱歉,我好像陷入了沉思。我想知道如何避免出现的多驱动器问题,因为我在组合块和顺序块中都为 A、B 分配了值。

标签: verilog synthesis greatest-common-divisor elaboration


【解决方案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等。另请注意,如果这意味着输出的时间将被延迟,因此如果您需要立即从组合块中推出一个值,您可以随时绕过寄存器。据我了解,您可能会在重置期间遇到加载问题,这是可以理解的,只要断言重置(nrst)(即 0),什么都不会加载。这是重置的全部要点,将系统保持在已知状态直到它被解除。所以在nrst 被置低之前,你的模块不应该做任何事情。其他几点:

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

希望这可以为您澄清事情。

【讨论】:

  • 首先,你的语法是对的,我写的代码没有使用标签(我在一个 linux 环境下工作,一个朋友向我推荐了一个代码段,它自动使它们成为在其他 Windows 平台上)。关于你在 case 语句之前编写的代码段,我不太了解一件事——正如我所说,A 和 B 是保存来自外部源的值的线,A_reg 可能是“A”(对于B_reg) 在段中,Aint_reg 代表 nextA。你的意思是我应该在开头写 A_reg=A 来放置初始值? ........
  • ......这确实意味着我不需要在案例中分配给 A_reg ,因为它在它的外部,但话又说回来,因为它是一个 always@(*) 条件,即使我正在计算输出,它不会总是将线值放入 A_reg 吗?
  • @RomanAndreevitchBiriukov 我分享的代码段只是一个模板,并没有直接解决您的代码需要采用的形式。我已经更新以使这一点更清楚;再加上几个 cmets,看看一切是如何融合在一起的
  • 希望这能阐明此类代码的一般结构,然后您可以将其调整为您自己的。请注意,如果当前实施存在特定的时间问题,则需要您提出更深入的要求,以便我们提供帮助。
  • 谢谢,您的编辑使其更清晰。就像我在上次编辑中所写的那样,我正在尝试解决如何将 A、B 线的初始值分配到寄存器中(在我开始操作之前),而不会出现诸如分配 (A_reg = A) 之类的多驱动器情况在初始 always 块中,并在顺序中分配 (A_reg=Aint_reg) - 因为这是在 2 个不同的 always 块中分配 2 个不同的值,这是不可合成的。我感谢您到现在为止的帮助,希望我不会打扰您过度解释,因为到目前为止,您的帮助远远超出了我的需要。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
相关资源
最近更新 更多