首页 > 解决方案 > 我需要生成如图所示的波形。在verilog代码中

问题描述

我需要生成一个波形,如图所示。但是使用我的代码,我没有得到预期的波形

在设计中,零件从测试台获得了随机周期内的最后一个有效值。我的问题是为什么我的值在有效不等于一时增加

设计代码:

module design_d(clk,valid,last,data);

   input clk,valid,last;
   output reg [7:0] data;

     reg [7:0] i; 
     initial
       begin
       data=0;
       i=0;
      end

always @(posedge clk,valid)
    begin

   if (valid)
   begin
     data<=i;
     i=i+1;
     $display("i=%d data=%d ",i,data);
   end
   else 
     begin
       data <=8'bz; 
     end
    end
endmodule    

测试台代码:

module test;

  reg clk,valid,last;
  wire [7:0] data;

  parameter clk_period=2;

  design_d dut(clk,valid,last,data);

  initial
  begin
    clk=1;
    valid=1;
    last=0;
  end

  always #(clk_period/2) clk=~clk;

  always @(posedge clk)
  begin 
    last=0;
    #4 last=1;
    #clk_period last=0;
    #8 last=1;
    #clk_period last=0;
    #10 last=1;
    #clk_period last=0;
    #16last=1;
    #clk_period last=0;  

    #20 last=1;
    #clk_period last=0;
  end

  always @(posedge clk or last)
  begin
     valid<=1;
     wait(last==1)
     #clk_period;
     valid<=0;
     #clk_period;
     valid<=1;
  end

  initial
  begin 
     $dumpfile("dump.vcd");
     $dumpvars(1);
     #24 $finish;
  end
endmodule

在此处输入图像描述

标签: verilog

解决方案


看来你的英语有困难,这不是你的错,但正因为如此,我可能会错误地解释你的问题。

你有一个你需要实现的波形。这对我来说表明这是一项学校作业,因此我会这样对待它。这意味着我**不会*给你一个完整的答案,但会给你一些关于你哪里出错的指示。(这都应该在评论中,但现在有合适的方式)。

...从测试台获得随机时间段内的最后一个有效值。

首先要意识到的是,编写测试平台与编写 RTL 代码本身一样困难,如果不是更困难的话。

在您的测试台中您正在使用always @(posedge clk)但在该部分中您使用#...语句。这本身并没有错。危险,是的,但没必要错。

但是
您的时钟的时间周期为 2 ( parameter clk_period=2;),并且在您的 posedge 时钟内,您使用的延迟等于或大于时钟周期。正如您所发现的,这通常会导致灾难。
阅读 Verilog 的工作原理,尤其是在使用敏感度列表时always @...:在处理完该部分中的所有语句之前不会触发它。在您的情况下,这意味着它将需要几个时钟边沿,直到再次启动 always 块。

测试台
我不知道任务是什么,所以我会使用你给出的波形。作为模块lastvalid输入,我将为您提供如何制作这些的指示。

valid4 个时钟周期为高电平,然后在 1 个时钟周期为低电平,然后重复。这意味着您需要一个每 5 个时钟周期重复一次的模式,因此您需要制作一个计数 0、1、2、3、4、0、1、2、3、4、...的计数器

你不应该这样做 using#.....语句。您应该使用测试台时钟并制作一个计数的计数器!
制作一个如上所述计数的计数器是您需要在 HDL 中学习的第一件事!你会发现你必须一遍又一遍地这样做……在每一段 RTL 代码和每一个测试台上。

模 5 计数器。

我更喜欢我的所有模块和我的测试台进行重置。如果它允许我从已知状态开始新测试就好了。

reg [2:0] counter;

always @(posedge clk or negedge reset_n)
begin
   if (reset_n)
      counter <= ...
   else // clocked section
   begin
      if (..)
        counter <= ...
      else       
        counter <= ...
   end
end

重新开始并首先运行上述代码。观察计数器确实在运行 0,1 2, 3, 4, 0, .. 在继续之前。

派生信号。
接下来学习从中获取信号。
基本规则:在时钟部分,如果您需要计数器值为 X 的信号,则必须在周期 X-1 生成该信号。

因此,要在计数器为 3 时设置为最后一个高电平,您必须在计数器为 2 时设置它:

always @(posedge clk...
...
   if (counter==3'h2)
      last <= 1'b1;
   else
      last <= 1'b0;

我把有效的留给你。

一旦你开始运行你的测试台,就开始使用你的 design_d 模块。

一些技巧:

  • <=在时钟部分中始终使用非阻塞分配。**

  • 不要使用 2 的时钟周期,使用 100 或 1000。您会在适当的时候发现为什么这样更好。

  • always @(posedge clk or [one or more signals] )除非按照我的示例,否则不要使用。**

  • 注意缩进。我不得不对您的代码进行一些市长编辑。

**抱歉,我无法详细说明为什么大多数时候这是一种好习惯,因为这会使这个答案的大小增加三倍。现在请按照提示操作。

我本可以在我编写所有代码所用时间的十分之一的时间内编写实际代码,因此我希望您不会删除该问题,因为其他人可能会从中受益。


推荐阅读