Author Topic: How to read data in Verilog at a particular clock edge?  (Read 1054 times)

0 Members and 1 Guest are viewing this topic.

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
How to read data in Verilog at a particular clock edge?
« on: August 18, 2022, 03:19:27 am »
I'm trying to simulate the following code block in Verilog testbench but the data doesn't get read at the desired clock frequency.
Code: [Select]
always #(CLK_PERIOD/2) adc_clk = ~adc_clk;
always #((CLK_PERIOD/2)*ratio) fpga_clk = ~fpga_clk;  // fpga_clk = adc_clk/8

fdin = $fopen ("signaldata.txt", "r");
    nend_file=1;
       
    while(nend_file)
    begin       
        nend_file = $fgets(string, fdin);
        unused = $sscanf(string, "%d", txt_in);
        begin
                adc_data_in_vld = 1'b1;
                @(posedge adc_clk)
                adc_data_in = txt_in; // this data should be read at every posedge of adc_clk

        end
    end


This is the main code:
Code: [Select]
module raw_sp(fpga_clk, adc_clk, rst, adc_data_in_vld, adc_data_in, start, I_out, Q_out, done);
    parameter ADC_DATA_WIDTH = 16;
    parameter ratio = 8;
    parameter shift_reg_size = ADC_DATA_WIDTH * ratio;
   
    input fpga_clk;
    input adc_clk;
    input rst;
    input adc_data_in_vld;
    input signed [ADC_DATA_WIDTH-1:0] adc_data_in;
    input start;
    output [47:0] I_out;
    output [47:0] Q_out;
    output done;
   
    localparam READOUT_SIGNAL_FREQ = 1000000;
    localparam ADC_SAMPLE_SIZE = 65536;
    localparam ADC_SR = 1966080000;
    localparam SAMPLE_COUNT = ADC_SAMPLE_SIZE/ratio;
    localparam NCO_BITS = 20;
    localparam s0=2'd0, s1=2'd1, s2=2'd2, s3=2'd3;
    real PHASE_WORD = (READOUT_SIGNAL_FREQ * (2**(NCO_BITS)))/(ADC_SR/ratio);
   
    reg [NCO_BITS-1:0] phase_word [ratio-1:0];
 
    reg [15:0] sample_count;
    reg [NCO_BITS-1:0] temp;
   
    reg adc_data_in_vld_dly0;
    reg adc_data_in_vld_dly1;
    reg start_dly0;
    reg done_int;
    reg [1:0] state;
   
    always @(posedge fpga_clk or negedge rst)
        begin
            if(~rst)
                begin
                    adc_data_in_vld_dly0 <= 1'b0;
                    adc_data_in_vld_dly1 <= 1'b0;
                end
            else
                begin
                    adc_data_in_vld_dly0 <= adc_data_in_vld;
                    adc_data_in_vld_dly1 <= adc_data_in_vld_dly0;
                end
        end
       
    always @(posedge fpga_clk or negedge rst)
        begin
            if(~rst)
                    start_dly0 <= 1'b0;
            else
                    start_dly0 <= start; 
        end
   
    // PHASE WORD GENERATION
    integer i;
    always @(posedge fpga_clk or negedge rst)
        begin
            if (~rst | (sample_count == SAMPLE_COUNT))
                begin
                    temp <= PHASE_WORD;
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            phase_word[i] <= 0;
                        end   
                end
            else
                begin
                    phase_word[0] = temp;
                    for (i = 1; i < ratio; i = i + 1)
                        begin
                            phase_word[i] = phase_word[i-1] + PHASE_WORD;
                        end
                    temp = phase_word[ratio-1] + PHASE_WORD;
                end         
        end
           
    wire [15:0] sin_out [ratio-1:0];
    wire [15:0] cos_out [ratio-1:0];
    wire [15:0] sin_data [ratio-1:0];
    wire [15:0] cos_data [ratio-1:0];
   
    // CORDIC Module Instantiation
    genvar k;
    generate
        for (k = 0; k < ratio; k = k + 1)
            begin
                ddfs CDC(fpga_clk, rst, phase_word[k], sin_out[k], cos_out[k]);
            end
    endgenerate
       
    // Assign Sin and Cos Values   
    genvar l;
    generate
        for (l = 0; l < ratio; l = l + 1)
            begin
                assign sin_data[l] = sin_out[l];
                assign cos_data[l] = cos_out[l];
            end
    endgenerate
   
    //reg signed [shift_reg_size-1:0] shift_reg;
    reg signed [ADC_DATA_WIDTH-1:0] adc_sample [ratio-1:0];
    reg signed [ADC_DATA_WIDTH-1:0] data_reg [ratio-1:0];
    integer count;
    // Shift register to input incoming ADC Data
    always @(posedge adc_clk or negedge rst)
        begin
            if (~rst)
                begin
                    count = 0;
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            data_reg[i] <= 0;
                        end
                end
            else
                if (count == ratio)
                    count = 0;
                else
                    begin
                        data_reg[count] = adc_data_in;
                        count = count + 1;
                    end
        end
   
    always @(posedge fpga_clk or negedge rst)
        begin
            if (~rst | sample_count == SAMPLE_COUNT)
                begin
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            adc_sample[i] <= 0;
                        end
                end
            else
                begin
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            adc_sample[i] <= data_reg[i];
                        end
                end
        end       
   
    reg [47:0] accu_I [ratio-1:0];
    reg [47:0] accu_Q [ratio-1:0];
    reg [47:0] temp_I, temp_Q;
    // I, Q data processing   
    always @(posedge fpga_clk or negedge rst)
        begin
            if (~rst | (sample_count == SAMPLE_COUNT))
                begin
                    temp_I <= 0;
                    temp_Q <= 0;
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            accu_I[i] <= 0;
                            accu_Q[i] <= 0;
                        end
                end
            else
                begin
                    if (adc_data_in_vld_dly1)
                    begin
                    accu_I[0] <= temp_I + cos_data[0] * adc_sample[0];
                    accu_Q[0] <= temp_Q + sin_data[0] * adc_sample[0];
                    for (i = 1; i < ratio; i = i + 1)
                        begin
                            accu_I[i] = accu_I[i-1] + cos_data[i] * adc_sample[i];
                            accu_Q[i] = accu_Q[i-1] + sin_data[i] * adc_sample[i];
                        end
                    temp_I <= accu_I[ratio-1];
                    temp_Q <= accu_Q[ratio-1];
                    end
                end
        end
     
    assign I_out = temp_I;
    assign Q_out = temp_Q;
   
    always @(posedge fpga_clk or negedge rst)
        begin
            if (~rst)
                sample_count <= 0;
            else if (adc_data_in_vld_dly0)
                sample_count <= sample_count + ratio;
        end
       
    always @(posedge fpga_clk or negedge rst)
        begin
            if(~rst)
                begin
                    state <= s0;
                    done_int <= 1'b0;
                end
            else
                begin
                    case (state)
                        s0: begin
                            done_int <= 1'b0;
                            if(adc_data_in_vld_dly0 & start_dly0)
                                state <= s1;
                            else
                                state <= s0;
                            end
           
                        s1: begin
                            if(sample_count == SAMPLE_COUNT)
                                begin
                                    state <= s2;
                                    done_int <= 1'b1;
                                    sample_count <= 0;
                                end
                            else
                                begin
                                    state <= s1;
                                    done_int <= 1'b0;
                                end
                            end
           
                        s2: begin
                            state <= s0;
                            done_int <= 1'b0;
                            end
           
                        s3: begin
                            state <= s0;
                            done_int <= 1'b0;
                            end
           
                        default: state <= s0;
                    endcase
                end
        end

    assign done = done_int;   
                       
endmodule


Simulation output:
« Last Edit: August 18, 2022, 03:52:20 am by knight »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: How to read data in Verilog at a particular clock edge?
« Reply #1 on: August 18, 2022, 03:27:56 am »
Why not run you FPGA at 'fpga_clk'?
 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: How to read data in Verilog at a particular clock edge?
« Reply #2 on: August 18, 2022, 03:32:54 am »
Why not run you FPGA at 'fpga_clk'?
It runs at fpga_clk only, but adc_data should be clocked at adc_clk.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: How to read data in Verilog at a particular clock edge?
« Reply #3 on: August 18, 2022, 03:40:45 am »
Ok, clocking at ADC clock may be too fast for your FPGA fabric then.  Any code you make will then need to run at that frequency.

where does ADC clock come from?
Is it at that frequency we see in your snapshot?

Not that this is what usually PLLs are for.
They are designed to multiply and divide clock sources with multiple outputs whose phase you may set in relation to each other.

Otherwise, what you ask is ok, it's just that you would be running your code at the ADC frequency.
The PLL built into  or part of de-serializer also should have this functionality.
« Last Edit: August 18, 2022, 03:42:59 am by BrianHG »
 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: How to read data in Verilog at a particular clock edge?
« Reply #4 on: August 18, 2022, 03:50:26 am »
Ok, clocking at ADC clock may be too fast for your FPGA fabric then.  Any code you make will then need to run at that frequency.

where does ADC clock come from?
Is it at that frequency we see in your snapshot?

Not that this is what usually PLLs are for.
They are designed to multiply and divide clock sources with multiple outputs whose phase you may set in relation to each other.

Otherwise, what you ask is ok, it's just that you would be running your code at the ADC frequency.
The PLL built into  or part of de-serializer also should have this functionality.
Yes, just for simulation purpose I'm asking. I want the adc_data_in to be read at every posedge of adc_clk but it looks like it's synchronized to be read at fpga_clk. I have posted the main code as well for reference.
« Last Edit: August 18, 2022, 03:52:57 am by knight »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: How to read data in Verilog at a particular clock edge?
« Reply #5 on: August 18, 2022, 04:00:32 am »
Then why not do it the old fashioned way?

Code: [Select]
always @(posedge adc_clk) begin

     last_fpga_clk <= fpga_clk;
     if (!last_fpga_clk && fpga_clk ) pos_counter <= 3'd0; // Change this number to synthesize a selected sample position.
     else pos_counter <= pos_counter +3'd1;

end

wire sample_ena      = (pos_counter == 3'd0) ; // choose an enable option for logic running at adc_clk.
wire new_core_clock  = pos_counter[2];          // create a new clock output.
 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: How to read data in Verilog at a particular clock edge?
« Reply #6 on: August 18, 2022, 04:17:10 am »
Then why not do it the old fashioned way?

Code: [Select]
always @(posedge adc_clk) begin

     last_fpga_clk <= fpga_clk;
     if (!last_fpga_clk && fpga_clk ) pos_counter <= 3'd0; // Change this number to synthesize a selected sample position.
     else pos_counter <= pos_counter +3'd1;

end

wire sample_ena      = (pos_counter == 3'd0) ; // choose an enable option for logic running at adc_clk.
wire new_core_clock  = pos_counter[2];          // create a new clock output.
This is to be done in the main code?
 

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4525
  • Country: au
    • send complaints here
 
The following users thanked this post: Bassman59, BrianHG

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: How to read data in Verilog at a particular clock edge?
« Reply #8 on: August 18, 2022, 04:31:10 am »
I though this was for your testbench.
You are creating a new 'clock' or 'enable' signal to drive your code.
You can place it in you code.
You can also change the conditions of the 'if (!last_fpga_clk && fpga_clk )', this one being a clock period beginning at the rise of the fpga_clk.

It was for synthesizing a new clock for your FPGA code.

'adc_clk' looks to be too fast for generic FPGA logic code like this.  It looks to be around 2GHz.
On the other hand, if you are making an asic, then my code can easily be done as a software 3 bit counter running at 2GHz hardwired on silicon is an easy feat.
 



Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf