简体   繁体   中英

Is there a way I can use an input to determine the clock period?

This program needs to be able to output a sinewave to the testbench, where the frequency of the output signal should be specified by an eight bit input. My understnading is that I need to change the clock period which will alter the frequency of the waveform accordingly.The code is provided below:

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

Testbench

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
always #5 Clk = ~Clk;

This statement is part of your testbench, not part of the UUT. You aren't supposed to change it; the expectation is that the clock frequency remains constant.

Your functionGenerator module currently doesn't make any use of the freq input. You will need to come up with some way to control how quickly the synthesizer steps through the sine array based on the value of freq . This may involve either making less than one step per clk period, or making multiple steps per period, depending on your requirements.

This is a typical case in which a phase-acummulator oscillator is used to generate the ROM address for the new sample to output.

Something like this: the phase accumulator here is 14 bits wide, and we are using the 6 most significant bits to have a sine wave of 64 samples. The output frequency of such sine wave is CLK * freq / 16384

Actually, the ROM has only 16 cells, as it needs only to store one quarter of a sine wave. Bits 3 to 0 from the calculated address from the phase accumulator are used to address the ROM, and bits 5 to 4 are used to find out which quadrant we are in, so the actual address may need to be inverted and/or the actual output may need to be negated.

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

A minimal testbench can be used to let this function generator to run for a thousand or so clock cycles, and then take the output to GTKWave and display it as an analog output:

`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

This is the result, simulated with iverilog / GTKWave:

GTKWave模拟输出

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM