有没有一种方法可以使用输入来确定时钟周期?

时间:2019-04-26 22:40:08

标签: verilog clock vivado test-bench

该程序需要能够向测试台输出正弦波,其中输出信号的频率应由八位指定 输入。我的理解是,我需要更改时钟周期,这将相应地改变波形的频率。代码如下:

module functionGenerator(Clk,data_out, freq);
//declare input and output
    input [7:0] freq;
    input Clk;
    output [9:0] data_out;
//declare the sine ROM - 30 registers each 8 bit wide.  
    reg [9:0] sine [0:99];
//Internal signals  
    integer i;  
    reg [9:0] data_out;
//Initialize the sine rom with samples. 
    initial begin
        i = 0;
        sine[0] = 0;        sine[1] = 10;        sine[2] = 20;        sine[3] = 29;        sine[4] = 39;   
        sine[5] = 48;       sine[6] = 58;        sine[7] = 67;        sine[8] = 75;        sine[9] = 84;
        sine[10] = 92;      sine[11] = 100;      sine[12] = 107;      sine[13] = 114;      sine[14] = 120;
        sine[15] = 126;     sine[16] = 132;      sine[17] = 137;      sine[18] = 141;      sine[19] = 145;   
        sine[20] = 149;     sine[21] = 151;      sine[22] = 153;      sine[23] = 155;      sine[24] = 156;
        sine[25] = 156;     sine[26] = 156;      sine[27] = 155;      sine[28] = 153;      sine[29] = 151;
        sine[30] = 149;     sine[31] = 145;      sine[32] = 141;      sine[33] = 137;      sine[34] = 132;   
        sine[35] = 126;     sine[36] = 120;      sine[37] = 114;      sine[38] = 107;      sine[39] = 100;
        sine[40] = 92;      sine[41] = 84;       sine[42] = 75;       sine[43] = 67;       sine[44] = 58;
        sine[45] = 48;      sine[46] = 39;       sine[47] = 29;       sine[48] = 20;       sine[49] = 10;   
        sine[50] = 0;       sine[51] = -10;      sine[52] = -20;      sine[53] = -29;      sine[54] = -39;
        sine[55] = -48;     sine[56] = -58;      sine[57] = -67;      sine[58] = -75;      sine[59] = -84;
        sine[60] = -92;     sine[61] = -100;     sine[62] = -107;     sine[63] = -114;     sine[64] = -120;   
        sine[65] = -126;    sine[66] = -132;     sine[67] = -137;     sine[68] = -141;     sine[69] = -145;
        sine[70] = -149;    sine[71] = -151;     sine[72] = -153;     sine[73] = -155;     sine[74] = -156;
        sine[75] = -156;    sine[76] = -156;     sine[77] = -155;     sine[78] = -153;     sine[79] = -151;   
        sine[80] = -149;    sine[81] = -145;     sine[82] = -141;     sine[83] = -137;     sine[84] = -132;
        sine[85] = -126;    sine[86] = -120;     sine[87] = -114;     sine[88] = -107;     sine[89] = -100;
        sine[90] = -92;     sine[91] = -84;      sine[92] = -75;      sine[93] = -67;      sine[94] = -58;
        sine[95] = -48;     sine[96] = -39;      sine[97] = -29;      sine[98] = -20;      sine[99] = -10;
    end

    //At every positive edge of the clock, output a sine wave sample.
    always@ (posedge(Clk))
    begin
        data_out = sine[i];
        i = i+ 1;
        if(i == 99)
            i = 0;
    end

endmodule

测试台

module functionGeneratror_tb();

    // Inputs
    reg Clk;
    reg freq;

    // Outputs
    wire [9:0] data_out;

    // Instantiate the Unit Under Test (UUT)
    functionGenerator uut (
        .Clk(Clk), 
        .data_out(data_out),
        .freq(freq)
    );

    //Generate a clock with 10 ns clock period.
    initial Clk = 0;
    always #5 Clk = ~Clk; // CAN I PASS IN AN INPUT HERE INSTEAD OF 5?
    initial
    #10000 $finish;

endmodule

2 个答案:

答案 0 :(得分:0)

always #5 Clk = ~Clk;

此语句是测试平台的一部分,而不是UUT的一部分。您不应该更改它;期望时钟频率保持恒定。

您的functionGenerator模块当前未使用任何freq输入。您将需要提出一些方法来基于sine的值来控制合成器完成freq数组的速度。根据您的要求,这可能涉及在每个clk期间执行少于一个步骤,或在每个期间执行多个步骤。

答案 1 :(得分:0)

这是典型的情况,其中使用相位累加器振荡器生成ROM地址以供新样本输出。

类似这样的事情:这里的相位累加器为14位宽,我们使用6个最高有效位来产生64个采样的正弦波。这种正弦波的输出频率为CLK * freq / 16384

实际上,ROM只有16个单元,因为它只需要存储四分之一的正弦波。来自相位累加器的计算地址中的位3至0用于寻址ROM,而位5至4用于找出我们所在的象限,因此实际地址可能需要反转和/或实际输出可能需要否定。

module FunctionGenerator (
  input wire clk,
  input wire [7:0] freq, // frequency of output signal is: clk * freq / 16384
  output reg signed [9:0] out
  );

  reg signed [9:0] quartersin[0:15];
  // Generate initial values with this little C program:
  //   #include <stdio.h>
  //   #include <math.h>
  // 
  //   #define PI 3.141592654
  // 
  //   int main()
  //   {
  //     int i;
  //     
  //     for (i=0;i<16;i++)
  //     {
  //         printf ("    quartersin[%2d] = %d;\n", i, (int)(511*sin(i*2*PI/64.0)));
  //     }
  //
  //     return 0;
  //   }
  initial begin
    quartersin[ 0] = 0;
    quartersin[ 1] = 50;
    quartersin[ 2] = 99;
    quartersin[ 3] = 148;
    quartersin[ 4] = 195;
    quartersin[ 5] = 240;
    quartersin[ 6] = 283;
    quartersin[ 7] = 324;
    quartersin[ 8] = 361;
    quartersin[ 9] = 395;
    quartersin[10] = 424;
    quartersin[11] = 450;
    quartersin[12] = 472;
    quartersin[13] = 488;
    quartersin[14] = 501;
    quartersin[15] = 508;
  end

  reg [13:0] phaseacum = 14'h0000;
  reg [3:0] indx;
  always @(posedge clk) begin
    phaseacum <= phaseacum + {6'b000000, freq};
    if (phaseacum[13] == 1'b0)  // if in quadrants 0 or 1, out as is
      out <= quartersin[indx];
    else
      out <= -quartersin[indx];  // if in quadrants 2 or 3, negate out
  end

  always @* begin
    if (phaseacum[12] == 1'b0)   // which quadrant am I ?
      indx = phaseacum[11:8];  // if in quadrant 0 or 2
    else
      indx = ~phaseacum[11:8]; // else, in quadrant 1 or 3
    endcase
  end
endmodule

可以使用最小的测试平台使该函数生成器运行一千个时钟周期,然后将输出输出到GTKWave并将其显示为模拟输出:

`timescale 1ns / 1ns

module tb;
  reg clk;
  reg [7:0] freq;
  wire [9:0] out;

  FunctionGenerator uut (
    .clk(clk),
    .freq(freq),
    .out(out)
  );

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(1,uut);

    clk = 1'b0;
    freq = 8'd16;  // aprox. 1 kHz sine wave for a 1 MHz clk

    repeat (2000) begin
      @(posedge clk);
    end
    $finish;
  end

  always begin
    clk = #500 ~clk;  // a 1 MHz clock
  end
endmodule

这是用iverilog / GTKWave模拟的结果:

GTKWave simulated output