【问题标题】:Verilog: assigning value to regVerilog:为reg赋值
【发布时间】:2023-03-26 16:53:02
【问题描述】:

我有一个关于 Verilog 的非常初学者的问题,希望得到一些帮助。

您可以在下面看到一个简单计数器的代码:

  1. 输入:单时钟信号,接时钟
  2. 输入:复位信号,与物理按键相连
  3. 输出:计数器输出
  4. 输出:led 等于复位输入

奇怪的行为是,当复位信号为高电平时,计数器不会复位为零。 在板上我可以看到当我按下按钮时 LED 会打开和关闭,所以复位是真的,但是 if 指令 internal_counter <= 0; 没有执行(?)

我正在使用 Quartus Prime II Lite 和 DE-10 Nano Terasic 板

有什么建议吗?谢谢!

//Single clock input and a 32bit output port
    //reset will zero the internal_counter 
    module simple_counter (
                                    CLOCK_50,
                                    counter_out,
                                    reset,
                                    led
                                );          

    input CLOCK_50 ;
    input reset ;
    output led;
    output [31:0] counter_out;
    reg [31:0] counter_out;
    reg [31:0] internal_counter;
    reg led;

    always @ (posedge CLOCK_50) // on positive clock edge
        begin
            if (reset)
                        internal_counter <= 0;

            led <= reset;
            internal_counter <= internal_counter + 1;
            counter_out <= internal_counter;// increment counter
        end

    endmodule // end of module counter

【问题讨论】:

  • 只需在 `led
  • 你对internal_counter 的哪个分配有效?
  • 嗨@RAMAKRISHNAMEDA,谢谢你的建议。正如 Seaotter211 和 Oldfart 所建议的那样,我实现了它并工作了。干杯!
  • 嗨@TomServo,这是我早先应该问自己的问题:) 显然这是最后一个问题。干杯!

标签: verilog


【解决方案1】:

您的代码不起作用,因为您对internal_counter 进行了两次分配。这是允许的,但规则是最后一个分配“获胜”

所以让我们在重置激活时单步执行代码:

if (reset)   
  internal_counter <= 0; 

这使得internal_counter 被重置(设置为零)。
但后来我们得到了另一个任务:

internal_counter <= internal_counter + 1;

因为这个任务在前一个任务之后/后面,所以它“获胜”。这里没有 no 条件,所以这个 always 替换了之前的 if ...。这样if... 代码就变得多余了。它永远不会被执行,综合工具将为此删除任何逻辑。

正如其他人指出的那样:您需要一个 else 部分。最好在重置部分重置所有变量:

always @ (posedge CLOCK_50) // on positive clock edge
begin
   if (reset)
   begin
      internal_counter <= 0;
      led <= 1'b1; 
      counter_out  <= 0;
   end // reset section
   else
   begin // clocked section
      internal_counter <= internal_counter + 1;
      led <= 1'b0; 
      counter_out <= internal_counter; 
   end
end // clocked section 

现在我们得到一些一般性的评论:

我建议您切换到 ANSI 端口定义。当你把所有东西放在一起时会更容易。如果您需要更改,例如counter_out 的宽度你可以在一个地方做到这一点:

module simple_counter (
    input      CLOCK_50 ,
    input      reset ,
    output reg led,
    output reg [31:0] counter_out  
   ); 

你的led 有点奇怪。复位时为高电平,否则为低电平。我假设你这样做是为了调试。

counter_out 始终是 internal_counter 后面的一个值。这是你想要的吗?它还花费您 32 个额外的寄存器。我希望不使用内部计数器并直接使用 counter_out:

always @ (posedge CLOCK_50) // on positive clock edge
begin
   if (reset)
   begin
      led <= 1'b1; 
      counter_out  <= 0;
   end // reset section
   else
   begin // clocked section
      led <= 1'b0; 
      counter_out <= counter_out + 1; 
   end
end // clocked section 

【讨论】:

  • 您好 Oldfart,感谢您的回复。我非常感谢您花时间解释“最后分配获胜”规则和 ANSI 端口定义的好处。你是对的,led 变量是用来调试的,很明显!对于 intenal_counter: 再次,我应该把它拿走。再次感谢,非常感谢。
【解决方案2】:

我不知道您的代码为什么不起作用。我现在使用 VHDL。 但是,我会这样写:

module simple_counter (CLOCK_50, reset, led, counter_out);          

    input CLOCK_50 ;
    input reset ;
    output led;
    output [31:0] counter_out;

    reg [31:0] internal_counter;

    always @ (posedge CLOCK_50)
      begin
         if (reset)
            internal_counter <= 0;
         else
            internal_counter <= internal_counter + 1;

         led <= reset;
         counter_out <= internal_counter;
      end
endmodule

【讨论】:

  • 非常感谢 Seaotter211,您的结构看起来更好!我会执行你的建议并让你知道结果。再次干杯!
  • 太好了,成功了。我不知道“最后一个任务获胜”的规则,只是添加一个 else 语句就可以了。谢谢SeaOtter211!
【解决方案3】:

我建议使用 Verilog-2001 变体进行更多改进,但您的代码无法正常工作,因为在重置期间您分配了 internal_counter &lt;= 0internal_counter &lt;= internal_counter + 1'b1,所以通常当您像这样进行修改时,工具将进行第二次分配在重置条件下,因此它不会导致分配给 0.. 我在您的代码中添加了 reset_synchronizer,因此您可能不会在此实现中遇到 led 的开/关问题(基于您使用的某些开关,它也可能不起作用)。

module simple_counter (
   input             clock_50
  ,input             reset
  ,output reg        led
  ,output reg [31:0] counter_out
);

reg [9:0] reset_sync = 10'h3_FF;
reg       system_reset = 1'b1 ;

// to remove glitches in PUSH Button reset
always@(posedge clock_50) begin
      reset_sync   <= #1  {reset_sync[8:0],reset};
      system_reset <= #1 &(reset_sync[9:2]);
end

always@(posedge clock_50)begin
  if (system_reset) begin
        led         <= #1 1'b0;
        counter_out <= #1 32'b0;
  end else begin
        led         <= #1 1'b1;
        counter_out <= #1 counter_out + 1'b1 ;// increment counter
  end
 end

endmodule

【讨论】:

  • 同步不需要10个寄存器,2个就够了。您的重置同步有缺陷,因为它没有导致问题的初始值:您如何重置重置电路?有解决方案,但它们超出了这个问题的范围。
  • 感谢oldfart,我修改了代码,忘了做reduce和操作,谢谢指出
  • 谢谢@RAMAKRISHNAMEDA,reset_sync 的有趣解决方案。非常感谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 2014-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多