How to read data in Verilog at a particular clock edge? - Page 1
Forum section: electronics / general

author: knight
author_rank: Regular Contributor
timestamp: August 18, 2022, 03:19:27 am
content: 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:always #(CLK_PERIOD/2) adc_clk = ~adc_clk;always #((CLK_PERIOD/2)*ratio) fpga_clk = ~fpga_clk; // fpga_clk = adc_clk/8fdin = $fopen ("signaldata.txt", "r");nend_file=1;while(nend_file)beginnend_file = $fgets(string, fdin);unused = $sscanf(string, "%d", txt_in);beginadc_data_in_vld = 1'b1;@(posedge adc_clk)adc_data_in = txt_in; // this data should be read at every posedge of adc_clkendendThis is the main code:Code: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)beginif(~rst)beginadc_data_in_vld_dly0 <= 1'b0;adc_data_in_vld_dly1 <= 1'b0;endelsebeginadc_data_in_vld_dly0 <= adc_data_in_vld;adc_data_in_vld_dly1 <= adc_data_in_vld_dly0;endendalways @(posedge fpga_clk or negedge rst)beginif(~rst)start_dly0 <= 1'b0;elsestart_dly0 <= start;end// PHASE WORD GENERATIONinteger i;always @(posedge fpga_clk or negedge rst)beginif (~rst | (sample_count == SAMPLE_COUNT))begintemp <= PHASE_WORD;for (i = 0; i < ratio; i = i + 1)beginphase_word <= 0;endendelsebeginphase_word = temp;for (i = 1; i < ratio; i = i + 1)beginphase_word = phase_word[i-1] + PHASE_WORD;endtemp = phase_word[ratio-1] + PHASE_WORD;endendwire [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 Instantiationgenvar k;generatefor (k = 0; k < ratio; k = k + 1)beginddfs CDC(fpga_clk, rst, phase_word, sin_out, cos_out);endendgenerate// Assign Sin and Cos Valuesgenvar l;generatefor (l = 0; l < ratio; l = l + 1)beginassign sin_data = sin_out;assign cos_data = cos_out;endendgenerate//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 Dataalways @(posedge adc_clk or negedge rst)beginif (~rst)begincount = 0;for (i = 0; i < ratio; i = i + 1)begindata_reg <= 0;endendelseif (count == ratio)count = 0;elsebegindata_reg = adc_data_in;count = count + 1;endendalways @(posedge fpga_clk or negedge rst)beginif (~rst | sample_count == SAMPLE_COUNT)beginfor (i = 0; i < ratio; i = i + 1)beginadc_sample <= 0;endendelsebeginfor (i = 0; i < ratio; i = i + 1)beginadc_sample <= data_reg;endendendreg [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 processingalways @(posedge fpga_clk or negedge rst)beginif (~rst | (sample_count == SAMPLE_COUNT))begintemp_I <= 0;temp_Q <= 0;for (i = 0; i < ratio; i = i + 1)beginaccu_I <= 0;accu_Q <= 0;endendelsebeginif (adc_data_in_vld_dly1)beginaccu_I <= temp_I + cos_data * adc_sample;accu_Q <= temp_Q + sin_data * adc_sample;for (i = 1; i < ratio; i = i + 1)beginaccu_I = accu_I[i-1] + cos_data * adc_sample;accu_Q = accu_Q[i-1] + sin_data * adc_sample;endtemp_I <= accu_I[ratio-1];temp_Q <= accu_Q[ratio-1];endendendassign I_out = temp_I;assign Q_out = temp_Q;always @(posedge fpga_clk or negedge rst)beginif (~rst)sample_count <= 0;else if (adc_data_in_vld_dly0)sample_count <= sample_count + ratio;endalways @(posedge fpga_clk or negedge rst)beginif(~rst)beginstate <= s0;done_int <= 1'b0;endelsebegincase (state)s0: begindone_int <= 1'b0;if(adc_data_in_vld_dly0 & start_dly0)state <= s1;elsestate <= s0;ends1: beginif(sample_count == SAMPLE_COUNT)beginstate <= s2;done_int <= 1'b1;sample_count <= 0;endelsebeginstate <= s1;done_int <= 1'b0;endends2: beginstate <= s0;done_int <= 1'b0;ends3: beginstate <= s0;done_int <= 1'b0;enddefault: state <= s0;endcaseendendassign done = done_int;endmoduleSimulation output:

author: BrianHG
author_rank: Super Contributor
timestamp: August 18, 2022, 03:27:56 am
content: Why not run you FPGA at 'fpga_clk'?

author: knight
author_rank: Regular Contributor
timestamp: August 18, 2022, 03:32:54 am
content: Quote from: BrianHG on August 18, 2022, 03:27:56 amIt runs at fpga_clk only, but adc_data should be clocked at adc_clk.

author: BrianHG
author_rank: Super Contributor
timestamp: August 18, 2022, 03:40:45 am
content: 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.

author: knight
author_rank: Regular Contributor
timestamp: August 18, 2022, 03:50:26 am
content: Quote from: BrianHG on August 18, 2022, 03:40:45 amYes, 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.

author: BrianHG
author_rank: Super Contributor
timestamp: August 18, 2022, 04:00:32 am
content: Then why not do it the old fashioned way?Code:always @(posedge adc_clk) beginlast_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;endwire sample_ena = (pos_counter == 3'd0) ; // choose an enable option for logic running at adc_clk.wire new_core_clock = pos_counter; // create a new clock output.

author: knight
author_rank: Regular Contributor
timestamp: August 18, 2022, 04:17:10 am
content: Quote from: BrianHG on August 18, 2022, 04:00:32 amThis is to be done in the main code?

author: Someone
author_rank: Super Contributor
timestamp: August 18, 2022, 04:26:03 am
content: 3rd iteration of same topic, trapping "new" users:https://www.eevblog.com/forum/fpga/fast-adc-interface-with-fpga/https://www.eevblog.com/forum/fpga/how-to-use-fifo-to-process-fast-adc-data/

author: BrianHG
author_rank: Super Contributor
timestamp: August 18, 2022, 04:31:10 am
content: 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.

author: BrianHG
author_rank: Super Contributor
timestamp: August 18, 2022, 04:33:34 am
content: Quote from: Someone on August 18, 2022, 04:26:03 amIt goes even further back:https://www.eevblog.com/forum/fpga/vhdl-code-to-verilog-code/https://www.eevblog.com/forum/fpga/verilog-right-shift-help/